From 8035f92dbdeee5659bc3b0fca36c2068d2b1f07f Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 17 Mar 2023 11:49:58 -0400 Subject: [PATCH 01/17] Fix findClosestVersionTagLessThanVersion in release tool (#7374) Signed-off-by: Sebastian Malton --- packages/release-tool/src/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/release-tool/src/index.ts b/packages/release-tool/src/index.ts index 7d795acc38..9e30cf29a5 100755 --- a/packages/release-tool/src/index.ts +++ b/packages/release-tool/src/index.ts @@ -120,7 +120,7 @@ function findClosestVersionTagLessThanVersion(tags: string[], version: SemVer): .filter(isDefined) .filter(version => !version.prerelease.includes("cron")) .sort(semver.rcompare) - .filter(version => semver.lte(version, version)); + .filter(v => semver.lte(v, version)); assert(lessThanTags.length > 0, `Cannot find version tag less than ${version.format()}`); From d7b2202c1f9e72683174645a3d876a6f94f8697c Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Fri, 17 Mar 2023 19:57:32 +0300 Subject: [PATCH 02/17] Fix catalog & workloads table view (#7371) * Fix catalog list table view Signed-off-by: Alex Andreev * Wrap ingresses rules Signed-off-by: Alex Andreev * Reduce Badge sizing Signed-off-by: Alex Andreev * Do not text-overflow:ellipsis in Pod names Signed-off-by: Alex Andreev * Save a room to table head cells Signed-off-by: Alex Andreev * Update snapshots Signed-off-by: Alex Andreev --------- Signed-off-by: Alex Andreev --- .../entity-running.test.tsx.snap | 8 +-- .../opening-entity-details.test.tsx.snap | 56 +++++++++---------- .../components/+catalog/catalog.module.scss | 4 ++ .../renderer/components/+catalog/catalog.tsx | 3 + .../+network-ingresses/ingresses.scss | 3 +- .../components/+workloads-pods/pods.tsx | 16 +++--- .../components/badge/badge.module.scss | 3 +- .../line-progress/line-progress.scss | 1 + .../renderer/components/table/table-cell.scss | 48 ++++++---------- .../renderer/components/table/table-head.scss | 2 + 10 files changed, 72 insertions(+), 72 deletions(-) diff --git a/packages/core/src/features/catalog/__snapshots__/entity-running.test.tsx.snap b/packages/core/src/features/catalog/__snapshots__/entity-running.test.tsx.snap index 2d5653372c..8586d4538c 100644 --- a/packages/core/src/features/catalog/__snapshots__/entity-running.test.tsx.snap +++ b/packages/core/src/features/catalog/__snapshots__/entity-running.test.tsx.snap @@ -490,10 +490,10 @@ exports[`entity running technical tests when navigated to catalog renders 1`] = style="position: relative; height: 420000px; width: 100%; overflow: auto; will-change: transform; direction: ltr;" >
{ {...getCategoryColumns({ activeCategory })} onDetails={this.props.onCatalogEntityListClick} renderItemMenu={this.renderItemMenu} + tableProps={{ + customRowHeights: () => 36, // Entity avatar size + padding + }} data-testid={`catalog-list-for-${activeCategory?.metadata.name ?? "browse-all"}`} /> ); diff --git a/packages/core/src/renderer/components/+network-ingresses/ingresses.scss b/packages/core/src/renderer/components/+network-ingresses/ingresses.scss index 4c6d5a75c1..f0b754d03d 100644 --- a/packages/core/src/renderer/components/+network-ingresses/ingresses.scss +++ b/packages/core/src/renderer/components/+network-ingresses/ingresses.scss @@ -12,7 +12,7 @@ &.rules { flex-grow: 3.0; overflow-x: scroll; - text-overflow: unset; + flex-wrap: wrap; &::-webkit-scrollbar { display: none; @@ -20,7 +20,6 @@ .ingressRule { overflow: hidden; - text-overflow: ellipsis; } .ingressRule + .ingressRule { diff --git a/packages/core/src/renderer/components/+workloads-pods/pods.tsx b/packages/core/src/renderer/components/+workloads-pods/pods.tsx index 849a101ae1..1132c00a0c 100644 --- a/packages/core/src/renderer/components/+workloads-pods/pods.tsx +++ b/packages/core/src/renderer/components/+workloads-pods/pods.tsx @@ -29,6 +29,7 @@ import nodeApiInjectable from "../../../common/k8s-api/endpoints/node.api.inject import eventStoreInjectable from "../+events/store.injectable"; import podStoreInjectable from "./store.injectable"; import { NamespaceSelectBadge } from "../+namespaces/namespace-select-badge"; +import { Tooltip } from "../tooltip"; enum columnId { name = "name", @@ -163,13 +164,14 @@ class NonInjectedPods extends React.Component { { title: "Status", className: "status", sortBy: columnId.status, id: columnId.status }, ]} renderTableContents={pod => [ - , + <> + + {pod.getName()} + + + {pod.getName()} + + , , and there is not enough space to show all the content &.sorting.nowrap { display: flex; align-items: center; + } - > * { - flex-shrink: 0; - } + .sortIcon { + transition: 150ms opacity; + opacity: 0; + position: absolute; + right: 0; + background: var(--tableHeaderBackground); - > .content { - flex-shrink: 1; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - } - - > .sortIcon { - margin: 0; + &.enabled { + opacity: 1; } } - .Table.sortable > .TableHead & { - user-select: none; - white-space: nowrap; + &:hover .sortIcon { + opacity: 1; + } - &.sorting { - cursor: pointer; - } - - .sortIcon { - transition: 350ms opacity; - opacity: .3; - - &.enabled { - opacity: 1; - } - } + &.sorting { + cursor: pointer; } a { diff --git a/packages/core/src/renderer/components/table/table-head.scss b/packages/core/src/renderer/components/table/table-head.scss index ca51e39d63..c58600b038 100644 --- a/packages/core/src/renderer/components/table/table-head.scss +++ b/packages/core/src/renderer/components/table/table-head.scss @@ -9,6 +9,8 @@ color: var(--tableHeaderColor); display: flex; flex-shrink: 0; + user-select: none; + white-space: nowrap; &.topLine { border-top: 1px solid var(--borderFaintColor); From 37513dee29bbf94cc0c755b96a87e1a7ecc6a7a2 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Fri, 17 Mar 2023 12:59:57 -0400 Subject: [PATCH 03/17] Remove direct dependency on 'abort-controller' package (#7366) Signed-off-by: Sebastian Malton --- package-lock.json | 2 -- packages/core/package.json | 1 - packages/core/src/common/fetch/timeout-controller.ts | 4 +++- packages/core/src/common/k8s-api/__tests__/kube-api.test.ts | 1 - packages/core/src/common/k8s-api/kube-api.ts | 1 - packages/core/src/common/k8s-api/kube-object.store.ts | 1 - packages/core/src/main/k8s-request.injectable.ts | 4 ++-- packages/core/src/renderer/kube-watch-api/kube-watch-api.ts | 1 - packages/open-lens/package.json | 1 - packages/utility-features/utilities/src/abort-controller.ts | 2 -- packages/utility-features/utilities/src/delay.ts | 2 -- packages/utility-features/utilities/src/reject-promise.ts | 2 -- 12 files changed, 5 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2b313d03d2..dc05949860 100644 --- a/package-lock.json +++ b/package-lock.json @@ -34401,7 +34401,6 @@ "@sentry/electron": "^3.0.8", "@sentry/integrations": "^6.19.3", "@side/jest-runtime": "^1.1.0", - "abort-controller": "^3.0.0", "auto-bind": "^4.0.0", "await-lock": "^2.2.2", "byline": "^5.0.0", @@ -36702,7 +36701,6 @@ "@types/webpack-dev-server": "^4.7.2", "@types/webpack-env": "^1.18.0", "@types/webpack-node-externals": "2.5.3", - "abort-controller": "^3.0.0", "autoprefixer": "^10.4.13", "circular-dependency-plugin": "^5.2.2", "concurrently": "^7.6.0", diff --git a/packages/core/package.json b/packages/core/package.json index bf304a4c13..deceb2161c 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -134,7 +134,6 @@ "@sentry/electron": "^3.0.8", "@sentry/integrations": "^6.19.3", "@side/jest-runtime": "^1.1.0", - "abort-controller": "^3.0.0", "auto-bind": "^4.0.0", "await-lock": "^2.2.2", "byline": "^5.0.0", diff --git a/packages/core/src/common/fetch/timeout-controller.ts b/packages/core/src/common/fetch/timeout-controller.ts index 702becdc9d..c4688218db 100644 --- a/packages/core/src/common/fetch/timeout-controller.ts +++ b/packages/core/src/common/fetch/timeout-controller.ts @@ -3,13 +3,15 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ +import { formatDuration } from "@k8slens/utilities"; + /** * Creates an AbortController with an associated timeout * @param timeout The number of milliseconds before this controller will auto abort */ export function withTimeout(timeout: number): AbortController { const controller = new AbortController(); - const id = setTimeout(() => controller.abort(), timeout); + const id = setTimeout(() => controller.abort(`Operation timed out: timeout ${formatDuration(timeout)}`), timeout); controller.signal.addEventListener("abort", () => clearTimeout(id)); diff --git a/packages/core/src/common/k8s-api/__tests__/kube-api.test.ts b/packages/core/src/common/k8s-api/__tests__/kube-api.test.ts index 2b3978c0eb..eaa355d0e0 100644 --- a/packages/core/src/common/k8s-api/__tests__/kube-api.test.ts +++ b/packages/core/src/common/k8s-api/__tests__/kube-api.test.ts @@ -19,7 +19,6 @@ import { flushPromises } from "@k8slens/test-utils"; import createKubeJsonApiInjectable from "../create-kube-json-api.injectable"; import type { IKubeWatchEvent } from "../kube-watch-event"; import type { KubeJsonApiDataFor } from "../kube-object"; -import AbortController from "abort-controller"; import setupAutoRegistrationInjectable from "../../../renderer/before-frame-starts/runnables/setup-auto-registration.injectable"; import { createMockResponseFromStream, createMockResponseFromString } from "../../../test-utils/mock-responses"; import storesAndApisCanBeCreatedInjectable from "../../../renderer/stores-apis-can-be-created.injectable"; diff --git a/packages/core/src/common/k8s-api/kube-api.ts b/packages/core/src/common/k8s-api/kube-api.ts index 95210478a1..f34ef6bdbb 100644 --- a/packages/core/src/common/k8s-api/kube-api.ts +++ b/packages/core/src/common/k8s-api/kube-api.ts @@ -20,7 +20,6 @@ import type { Patch } from "rfc6902"; import assert from "assert"; import type { PartialDeep } from "type-fest"; import type { Logger } from "../logger"; -import type AbortController from "abort-controller"; import { matches } from "lodash/fp"; import { makeObservable, observable } from "mobx"; diff --git a/packages/core/src/common/k8s-api/kube-object.store.ts b/packages/core/src/common/k8s-api/kube-object.store.ts index f26b05283e..09b26d4142 100644 --- a/packages/core/src/common/k8s-api/kube-object.store.ts +++ b/packages/core/src/common/k8s-api/kube-object.store.ts @@ -17,7 +17,6 @@ import type { Patch } from "rfc6902"; import type { Logger } from "../logger"; import assert from "assert"; import type { PartialDeep } from "type-fest"; -import AbortController from "abort-controller"; import type { ClusterContext } from "../../renderer/cluster-frame-context/cluster-frame-context"; import autoBind from "auto-bind"; diff --git a/packages/core/src/main/k8s-request.injectable.ts b/packages/core/src/main/k8s-request.injectable.ts index 70ca3c3b6e..efa9df1fe7 100644 --- a/packages/core/src/main/k8s-request.injectable.ts +++ b/packages/core/src/main/k8s-request.injectable.ts @@ -34,8 +34,8 @@ const k8sRequestInjectable = getInjectable({ ) => { const controller = timeout ? withTimeout(timeout) : undefined; - if (controller) { - signal?.addEventListener("abort", () => controller.abort()); + if (controller && signal) { + signal.addEventListener("abort", () => controller.abort()); } const response = await lensFetch(`/${cluster.id}${pathnameAndQuery}`, { diff --git a/packages/core/src/renderer/kube-watch-api/kube-watch-api.ts b/packages/core/src/renderer/kube-watch-api/kube-watch-api.ts index f3dc0ae237..cf6e6486e8 100644 --- a/packages/core/src/renderer/kube-watch-api/kube-watch-api.ts +++ b/packages/core/src/renderer/kube-watch-api/kube-watch-api.ts @@ -8,7 +8,6 @@ import { disposer, getOrInsert, noop, WrappedAbortController } from "@k8slens/ut import { once } from "lodash"; import type { Logger } from "../../common/logger"; import type { KubeObjectStoreLoadAllParams, KubeObjectStoreSubscribeParams } from "../../common/k8s-api/kube-object.store"; -import AbortController from "abort-controller"; import type { ClusterContext } from "../cluster-frame-context/cluster-frame-context"; // Kubernetes watch-api client diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index c6fe1d227a..539f3ecb55 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -241,7 +241,6 @@ "@types/webpack-dev-server": "^4.7.2", "@types/webpack-env": "^1.18.0", "@types/webpack-node-externals": "2.5.3", - "abort-controller": "^3.0.0", "autoprefixer": "^10.4.13", "circular-dependency-plugin": "^5.2.2", "concurrently": "^7.6.0", diff --git a/packages/utility-features/utilities/src/abort-controller.ts b/packages/utility-features/utilities/src/abort-controller.ts index b062fce487..784b495a9e 100644 --- a/packages/utility-features/utilities/src/abort-controller.ts +++ b/packages/utility-features/utilities/src/abort-controller.ts @@ -3,8 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import AbortController from "abort-controller"; - /** * This is like an `AbortController` but will also abort if the parent aborts, * but won't make the parent abort if this aborts (single direction) diff --git a/packages/utility-features/utilities/src/delay.ts b/packages/utility-features/utilities/src/delay.ts index 96171f6535..d86395026b 100644 --- a/packages/utility-features/utilities/src/delay.ts +++ b/packages/utility-features/utilities/src/delay.ts @@ -3,8 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type AbortController from "abort-controller"; - /** * Return a promise that will be resolved after at least `timeout` ms have * passed. If `failFast` is provided then the promise is also resolved if it has diff --git a/packages/utility-features/utilities/src/reject-promise.ts b/packages/utility-features/utilities/src/reject-promise.ts index 8212bacd3f..0211586783 100644 --- a/packages/utility-features/utilities/src/reject-promise.ts +++ b/packages/utility-features/utilities/src/reject-promise.ts @@ -3,8 +3,6 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { AbortSignal } from "abort-controller"; - /** * Creates a new promise that will be rejected when the signal rejects. * From 52ede670bb7d39a996f62874051b9b7e72bff62b Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Fri, 17 Mar 2023 21:03:55 +0200 Subject: [PATCH 04/17] Fix resolve system proxy error when no windows available (#7375) * fix resolve system proxy error when no windows available Signed-off-by: Jari Kolehmainen * fix electronBrowserWindowInjectable id Signed-off-by: Jari Kolehmainen --------- Signed-off-by: Jari Kolehmainen --- packages/core/src/main/getDiForUnitTesting.ts | 2 - ...r-window.global-override-for-injectable.ts | 19 +++++ .../electron-browser-window.injectable.ts | 19 +++++ .../electron.injectable.ts | 14 ---- ...e-system-proxy-from-electron.injectable.ts | 18 ++-- ...resolve-system-proxy-from-electron.test.ts | 82 ++++++------------- 6 files changed, 70 insertions(+), 84 deletions(-) create mode 100644 packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.global-override-for-injectable.ts create mode 100644 packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.injectable.ts delete mode 100644 packages/core/src/main/utils/resolve-system-proxy/electron.injectable.ts diff --git a/packages/core/src/main/getDiForUnitTesting.ts b/packages/core/src/main/getDiForUnitTesting.ts index b71ab53239..0712f1e128 100644 --- a/packages/core/src/main/getDiForUnitTesting.ts +++ b/packages/core/src/main/getDiForUnitTesting.ts @@ -22,7 +22,6 @@ import electronQuitAndInstallUpdateInjectable from "./electron-app/features/elec import electronUpdaterIsActiveInjectable from "./electron-app/features/electron-updater-is-active.injectable"; import setUpdateOnQuitInjectable from "./electron-app/features/set-update-on-quit.injectable"; import waitUntilBundledExtensionsAreLoadedInjectable from "./start-main-application/lens-window/application-window/wait-until-bundled-extensions-are-loaded.injectable"; -import electronInjectable from "./utils/resolve-system-proxy/electron.injectable"; import initializeClusterManagerInjectable from "./cluster/initialize-manager.injectable"; import type { GlobalOverride } from "@k8slens/test-utils"; import { getOverrideFsWithFakes } from "../test-utils/override-fs-with-fakes"; @@ -56,7 +55,6 @@ export function getDiForUnitTesting() { di.override(globalOverride.injectable, globalOverride.overridingInstantiate); } - di.override(electronInjectable, () => ({})); di.override(waitUntilBundledExtensionsAreLoadedInjectable, () => async () => {}); overrideRunnablesHavingSideEffects(di); diff --git a/packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.global-override-for-injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.global-override-for-injectable.ts new file mode 100644 index 0000000000..c6535e9ef2 --- /dev/null +++ b/packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.global-override-for-injectable.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getGlobalOverride } from "@k8slens/test-utils"; +import type { BrowserWindow, Session, WebContents } from "electron"; +import electronBrowserWindowInjectable from "./electron-browser-window.injectable"; + +export default getGlobalOverride( + electronBrowserWindowInjectable, + () => () => ({ + webContents: { + session: { + resolveProxy: () => "DIRECT", + } as unknown as Session, + } as unknown as WebContents, + } as unknown as BrowserWindow), +); diff --git a/packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.injectable.ts new file mode 100644 index 0000000000..93f2066f93 --- /dev/null +++ b/packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.injectable.ts @@ -0,0 +1,19 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import type { BrowserWindowConstructorOptions } from "electron"; +import { BrowserWindow } from "electron"; + +const electronBrowserWindowInjectable = getInjectable({ + id: "electron-browser-window", + instantiate: () => { + return (opts: BrowserWindowConstructorOptions) => { + return new BrowserWindow(opts); + }; + }, + causesSideEffects: true, +}); + +export default electronBrowserWindowInjectable; diff --git a/packages/core/src/main/utils/resolve-system-proxy/electron.injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/electron.injectable.ts deleted file mode 100644 index a5999c9e59..0000000000 --- a/packages/core/src/main/utils/resolve-system-proxy/electron.injectable.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import electron from "electron"; - -const electronInjectable = getInjectable({ - id: "electron", - instantiate: () => electron, - causesSideEffects: true, -}); - -export default electronInjectable; diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts index c663d59fde..caa13c89de 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts @@ -3,28 +3,22 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import electronInjectable from "./electron.injectable"; +import electronBrowserWindowInjectable from "./electron-browser-window.injectable"; import withErrorLoggingInjectable from "../../../common/utils/with-error-logging/with-error-logging.injectable"; const resolveSystemProxyFromElectronInjectable = getInjectable({ id: "resolve-system-proxy-from-electron", instantiate: (di) => { - const electron = di.inject(electronInjectable); + const browserWindow = di.inject(electronBrowserWindowInjectable); const withErrorLoggingFor = di.inject(withErrorLoggingInjectable); - const withErrorLogging = withErrorLoggingFor(() => "Error resolving proxy"); + const hiddenWindow = browserWindow({ + show: false, + }); return withErrorLogging(async (url: string) => { - const webContent = electron.webContents - .getAllWebContents() - .find((x) => !x.isDestroyed()); - - if (!webContent) { - throw new Error(`Tried to resolve proxy for "${url}", but no browser window was available`); - } - - return await webContent.session.resolveProxy(url); + return await hiddenWindow.webContents.session.resolveProxy(url); }); }, }); diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts index c197566a10..39b1904004 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts @@ -5,13 +5,13 @@ import { getDiForUnitTesting } from "../../getDiForUnitTesting"; import resolveSystemProxyFromElectronInjectable from "./resolve-system-proxy-from-electron.injectable"; -import electronInjectable from "./electron.injectable"; +import electronBrowserWindowInjectable from "./electron-browser-window.injectable"; import type { AsyncFnMock } from "@async-fn/jest"; import asyncFn from "@async-fn/jest"; -import type electron from "electron"; import { getPromiseStatus } from "@k8slens/test-utils"; import logErrorInjectable from "../../../common/log-error.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; +import type { BrowserWindow, Session, WebContents } from "electron"; describe("technical: resolve-system-proxy-from-electron", () => { let resolveSystemProxyMock: AsyncFnMock<(url: string) => Promise>; @@ -26,44 +26,19 @@ describe("technical: resolve-system-proxy-from-electron", () => { di.override(logErrorInjectable, () => logErrorMock); }); - describe("given there are non-destroyed Lens windows, when called with URL", () => { + describe("given there are no unexpected issues, when called with URL", () => { beforeEach(() => { resolveSystemProxyMock = asyncFn(); di.override( - electronInjectable, - - () => - ({ - webContents: { - getAllWebContents: () => [ - { - isDestroyed: () => true, - - session: { - resolveProxy: () => { - throw new Error("should never come here"); - }, - }, - }, - - { - isDestroyed: () => false, - session: { resolveProxy: resolveSystemProxyMock }, - }, - - { - isDestroyed: () => false, - - session: { - resolveProxy: () => { - throw new Error("should never come here"); - }, - }, - }, - ], - }, - } as unknown as typeof electron), + electronBrowserWindowInjectable, + () => () => ({ + webContents: { + session: { + resolveProxy: resolveSystemProxyMock, + } as unknown as Session, + } as unknown as WebContents, + } as unknown as BrowserWindow), ); const resolveSystemProxyFromElectron = di.inject( @@ -73,7 +48,7 @@ describe("technical: resolve-system-proxy-from-electron", () => { actualPromise = resolveSystemProxyFromElectron("some-url"); }); - it("calls to resolve proxy from the first window", () => { + it("calls to resolve proxy from the browser window", () => { expect(resolveSystemProxyMock).toHaveBeenCalledWith("some-url"); }); @@ -90,28 +65,23 @@ describe("technical: resolve-system-proxy-from-electron", () => { }); }); - describe("given there are only destroyed Lens windows, when called with URL", () => { + describe("given there are unexpected issues, when called with URL", () => { let error: any; beforeEach(async () => { - di.override( - electronInjectable, - () => - ({ - webContents: { - getAllWebContents: () => [ - { - isDestroyed: () => true, + resolveSystemProxyMock = asyncFn(); - session: { - resolveProxy: () => { - throw new Error("should never come here"); - }, - }, - }, - ], - }, - } as unknown as typeof electron), + di.override( + electronBrowserWindowInjectable, + () => () => ({ + webContents: { + session: { + resolveProxy: () => { + throw new Error("unexpected error"); + }, + } as unknown as Session, + } as unknown as WebContents, + } as unknown as BrowserWindow), ); resolveSystemProxyMock = asyncFn(); @@ -128,7 +98,7 @@ describe("technical: resolve-system-proxy-from-electron", () => { }); it("throws error", () => { - expect(error.message).toBe('Tried to resolve proxy for "some-url", but no browser window was available'); + expect(error.message).toBe("unexpected error"); }); it("logs error", () => { From 7ed99255cd144d7f3f07c151d68540ed76d15e23 Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Mon, 20 Mar 2023 15:25:04 +0200 Subject: [PATCH 05/17] Fix resolveSystemProxyFromElectron causing a crash on quit (#7379) * destroy resolve system proxy window on before quit Signed-off-by: Jari Kolehmainen * resolve system proxy window: load blank page Signed-off-by: Jari Kolehmainen * disable paintWhenInitiallyHidden Signed-off-by: Jari Kolehmainen --------- Signed-off-by: Jari Kolehmainen --- .../resolve-system-proxy-from-electron.injectable.ts | 11 ++++------- .../resolve-system-proxy-from-electron.test.ts | 10 +++++----- ...em-proxy-window.global-override-for-injectable.ts} | 6 +++--- ...e.ts => resolve-system-proxy-window.injectable.ts} | 11 ++++------- 4 files changed, 16 insertions(+), 22 deletions(-) rename packages/core/src/main/utils/resolve-system-proxy/{electron-browser-window.global-override-for-injectable.ts => resolve-system-proxy-window.global-override-for-injectable.ts} (77%) rename packages/core/src/main/utils/resolve-system-proxy/{electron-browser-window.injectable.ts => resolve-system-proxy-window.injectable.ts} (50%) diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts index caa13c89de..4ad2da39b8 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.injectable.ts @@ -3,22 +3,19 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import electronBrowserWindowInjectable from "./electron-browser-window.injectable"; import withErrorLoggingInjectable from "../../../common/utils/with-error-logging/with-error-logging.injectable"; +import resolveSystemProxyWindowInjectable from "./resolve-system-proxy-window.injectable"; const resolveSystemProxyFromElectronInjectable = getInjectable({ id: "resolve-system-proxy-from-electron", instantiate: (di) => { - const browserWindow = di.inject(electronBrowserWindowInjectable); + const helperWindow = di.inject(resolveSystemProxyWindowInjectable); const withErrorLoggingFor = di.inject(withErrorLoggingInjectable); const withErrorLogging = withErrorLoggingFor(() => "Error resolving proxy"); - const hiddenWindow = browserWindow({ - show: false, - }); - + return withErrorLogging(async (url: string) => { - return await hiddenWindow.webContents.session.resolveProxy(url); + return await helperWindow.webContents.session.resolveProxy(url); }); }, }); diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts index 39b1904004..a2e6d01627 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-from-electron.test.ts @@ -5,7 +5,7 @@ import { getDiForUnitTesting } from "../../getDiForUnitTesting"; import resolveSystemProxyFromElectronInjectable from "./resolve-system-proxy-from-electron.injectable"; -import electronBrowserWindowInjectable from "./electron-browser-window.injectable"; +import resolveSystemProxyWindowInjectable from "./resolve-system-proxy-window.injectable"; import type { AsyncFnMock } from "@async-fn/jest"; import asyncFn from "@async-fn/jest"; import { getPromiseStatus } from "@k8slens/test-utils"; @@ -31,8 +31,8 @@ describe("technical: resolve-system-proxy-from-electron", () => { resolveSystemProxyMock = asyncFn(); di.override( - electronBrowserWindowInjectable, - () => () => ({ + resolveSystemProxyWindowInjectable, + () => ({ webContents: { session: { resolveProxy: resolveSystemProxyMock, @@ -72,8 +72,8 @@ describe("technical: resolve-system-proxy-from-electron", () => { resolveSystemProxyMock = asyncFn(); di.override( - electronBrowserWindowInjectable, - () => () => ({ + resolveSystemProxyWindowInjectable, + () => ({ webContents: { session: { resolveProxy: () => { diff --git a/packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.global-override-for-injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.global-override-for-injectable.ts similarity index 77% rename from packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.global-override-for-injectable.ts rename to packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.global-override-for-injectable.ts index c6535e9ef2..4bf1ada952 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.global-override-for-injectable.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.global-override-for-injectable.ts @@ -5,11 +5,11 @@ import { getGlobalOverride } from "@k8slens/test-utils"; import type { BrowserWindow, Session, WebContents } from "electron"; -import electronBrowserWindowInjectable from "./electron-browser-window.injectable"; +import resolveSystemProxyWindowInjectable from "./resolve-system-proxy-window.injectable"; export default getGlobalOverride( - electronBrowserWindowInjectable, - () => () => ({ + resolveSystemProxyWindowInjectable, + () => ({ webContents: { session: { resolveProxy: () => "DIRECT", diff --git a/packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts similarity index 50% rename from packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.injectable.ts rename to packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts index 93f2066f93..88e4319fa0 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/electron-browser-window.injectable.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts @@ -3,17 +3,14 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { BrowserWindowConstructorOptions } from "electron"; import { BrowserWindow } from "electron"; -const electronBrowserWindowInjectable = getInjectable({ - id: "electron-browser-window", +const resolveSystemProxyWindowInjectable = getInjectable({ + id: "resolve-system-proxy-window", instantiate: () => { - return (opts: BrowserWindowConstructorOptions) => { - return new BrowserWindow(opts); - }; + return new BrowserWindow({ show: false, paintWhenInitiallyHidden: false }); }, causesSideEffects: true, }); -export default electronBrowserWindowInjectable; +export default resolveSystemProxyWindowInjectable; From 991da149f904b2088fbc04736fd935598aa46004 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 20 Mar 2023 10:54:31 -0400 Subject: [PATCH 06/17] Add note about major version bumps in release guide (#7382) Signed-off-by: Sebastian Malton --- RELEASE_GUIDE.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/RELEASE_GUIDE.md b/RELEASE_GUIDE.md index 8821fedc38..f89bfa3295 100644 --- a/RELEASE_GUIDE.md +++ b/RELEASE_GUIDE.md @@ -15,6 +15,8 @@ All releases will be made by creating a PR which bumps the version field in the 1. If you are making a patch release (or a prerelease for one) make sure you are on the `release/v.` branch. 1. Run `npm run create-release-pr`. 1. Pick the PRs that you want to include in this release using the keys listed. + - If you are making a patch release this might include fixing up some cherry-picking of commits. These actions should be done in a separate terminal. + - If a package version is having a major version bump then `npm` will complain about `peerDependency` conflicts. These will have to be fixed up separately. 1. Once the PR is created, approved, and then merged the `Release Open Lens` workflow will create a tag and release for you. 1. If you are making a major or minor release, create a `release/v.` branch and push it to `origin` so that future patch releases can be made from it. 1. If you released a major or minor version, create a new patch milestone and move all bug issues to that milestone and all enhancement issues to the next minor milestone. From df49ff9b96c38082484ac5c71211d491d95292bf Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Mon, 20 Mar 2023 15:43:08 -0400 Subject: [PATCH 07/17] Fix problems when using 'npm link' (#7380) * Fix problems when using 'npm link' - Add missing peerDependencies and devDependencies - Move 'overrides' to root package to fix audit issues Signed-off-by: Sebastian Malton * Fix type issue and remove deprecated @types/* deps Signed-off-by: Sebastian Malton * Fixing type errors harder Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- package-lock.json | 1027 +++++++---------- package.json | 5 + packages/core/package.json | 5 - .../utility-features/run-many/package.json | 8 +- .../utility-features/test-utils/package.json | 7 + .../utility-features/utilities/package.json | 23 +- 6 files changed, 462 insertions(+), 613 deletions(-) diff --git a/package-lock.json b/package-lock.json index dc05949860..b59d132b39 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2685,9 +2685,9 @@ "dev": true }, "node_modules/@esbuild/android-arm": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.11.tgz", - "integrity": "sha512-CdyX6sRVh1NzFCsf5vw3kULwlAhfy9wVt8SZlrhQ7eL2qBjGbFhRBWkkAzuZm9IIEOCKJw4DXA6R85g+qc8RDw==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.12.tgz", + "integrity": "sha512-E/sgkvwoIfj4aMAPL2e35VnUJspzVYl7+M1B2cqeubdBhADV4uPon0KCc8p2G+LqSJ6i8ocYPCqY3A4GGq0zkQ==", "cpu": [ "arm" ], @@ -2701,9 +2701,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.11.tgz", - "integrity": "sha512-QnK4d/zhVTuV4/pRM4HUjcsbl43POALU2zvBynmrrqZt9LPcLA3x1fTZPBg2RRguBQnJcnU059yKr+bydkntjg==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.12.tgz", + "integrity": "sha512-WQ9p5oiXXYJ33F2EkE3r0FRDFVpEdcDiwNX3u7Xaibxfx6vQE0Sb8ytrfQsA5WO6kDn6mDfKLh6KrPBjvkk7xA==", "cpu": [ "arm64" ], @@ -2717,9 +2717,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.11.tgz", - "integrity": "sha512-3PL3HKtsDIXGQcSCKtWD/dy+mgc4p2Tvo2qKgKHj9Yf+eniwFnuoQ0OUhlSfAEpKAFzF9N21Nwgnap6zy3L3MQ==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.12.tgz", + "integrity": "sha512-m4OsaCr5gT+se25rFPHKQXARMyAehHTQAz4XX1Vk3d27VtqiX0ALMBPoXZsGaB6JYryCLfgGwUslMqTfqeLU0w==", "cpu": [ "x64" ], @@ -2733,9 +2733,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.11.tgz", - "integrity": "sha512-pJ950bNKgzhkGNO3Z9TeHzIFtEyC2GDQL3wxkMApDEghYx5Qers84UTNc1bAxWbRkuJOgmOha5V0WUeh8G+YGw==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.12.tgz", + "integrity": "sha512-O3GCZghRIx+RAN0NDPhyyhRgwa19MoKlzGonIb5hgTj78krqp9XZbYCvFr9N1eUxg0ZQEpiiZ4QvsOQwBpP+lg==", "cpu": [ "arm64" ], @@ -2749,9 +2749,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.11.tgz", - "integrity": "sha512-iB0dQkIHXyczK3BZtzw1tqegf0F0Ab5texX2TvMQjiJIWXAfM4FQl7D909YfXWnB92OQz4ivBYQ2RlxBJrMJOw==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.12.tgz", + "integrity": "sha512-5D48jM3tW27h1qjaD9UNRuN+4v0zvksqZSPZqeSWggfMlsVdAhH3pwSfQIFJwcs9QJ9BRibPS4ViZgs3d2wsCA==", "cpu": [ "x64" ], @@ -2765,9 +2765,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.11.tgz", - "integrity": "sha512-7EFzUADmI1jCHeDRGKgbnF5sDIceZsQGapoO6dmw7r/ZBEKX7CCDnIz8m9yEclzr7mFsd+DyasHzpjfJnmBB1Q==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.12.tgz", + "integrity": "sha512-OWvHzmLNTdF1erSvrfoEBGlN94IE6vCEaGEkEH29uo/VoONqPnoDFfShi41Ew+yKimx4vrmmAJEGNoyyP+OgOQ==", "cpu": [ "arm64" ], @@ -2781,9 +2781,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.11.tgz", - "integrity": "sha512-iPgenptC8i8pdvkHQvXJFzc1eVMR7W2lBPrTE6GbhR54sLcF42mk3zBOjKPOodezzuAz/KSu8CPyFSjcBMkE9g==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.12.tgz", + "integrity": "sha512-A0Xg5CZv8MU9xh4a+7NUpi5VHBKh1RaGJKqjxe4KG87X+mTjDE6ZvlJqpWoeJxgfXHT7IMP9tDFu7IZ03OtJAw==", "cpu": [ "x64" ], @@ -2797,9 +2797,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.11.tgz", - "integrity": "sha512-M9iK/d4lgZH0U5M1R2p2gqhPV/7JPJcRz+8O8GBKVgqndTzydQ7B2XGDbxtbvFkvIs53uXTobOhv+RyaqhUiMg==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.12.tgz", + "integrity": "sha512-WsHyJ7b7vzHdJ1fv67Yf++2dz3D726oO3QCu8iNYik4fb5YuuReOI9OtA+n7Mk0xyQivNTPbl181s+5oZ38gyA==", "cpu": [ "arm" ], @@ -2813,9 +2813,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.11.tgz", - "integrity": "sha512-Qxth3gsWWGKz2/qG2d5DsW/57SeA2AmpSMhdg9TSB5Svn2KDob3qxfQSkdnWjSd42kqoxIPy3EJFs+6w1+6Qjg==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.12.tgz", + "integrity": "sha512-cK3AjkEc+8v8YG02hYLQIQlOznW+v9N+OI9BAFuyqkfQFR+DnDLhEM5N8QRxAUz99cJTo1rLNXqRrvY15gbQUg==", "cpu": [ "arm64" ], @@ -2829,9 +2829,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.11.tgz", - "integrity": "sha512-dB1nGaVWtUlb/rRDHmuDQhfqazWE0LMro/AIbT2lWM3CDMHJNpLckH+gCddQyhhcLac2OYw69ikUMO34JLt3wA==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.12.tgz", + "integrity": "sha512-jdOBXJqcgHlah/nYHnj3Hrnl9l63RjtQ4vn9+bohjQPI2QafASB5MtHAoEv0JQHVb/xYQTFOeuHnNYE1zF7tYw==", "cpu": [ "ia32" ], @@ -2845,9 +2845,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.11.tgz", - "integrity": "sha512-aCWlq70Q7Nc9WDnormntGS1ar6ZFvUpqr8gXtO+HRejRYPweAFQN615PcgaSJkZjhHp61+MNLhzyVALSF2/Q0g==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.12.tgz", + "integrity": "sha512-GTOEtj8h9qPKXCyiBBnHconSCV9LwFyx/gv3Phw0pa25qPYjVuuGZ4Dk14bGCfGX3qKF0+ceeQvwmtI+aYBbVA==", "cpu": [ "loong64" ], @@ -2861,9 +2861,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.11.tgz", - "integrity": "sha512-cGeGNdQxqY8qJwlYH1BP6rjIIiEcrM05H7k3tR7WxOLmD1ZxRMd6/QIOWMb8mD2s2YJFNRuNQ+wjMhgEL2oCEw==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.12.tgz", + "integrity": "sha512-o8CIhfBwKcxmEENOH9RwmUejs5jFiNoDw7YgS0EJTF6kgPgcqLFjgoc5kDey5cMHRVCIWc6kK2ShUePOcc7RbA==", "cpu": [ "mips64el" ], @@ -2877,9 +2877,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.11.tgz", - "integrity": "sha512-BdlziJQPW/bNe0E8eYsHB40mYOluS+jULPCjlWiHzDgr+ZBRXPtgMV1nkLEGdpjrwgmtkZHEGEPaKdS/8faLDA==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.12.tgz", + "integrity": "sha512-biMLH6NR/GR4z+ap0oJYb877LdBpGac8KfZoEnDiBKd7MD/xt8eaw1SFfYRUeMVx519kVkAOL2GExdFmYnZx3A==", "cpu": [ "ppc64" ], @@ -2893,9 +2893,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.11.tgz", - "integrity": "sha512-MDLwQbtF+83oJCI1Cixn68Et/ME6gelmhssPebC40RdJaect+IM+l7o/CuG0ZlDs6tZTEIoxUe53H3GmMn8oMA==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.12.tgz", + "integrity": "sha512-jkphYUiO38wZGeWlfIBMB72auOllNA2sLfiZPGDtOBb1ELN8lmqBrlMiucgL8awBw1zBXN69PmZM6g4yTX84TA==", "cpu": [ "riscv64" ], @@ -2909,9 +2909,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.11.tgz", - "integrity": "sha512-4N5EMESvws0Ozr2J94VoUD8HIRi7X0uvUv4c0wpTHZyZY9qpaaN7THjosdiW56irQ4qnJ6Lsc+i+5zGWnyqWqQ==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.12.tgz", + "integrity": "sha512-j3ucLdeY9HBcvODhCY4b+Ds3hWGO8t+SAidtmWu/ukfLLG/oYDMaA+dnugTVAg5fnUOGNbIYL9TOjhWgQB8W5g==", "cpu": [ "s390x" ], @@ -2925,9 +2925,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.11.tgz", - "integrity": "sha512-rM/v8UlluxpytFSmVdbCe1yyKQd/e+FmIJE2oPJvbBo+D0XVWi1y/NQ4iTNx+436WmDHQBjVLrbnAQLQ6U7wlw==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.12.tgz", + "integrity": "sha512-uo5JL3cgaEGotaqSaJdRfFNSCUJOIliKLnDGWaVCgIKkHxwhYMm95pfMbWZ9l7GeW9kDg0tSxcy9NYdEtjwwmA==", "cpu": [ "x64" ], @@ -2941,9 +2941,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.11.tgz", - "integrity": "sha512-4WaAhuz5f91h3/g43VBGdto1Q+X7VEZfpcWGtOFXnggEuLvjV+cP6DyLRU15IjiU9fKLLk41OoJfBFN5DhPvag==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.12.tgz", + "integrity": "sha512-DNdoRg8JX+gGsbqt2gPgkgb00mqOgOO27KnrWZtdABl6yWTST30aibGJ6geBq3WM2TIeW6COs5AScnC7GwtGPg==", "cpu": [ "x64" ], @@ -2957,9 +2957,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.11.tgz", - "integrity": "sha512-UBj135Nx4FpnvtE+C8TWGp98oUgBcmNmdYgl5ToKc0mBHxVVqVE7FUS5/ELMImOp205qDAittL6Ezhasc2Ev/w==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.12.tgz", + "integrity": "sha512-aVsENlr7B64w8I1lhHShND5o8cW6sB9n9MUtLumFlPhG3elhNWtE7M1TFpj3m7lT3sKQUMkGFjTQBrvDDO1YWA==", "cpu": [ "x64" ], @@ -2973,9 +2973,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.11.tgz", - "integrity": "sha512-1/gxTifDC9aXbV2xOfCbOceh5AlIidUrPsMpivgzo8P8zUtczlq1ncFpeN1ZyQJ9lVs2hILy1PG5KPp+w8QPPg==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.12.tgz", + "integrity": "sha512-qbHGVQdKSwi0JQJuZznS4SyY27tYXYF0mrgthbxXrZI3AHKuRvU+Eqbg/F0rmLDpW/jkIZBlCO1XfHUBMNJ1pg==", "cpu": [ "x64" ], @@ -2989,9 +2989,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.11.tgz", - "integrity": "sha512-vtSfyx5yRdpiOW9yp6Ax0zyNOv9HjOAw8WaZg3dF5djEHKKm3UnoohftVvIJtRh0Ec7Hso0RIdTqZvPXJ7FdvQ==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.12.tgz", + "integrity": "sha512-zsCp8Ql+96xXTVTmm6ffvoTSZSV2B/LzzkUXAY33F/76EajNw1m+jZ9zPfNJlJ3Rh4EzOszNDHsmG/fZOhtqDg==", "cpu": [ "arm64" ], @@ -3005,9 +3005,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.11.tgz", - "integrity": "sha512-GFPSLEGQr4wHFTiIUJQrnJKZhZjjq4Sphf+mM76nQR6WkQn73vm7IsacmBRPkALfpOCHsopSvLgqdd4iUW2mYw==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.12.tgz", + "integrity": "sha512-FfrFjR4id7wcFYOdqbDfDET3tjxCozUgbqdkOABsSFzoZGFC92UK7mg4JKRc/B3NNEf1s2WHxJ7VfTdVDPN3ng==", "cpu": [ "ia32" ], @@ -3021,9 +3021,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.11.tgz", - "integrity": "sha512-N9vXqLP3eRL8BqSy8yn4Y98cZI2pZ8fyuHx6lKjiG2WABpT2l01TXdzq5Ma2ZUBzfB7tx5dXVhge8X9u0S70ZQ==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.12.tgz", + "integrity": "sha512-JOOxw49BVZx2/5tW3FqkdjSD/5gXYeVGPDcB0lvap0gLQshkh1Nyel1QazC+wNxus3xPlsYAgqU1BUmrmCvWtw==", "cpu": [ "x64" ], @@ -3037,9 +3037,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz", - "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", + "integrity": "sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==", "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -3120,19 +3120,18 @@ "dev": true }, "node_modules/@floating-ui/dom": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.4.tgz", - "integrity": "sha512-4+k+BLhtWj+peCU60gp0+rHeR8+Ohqx6kjJf/lHMnJ8JD5Qj6jytcq1+SZzRwD7rvHKRhR7TDiWWddrNrfwQLg==", + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.5.tgz", + "integrity": "sha512-+sAUfpQ3Frz+VCbPCqj+cZzvEESy3fjSeT/pDWkYCWOBXYNNKZfuVsHuv8/JO2zze8+Eb/Q7a6hZVgzS81fLbQ==", "dev": true, "dependencies": { - "@floating-ui/core": "^1.2.3" + "@floating-ui/core": "^1.2.4" } }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", - "dev": true + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, "node_modules/@hapi/b64": { "version": "5.0.0", @@ -3360,8 +3359,7 @@ "node_modules/@isaacs/string-locale-compare": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", - "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", - "dev": true + "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==" }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -4780,11 +4778,6 @@ "openid-client": "^5.3.0" } }, - "node_modules/@kubernetes/client-node/node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" - }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -5187,7 +5180,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-5.3.0.tgz", "integrity": "sha512-+rZ9zgL1lnbl8Xbb1NQdMjveOMwj4lIYfcDtyJHHi5x4X8jtR6m8SXooJMZy5vmFVZ8w7A2Bnd/oX9eTuU8w5A==", - "dev": true, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -5235,7 +5227,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -5247,7 +5238,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -5256,7 +5246,6 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", - "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -5271,7 +5260,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -5286,7 +5274,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", - "dev": true, "dependencies": { "@gar/promisify": "^1.1.3", "semver": "^7.3.5" @@ -5299,7 +5286,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", - "dev": true, "dependencies": { "@npmcli/promise-spawn": "^3.0.0", "lru-cache": "^7.4.4", @@ -5319,7 +5305,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -5328,7 +5313,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", - "dev": true, "dependencies": { "npm-bundled": "^1.1.1", "npm-normalize-package-bin": "^1.0.1" @@ -5344,7 +5328,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-2.0.4.tgz", "integrity": "sha512-bMo0aAfwhVwqoVM5UzX1DJnlvVvzDCHae821jv48L1EsrYwfOZChlqWYXEtto/+BkBXetPbEWgau++/brh4oVg==", - "dev": true, "dependencies": { "@npmcli/name-from-folder": "^1.0.1", "glob": "^8.0.1", @@ -5359,7 +5342,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -5368,7 +5350,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -5387,7 +5368,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -5399,7 +5379,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-3.1.1.tgz", "integrity": "sha512-n69ygIaqAedecLeVH3KnO39M6ZHiJ2dEv5A7DGvcqCB8q17BGUgW8QaanIkbWUo2aYGZqJaOORTLAlIvKjNDKA==", - "dev": true, "dependencies": { "cacache": "^16.0.0", "json-parse-even-better-errors": "^2.3.1", @@ -5415,7 +5394,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -5428,7 +5406,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -5442,14 +5419,12 @@ "node_modules/@npmcli/name-from-folder": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz", - "integrity": "sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA==", - "dev": true + "integrity": "sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA==" }, "node_modules/@npmcli/node-gyp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", - "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -5458,7 +5433,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-2.0.0.tgz", "integrity": "sha512-42jnZ6yl16GzjWSH7vtrmWyJDGVa/LXPdpN2rcUWolFjc9ON2N3uz0qdBbQACfmhuJZ2lbKYtmK5qx68ZPLHMA==", - "dev": true, "dependencies": { "json-parse-even-better-errors": "^2.3.1" }, @@ -5470,7 +5444,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", - "dev": true, "dependencies": { "infer-owner": "^1.0.4" }, @@ -5482,7 +5455,6 @@ "version": "4.1.7", "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.1.7.tgz", "integrity": "sha512-WXr/MyM4tpKA4BotB81NccGAv8B48lNH0gRoILucbcAhTQXLCoi6HflMV3KdXubIqvP9SuLsFn68Z7r4jl+ppw==", - "dev": true, "dependencies": { "@npmcli/node-gyp": "^2.0.0", "@npmcli/promise-spawn": "^3.0.0", @@ -5498,7 +5470,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -5507,7 +5478,6 @@ "version": "10.2.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^16.1.0", @@ -5534,7 +5504,6 @@ "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" }, @@ -5546,7 +5515,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, "dependencies": { "minipass": "^3.1.6", "minipass-sized": "^1.0.3", @@ -5563,7 +5531,6 @@ "version": "9.3.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", - "dev": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -5587,7 +5554,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", - "dev": true, "dependencies": { "abbrev": "^1.0.0" }, @@ -5602,7 +5568,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -5617,7 +5582,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -5630,22 +5594,21 @@ "node_modules/@npmcli/run-script/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/@nrwl/cli": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/cli/-/cli-15.8.6.tgz", - "integrity": "sha512-KrWoYcZgE6woCubPO1QSnwbZAjs2rdV4dotHxR+iRkeHRPAq0D6w83CVo5oP/krfUri2pxwzhnbkgAK1LSPBYg==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/cli/-/cli-15.8.7.tgz", + "integrity": "sha512-G1NEy4jGuZJ/7KjhLQNOe11XmoTgwJS82FW8Tbo4iceq2ItSEbe7bkA8xTSK/AzUixZIMimztb9Oyxw/n1ajGQ==", "dev": true, "dependencies": { - "nx": "15.8.6" + "nx": "15.8.7" } }, "node_modules/@nrwl/devkit": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-15.8.6.tgz", - "integrity": "sha512-yA5hBpeqoIlyEN5lUkejUrmB/5vfg+k6xoT4KhXnmj6bLPDGOYTuixg8k+iYrIAFIRMx0F8zYbYOYzXG3lmvHg==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-15.8.7.tgz", + "integrity": "sha512-A99nZrA5KN9wRn2uYX2vKByA+t2XEGoZBR5TU/bpXbPYrh92qAHkIJ8ke3ImGQOlzk4iIaZ5Me0k7k1p9Zx4wA==", "dev": true, "dependencies": { "@phenomnomnominal/tsquery": "4.1.1", @@ -5720,9 +5683,9 @@ "dev": true }, "node_modules/@nrwl/nx-darwin-arm64": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-arm64/-/nx-darwin-arm64-15.8.6.tgz", - "integrity": "sha512-8diQitlyjHxpkWcXNecd6T2ch8fHR7LOMaZg9+qgrt5AypWkEGf+UHMxTSNRObAiBGnoxySa+AL/UKVtpQ203Q==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-arm64/-/nx-darwin-arm64-15.8.7.tgz", + "integrity": "sha512-+cu8J337gRxUHjz2TGwS/2Oh3yw8d3/T6SoBfvee1DY72VQaeYd8UTz0doOhDtmc/zowvRu7ZVsW0ytNB0jIXQ==", "cpu": [ "arm64" ], @@ -5736,9 +5699,9 @@ } }, "node_modules/@nrwl/nx-darwin-x64": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-x64/-/nx-darwin-x64-15.8.6.tgz", - "integrity": "sha512-h9/JULzPZTpt6oNpKMZLc1NGDu+CLyx91c8DJUh/hH0Zh/7dS9LFxe9jWeFIdh18iAu7ZAoktK2KJ5YhOrUYhA==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-x64/-/nx-darwin-x64-15.8.7.tgz", + "integrity": "sha512-VqHJEP0wgFu1MU0Bo1vKZ5/s7ThRfYkX8SyGUxjVTzR02CrsjC4rNxFoKD8Cc4YkUn44U/F78toGf+i2gRcjSQ==", "cpu": [ "x64" ], @@ -5752,9 +5715,9 @@ } }, "node_modules/@nrwl/nx-linux-arm-gnueabihf": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-15.8.6.tgz", - "integrity": "sha512-Yp/YjzcIHW+OW4revPRZIt0Px9cKRsOL69FPLlYSxWuR/PD9SPeXWcbo3pKkjnIWIjOL2YT8z5cHiQ3bV1NVfw==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-15.8.7.tgz", + "integrity": "sha512-4F/8awwqPTt7zKQolvjBNrcR1wYicPjGchLOdaqnfMxn/iRRUdh0hD11mEP5zHNv9gZs/nOIvhdBUErNjFkplQ==", "cpu": [ "arm" ], @@ -5768,9 +5731,9 @@ } }, "node_modules/@nrwl/nx-linux-arm64-gnu": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-15.8.6.tgz", - "integrity": "sha512-b+OenpPhhxqgaG6EFHRLfVGtAU4+UbKqOhv7DLLh5P7tX3RAQAtyrT6tVkfDRFYl6kgEme/I5ZrevcbaGyDO+w==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-15.8.7.tgz", + "integrity": "sha512-3ZTSZx02Vv5emQOpaDROIcLtQucoXAe73zGKYDTXB95mxbOPSjjQJ8Rtx+BeqWq9JQoZZyRcD0qnBkTTy1aLRg==", "cpu": [ "arm64" ], @@ -5784,9 +5747,9 @@ } }, "node_modules/@nrwl/nx-linux-arm64-musl": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-musl/-/nx-linux-arm64-musl-15.8.6.tgz", - "integrity": "sha512-F9D8moy+lfJQhVrZoY54vDwpigBgxQy4HB9PRmc6Ln9mIk3ouOvKNC99OjUYEO+ensHr9eMpsbghsRCjod//uw==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-musl/-/nx-linux-arm64-musl-15.8.7.tgz", + "integrity": "sha512-SZxTomiHxAh8El+swbmGSGcaA0vGbHb/rmhFAixo19INu1wBJfD6hjkVJt17h6PyEO7BIYPOpRia6Poxnyv8hA==", "cpu": [ "arm64" ], @@ -5800,9 +5763,9 @@ } }, "node_modules/@nrwl/nx-linux-x64-gnu": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-gnu/-/nx-linux-x64-gnu-15.8.6.tgz", - "integrity": "sha512-an0zD6lKpblexazKssFvcfOx7BuGutwlrzmwScxISPXj5+ly99u+sYclDg2P56YRHYXIuYGBK0c0VWaJ91QIcw==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-gnu/-/nx-linux-x64-gnu-15.8.7.tgz", + "integrity": "sha512-BlNC6Zz1/x6CFbBFTVrgRGMOPqb7zWh5cOjBVNpoBXYTEth1UXb2r1U+gpuQ4xdUqG+uXoWhy6BHJjqBIjzLJA==", "cpu": [ "x64" ], @@ -5816,9 +5779,9 @@ } }, "node_modules/@nrwl/nx-linux-x64-musl": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-musl/-/nx-linux-x64-musl-15.8.6.tgz", - "integrity": "sha512-LOurlSuLf9LWdjvpHHIsHC0auxgMVrkeOFFCUJ3oVv/dN4uZ0vuNG98XM2E7fPDXDacBZIyKdx34KQlmFfBHsA==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-musl/-/nx-linux-x64-musl-15.8.7.tgz", + "integrity": "sha512-FNYX/IKy8SUbw6bJpvwZrup2YQBYmSJwP6Rw76Vf7c32XHk7uA6AjiPWMIrZCSndXcry8fnwXvR+J2Dnyo82nQ==", "cpu": [ "x64" ], @@ -5832,9 +5795,9 @@ } }, "node_modules/@nrwl/nx-win32-arm64-msvc": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-15.8.6.tgz", - "integrity": "sha512-MvH84nLv1tdM96z92abeQd+tguY/zKC22AFHek9PSR1StUQzwwPu6rR7XDn3mggwnkLm11jTUXlk7wdbE5sldQ==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-15.8.7.tgz", + "integrity": "sha512-sZALEzazjPAeLlw6IbFWsMidCZ4ZM3GKWZZ6rsAqG2y7I9t4nlUPH/y/Isl9MuLBvrBCBXbVnD20wh6EhtuwTw==", "cpu": [ "arm64" ], @@ -5848,9 +5811,9 @@ } }, "node_modules/@nrwl/nx-win32-x64-msvc": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-x64-msvc/-/nx-win32-x64-msvc-15.8.6.tgz", - "integrity": "sha512-P0Sb4HJCeoeTvPFdUMKljRUIjzso0go36cn1Zpl+Z5CG/nbOvLlbnzh6rg15SRNu9OLWTHNPtyQIvKxjqEDoxg==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-x64-msvc/-/nx-win32-x64-msvc-15.8.7.tgz", + "integrity": "sha512-VMdDptI2rqkLQRCvertF29QeA/V/MnFtHbsmVzMCEv5EUfrkHbA5LLxV66LLfngmkDT1FHktffztlsMpbxvhRw==", "cpu": [ "x64" ], @@ -5864,12 +5827,12 @@ } }, "node_modules/@nrwl/tao": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-15.8.6.tgz", - "integrity": "sha512-dY205cotLiKTV+5BrUlneZEOucDmXiJU4asj1G4vQCf8Nt7awwuLYOmgbsACS27gkopSVV+DPl1zmtkSJX8Cjg==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-15.8.7.tgz", + "integrity": "sha512-wA7QIEh0VwWcyo32Y/xSCTwnQTGcZupe933nResXv8mAb36W8MoR5SXRx+Wdd8fJ1eWlm2tuotIrslhN+lYx/Q==", "dev": true, "dependencies": { - "nx": "15.8.6" + "nx": "15.8.7" }, "bin": { "tao": "index.js" @@ -6618,9 +6581,9 @@ } }, "node_modules/@swc/core": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.40.tgz", - "integrity": "sha512-ZQJ+NID24PQkPIHnbO2B68YNQ6aMEyDz6dcsZucpRK4r7+aPqQ2yVLaqFcQU9VcGMyo4JJydmokzyTr1roWPIQ==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.41.tgz", + "integrity": "sha512-v6P2dfqJDpZ/7RXPvWge9oI6YgolDM0jtNhQZ2qdXrLBzaWQdDoBGBTJ8KN/nTgGhX3IkNvSB1fafXQ+nVnqAQ==", "hasInstallScript": true, "engines": { "node": ">=10" @@ -6630,22 +6593,22 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.40", - "@swc/core-darwin-x64": "1.3.40", - "@swc/core-linux-arm-gnueabihf": "1.3.40", - "@swc/core-linux-arm64-gnu": "1.3.40", - "@swc/core-linux-arm64-musl": "1.3.40", - "@swc/core-linux-x64-gnu": "1.3.40", - "@swc/core-linux-x64-musl": "1.3.40", - "@swc/core-win32-arm64-msvc": "1.3.40", - "@swc/core-win32-ia32-msvc": "1.3.40", - "@swc/core-win32-x64-msvc": "1.3.40" + "@swc/core-darwin-arm64": "1.3.41", + "@swc/core-darwin-x64": "1.3.41", + "@swc/core-linux-arm-gnueabihf": "1.3.41", + "@swc/core-linux-arm64-gnu": "1.3.41", + "@swc/core-linux-arm64-musl": "1.3.41", + "@swc/core-linux-x64-gnu": "1.3.41", + "@swc/core-linux-x64-musl": "1.3.41", + "@swc/core-win32-arm64-msvc": "1.3.41", + "@swc/core-win32-ia32-msvc": "1.3.41", + "@swc/core-win32-x64-msvc": "1.3.41" } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.40.tgz", - "integrity": "sha512-x4JHshTVB2o5xOedLL54/jsKkfUlsMw25tNM5fWkehiKWXlQuxEasl5/roceAFETWm8mEESuL8pWgZaiyTDl4Q==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.41.tgz", + "integrity": "sha512-D4fybODToO/BvuP35bionDUrSuTVVr8eW+mApr1unOqb3mfiqOrVv0VP2fpWNRYiA+xMq+oBCB6KcGpL60HKWQ==", "cpu": [ "arm64" ], @@ -6658,9 +6621,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.40.tgz", - "integrity": "sha512-2QaW9HtlvatiQscQACVIyKtj+vAEFEC6Tn+8rqxm8ikYHUD33M/FVXGWEvMLTI7T3P25zjhs+toAlLsjHgfzQQ==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.41.tgz", + "integrity": "sha512-0RoVyiPCnylf3TG77C3S86PRSmaq+SaYB4VDLJFz3qcEHz1pfP0LhyskhgX4wjQV1mveDzFEn1BVAuo0eOMwZA==", "cpu": [ "x64" ], @@ -6673,9 +6636,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.40.tgz", - "integrity": "sha512-cJPgSg8222gezj5Db2S8PNvcALJLokvXqvFjyzRR253SMFFkq9JKWk0uwO3wg8i8jhe78xMB6EO6AteQqFWvCg==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.41.tgz", + "integrity": "sha512-mZW7GeY7Uw1nkKoWpx898ou20oCSt8MR+jAVuAhMjX+G4Zr0WWXYSigWNiRymhR6Q9KhyvoFpMckguSvYWmXsw==", "cpu": [ "arm" ], @@ -6688,9 +6651,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.40.tgz", - "integrity": "sha512-s76n4/vpQzV7dpS703m1WnCxyG7OfGk+EeJf+KEl/m6KP7c5MHHOLOf8hpagI/QI1H8jb9j1ADqNu2C7tEUR8Q==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.41.tgz", + "integrity": "sha512-e91LGn+6KuLFw3sWk5swwGc/dP4tXs0mg3HrhjImRoofU02Bb9aHcj5zgrSO8ZByvDtm/Knn16h1ojxIMOFaxg==", "cpu": [ "arm64" ], @@ -6703,9 +6666,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.40.tgz", - "integrity": "sha512-aTkeImCq1WrkljAQNnqlbk/1ermotONkBl11GH7Ia+8yhsmgt8ZiNBIi0tJ5UjdfXDtnl58Iek43Vo8LWaPUKA==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.41.tgz", + "integrity": "sha512-Q7hmrniLWsQ7zjtImGcjx1tl5/Qxpel+fC+OXTnGvAyyoGssSftIBlXMnqVLteL78zhxIPAzi+gizWAe5RGqrA==", "cpu": [ "arm64" ], @@ -6718,9 +6681,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.40.tgz", - "integrity": "sha512-ZsfVlzXSXvNZBuK1fCrenoLSLVv0Zk7OdmkAG9cWN3bKkc/ynxO+6njXLEKWfv9bRfDBXhxifyHGOVOQlIFIAA==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.41.tgz", + "integrity": "sha512-h4sv1sCfZQgRIwmykz8WPqVpbvHb13Qm3SsrbOudhAp2MuzpWzsgMP5hAEpdCP/nWreiCz3aoM6L8JeakRDq0g==", "cpu": [ "x64" ], @@ -6733,9 +6696,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.40.tgz", - "integrity": "sha512-5GgMuadbd6fhHg/+7W25i+9OQTW4nTMGECias0BNPlcW8nnohzSphpj5jLI/Ub5bWzMwE2hua6e2uiZ17rTySg==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.41.tgz", + "integrity": "sha512-Z7c26i38378d0NT/dcz8qPSAXm41lqhNzykdhKhI+95mA9m4pskP18T/0I45rmyx1ywifypu+Ip+SXmKeVSPgQ==", "cpu": [ "x64" ], @@ -6748,9 +6711,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.40.tgz", - "integrity": "sha512-TqiK28eaK3YOKSp8iESlrrbSzDGRQqM0zR4hvCgfHwL4L1BPh/M0aIMC/vyYh2gqpz2quyNqgi/DxoZ2+WxlUg==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.41.tgz", + "integrity": "sha512-I0CYnPc+ZGc912YeN0TykIOf/Q7yJQHRwDuhewwD6RkbiSEaVfSux5pAmmdoKw2aGMSq+cwLmgPe9HYLRNz+4w==", "cpu": [ "arm64" ], @@ -6763,9 +6726,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.40.tgz", - "integrity": "sha512-PqtCXFs5+ZbrfFe1VZAcCl8k9h47wE65mKDhDvZ9/SQhXxZX2+f5mUGXuH4G5rA0CyijsVpHnpA/5rqE7f2Sxw==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.41.tgz", + "integrity": "sha512-EygN4CVDWF29/U2T5fXGfWyLvRbMd2hiUgkciAl7zHuyJ6nKl+kpodqV2A0Wd4sFtSNedU0gQEBEXEe7cqvmsA==", "cpu": [ "ia32" ], @@ -6778,9 +6741,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.40", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.40.tgz", - "integrity": "sha512-73DGsjsJYSzmoRbfomPj5jcQawtK2H0bCDi/1wgfl8NKVOuzrq+PpaTry3lzx+gvTHxUX6mUHV22i7C9ITL74Q==", + "version": "1.3.41", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.41.tgz", + "integrity": "sha512-Mfp8qD1hNwWWRy0ISdwQJu1g0UYoVTtuQlO0z3aGbXqL51ew9e56+8j3M1U9i95lXFyWkARgjDCcKkQi+WezyA==", "cpu": [ "x64" ], @@ -7205,9 +7168,9 @@ "dev": true }, "node_modules/@types/eslint": { - "version": "8.21.2", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.2.tgz", - "integrity": "sha512-EMpxUyystd3uZVByZap1DACsMXvb82ypQnGn89e1Y0a+LYu3JJscUd/gqhRsVFDkaD2MIiWo0MT8EfXr3DGRKw==", + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.3.tgz", + "integrity": "sha512-fa7GkppZVEByMWGbTtE5MbmXWJTVbrjjaS8K6uQj+XtuuUv1fsuPAxhygfqLmsb/Ufb3CV8deFCpiMfAgi00Sw==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -7506,16 +7469,6 @@ "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", "dev": true }, - "node_modules/@types/mini-css-extract-plugin": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/@types/mini-css-extract-plugin/-/mini-css-extract-plugin-2.5.1.tgz", - "integrity": "sha512-evjjtJttaUexgg3au9ZJFy76tV9mySwX3a4Jl82BuormBYluWLRt0xk2urWrhOdPgDWzulRFyotwYOJTmkSgKw==", - "deprecated": "This is a stub types definition. mini-css-extract-plugin provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "mini-css-extract-plugin": "*" - } - }, "node_modules/@types/minimatch": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", @@ -7862,16 +7815,6 @@ "integrity": "sha512-6pwWTx8oUtWvsiZUCrhrK/53MzKVLnuNSSaZILPy3uMes9QnTrLMar9BDlJArbMOjDcjb3QXFk6Rz8qmmuySZw==", "dev": true }, - "node_modules/@types/tempy": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/@types/tempy/-/tempy-0.3.0.tgz", - "integrity": "sha512-graSgBSy4TEsenfAasXh28mxfdrLkgrFlXU8QFShFVNHEGHCg5IfO5LBlZjq2SAUnCm/VdxvuQKlp2buPR/YwA==", - "deprecated": "This is a stub types definition. tempy provides its own type definitions, so you do not need this installed.", - "dev": true, - "dependencies": { - "tempy": "*" - } - }, "node_modules/@types/testing-library__jest-dom": { "version": "5.14.5", "resolved": "https://registry.npmjs.org/@types/testing-library__jest-dom/-/testing-library__jest-dom-5.14.5.tgz", @@ -8440,8 +8383,7 @@ "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", - "dev": true + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" }, "node_modules/abort-controller": { "version": "3.0.0", @@ -8594,7 +8536,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", - "dev": true, "dependencies": { "debug": "^4.1.0", "depd": "^2.0.0", @@ -8865,8 +8806,7 @@ "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", - "dev": true + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" }, "node_modules/arch": { "version": "2.2.0", @@ -8892,7 +8832,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", - "dev": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -9049,8 +8988,7 @@ "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", - "dev": true + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" }, "node_modules/asar": { "version": "3.2.0", @@ -9278,9 +9216,9 @@ } }, "node_modules/b4a": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.2.tgz", - "integrity": "sha512-YFqjbZ8iqX/wWJVmF1SSOB5TYDwsPd/sZzhSdu2PskElf55PjEe+0MhsEPgoa5eTK1VS/WqJMz9qwIFwZta+3g==" + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.3.tgz", + "integrity": "sha512-aX6/FqpWQve8VN9kyTExy7GlmwNShvxcCWWD5QVR3ZbRlyBGtCrG5Autu95xxSPH4CRs+5PSV4d7PRnWpmqFlA==" }, "node_modules/babel-jest": { "version": "28.1.3", @@ -9640,7 +9578,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-3.0.3.tgz", "integrity": "sha512-zKdnMPWEdh4F5INR07/eBrodC7QrF5JKvqskjz/ZZRXg5YSAZIbn8zGhbhUrElzHBZ2fvEQdOU59RHcTG3GiwA==", - "dev": true, "dependencies": { "cmd-shim": "^5.0.0", "mkdirp-infer-owner": "^2.0.0", @@ -9657,7 +9594,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", - "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -9666,7 +9602,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -10104,7 +10039,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", - "dev": true, "dependencies": { "semver": "^7.0.0" } @@ -10139,7 +10073,6 @@ "version": "16.1.3", "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", - "dev": true, "dependencies": { "@npmcli/fs": "^2.1.0", "@npmcli/move-file": "^2.0.0", @@ -10168,7 +10101,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -10177,7 +10109,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -10196,7 +10127,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -10205,7 +10135,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -10217,7 +10146,6 @@ "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" }, @@ -10229,7 +10157,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -10244,7 +10171,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -10254,7 +10180,6 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -10274,7 +10199,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -10285,8 +10209,7 @@ "node_modules/cacache/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/cacheable-lookup": { "version": "5.0.4", @@ -10410,9 +10333,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001466", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001466.tgz", - "integrity": "sha512-ewtFBSfWjEmxUgNBSZItFSmVtvk9zkwkl1OfRZlKA8slltRN+/C/tuGVrF9styXkN36Yu3+SeJ1qkXxDEyNZ5w==", + "version": "1.0.30001468", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz", + "integrity": "sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A==", "funding": [ { "type": "opencollective", @@ -10811,7 +10734,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-5.0.0.tgz", "integrity": "sha512-qkCtZ59BidfEwHltnJwkyVZn+XQojdAySM1D1gSeh11Z4pW1Kpolkyo53L5noc0nrxmIvyFwTmJRo4xs7FFLPw==", - "dev": true, "dependencies": { "mkdirp-infer-owner": "^2.0.0" }, @@ -10885,7 +10807,6 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "dev": true, "bin": { "color-support": "bin.js" } @@ -10930,7 +10851,6 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", - "dev": true, "dependencies": { "strip-ansi": "^6.0.1", "wcwidth": "^1.0.0" @@ -10976,8 +10896,7 @@ "node_modules/common-ancestor-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", - "dev": true + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==" }, "node_modules/common-path-prefix": { "version": "3.0.0", @@ -11206,8 +11125,7 @@ "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "dev": true + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" }, "node_modules/content-disposition": { "version": "0.5.4", @@ -11933,7 +11851,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", - "dev": true, "engines": { "node": "*" } @@ -12066,9 +11983,9 @@ } }, "node_modules/deepmerge": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz", - "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==", + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", "engines": { "node": ">=0.10.0" } @@ -12242,14 +12159,12 @@ "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "dev": true + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, "engines": { "node": ">= 0.8" } @@ -12322,7 +12237,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", - "dev": true, "dependencies": { "asap": "^2.0.0", "wrappy": "1" @@ -12944,9 +12858,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.329", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.329.tgz", - "integrity": "sha512-dcwPzNUG4+reo5z+wHnrl2eZMu4kz+nLQEeepxLEDTLDC7Mi7AVTM4NXWct1TZyu3G4oQgygaAfbByaBtPqw2Q==" + "version": "1.4.333", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.333.tgz", + "integrity": "sha512-YyE8+GKyGtPEP1/kpvqsdhD6rA/TP1DUFDN4uiU/YI52NzDxmwHkEb3qjId8hLBa5siJvG0sfC3O66501jMruQ==" }, "node_modules/electron-updater": { "version": "4.6.5", @@ -13067,7 +12981,6 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", - "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -13144,8 +13057,7 @@ "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" }, "node_modules/errno": { "version": "0.1.8", @@ -13292,9 +13204,9 @@ "peer": true }, "node_modules/esbuild": { - "version": "0.17.11", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.11.tgz", - "integrity": "sha512-pAMImyokbWDtnA/ufPxjQg0fYo2DDuzAlqwnDvbXqHLphe+m80eF++perYKVm8LeTuj2zUuFXC+xgSVxyoHUdg==", + "version": "0.17.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.12.tgz", + "integrity": "sha512-bX/zHl7Gn2CpQwcMtRogTTBf9l1nl+H6R8nUbjk+RuKqAE3+8FDulLA+pHvX7aA7Xe07Iwa+CWvy9I8Y2qqPKQ==", "dev": true, "hasInstallScript": true, "bin": { @@ -13304,28 +13216,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.11", - "@esbuild/android-arm64": "0.17.11", - "@esbuild/android-x64": "0.17.11", - "@esbuild/darwin-arm64": "0.17.11", - "@esbuild/darwin-x64": "0.17.11", - "@esbuild/freebsd-arm64": "0.17.11", - "@esbuild/freebsd-x64": "0.17.11", - "@esbuild/linux-arm": "0.17.11", - "@esbuild/linux-arm64": "0.17.11", - "@esbuild/linux-ia32": "0.17.11", - "@esbuild/linux-loong64": "0.17.11", - "@esbuild/linux-mips64el": "0.17.11", - "@esbuild/linux-ppc64": "0.17.11", - "@esbuild/linux-riscv64": "0.17.11", - "@esbuild/linux-s390x": "0.17.11", - "@esbuild/linux-x64": "0.17.11", - "@esbuild/netbsd-x64": "0.17.11", - "@esbuild/openbsd-x64": "0.17.11", - "@esbuild/sunos-x64": "0.17.11", - "@esbuild/win32-arm64": "0.17.11", - "@esbuild/win32-ia32": "0.17.11", - "@esbuild/win32-x64": "0.17.11" + "@esbuild/android-arm": "0.17.12", + "@esbuild/android-arm64": "0.17.12", + "@esbuild/android-x64": "0.17.12", + "@esbuild/darwin-arm64": "0.17.12", + "@esbuild/darwin-x64": "0.17.12", + "@esbuild/freebsd-arm64": "0.17.12", + "@esbuild/freebsd-x64": "0.17.12", + "@esbuild/linux-arm": "0.17.12", + "@esbuild/linux-arm64": "0.17.12", + "@esbuild/linux-ia32": "0.17.12", + "@esbuild/linux-loong64": "0.17.12", + "@esbuild/linux-mips64el": "0.17.12", + "@esbuild/linux-ppc64": "0.17.12", + "@esbuild/linux-riscv64": "0.17.12", + "@esbuild/linux-s390x": "0.17.12", + "@esbuild/linux-x64": "0.17.12", + "@esbuild/netbsd-x64": "0.17.12", + "@esbuild/openbsd-x64": "0.17.12", + "@esbuild/sunos-x64": "0.17.12", + "@esbuild/win32-arm64": "0.17.12", + "@esbuild/win32-ia32": "0.17.12", + "@esbuild/win32-x64": "0.17.12" } }, "node_modules/esbuild-loader": { @@ -15774,7 +15686,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", - "dev": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -16215,9 +16126,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" }, "node_modules/graceful-readlink": { "version": "1.0.1", @@ -16482,8 +16393,7 @@ "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "dev": true + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" }, "node_modules/he": { "version": "1.2.0", @@ -16524,7 +16434,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -16536,7 +16445,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -16547,8 +16455,7 @@ "node_modules/hosted-git-info/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/hpack.js": { "version": "2.1.6", @@ -16848,7 +16755,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dev": true, "dependencies": { "ms": "^2.0.0" } @@ -16951,7 +16857,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", - "dev": true, "dependencies": { "minimatch": "^5.0.1" }, @@ -16963,7 +16868,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -16972,7 +16876,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -17077,8 +16980,7 @@ "node_modules/infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", - "dev": true + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" }, "node_modules/inflight": { "version": "1.0.6", @@ -17103,7 +17005,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-3.0.2.tgz", "integrity": "sha512-YhlQPEjNFqlGdzrBfDNRLhvoSgX7iQRgSxgsNknRQ9ITXFT7UMfVMWhBTOh2Y+25lRnGrv5Xz8yZwQ3ACR6T3A==", - "dev": true, "dependencies": { "npm-package-arg": "^9.0.1", "promzard": "^0.3.0", @@ -17121,7 +17022,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -17133,7 +17033,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -17142,7 +17041,6 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", - "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -17219,8 +17117,7 @@ "node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", - "dev": true + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" }, "node_modules/ip-regex": { "version": "4.3.0", @@ -17457,8 +17354,7 @@ "node_modules/is-lambda": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", - "dev": true + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" }, "node_modules/is-map": { "version": "2.0.2", @@ -20421,9 +20317,9 @@ } }, "node_modules/jest-watch-typeahead/node_modules/ansi-escapes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.0.0.tgz", - "integrity": "sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.1.0.tgz", + "integrity": "sha512-bQyg9bzRntwR/8b89DOEhGwctcwCrbWW/TuqTQnpqpy5Fz3aovcOTj5i8NJV6AHc8OGNdMaqdxAWww8pz2kiKg==", "dependencies": { "type-fest": "^3.0.0" }, @@ -20812,9 +20708,9 @@ "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" }, "node_modules/joi": { - "version": "17.8.4", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.8.4.tgz", - "integrity": "sha512-jjdRHb5WtL+KgSHvOULQEPPv4kcl+ixd1ybOFQq3rWLgEEqc03QMmilodL0GVJE14U/SQDXkUhQUSZANGDH/AA==", + "version": "17.9.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.9.0.tgz", + "integrity": "sha512-PWirKfKoZL3kWHfkGKzdCLGv23c00rI31PKVDMg33b/ANe+bMC/ZPdEnHAoHzn5Hy6BTg3J0A2yRVKzT64e6Xw==", "dependencies": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", @@ -20984,7 +20880,6 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", - "dev": true, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -21025,7 +20920,6 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", - "dev": true, "engines": [ "node >= 0.2.0" ] @@ -21234,14 +21128,12 @@ "node_modules/just-diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-5.2.0.tgz", - "integrity": "sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw==", - "dev": true + "integrity": "sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw==" }, "node_modules/just-diff-apply": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz", - "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", - "dev": true + "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==" }, "node_modules/keyv": { "version": "4.5.2", @@ -21500,6 +21392,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lerna/node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, "node_modules/lerna/node_modules/inquirer": { "version": "8.2.5", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", @@ -21850,7 +21748,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-6.0.3.tgz", "integrity": "sha512-4tkfUZprwvih2VUZYMozL7EMKgQ5q9VW2NtRyxWtQWlkLTAWHRklcAvBN49CVqEkhUw7vTX2fNgB5LzgUucgYg==", - "dev": true, "dependencies": { "aproba": "^2.0.0", "minipass": "^3.1.1", @@ -21865,7 +21762,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -21877,7 +21773,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -21886,7 +21781,6 @@ "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" }, @@ -21898,7 +21792,6 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", - "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -21912,14 +21805,12 @@ "node_modules/libnpmaccess/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/libnpmpublish": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-6.0.4.tgz", "integrity": "sha512-lvAEYW8mB8QblL6Q/PI/wMzKNvIrF7Kpujf/4fGS/32a2i3jzUXi04TNyIBcK6dQJ34IgywfaKGh+Jq4HYPFmg==", - "dev": true, "dependencies": { "normalize-package-data": "^4.0.0", "npm-package-arg": "^9.0.1", @@ -21935,7 +21826,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -21947,7 +21837,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -21956,7 +21845,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", - "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "is-core-module": "^2.8.1", @@ -21971,7 +21859,6 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", - "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -22302,7 +22189,6 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", - "dev": true, "dependencies": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", @@ -22329,7 +22215,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", - "dev": true, "dependencies": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" @@ -22340,7 +22225,6 @@ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -22353,7 +22237,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", - "dev": true, "engines": { "node": ">= 6" } @@ -22362,7 +22245,6 @@ "version": "15.3.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", - "dev": true, "dependencies": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", @@ -22391,7 +22273,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", - "dev": true, "dependencies": { "@tootallnate/once": "1", "agent-base": "6", @@ -22405,7 +22286,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -22417,7 +22297,6 @@ "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" }, @@ -22429,7 +22308,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -22444,7 +22322,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", - "dev": true, "dependencies": { "minipass": "^3.1.1" }, @@ -22456,7 +22333,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", - "dev": true, "dependencies": { "unique-slug": "^2.0.0" } @@ -22465,7 +22341,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", - "dev": true, "dependencies": { "imurmurhash": "^0.1.4" } @@ -22473,8 +22348,7 @@ "node_modules/make-fetch-happen/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/make-plural": { "version": "6.2.2", @@ -22970,9 +22844,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.3.tgz", - "integrity": "sha512-CD9cXeKeXLcnMw8FZdtfrRrLaM7gwCl4nKuKn2YkY2Bw5wdlB8zU2cCzw+w2zS9RFvbrufTBkMCJACNPwqQA0w==", + "version": "2.7.5", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.5.tgz", + "integrity": "sha512-9HaR++0mlgom81s95vvNjxkg52n2b5s//3ZTI1EtzFb98awsLSivs2LMsVqnQ3ay0PVhqWcGNyDaTE961FOcjQ==", "dependencies": { "schema-utils": "^4.0.0" }, @@ -23087,7 +22961,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -23099,7 +22972,6 @@ "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" }, @@ -23110,14 +22982,12 @@ "node_modules/minipass-collect/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/minipass-fetch": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", - "dev": true, "dependencies": { "minipass": "^3.1.0", "minipass-sized": "^1.0.3", @@ -23134,7 +23004,6 @@ "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" }, @@ -23145,14 +23014,12 @@ "node_modules/minipass-fetch/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -23164,7 +23031,6 @@ "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" }, @@ -23175,14 +23041,12 @@ "node_modules/minipass-flush/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/minipass-json-stream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "dev": true, "dependencies": { "jsonparse": "^1.3.1", "minipass": "^3.0.0" @@ -23192,7 +23056,6 @@ "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" }, @@ -23203,14 +23066,12 @@ "node_modules/minipass-json-stream/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -23222,7 +23083,6 @@ "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" }, @@ -23233,14 +23093,12 @@ "node_modules/minipass-pipeline/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -23252,7 +23110,6 @@ "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" }, @@ -23263,8 +23120,7 @@ "node_modules/minipass-sized/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/minizlib": { "version": "2.1.2", @@ -23351,7 +23207,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz", "integrity": "sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw==", - "dev": true, "dependencies": { "chownr": "^2.0.0", "infer-owner": "^1.0.4", @@ -23619,7 +23474,6 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -23718,7 +23572,6 @@ "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", - "dev": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -23753,7 +23606,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -23873,7 +23725,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dev": true, "dependencies": { "abbrev": "1" }, @@ -24093,7 +23944,6 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", - "dev": true, "dependencies": { "npm-normalize-package-bin": "^1.0.1" } @@ -24126,7 +23976,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", - "dev": true, "dependencies": { "semver": "^7.1.1" }, @@ -24137,14 +23986,12 @@ "node_modules/npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", - "dev": true + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" }, "node_modules/npm-package-arg": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.1.tgz", "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", - "dev": true, "dependencies": { "hosted-git-info": "^3.0.6", "semver": "^7.0.0", @@ -24157,14 +24004,12 @@ "node_modules/npm-package-arg/node_modules/builtins": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", - "dev": true + "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==" }, "node_modules/npm-package-arg/node_modules/hosted-git-info": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -24176,7 +24021,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -24188,7 +24032,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", - "dev": true, "dependencies": { "builtins": "^1.0.3" } @@ -24196,14 +24039,12 @@ "node_modules/npm-package-arg/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/npm-packlist": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.1.tgz", "integrity": "sha512-UfpSvQ5YKwctmodvPPkK6Fwk603aoVsf8AEbmVKAEECrfvL8SSe1A2YIwrJ6xmTHAITKPwwZsWo7WwEbNk0kxw==", - "dev": true, "dependencies": { "glob": "^8.0.1", "ignore-walk": "^5.0.1", @@ -24221,7 +24062,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -24230,7 +24070,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -24249,7 +24088,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -24261,7 +24099,6 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.2.tgz", "integrity": "sha512-gk37SyRmlIjvTfcYl6RzDbSmS9Y4TOBXfsPnoYqTHARNgWbyDiCSMLUpmALDj4jjcTZpURiEfsSHJj9k7EV4Rw==", - "dev": true, "dependencies": { "npm-install-checks": "^5.0.0", "npm-normalize-package-bin": "^2.0.0", @@ -24276,7 +24113,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -24288,7 +24124,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -24297,7 +24132,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", - "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -24306,7 +24140,6 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", - "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -24321,7 +24154,6 @@ "version": "13.3.0", "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.0.tgz", "integrity": "sha512-10LJQ/1+VhKrZjIuY9I/+gQTvumqqlgnsCufoXETHAPFTS3+M+Z5CFhZRDHGavmJ6rOye3UvNga88vl8n1r6gg==", - "dev": true, "dependencies": { "make-fetch-happen": "^10.0.6", "minipass": "^3.1.6", @@ -24339,7 +24171,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -24351,7 +24182,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -24360,7 +24190,6 @@ "version": "10.2.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", - "dev": true, "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^16.1.0", @@ -24387,7 +24216,6 @@ "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" }, @@ -24399,7 +24227,6 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", - "dev": true, "dependencies": { "minipass": "^3.1.6", "minipass-sized": "^1.0.3", @@ -24416,7 +24243,6 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", - "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -24431,7 +24257,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", - "dev": true, "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -24444,8 +24269,7 @@ "node_modules/npm-registry-fetch/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/npm-run-path": { "version": "2.0.2", @@ -26665,7 +26489,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", - "dev": true, "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -26694,14 +26517,14 @@ "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==" }, "node_modules/nx": { - "version": "15.8.6", - "resolved": "https://registry.npmjs.org/nx/-/nx-15.8.6.tgz", - "integrity": "sha512-3OsT6HMyyUyRuP07vLr7iuWzqziQvkh/vSfOWQb3PXakm6N1IvaLxF+NuUCtSaBDUACfqoVO4MC7WE2270OrKQ==", + "version": "15.8.7", + "resolved": "https://registry.npmjs.org/nx/-/nx-15.8.7.tgz", + "integrity": "sha512-u6p/1gU20WU61orxK7hcXBsVspPHy3X66XVAAakkYcaOBlsJhJrR7Og191qIyjEkqEWmcekiDQVw3D6XfagL4Q==", "dev": true, "hasInstallScript": true, "dependencies": { - "@nrwl/cli": "15.8.6", - "@nrwl/tao": "15.8.6", + "@nrwl/cli": "15.8.7", + "@nrwl/tao": "15.8.7", "@parcel/watcher": "2.0.4", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "^3.0.0-rc.18", @@ -26740,15 +26563,15 @@ "nx": "bin/nx.js" }, "optionalDependencies": { - "@nrwl/nx-darwin-arm64": "15.8.6", - "@nrwl/nx-darwin-x64": "15.8.6", - "@nrwl/nx-linux-arm-gnueabihf": "15.8.6", - "@nrwl/nx-linux-arm64-gnu": "15.8.6", - "@nrwl/nx-linux-arm64-musl": "15.8.6", - "@nrwl/nx-linux-x64-gnu": "15.8.6", - "@nrwl/nx-linux-x64-musl": "15.8.6", - "@nrwl/nx-win32-arm64-msvc": "15.8.6", - "@nrwl/nx-win32-x64-msvc": "15.8.6" + "@nrwl/nx-darwin-arm64": "15.8.7", + "@nrwl/nx-darwin-x64": "15.8.7", + "@nrwl/nx-linux-arm-gnueabihf": "15.8.7", + "@nrwl/nx-linux-arm64-gnu": "15.8.7", + "@nrwl/nx-linux-arm64-musl": "15.8.7", + "@nrwl/nx-linux-x64-gnu": "15.8.7", + "@nrwl/nx-linux-x64-musl": "15.8.7", + "@nrwl/nx-win32-arm64-msvc": "15.8.7", + "@nrwl/nx-win32-x64-msvc": "15.8.7" }, "peerDependencies": { "@swc-node/register": "^1.4.2", @@ -26780,9 +26603,9 @@ } }, "node_modules/nx/node_modules/fs-extra": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", - "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -27468,7 +27291,6 @@ "version": "13.6.1", "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.1.tgz", "integrity": "sha512-L+2BI1ougAPsFjXRyBhcKmfT016NscRFLv6Pz5EiNf1CCFJFU0pSKKQwsZTyAQB+sTuUL4TyFyp6J1Ork3dOqw==", - "dev": true, "dependencies": { "@npmcli/git": "^3.0.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -27503,7 +27325,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -27515,7 +27336,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -27524,7 +27344,6 @@ "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" }, @@ -27536,7 +27355,6 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", - "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -27551,7 +27369,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -27565,8 +27382,7 @@ "node_modules/pacote/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/pako": { "version": "0.2.9", @@ -27598,7 +27414,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-2.0.2.tgz", "integrity": "sha512-jDbRGb00TAPFsKWCpZZOT93SxVP9nONOSgES3AevqRq/CHvavEBvKAjxX9p5Y5F0RZLxH9Ufd9+RwtCsa+lFDA==", - "dev": true, "dependencies": { "json-parse-even-better-errors": "^2.3.1", "just-diff": "^5.0.1", @@ -27719,7 +27534,6 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.1.tgz", "integrity": "sha512-OW+5s+7cw6253Q4E+8qQ/u1fVvcJQCJo/VFD8pje+dbJCF1n5ZRMV2AEHbGp+5Q7jxQIYJxkHopnj6nzdGeZLA==", - "dev": true, "dependencies": { "lru-cache": "^7.14.1", "minipass": "^4.0.2" @@ -27735,7 +27549,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -28548,9 +28361,9 @@ } }, "node_modules/prettier": { - "version": "2.8.4", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", - "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.5.tgz", + "integrity": "sha512-3gzuxrHbKUePRBB4ZeU08VNkUcqEHaUaouNt0m7LGP4Hti/NuB07C7PPTM/LkWqXoJYJn2McEo5+kxPNrtQkLQ==", "peer": true, "bin": { "prettier": "bin-prettier.js" @@ -28628,7 +28441,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", - "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -28658,7 +28470,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", - "dev": true, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -28667,7 +28478,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.1.tgz", "integrity": "sha512-3+hgaa19jzCGLuSCbieeRsu5C2joKfYn8pY6JAuXFRVfF4IO+L7UPpFWNTeWT9pM7uhskvbPPd/oEOktCn317Q==", - "dev": true, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -28675,14 +28485,12 @@ "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", - "dev": true + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -28707,7 +28515,6 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", "integrity": "sha512-JZeYqd7UAcHCwI+sTOeUDYkvEU+1bQ7iE0UT1MgB/tERkAPkesW46MrpIySzODi+owTjZtiF8Ay5j9m60KmMBw==", - "dev": true, "dependencies": { "read": "1" } @@ -29092,16 +28899,6 @@ "react-dom": "^16.13.1 || ^17.0.1" } }, - "node_modules/react-material-ui-carousel/node_modules/@types/react": { - "version": "16.14.35", - "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.35.tgz", - "integrity": "sha512-NUEiwmSS1XXtmBcsm1NyRRPYjoZF2YTE89/5QiLt5mlGffYK9FQqOKuOLuXNrjPQV04oQgaZG+Yq02ZfHoFyyg==", - "dependencies": { - "@types/prop-types": "*", - "@types/scheduler": "*", - "csstype": "^3.0.2" - } - }, "node_modules/react-material-ui-carousel/node_modules/auto-bind": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-2.1.1.tgz", @@ -29113,11 +28910,6 @@ "node": ">=6" } }, - "node_modules/react-material-ui-carousel/node_modules/csstype": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", - "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" - }, "node_modules/react-redux": { "version": "7.2.9", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", @@ -29218,9 +29010,9 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-select": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.0.tgz", - "integrity": "sha512-lJGiMxCa3cqnUr2Jjtg9YHsaytiZqeNOKeibv6WF5zbK/fPegZ1hg3y/9P1RZVLhqBTs0PfqQLKuAACednYGhQ==", + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.1.tgz", + "integrity": "sha512-u/brzm3B6vgI+PtxNyE4/18kXgaf6bn5sOAjKhaQ54EItBfW41SRLH1AJC5fefPnGM4JmMcM51t/HAVCi5GrpQ==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.0", @@ -29322,7 +29114,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", - "dev": true, "dependencies": { "mute-stream": "~0.0.4" }, @@ -29343,7 +29134,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-3.0.0.tgz", "integrity": "sha512-KQDVjGqhZk92PPNRj9ZEXEuqg8bUobSKRw+q0YQ3TKI5xkce7bUJobL4Z/OtiEbAAv70yEpYIXp4iQ9L8oPVog==", - "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -29377,7 +29167,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.1.tgz", "integrity": "sha512-MALHuNgYWdGW3gKzuNMuYtcSSZbGQm94fAp16xt8VsYTLBjUSc55bLMKe6gzpWue0Tfi6CBgwCSdDAqutGDhMg==", - "dev": true, "dependencies": { "glob": "^8.0.1", "json-parse-even-better-errors": "^2.3.1", @@ -29392,7 +29181,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", - "dev": true, "dependencies": { "json-parse-even-better-errors": "^2.3.0", "npm-normalize-package-bin": "^1.0.1" @@ -29405,7 +29193,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -29414,7 +29201,6 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -29433,7 +29219,6 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", - "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -29445,7 +29230,6 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", - "dev": true, "engines": { "node": ">=12" } @@ -29454,7 +29238,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -29466,7 +29249,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", - "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "is-core-module": "^2.8.1", @@ -29690,7 +29472,6 @@ "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", "deprecated": "This functionality has been moved to @npmcli/fs", - "dev": true, "dependencies": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", @@ -30121,7 +29902,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.0.tgz", "integrity": "sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==", - "dev": true, "dependencies": { "glob": "^9.2.0" }, @@ -30139,7 +29919,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -30148,7 +29927,6 @@ "version": "9.3.0", "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.0.tgz", "integrity": "sha512-EAZejC7JvnQINayvB/7BJbpZpNOJ8Lrw2OZNEvQxe0vaLn1SuwMcfV7/MNaX8L/T0wmptBFI4YMtDvSBxYDc7w==", - "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^7.4.1", @@ -30166,7 +29944,6 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.2.tgz", "integrity": "sha512-xy4q7wou3vUoC9k1xGTXc+awNdGaGVHtFUaey8tiX4H1QRc04DZ/rmDFwNm2EBsuYEhAZ6SgMmYf3InGY6OauA==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -30276,9 +30053,9 @@ } }, "node_modules/safe-stable-stringify": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", - "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", + "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", "engines": { "node": ">=10" } @@ -30298,9 +30075,9 @@ } }, "node_modules/sass": { - "version": "1.59.2", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.59.2.tgz", - "integrity": "sha512-jJyO6SmbzkJexF8MUorHx5tAilcgabioYxT/BHbY4+OvoqmbHxsYlrjZ8Adhqcgl6Zqwie0TgMXLCAmPFxXOuw==", + "version": "1.59.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.59.3.tgz", + "integrity": "sha512-QCq98N3hX1jfTCoUAsF3eyGuXLsY7BCnCEg9qAact94Yc21npG2/mVOqoDvE0fCbWDqiM4WlcJQla0gWG2YlxQ==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -30670,8 +30447,7 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", - "dev": true + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" }, "node_modules/set-getter": { "version": "0.1.1", @@ -30916,7 +30692,6 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "dev": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -30937,7 +30712,6 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", - "dev": true, "dependencies": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" @@ -30951,7 +30725,6 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", - "dev": true, "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -31053,7 +30826,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", - "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -31062,14 +30834,12 @@ "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", - "dev": true + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" }, "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", - "dev": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -31078,8 +30848,7 @@ "node_modules/spdx-license-ids": { "version": "3.0.13", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", - "dev": true + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==" }, "node_modules/spdy": { "version": "4.0.2", @@ -31175,7 +30944,6 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", - "dev": true, "dependencies": { "minipass": "^3.1.1" }, @@ -31187,7 +30955,6 @@ "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" }, @@ -31198,8 +30965,7 @@ "node_modules/ssri/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/stack-trace": { "version": "0.0.10", @@ -31357,6 +31123,53 @@ "node": ">= 0.8" } }, + "node_modules/stdin-discarder": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", + "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", + "dependencies": { + "bl": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/stdin-discarder/node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/stdin-discarder/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -32011,9 +31824,9 @@ } }, "node_modules/tar-stream/node_modules/bl": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.0.tgz", - "integrity": "sha512-Ik9BVIMdcWzSOCpzDv2XpQ4rJ4oZBuk3ck6MgiOv0EopdgtohN2uSCrrLlkH1Jf0KnpZZMBA3D0bUMbCdj/jgA==", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.1.tgz", + "integrity": "sha512-zk1P1eAEBHhhB+4NfGxqmuV6NgwECnIoRgsOq2ObdEsmoFVIYzJ/Jjcgaj7JOY/8ekH27bIHSV4Si2T+evqu+Q==", "dependencies": { "buffer": "^6.0.3", "inherits": "^2.0.4", @@ -32583,7 +32396,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-2.0.0.tgz", "integrity": "sha512-N5gJCkLu1aXccpOTtqV6ddSEi6ZmGkh3hjmbu1IjcavJK4qyOVQmi0myQKM7z5jVGmD68SJoliaVrMmVObhj6A==", - "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -32850,8 +32662,7 @@ "node_modules/typed-emitter": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/typed-emitter/-/typed-emitter-1.4.0.tgz", - "integrity": "sha512-weBmoo3HhpKGgLBOYwe8EB31CzDFuaK7CCL+axXhUYhn4jo6DSkHnbefboCF5i4DQ2aMFe0C/FdTWcPdObgHyg==", - "dev": true + "integrity": "sha512-weBmoo3HhpKGgLBOYwe8EB31CzDFuaK7CCL+axXhUYhn4jo6DSkHnbefboCF5i4DQ2aMFe0C/FdTWcPdObgHyg==" }, "node_modules/typed-regex": { "version": "0.0.8", @@ -32996,9 +32807,9 @@ "dev": true }, "node_modules/underscore": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==" + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -33044,7 +32855,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", - "dev": true, "dependencies": { "unique-slug": "^3.0.0" }, @@ -33056,7 +32866,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", - "dev": true, "dependencies": { "imurmurhash": "^0.1.4" }, @@ -33287,7 +33096,6 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -33297,7 +33105,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", - "dev": true, "dependencies": { "builtins": "^5.0.0" }, @@ -33400,8 +33207,7 @@ "node_modules/walk-up-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-1.0.0.tgz", - "integrity": "sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg==", - "dev": true + "integrity": "sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg==" }, "node_modules/walker": { "version": "1.0.8", @@ -33457,9 +33263,9 @@ } }, "node_modules/webpack": { - "version": "5.76.1", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", - "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", + "version": "5.76.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz", + "integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", @@ -33633,9 +33439,9 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.12.0.tgz", - "integrity": "sha512-XRN9YRnvOj3TQQ5w/0pR1y1xDcVnbWtNkTri46kuEbaWUPTHsWUvOyAAI7PZHLY+hsFki2kRltJjKMw7e+IiqA==", + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.1.tgz", + "integrity": "sha512-5tWg00bnWbYgkN+pd5yISQKDejRBYGEw15RaEEslH+zdbNDxxaZvEAO2WulaSaFKb5n3YG8JXsGaDsut1D0xdA==", "dev": true, "dependencies": { "@types/bonjour": "^3.5.9", @@ -33683,6 +33489,9 @@ "webpack": "^4.37.0 || ^5.0.0" }, "peerDependenciesMeta": { + "webpack": { + "optional": true + }, "webpack-cli": { "optional": true } @@ -33928,7 +33737,6 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dev": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -34489,7 +34297,6 @@ "@types/marked": "^4.0.8", "@types/md5-file": "^4.0.2", "@types/memorystream": "^0.3.0", - "@types/mini-css-extract-plugin": "^2.4.0", "@types/mock-fs": "^4.13.1", "@types/node": "^16.18.11", "@types/proper-lockfile": "^4.1.2", @@ -34506,7 +34313,6 @@ "@types/semver": "^7.3.13", "@types/tar": "^6.1.4", "@types/tcp-port-used": "^1.0.1", - "@types/tempy": "^0.3.0", "@types/triple-beam": "^1.3.2", "@types/url-parse": "^1.4.8", "@types/uuid": "^8.3.4", @@ -35267,9 +35073,9 @@ "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" }, "packages/infrastructure/jest/node_modules/@types/jest": { - "version": "29.4.1", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.1.tgz", - "integrity": "sha512-zDQSWXG+ZkEvs2zFFMszePhx4euKz+Yt3Gg1P+RHjfJBinTTr6L2DEyovO4V/WrKXuF0Dgn56GWGZPDa6TW9eQ==", + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -36165,18 +35971,6 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "packages/infrastructure/jest/node_modules/react": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", - "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", - "peer": true, - "dependencies": { - "loose-envify": "^1.1.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "packages/infrastructure/jest/node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -36338,11 +36132,11 @@ } }, "packages/infrastructure/webpack/node_modules/sass-loader": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", - "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.1.tgz", + "integrity": "sha512-VQUrgUa5/waIzMrzyuko3sj5WD9NMsYph91cNICx+OaODbRtLl6To2fswLx8MH2qNxXFqRtpvdPQIa7mE93YOA==", "dependencies": { - "klona": "^2.0.4", + "klona": "^2.0.6", "neo-async": "^2.6.2" }, "engines": { @@ -36860,9 +36654,9 @@ "dev": true }, "packages/release-tool/node_modules/ansi-escapes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.0.0.tgz", - "integrity": "sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.1.0.tgz", + "integrity": "sha512-bQyg9bzRntwR/8b89DOEhGwctcwCrbWW/TuqTQnpqpy5Fz3aovcOTj5i8NJV6AHc8OGNdMaqdxAWww8pz2kiKg==", "dependencies": { "type-fest": "^3.0.0" }, @@ -36895,39 +36689,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "packages/release-tool/node_modules/bl": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", - "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", - "dependencies": { - "buffer": "^6.0.3", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "packages/release-tool/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "packages/release-tool/node_modules/chalk": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", @@ -36993,28 +36754,28 @@ } }, "packages/release-tool/node_modules/inquirer": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.1.4.tgz", - "integrity": "sha512-9hiJxE5gkK/cM2d1mTEnuurGTAoHebbkX0BYl3h7iEg7FYfuNIom+nDfBCSWtvSnoSrWCeBxqqBZu26xdlJlXA==", + "version": "9.1.5", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.1.5.tgz", + "integrity": "sha512-3ygAIh8gcZavV9bj6MTdYddG2zPSYswP808fKS46NOwlF0zZljVpnLCHODDqItWJDbDpLb3aouAxGaJbkxoppA==", "dependencies": { "ansi-escapes": "^6.0.0", - "chalk": "^5.1.2", + "chalk": "^5.2.0", "cli-cursor": "^4.0.0", "cli-width": "^4.0.0", "external-editor": "^3.0.3", "figures": "^5.0.0", "lodash": "^4.17.21", - "mute-stream": "0.0.8", + "mute-stream": "1.0.0", "ora": "^6.1.2", "run-async": "^2.4.0", - "rxjs": "^7.5.7", + "rxjs": "^7.8.0", "string-width": "^5.1.2", "strip-ansi": "^7.0.1", "through": "^2.3.6", - "wrap-ansi": "^8.0.1" + "wrap-ansi": "^8.1.0" }, "engines": { - "node": ">=12.0.0" + "node": ">=14.18.0" } }, "packages/release-tool/node_modules/is-interactive": { @@ -37054,18 +36815,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "packages/release-tool/node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, "packages/release-tool/node_modules/ora": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.1.2.tgz", - "integrity": "sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-6.2.0.tgz", + "integrity": "sha512-c1qb/1rdE+EFDYiLXh10VY459uMh7DN9zlgd8mZJLoeiPpYllN8eAOiih2Rkah5ywxRm5tHN5C9zPheDq8d1MA==", "dependencies": { - "bl": "^5.0.0", "chalk": "^5.0.0", "cli-cursor": "^4.0.0", "cli-spinners": "^2.6.1", "is-interactive": "^2.0.0", "is-unicode-supported": "^1.1.0", "log-symbols": "^5.1.0", + "stdin-discarder": "^0.1.0", "strip-ansi": "^7.0.1", "wcwidth": "^1.0.1" }, @@ -37230,26 +36999,72 @@ "name": "@k8slens/run-many", "version": "1.0.0-alpha.1", "license": "MIT", + "devDependencies": { + "@types/uuid": "^9.0.1" + }, "peerDependencies": { "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", "@ogre-tools/fp": "^15.1.1", - "@ogre-tools/injectable": "^15.1.1" + "@ogre-tools/injectable": "^15.1.2", + "type-fest": "^2.19.0", + "typed-emitter": "^1.4.0", + "uuid": "^8.3.2" } }, + "packages/utility-features/run-many/node_modules/@types/uuid": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-9.0.1.tgz", + "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", + "dev": true + }, "packages/utility-features/test-utils": { "name": "@k8slens/test-utils", "version": "1.0.0-alpha.1", - "license": "MIT" + "license": "MIT", + "devDependencies": { + "@types/lodash": "^4.14.191" + }, + "peerDependencies": { + "@ogre-tools/injectable": "^15.1.2", + "lodash": "^4.17.21" + } }, "packages/utility-features/utilities": { "name": "@k8slens/utilities", "version": "1.0.0-alpha.1", "license": "MIT", + "devDependencies": { + "@types/crypto-js": "^4.1.1", + "@types/lodash": "^4.14.191", + "@types/react": "^17.0.2", + "@types/react-router": "^5.1.20", + "@types/readable-stream": "^2.3.15", + "@types/semver": "^7.3.13", + "@types/tar": "^6.1.4" + }, "peerDependencies": { + "@astronautlabs/jsonpath": "^1.1.0", + "crypto-js": "^4.1.1", + "lodash": "^4.17.21", "mobx": "^6.8.0", - "type-fest": "^2.19.0" + "moment": "^2.29.4", + "p-limit": "^3.1.0", + "path-to-regexp": "^6.2.1", + "react": "^17.0.2", + "react-router": "^5.3.4", + "readable-stream": "^3.6.2", + "semver": "^7.3.8", + "tar": "^6.1.13", + "type-fest": "^2.19.0", + "typed-regex": "^0.0.8" } + }, + "packages/utility-features/utilities/node_modules/@types/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==", + "dev": true } } } diff --git a/package.json b/package.json index 982724f37f..bc6c89ab37 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,11 @@ "precreate-release-pr": "cd packages/release-tool && npm run build", "create-release-pr": "node packages/release-tool/dist/index.js" }, + "overrides": { + "underscore": "^1.12.1", + "react": "^17", + "@types/react": "^17" + }, "devDependencies": { "adr": "^1.4.3", "cross-env": "^7.0.3", diff --git a/packages/core/package.json b/packages/core/package.json index deceb2161c..6b4aecf2cc 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -116,9 +116,6 @@ } } }, - "resolutions": { - "@astronautlabs/jsonpath/underscore": "^1.12.1" - }, "dependencies": { "@astronautlabs/jsonpath": "^1.1.0", "@hapi/call": "^9.0.1", @@ -222,7 +219,6 @@ "@types/marked": "^4.0.8", "@types/md5-file": "^4.0.2", "@types/memorystream": "^0.3.0", - "@types/mini-css-extract-plugin": "^2.4.0", "@types/mock-fs": "^4.13.1", "@types/node": "^16.18.11", "@types/proper-lockfile": "^4.1.2", @@ -239,7 +235,6 @@ "@types/semver": "^7.3.13", "@types/tar": "^6.1.4", "@types/tcp-port-used": "^1.0.1", - "@types/tempy": "^0.3.0", "@types/triple-beam": "^1.3.2", "@types/url-parse": "^1.4.8", "@types/uuid": "^8.3.4", diff --git a/packages/utility-features/run-many/package.json b/packages/utility-features/run-many/package.json index 52410ecb5b..1dd0229afd 100644 --- a/packages/utility-features/run-many/package.json +++ b/packages/utility-features/run-many/package.json @@ -28,6 +28,12 @@ "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", "@ogre-tools/fp": "^15.1.1", - "@ogre-tools/injectable": "^15.1.1" + "@ogre-tools/injectable": "^15.1.2", + "type-fest": "^2.19.0", + "typed-emitter": "^1.4.0", + "uuid": "^8.3.2" + }, + "devDependencies": { + "@types/uuid": "^9.0.1" } } diff --git a/packages/utility-features/test-utils/package.json b/packages/utility-features/test-utils/package.json index 3adf142d0c..0dc5170a07 100644 --- a/packages/utility-features/test-utils/package.json +++ b/packages/utility-features/test-utils/package.json @@ -23,5 +23,12 @@ "build": "webpack", "dev": "webpack --mode=development --watch", "test": "jest --coverage --runInBand" + }, + "peerDependencies": { + "@ogre-tools/injectable": "^15.1.2", + "lodash": "^4.17.21" + }, + "devDependencies": { + "@types/lodash": "^4.14.191" } } diff --git a/packages/utility-features/utilities/package.json b/packages/utility-features/utilities/package.json index ba22c430aa..01c75c4d7c 100644 --- a/packages/utility-features/utilities/package.json +++ b/packages/utility-features/utilities/package.json @@ -25,7 +25,28 @@ "test": "jest --coverage --runInBand" }, "peerDependencies": { + "@astronautlabs/jsonpath": "^1.1.0", + "crypto-js": "^4.1.1", + "lodash": "^4.17.21", "mobx": "^6.8.0", - "type-fest": "^2.19.0" + "moment": "^2.29.4", + "p-limit": "^3.1.0", + "path-to-regexp": "^6.2.1", + "react": "^17.0.2", + "react-router": "^5.3.4", + "readable-stream": "^3.6.2", + "semver": "^7.3.8", + "tar": "^6.1.13", + "type-fest": "^2.19.0", + "typed-regex": "^0.0.8" + }, + "devDependencies": { + "@types/crypto-js": "^4.1.1", + "@types/lodash": "^4.14.191", + "@types/react": "^17.0.2", + "@types/react-router": "^5.1.20", + "@types/readable-stream": "^2.3.15", + "@types/semver": "^7.3.13", + "@types/tar": "^6.1.4" } } From 0f1f030a06cb3625eb62194696547d4c4fb0d703 Mon Sep 17 00:00:00 2001 From: Janne Savolainen Date: Tue, 21 Mar 2023 11:38:43 +0200 Subject: [PATCH 08/17] Switch to using messaging and startable stoppable from NPM package (#7368) * Add custom jest resolver to fix requiring "uuid" module Signed-off-by: Janne Savolainen * Update dependencies Signed-off-by: Janne Savolainen * Introduce test utils for rendering and running with thrown mobx reactions Signed-off-by: Janne Savolainen * Extract startable-stoppable to NPM package Signed-off-by: Janne Savolainen * Extract messaging to NPM package Co-authored-by: Mikko Aspiala Signed-off-by: Janne Savolainen * Switch to using startable-stoppable from NPM package Signed-off-by: Janne Savolainen * Switch to using messaging from the Feature Signed-off-by: Janne Savolainen * Remove old implementation of messaging Signed-off-by: Janne Savolainen * Make setupping app paths happen earlier in renderer Signed-off-by: Janne Savolainen * Fix typo Signed-off-by: Janne Savolainen * Add kludge to make testing-library work properly from test-utils package Signed-off-by: Janne Savolainen * Fix code style Signed-off-by: Janne Savolainen * Add lint:fix -root script Signed-off-by: Janne Savolainen * Fix unrelated failing unit tests Signed-off-by: Janne Savolainen * Turn of no-floating-promises from typescript linting for being broken Signed-off-by: Janne Savolainen * Make linting not happen for dist -directories Signed-off-by: Janne Savolainen * Make linting failures appear as failure Signed-off-by: Janne Savolainen * Stop running prettier twice It already gets ran as eslint-plugin. Signed-off-by: Janne Savolainen * Make CI run unit tests for all packages by consolidating name of NPM script Co-authored-by: Mikko Aspiala Signed-off-by: Janne Savolainen * Add missing unit tests for coverage Co-authored-by: Mikko Aspiala Signed-off-by: Janne Savolainen * Skip coverage for test utils Co-authored-by: Mikko Aspiala Signed-off-by: Janne Savolainen * Remove check for coverage in packages which are not ready for it Signed-off-by: Janne Savolainen * Stop collecting coverage from index.ts files them being indirections to the implementation Co-authored-by: Mikko Aspiala Signed-off-by: Janne Savolainen * Implement sending message to channel in main Signed-off-by: Janne Savolainen * Add missing feature dependencies Signed-off-by: Janne Savolainen * Add dummy implementations for requesting in main from renderer Signed-off-by: Janne Savolainen * Re-enable communicating from main to cluster frames Signed-off-by: Janne Savolainen * Ignore trivial files from coverage Signed-off-by: Janne Savolainen * Update package-lock Signed-off-by: Janne Savolainen * Extract message-bridge to separate NPM package to prevent dev dependencies being in the production bundle Signed-off-by: Janne Savolainen * Extract computed channel to own NPM package for clear dependencies Signed-off-by: Janne Savolainen * Consolidate electron related stuff to a directory Signed-off-by: Janne Savolainen * Add missing publish configurations Signed-off-by: Janne Savolainen * Ignore test implementation from coverage being not interesting Signed-off-by: Janne Savolainen --------- Signed-off-by: Janne Savolainen --- package-lock.json | 1200 +++++++++++------ package.json | 1 + packages/core/package.json | 5 + .../src/common/app-paths/app-paths-channel.ts | 8 +- .../core/src/common/base-store/base-store.ts | 3 +- .../lens-proxy-certificate-channel.ts | 2 +- .../cluster-store/cluster-store.injectable.ts | 2 +- .../common/cluster/current-cluster-channel.ts | 2 +- .../src/common/cluster/visibility-channel.ts | 2 +- .../app-navigation-channel.ts | 2 +- .../cluster-frame-navigation-channel.ts | 2 +- .../helm/add-helm-repository-channel.ts | 13 +- .../get-active-helm-repositories-channel.ts | 11 +- .../helm/remove-helm-repository-channel.ts | 11 +- .../src/common/hotbars/store.injectable.ts | 2 +- .../core/src/common/kube-helpers/channels.ts | 24 +- .../root-frame/root-frame-rendered-channel.ts | 2 +- .../user-store/user-store.injectable.ts | 2 +- .../src/common/utils/channel/channel.test.ts | 245 ---- ...essage-channel-listener-injection-token.ts | 13 - .../utils/channel/get-request-channel.ts | 9 - ...istening-on-message-channels.injectable.ts | 25 - ...essage-channel-listener-injection-token.ts | 51 - ...equest-channel-listener-injection-token.ts | 10 - .../resolve-system-proxy-channel.ts | 10 +- .../sync-box/channel-listener.injectable.ts | 4 +- .../src/common/utils/sync-box/channels.ts | 18 +- .../sync-box/create-sync-box.injectable.ts | 2 +- .../utils/sync-box/handler.injectable.ts | 19 - .../vars/build-semantic-version.injectable.ts | 2 +- .../weblink-store.injectable.ts | 2 +- ...ile-system-provisioner-store.injectable.ts | 2 +- .../core/src/extensions/extension-store.ts | 2 +- .../extensions-store.injectable.ts | 2 +- .../application-menu-reactivity.injectable.ts | 2 +- ...periodical-check-for-updates.injectable.ts | 2 +- .../restart-and-install-update-channel.ts | 2 +- ...-and-install-update-listener.injectable.ts | 4 +- ...update-should-happen-on-quit.injectable.ts | 2 +- .../restart-and-install-update.injectable.ts | 4 +- .../certificate-authorities/common/channel.ts | 3 +- ...-handler.global-override-for-injectable.ts | 1 + .../main/channel-handler.injectable.ts | 5 +- .../renderer/request-system-cas.injectable.ts | 2 +- .../cluster/activation/common/channels.ts | 2 +- .../activation/common/request-token.ts | 2 +- .../main/activate-listener.injectable.ts | 5 +- .../main/deactivate-listener.injectable.ts | 5 +- .../renderer/request-activation.injectable.ts | 4 +- .../request-deactivation.injectable.ts | 4 +- .../common/clear-as-deleting-channel.ts | 10 +- .../delete-dialog/common/delete-channel.ts | 9 +- .../common/set-as-deleting-channel.ts | 10 +- ...as-deleting-channel-listener.injectable.ts | 5 +- .../delete-channel-listener.injectable.ts | 5 +- ...s-deleteing-channel-listener.injectable.ts | 5 +- .../request-clear-as-deleting.injectable.ts | 4 +- .../renderer/request-delete.injectable.ts | 4 +- .../request-set-as-deleting.injectable.ts | 4 +- .../cluster/state-sync/common/channels.ts | 3 +- .../state-sync/main/emit-update.injectable.ts | 10 +- .../main/handle-initial.injectable.ts | 5 +- .../renderer/listener.injectable.ts | 4 +- .../renderer/request-initial.injectable.ts | 6 +- .../extensions/navigate/common/channel.ts | 2 +- .../navigate/renderer/listener.injectable.ts | 6 +- .../active-helm-repositories.injectable.ts | 2 +- .../add-helm-repository.injectable.ts | 2 +- .../remove-helm-repository.injectable.ts | 2 +- .../navigation/reload-page/common/channel.ts | 2 +- ...listener.global-override-for-injectable.ts | 1 + .../renderer/register-listener.injectable.ts | 4 +- .../path-picking-dialog/common/channel.ts | 2 +- .../main/handle-pick-paths.injectable.ts | 5 +- .../renderer/pick-paths.injectable.ts | 4 +- .../shell-sync/common/failure-channel.ts | 2 +- .../main/emit-failure.injectable.ts | 7 +- .../renderer/failure-listener.injectable.ts | 4 +- .../theme/system-type/common/channels.ts | 3 +- .../main/emit-update.injectable.ts | 10 +- .../main/handle-initial.injectable.ts | 5 +- .../renderer/request-initial.injectable.ts | 6 +- .../renderer/update-listener.injectable.ts | 4 +- packages/core/src/jest-after-env.setup.ts | 5 + ...ths-request-channel-listener.injectable.ts | 5 +- .../build-version/setup-channel.injectable.ts | 5 +- .../catalog-sync-to-renderer.injectable.ts | 2 +- .../cluster/visibility-handler.injectable.ts | 4 +- ...-theme-from-operating-system.injectable.ts | 2 +- packages/core/src/main/getDiForUnitTesting.ts | 7 + ...-repository-channel-listener.injectable.ts | 12 +- .../add-helm-repository.injectable.ts | 11 +- ...epositories-channel-listener.injectable.ts | 5 +- ...-repository-channel-listener.injectable.ts | 5 +- .../ipc/ask-user-for-file-paths.injectable.ts | 2 +- .../kubectl/apply-all-handler.injectable.ts | 5 +- .../kubectl/delete-all-handler.injectable.ts | 5 +- ...-certificate-request-handler.injectable.ts | 5 +- .../listener.injectable.ts | 10 +- .../channel-listener.injectable.ts | 4 +- .../tray/menu-icon/reactive.injectable.ts | 2 +- .../reactive-tray-menu-items.injectable.ts | 2 +- ...ist-message-channel-listener.injectable.ts | 32 - ...istening-on-request-channels.injectable.ts | 34 - .../start-listening-on-channels.injectable.ts | 26 - .../channel/message-to-channel.injectable.ts | 32 - .../utils/channel/message-to-channel.test.ts | 115 -- ...stem-proxy-channel-responder.injectable.ts | 5 +- ...itial-value-channel-listener.injectable.ts | 5 +- .../app-paths/setup-app-paths.injectable.ts | 6 +- ...up-current-cluster-broadcast.injectable.ts | 2 +- ...quest-lens-proxy-certificate.injectable.ts | 4 +- .../attempt-install-by-info.injectable.tsx | 1 + .../cluster-manager/cluster-frame-handler.ts | 3 +- .../emit-cluster-visibility.injectable.ts | 10 +- .../test-utils/get-application-builder.tsx | 18 +- ...-that-root-frame-is-rendered.injectable.ts | 2 +- .../core/src/renderer/getDiForUnitTesting.tsx | 9 +- .../renderer/kubectl/apply-all.injectable.ts | 4 +- .../renderer/kubectl/delete-all.injectable.ts | 4 +- .../navigation-channel-listener.injectable.ts | 11 +- .../start-listening-of-channels.injectable.ts | 23 - .../channel/message-to-channel.injectable.ts | 24 - .../request-from-channel.injectable.ts | 22 - .../utils/channel/send-to-main.injectable.ts | 20 - .../initialize-state.injectable.ts | 4 +- .../resolve-system-proxy.injectable.ts | 4 +- ...nitial-values-for-sync-boxes.injectable.ts | 2 +- .../build-version/build-version.injectable.ts | 2 +- .../channel-fakes/override-channels.ts | 29 - .../override-messaging-from-main-to-window.ts | 79 -- .../override-messaging-from-window-to-main.ts | 53 - ...override-requesting-from-window-to-main.ts | 60 - .../infrastructure/eslint-config/bin/lint | 10 +- .../eslint-config/eslint-config.js | 3 +- .../infrastructure/jest/jest-28-resolver.js | 34 + .../jest/monorepo-package-config.js | 6 + .../legacy-extension-example/jest.config.js | 3 +- .../legacy-extension-example/package.json | 1 - packages/open-lens/package.json | 4 + packages/open-lens/src/main/index.ts | 3 +- packages/open-lens/src/renderer/index.ts | 3 +- .../application/agnostic/index.ts | 4 +- .../application/agnostic/package.json | 2 +- ...lication-information-token.no-coverage.ts} | 0 .../start-application.injectable.ts | 13 +- .../starting-of-application.test.ts | 29 +- .../application/electron-main/index.ts | 2 +- .../application/electron-main/package.json | 2 +- .../override-side-effects-with-fakes.ts | 2 +- .../legacy-extensions/jest.config.js | 3 +- .../legacy-extensions/package.json | 1 - .../feature-core/package.json | 2 +- .../messaging/agnostic/.eslintrc.json | 6 + .../messaging/agnostic/.prettierrc | 1 + .../messaging/agnostic/index.ts | 2 + .../messaging/agnostic/jest.config.js | 1 + .../messaging/agnostic/package.json | 49 + .../features/actual/channel.no-coverage.ts} | 7 - .../agnostic/src/features/actual/feature.ts | 18 + .../agnostic/src/features/actual/index.ts | 53 + .../listening-of-channels.injectable.ts | 106 ++ .../start-listening-of-channels.injectable.ts | 21 + ...essage-channel-listener-injection-token.ts | 15 + .../actual/message/get-message-channel.ts | 5 + ...essage-channel-listener-injection-token.ts | 51 + .../message-to-channel-injection-token.ts | 10 - ...equest-channel-listener-injection-token.ts | 15 + .../actual/request/get-request-channel.ts | 7 + ...quest-channel-listener-injection-token.ts} | 42 +- .../request-from-channel-injection-token.ts | 16 +- .../src/features/unit-testing/feature.ts | 18 + .../src/features/unit-testing/index.ts | 1 + .../unit-testing/test-doubles.injectable.ts | 31 + .../src/listening-of-messages.test.ts | 169 +++ .../src/listening-of-requests.test.ts | 204 +++ .../messaging/agnostic/tsconfig.json | 4 + .../messaging/agnostic/webpack.config.js | 1 + .../messaging/computed-channel/.eslintrc.json | 6 + .../messaging/computed-channel/.prettierrc | 1 + .../messaging/computed-channel/index.ts | 12 + .../messaging/computed-channel/jest.config.js | 1 + .../messaging/computed-channel/package.json | 51 + ...annel-administration-channel.injectable.ts | 64 + .../computed-channel.injectable.ts | 110 ++ .../computed-channel.test.tsx | 571 ++++++++ ...icate-channel-observer-guard.injectable.ts | 42 + .../messaging/computed-channel/src/feature.ts | 18 + .../messaging/computed-channel/tsconfig.json | 4 + .../computed-channel/webpack.config.js | 1 + .../messaging/electron/main/.eslintrc.json | 6 + .../messaging/electron/main/.prettierrc | 1 + .../messaging/electron/main/index.ts | 1 + .../messaging/electron/main/jest.config.js | 1 + .../messaging/electron/main/package.json | 47 + ...ist-message-channel-listener.injectable.ts | 28 + .../enlist-message-channel-listener.test.ts | 44 +- ...ist-request-channel-listener.injectable.ts | 19 +- .../enlist-request-channel-listener.test.ts | 28 +- .../messaging/electron/main/src/feature.ts | 18 + .../main/src/ipc-main/ipc-main.injectable.ts | 10 + .../main/src/ipc-main/ipc-main.test.ts | 21 + .../request-from-channel.injectable.ts | 23 + ...allow-communication-listener.injectable.ts | 21 + .../frameIds.injectable.ts | 8 + .../get-web-contents.injectable.ts | 12 + ...send-message-to-channel.injectable.test.ts | 121 ++ .../send-message-to-channel.injectable.ts | 48 + .../messaging/electron/main/tsconfig.json | 4 + .../messaging/electron/main/webpack.config.js | 1 + .../electron/renderer/.eslintrc.json | 6 + .../messaging/electron/renderer/.prettierrc | 1 + .../messaging/electron/renderer/index.ts | 1 + .../electron/renderer/jest.config.js | 1 + .../messaging/electron/renderer/package.json | 48 + ...llow-communication-to-iframe.injectable.ts | 25 + .../src/allow-communication-to-iframe.test.ts | 35 + .../electron/renderer/src/feature.ts | 18 + .../src/ipc/ipc-renderer.injectable.ts | 10 + .../renderer/src/ipc/ipc-renderer.test.ts | 27 + ...ist-message-channel-listener.injectable.ts | 8 +- .../enlist-message-channel-listener.test.ts | 30 +- ...ist-request-channel-listener.injectable.ts | 18 + .../invoke-ipc.injectable.ts | 10 + .../requesting-of-requests/invoke-ipc.test.ts | 21 + .../request-from-channel.injectable.ts | 18 + .../request-from-channel.test.ts | 46 + .../message-to-channel.injectable.ts | 19 + .../message-to-channel.test.ts | 38 + .../send-to-ipc.injectable.ts | 10 + .../sending-of-messages/send-to-ipc.test.ts | 21 + .../messaging/electron/renderer/tsconfig.json | 4 + .../electron/renderer/webpack.config.js | 1 + .../message-bridge-fake/.eslintrc.json | 6 + .../messaging/message-bridge-fake/.prettierrc | 1 + .../messaging/message-bridge-fake/index.ts | 3 + .../message-bridge-fake/jest.config.js | 1 + .../message-bridge-fake/package.json | 49 + .../get-message-bridge-fake.test.ts | 397 ++++++ .../get-message-bridge-fake.ts | 196 +++ .../message-bridge-fake/tsconfig.json | 4 + .../message-bridge-fake/webpack.config.js | 1 + .../utility-features/run-many/jest.config.js | 5 +- .../utility-features/run-many/package.json | 4 +- .../startable-stoppable/.eslintrc.json | 6 + .../startable-stoppable/.prettierrc | 1 + .../startable-stoppable/index.ts | 3 + .../startable-stoppable/jest.config.js | 1 + .../startable-stoppable/package.json | 38 + .../src}/get-startable-stoppable.test.ts | 10 +- .../src}/get-startable-stoppable.ts | 5 - .../startable-stoppable/tsconfig.json | 4 + .../startable-stoppable/webpack.config.js | 1 + packages/utility-features/test-utils/index.ts | 2 + .../utility-features/test-utils/package.json | 8 +- .../test-utils/src/render-for.tsx | 24 + .../src/run-with-thrown-mobx-reactions.ts | 38 + .../utility-features/utilities/jest.config.js | 5 +- .../utility-features/utilities/package.json | 5 +- .../utilities/src/splitArray.test.ts | 24 +- .../utilities/src/union-env-path.test.ts | 2 +- 261 files changed, 4447 insertions(+), 1795 deletions(-) delete mode 100644 packages/core/src/common/utils/channel/channel.test.ts delete mode 100644 packages/core/src/common/utils/channel/enlist-message-channel-listener-injection-token.ts delete mode 100644 packages/core/src/common/utils/channel/get-request-channel.ts delete mode 100644 packages/core/src/common/utils/channel/listening-on-message-channels.injectable.ts delete mode 100644 packages/core/src/common/utils/channel/message-channel-listener-injection-token.ts delete mode 100644 packages/core/src/common/utils/channel/request-channel-listener-injection-token.ts delete mode 100644 packages/core/src/common/utils/sync-box/handler.injectable.ts delete mode 100644 packages/core/src/main/utils/channel/channel-listeners/enlist-message-channel-listener.injectable.ts delete mode 100644 packages/core/src/main/utils/channel/channel-listeners/listening-on-request-channels.injectable.ts delete mode 100644 packages/core/src/main/utils/channel/channel-listeners/start-listening-on-channels.injectable.ts delete mode 100644 packages/core/src/main/utils/channel/message-to-channel.injectable.ts delete mode 100644 packages/core/src/main/utils/channel/message-to-channel.test.ts delete mode 100644 packages/core/src/renderer/utils/channel/channel-listeners/start-listening-of-channels.injectable.ts delete mode 100644 packages/core/src/renderer/utils/channel/message-to-channel.injectable.ts delete mode 100644 packages/core/src/renderer/utils/channel/request-from-channel.injectable.ts delete mode 100644 packages/core/src/renderer/utils/channel/send-to-main.injectable.ts delete mode 100644 packages/core/src/test-utils/channel-fakes/override-channels.ts delete mode 100644 packages/core/src/test-utils/channel-fakes/override-messaging-from-main-to-window.ts delete mode 100644 packages/core/src/test-utils/channel-fakes/override-messaging-from-window-to-main.ts delete mode 100644 packages/core/src/test-utils/channel-fakes/override-requesting-from-window-to-main.ts create mode 100644 packages/infrastructure/jest/jest-28-resolver.js rename packages/technical-features/application/agnostic/src/{application-information-token.ts => application-information-token.no-coverage.ts} (100%) rename packages/technical-features/application/electron-main/src/{ => test-utils}/override-side-effects-with-fakes.ts (69%) create mode 100644 packages/technical-features/messaging/agnostic/.eslintrc.json create mode 100644 packages/technical-features/messaging/agnostic/.prettierrc create mode 100644 packages/technical-features/messaging/agnostic/index.ts create mode 100644 packages/technical-features/messaging/agnostic/jest.config.js create mode 100644 packages/technical-features/messaging/agnostic/package.json rename packages/{core/src/common/utils/channel/channel-injection-token.ts => technical-features/messaging/agnostic/src/features/actual/channel.no-coverage.ts} (52%) create mode 100644 packages/technical-features/messaging/agnostic/src/features/actual/feature.ts create mode 100644 packages/technical-features/messaging/agnostic/src/features/actual/index.ts create mode 100644 packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/listening-of-channels.injectable.ts create mode 100644 packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/start-listening-of-channels.injectable.ts create mode 100644 packages/technical-features/messaging/agnostic/src/features/actual/message/enlist-message-channel-listener-injection-token.ts create mode 100644 packages/technical-features/messaging/agnostic/src/features/actual/message/get-message-channel.ts create mode 100644 packages/technical-features/messaging/agnostic/src/features/actual/message/message-channel-listener-injection-token.ts rename packages/{core/src/common/utils/channel => technical-features/messaging/agnostic/src/features/actual/message}/message-to-channel-injection-token.ts (55%) create mode 100644 packages/technical-features/messaging/agnostic/src/features/actual/request/enlist-request-channel-listener-injection-token.ts create mode 100644 packages/technical-features/messaging/agnostic/src/features/actual/request/get-request-channel.ts rename packages/{core/src/main/utils/channel/channel-listeners/listener-tokens.ts => technical-features/messaging/agnostic/src/features/actual/request/request-channel-listener-injection-token.ts} (56%) rename packages/{core/src/common/utils/channel => technical-features/messaging/agnostic/src/features/actual/request}/request-from-channel-injection-token.ts (53%) create mode 100644 packages/technical-features/messaging/agnostic/src/features/unit-testing/feature.ts create mode 100644 packages/technical-features/messaging/agnostic/src/features/unit-testing/index.ts create mode 100644 packages/technical-features/messaging/agnostic/src/features/unit-testing/test-doubles.injectable.ts create mode 100644 packages/technical-features/messaging/agnostic/src/listening-of-messages.test.ts create mode 100644 packages/technical-features/messaging/agnostic/src/listening-of-requests.test.ts create mode 100644 packages/technical-features/messaging/agnostic/tsconfig.json create mode 100644 packages/technical-features/messaging/agnostic/webpack.config.js create mode 100644 packages/technical-features/messaging/computed-channel/.eslintrc.json create mode 100644 packages/technical-features/messaging/computed-channel/.prettierrc create mode 100644 packages/technical-features/messaging/computed-channel/index.ts create mode 100644 packages/technical-features/messaging/computed-channel/jest.config.js create mode 100644 packages/technical-features/messaging/computed-channel/package.json create mode 100644 packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel-administration-channel.injectable.ts create mode 100644 packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.injectable.ts create mode 100644 packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx create mode 100644 packages/technical-features/messaging/computed-channel/src/computed-channel/duplicate-channel-observer-guard.injectable.ts create mode 100644 packages/technical-features/messaging/computed-channel/src/feature.ts create mode 100644 packages/technical-features/messaging/computed-channel/tsconfig.json create mode 100644 packages/technical-features/messaging/computed-channel/webpack.config.js create mode 100644 packages/technical-features/messaging/electron/main/.eslintrc.json create mode 100644 packages/technical-features/messaging/electron/main/.prettierrc create mode 100644 packages/technical-features/messaging/electron/main/index.ts create mode 100644 packages/technical-features/messaging/electron/main/jest.config.js create mode 100644 packages/technical-features/messaging/electron/main/package.json create mode 100644 packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.injectable.ts rename packages/{core/src/main/utils/channel => technical-features/messaging/electron/main/src}/channel-listeners/enlist-message-channel-listener.test.ts (59%) rename packages/{core/src/main/utils/channel => technical-features/messaging/electron/main/src}/channel-listeners/enlist-request-channel-listener.injectable.ts (53%) rename packages/{core/src/main/utils/channel => technical-features/messaging/electron/main/src}/channel-listeners/enlist-request-channel-listener.test.ts (86%) create mode 100644 packages/technical-features/messaging/electron/main/src/feature.ts create mode 100644 packages/technical-features/messaging/electron/main/src/ipc-main/ipc-main.injectable.ts create mode 100644 packages/technical-features/messaging/electron/main/src/ipc-main/ipc-main.test.ts create mode 100644 packages/technical-features/messaging/electron/main/src/request-from-channel/request-from-channel.injectable.ts create mode 100644 packages/technical-features/messaging/electron/main/src/send-message-to-channel/allow-communication-listener.injectable.ts create mode 100644 packages/technical-features/messaging/electron/main/src/send-message-to-channel/frameIds.injectable.ts create mode 100644 packages/technical-features/messaging/electron/main/src/send-message-to-channel/get-web-contents.injectable.ts create mode 100644 packages/technical-features/messaging/electron/main/src/send-message-to-channel/send-message-to-channel.injectable.test.ts create mode 100644 packages/technical-features/messaging/electron/main/src/send-message-to-channel/send-message-to-channel.injectable.ts create mode 100644 packages/technical-features/messaging/electron/main/tsconfig.json create mode 100644 packages/technical-features/messaging/electron/main/webpack.config.js create mode 100644 packages/technical-features/messaging/electron/renderer/.eslintrc.json create mode 100644 packages/technical-features/messaging/electron/renderer/.prettierrc create mode 100644 packages/technical-features/messaging/electron/renderer/index.ts create mode 100644 packages/technical-features/messaging/electron/renderer/jest.config.js create mode 100644 packages/technical-features/messaging/electron/renderer/package.json create mode 100644 packages/technical-features/messaging/electron/renderer/src/allow-communication-to-iframe.injectable.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/allow-communication-to-iframe.test.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/feature.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/ipc/ipc-renderer.injectable.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/ipc/ipc-renderer.test.ts rename packages/{core/src/renderer/utils/channel/channel-listeners => technical-features/messaging/electron/renderer/src/listening-of-messages}/enlist-message-channel-listener.injectable.ts (67%) rename packages/{core/src/renderer/utils/channel/channel-listeners => technical-features/messaging/electron/renderer/src/listening-of-messages}/enlist-message-channel-listener.test.ts (73%) create mode 100644 packages/technical-features/messaging/electron/renderer/src/listening-of-requests/enlist-request-channel-listener.injectable.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/invoke-ipc.injectable.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/invoke-ipc.test.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/request-from-channel.injectable.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/request-from-channel.test.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/sending-of-messages/message-to-channel.injectable.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/sending-of-messages/message-to-channel.test.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/sending-of-messages/send-to-ipc.injectable.ts create mode 100644 packages/technical-features/messaging/electron/renderer/src/sending-of-messages/send-to-ipc.test.ts create mode 100644 packages/technical-features/messaging/electron/renderer/tsconfig.json create mode 100644 packages/technical-features/messaging/electron/renderer/webpack.config.js create mode 100644 packages/technical-features/messaging/message-bridge-fake/.eslintrc.json create mode 100644 packages/technical-features/messaging/message-bridge-fake/.prettierrc create mode 100644 packages/technical-features/messaging/message-bridge-fake/index.ts create mode 100644 packages/technical-features/messaging/message-bridge-fake/jest.config.js create mode 100644 packages/technical-features/messaging/message-bridge-fake/package.json create mode 100644 packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.test.ts create mode 100644 packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.ts create mode 100644 packages/technical-features/messaging/message-bridge-fake/tsconfig.json create mode 100644 packages/technical-features/messaging/message-bridge-fake/webpack.config.js create mode 100644 packages/utility-features/startable-stoppable/.eslintrc.json create mode 100644 packages/utility-features/startable-stoppable/.prettierrc create mode 100644 packages/utility-features/startable-stoppable/index.ts create mode 100644 packages/utility-features/startable-stoppable/jest.config.js create mode 100644 packages/utility-features/startable-stoppable/package.json rename packages/{core/src/common/utils => utility-features/startable-stoppable/src}/get-startable-stoppable.test.ts (84%) rename packages/{core/src/common/utils => utility-features/startable-stoppable/src}/get-startable-stoppable.ts (86%) create mode 100644 packages/utility-features/startable-stoppable/tsconfig.json create mode 100644 packages/utility-features/startable-stoppable/webpack.config.js create mode 100644 packages/utility-features/test-utils/src/render-for.tsx create mode 100644 packages/utility-features/test-utils/src/run-with-thrown-mobx-reactions.ts diff --git a/package-lock.json b/package-lock.json index b59d132b39..fc13b55540 100644 --- a/package-lock.json +++ b/package-lock.json @@ -73,20 +73,20 @@ } }, "node_modules/@babel/core": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.3.tgz", - "integrity": "sha512-qIJONzoa/qiHghnm0l1n4i/6IIziDpzqc36FBs4pzMhDUraHqponwJLiAKm1hGLP3OSB/TVNz6rMwVGpwxxySw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.21.0.tgz", + "integrity": "sha512-PuxUbxcW6ZYe656yL3EAhpy7qXKq0DmYsrJLpbB8XrsCP9Nm+XCg9XFMb5vIDliPD7+U/+M+QJlH17XOcB7eXA==", "dependencies": { "@ampproject/remapping": "^2.2.0", "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", + "@babel/generator": "^7.21.0", "@babel/helper-compilation-targets": "^7.20.7", - "@babel/helper-module-transforms": "^7.21.2", + "@babel/helper-module-transforms": "^7.21.0", "@babel/helpers": "^7.21.0", - "@babel/parser": "^7.21.3", + "@babel/parser": "^7.21.0", "@babel/template": "^7.20.7", - "@babel/traverse": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/traverse": "^7.21.0", + "@babel/types": "^7.21.0", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -115,9 +115,9 @@ } }, "node_modules/@babel/eslint-parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.21.3.tgz", - "integrity": "sha512-kfhmPimwo6k4P8zxNs8+T7yR44q1LdpsZdE1NkCsVlfiuTPRfnGgjaF8Qgug9q9Pou17u6wneYF0lDCZJATMFg==", + "version": "7.19.1", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.19.1.tgz", + "integrity": "sha512-AqNf2QWt1rtu2/1rLswy6CDP7H9Oh3mMhk177Y67Rg8d7RD9WfOLLv8CGn6tisFvS2htm86yIe1yLF6I1UDaGQ==", "peer": true, "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", @@ -151,11 +151,11 @@ } }, "node_modules/@babel/generator": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz", - "integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==", + "version": "7.21.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.1.tgz", + "integrity": "sha512-1lT45bAYlQhFn/BHivJs43AiW2rg3/UbLyShGfF3C0KmHvO5fSghWd5kBJy30kpRRucGzXStvnnCFniCR2kXAA==", "dependencies": { - "@babel/types": "^7.21.3", + "@babel/types": "^7.21.0", "@jridgewell/gen-mapping": "^0.3.2", "@jridgewell/trace-mapping": "^0.3.17", "jsesc": "^2.5.1" @@ -595,9 +595,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz", - "integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==", + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.2.tgz", + "integrity": "sha512-URpaIJQwEkEC2T9Kn+Ai6Xe/02iNaVCuT/PtoRz3GPVJVDpPd7mLo+VddTbhCRU9TXqW5mSrQfXZyi8kDKOVpQ==", "bin": { "parser": "bin/babel-parser.js" }, @@ -1269,9 +1269,9 @@ } }, "node_modules/@babel/plugin-transform-destructuring": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.21.3.tgz", - "integrity": "sha512-bp6hwMFzuiE4HqYEyoGJ/V2LeIWn+hLVKc4pnj++E5XQptwhtcGmSayM029d/j2X1bPKGTlsyPwAubuU22KhMA==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.20.7.tgz", + "integrity": "sha512-Xwg403sRrZb81IVB79ZPqNQME23yhugYVqgTxAhT99h485F4f+GMELFhhOsscDUB7HCswepKeCKLn/GZvUKoBA==", "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" @@ -1523,9 +1523,9 @@ } }, "node_modules/@babel/plugin-transform-parameters": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.21.3.tgz", - "integrity": "sha512-Wxc+TvppQG9xWFYatvCGPvZ6+SIUxQ2ZdiBP+PHYMIjnPXD+uThCshaz4NZOnODAtBjjcVQQ/3OKs9LW28purQ==", + "version": "7.20.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.20.7.tgz", + "integrity": "sha512-WiWBIkeHKVOSYPO0pWkxGPfKeWrCJyD3NJ53+Lrp/QMSZbsVPovrVl2aWZ19D/LTVnaDv5Ap7GJ/B2CTOZdrfA==", "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.20.2" @@ -1754,12 +1754,11 @@ } }, "node_modules/@babel/plugin-transform-typescript": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.3.tgz", - "integrity": "sha512-RQxPz6Iqt8T0uw/WsJNReuBpWpBqs/n7mNo18sKLoTbMp+UrEekhH+pKSVC7gWz+DNjo9gryfV8YzCiT45RgMw==", + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.21.0.tgz", + "integrity": "sha512-xo///XTPp3mDzTtrqXoBlK9eiAYW3wv9JXglcn/u1bi60RW11dEUxIgA8cbnDhutS1zacjMRmAwxE0gMklLnZg==", "peer": true, "dependencies": { - "@babel/helper-annotate-as-pure": "^7.18.6", "@babel/helper-create-class-features-plugin": "^7.21.0", "@babel/helper-plugin-utils": "^7.20.2", "@babel/plugin-syntax-typescript": "^7.20.0" @@ -1997,18 +1996,18 @@ } }, "node_modules/@babel/traverse": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz", - "integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==", + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.2.tgz", + "integrity": "sha512-ts5FFU/dSUPS13tv8XiEObDu9K+iagEKME9kAbaP7r0Y9KtZJZ+NGndDvWoRAYNpeWafbpFeki3q9QoMD6gxyw==", "dependencies": { "@babel/code-frame": "^7.18.6", - "@babel/generator": "^7.21.3", + "@babel/generator": "^7.21.1", "@babel/helper-environment-visitor": "^7.18.9", "@babel/helper-function-name": "^7.21.0", "@babel/helper-hoist-variables": "^7.18.6", "@babel/helper-split-export-declaration": "^7.18.6", - "@babel/parser": "^7.21.3", - "@babel/types": "^7.21.3", + "@babel/parser": "^7.21.2", + "@babel/types": "^7.21.2", "debug": "^4.1.0", "globals": "^11.1.0" }, @@ -2017,9 +2016,9 @@ } }, "node_modules/@babel/types": { - "version": "7.21.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz", - "integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==", + "version": "7.21.2", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.2.tgz", + "integrity": "sha512-3wRZSs7jiFaB8AjxiiD+VqN5DTG2iRvJGQ+qYFrs/654lg6kGTQWIOFjlBo5RaXuAZjBmP3+OQH4dmhqiiyYxw==", "dependencies": { "@babel/helper-string-parser": "^7.19.4", "@babel/helper-validator-identifier": "^7.19.1", @@ -2685,9 +2684,9 @@ "dev": true }, "node_modules/@esbuild/android-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.12.tgz", - "integrity": "sha512-E/sgkvwoIfj4aMAPL2e35VnUJspzVYl7+M1B2cqeubdBhADV4uPon0KCc8p2G+LqSJ6i8ocYPCqY3A4GGq0zkQ==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.17.11.tgz", + "integrity": "sha512-CdyX6sRVh1NzFCsf5vw3kULwlAhfy9wVt8SZlrhQ7eL2qBjGbFhRBWkkAzuZm9IIEOCKJw4DXA6R85g+qc8RDw==", "cpu": [ "arm" ], @@ -2701,9 +2700,9 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.12.tgz", - "integrity": "sha512-WQ9p5oiXXYJ33F2EkE3r0FRDFVpEdcDiwNX3u7Xaibxfx6vQE0Sb8ytrfQsA5WO6kDn6mDfKLh6KrPBjvkk7xA==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.17.11.tgz", + "integrity": "sha512-QnK4d/zhVTuV4/pRM4HUjcsbl43POALU2zvBynmrrqZt9LPcLA3x1fTZPBg2RRguBQnJcnU059yKr+bydkntjg==", "cpu": [ "arm64" ], @@ -2717,9 +2716,9 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.12.tgz", - "integrity": "sha512-m4OsaCr5gT+se25rFPHKQXARMyAehHTQAz4XX1Vk3d27VtqiX0ALMBPoXZsGaB6JYryCLfgGwUslMqTfqeLU0w==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.17.11.tgz", + "integrity": "sha512-3PL3HKtsDIXGQcSCKtWD/dy+mgc4p2Tvo2qKgKHj9Yf+eniwFnuoQ0OUhlSfAEpKAFzF9N21Nwgnap6zy3L3MQ==", "cpu": [ "x64" ], @@ -2733,9 +2732,9 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.12.tgz", - "integrity": "sha512-O3GCZghRIx+RAN0NDPhyyhRgwa19MoKlzGonIb5hgTj78krqp9XZbYCvFr9N1eUxg0ZQEpiiZ4QvsOQwBpP+lg==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.17.11.tgz", + "integrity": "sha512-pJ950bNKgzhkGNO3Z9TeHzIFtEyC2GDQL3wxkMApDEghYx5Qers84UTNc1bAxWbRkuJOgmOha5V0WUeh8G+YGw==", "cpu": [ "arm64" ], @@ -2749,9 +2748,9 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.12.tgz", - "integrity": "sha512-5D48jM3tW27h1qjaD9UNRuN+4v0zvksqZSPZqeSWggfMlsVdAhH3pwSfQIFJwcs9QJ9BRibPS4ViZgs3d2wsCA==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.17.11.tgz", + "integrity": "sha512-iB0dQkIHXyczK3BZtzw1tqegf0F0Ab5texX2TvMQjiJIWXAfM4FQl7D909YfXWnB92OQz4ivBYQ2RlxBJrMJOw==", "cpu": [ "x64" ], @@ -2765,9 +2764,9 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.12.tgz", - "integrity": "sha512-OWvHzmLNTdF1erSvrfoEBGlN94IE6vCEaGEkEH29uo/VoONqPnoDFfShi41Ew+yKimx4vrmmAJEGNoyyP+OgOQ==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.11.tgz", + "integrity": "sha512-7EFzUADmI1jCHeDRGKgbnF5sDIceZsQGapoO6dmw7r/ZBEKX7CCDnIz8m9yEclzr7mFsd+DyasHzpjfJnmBB1Q==", "cpu": [ "arm64" ], @@ -2781,9 +2780,9 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.12.tgz", - "integrity": "sha512-A0Xg5CZv8MU9xh4a+7NUpi5VHBKh1RaGJKqjxe4KG87X+mTjDE6ZvlJqpWoeJxgfXHT7IMP9tDFu7IZ03OtJAw==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.17.11.tgz", + "integrity": "sha512-iPgenptC8i8pdvkHQvXJFzc1eVMR7W2lBPrTE6GbhR54sLcF42mk3zBOjKPOodezzuAz/KSu8CPyFSjcBMkE9g==", "cpu": [ "x64" ], @@ -2797,9 +2796,9 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.12.tgz", - "integrity": "sha512-WsHyJ7b7vzHdJ1fv67Yf++2dz3D726oO3QCu8iNYik4fb5YuuReOI9OtA+n7Mk0xyQivNTPbl181s+5oZ38gyA==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.17.11.tgz", + "integrity": "sha512-M9iK/d4lgZH0U5M1R2p2gqhPV/7JPJcRz+8O8GBKVgqndTzydQ7B2XGDbxtbvFkvIs53uXTobOhv+RyaqhUiMg==", "cpu": [ "arm" ], @@ -2813,9 +2812,9 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.12.tgz", - "integrity": "sha512-cK3AjkEc+8v8YG02hYLQIQlOznW+v9N+OI9BAFuyqkfQFR+DnDLhEM5N8QRxAUz99cJTo1rLNXqRrvY15gbQUg==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.17.11.tgz", + "integrity": "sha512-Qxth3gsWWGKz2/qG2d5DsW/57SeA2AmpSMhdg9TSB5Svn2KDob3qxfQSkdnWjSd42kqoxIPy3EJFs+6w1+6Qjg==", "cpu": [ "arm64" ], @@ -2829,9 +2828,9 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.12.tgz", - "integrity": "sha512-jdOBXJqcgHlah/nYHnj3Hrnl9l63RjtQ4vn9+bohjQPI2QafASB5MtHAoEv0JQHVb/xYQTFOeuHnNYE1zF7tYw==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.17.11.tgz", + "integrity": "sha512-dB1nGaVWtUlb/rRDHmuDQhfqazWE0LMro/AIbT2lWM3CDMHJNpLckH+gCddQyhhcLac2OYw69ikUMO34JLt3wA==", "cpu": [ "ia32" ], @@ -2845,9 +2844,9 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.12.tgz", - "integrity": "sha512-GTOEtj8h9qPKXCyiBBnHconSCV9LwFyx/gv3Phw0pa25qPYjVuuGZ4Dk14bGCfGX3qKF0+ceeQvwmtI+aYBbVA==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.17.11.tgz", + "integrity": "sha512-aCWlq70Q7Nc9WDnormntGS1ar6ZFvUpqr8gXtO+HRejRYPweAFQN615PcgaSJkZjhHp61+MNLhzyVALSF2/Q0g==", "cpu": [ "loong64" ], @@ -2861,9 +2860,9 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.12.tgz", - "integrity": "sha512-o8CIhfBwKcxmEENOH9RwmUejs5jFiNoDw7YgS0EJTF6kgPgcqLFjgoc5kDey5cMHRVCIWc6kK2ShUePOcc7RbA==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.17.11.tgz", + "integrity": "sha512-cGeGNdQxqY8qJwlYH1BP6rjIIiEcrM05H7k3tR7WxOLmD1ZxRMd6/QIOWMb8mD2s2YJFNRuNQ+wjMhgEL2oCEw==", "cpu": [ "mips64el" ], @@ -2877,9 +2876,9 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.12.tgz", - "integrity": "sha512-biMLH6NR/GR4z+ap0oJYb877LdBpGac8KfZoEnDiBKd7MD/xt8eaw1SFfYRUeMVx519kVkAOL2GExdFmYnZx3A==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.17.11.tgz", + "integrity": "sha512-BdlziJQPW/bNe0E8eYsHB40mYOluS+jULPCjlWiHzDgr+ZBRXPtgMV1nkLEGdpjrwgmtkZHEGEPaKdS/8faLDA==", "cpu": [ "ppc64" ], @@ -2893,9 +2892,9 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.12.tgz", - "integrity": "sha512-jkphYUiO38wZGeWlfIBMB72auOllNA2sLfiZPGDtOBb1ELN8lmqBrlMiucgL8awBw1zBXN69PmZM6g4yTX84TA==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.17.11.tgz", + "integrity": "sha512-MDLwQbtF+83oJCI1Cixn68Et/ME6gelmhssPebC40RdJaect+IM+l7o/CuG0ZlDs6tZTEIoxUe53H3GmMn8oMA==", "cpu": [ "riscv64" ], @@ -2909,9 +2908,9 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.12.tgz", - "integrity": "sha512-j3ucLdeY9HBcvODhCY4b+Ds3hWGO8t+SAidtmWu/ukfLLG/oYDMaA+dnugTVAg5fnUOGNbIYL9TOjhWgQB8W5g==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.17.11.tgz", + "integrity": "sha512-4N5EMESvws0Ozr2J94VoUD8HIRi7X0uvUv4c0wpTHZyZY9qpaaN7THjosdiW56irQ4qnJ6Lsc+i+5zGWnyqWqQ==", "cpu": [ "s390x" ], @@ -2925,9 +2924,9 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.12.tgz", - "integrity": "sha512-uo5JL3cgaEGotaqSaJdRfFNSCUJOIliKLnDGWaVCgIKkHxwhYMm95pfMbWZ9l7GeW9kDg0tSxcy9NYdEtjwwmA==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.17.11.tgz", + "integrity": "sha512-rM/v8UlluxpytFSmVdbCe1yyKQd/e+FmIJE2oPJvbBo+D0XVWi1y/NQ4iTNx+436WmDHQBjVLrbnAQLQ6U7wlw==", "cpu": [ "x64" ], @@ -2941,9 +2940,9 @@ } }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.12.tgz", - "integrity": "sha512-DNdoRg8JX+gGsbqt2gPgkgb00mqOgOO27KnrWZtdABl6yWTST30aibGJ6geBq3WM2TIeW6COs5AScnC7GwtGPg==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.17.11.tgz", + "integrity": "sha512-4WaAhuz5f91h3/g43VBGdto1Q+X7VEZfpcWGtOFXnggEuLvjV+cP6DyLRU15IjiU9fKLLk41OoJfBFN5DhPvag==", "cpu": [ "x64" ], @@ -2957,9 +2956,9 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.12.tgz", - "integrity": "sha512-aVsENlr7B64w8I1lhHShND5o8cW6sB9n9MUtLumFlPhG3elhNWtE7M1TFpj3m7lT3sKQUMkGFjTQBrvDDO1YWA==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.17.11.tgz", + "integrity": "sha512-UBj135Nx4FpnvtE+C8TWGp98oUgBcmNmdYgl5ToKc0mBHxVVqVE7FUS5/ELMImOp205qDAittL6Ezhasc2Ev/w==", "cpu": [ "x64" ], @@ -2973,9 +2972,9 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.12.tgz", - "integrity": "sha512-qbHGVQdKSwi0JQJuZznS4SyY27tYXYF0mrgthbxXrZI3AHKuRvU+Eqbg/F0rmLDpW/jkIZBlCO1XfHUBMNJ1pg==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.17.11.tgz", + "integrity": "sha512-1/gxTifDC9aXbV2xOfCbOceh5AlIidUrPsMpivgzo8P8zUtczlq1ncFpeN1ZyQJ9lVs2hILy1PG5KPp+w8QPPg==", "cpu": [ "x64" ], @@ -2989,9 +2988,9 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.12.tgz", - "integrity": "sha512-zsCp8Ql+96xXTVTmm6ffvoTSZSV2B/LzzkUXAY33F/76EajNw1m+jZ9zPfNJlJ3Rh4EzOszNDHsmG/fZOhtqDg==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.17.11.tgz", + "integrity": "sha512-vtSfyx5yRdpiOW9yp6Ax0zyNOv9HjOAw8WaZg3dF5djEHKKm3UnoohftVvIJtRh0Ec7Hso0RIdTqZvPXJ7FdvQ==", "cpu": [ "arm64" ], @@ -3005,9 +3004,9 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.12.tgz", - "integrity": "sha512-FfrFjR4id7wcFYOdqbDfDET3tjxCozUgbqdkOABsSFzoZGFC92UK7mg4JKRc/B3NNEf1s2WHxJ7VfTdVDPN3ng==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.17.11.tgz", + "integrity": "sha512-GFPSLEGQr4wHFTiIUJQrnJKZhZjjq4Sphf+mM76nQR6WkQn73vm7IsacmBRPkALfpOCHsopSvLgqdd4iUW2mYw==", "cpu": [ "ia32" ], @@ -3021,9 +3020,9 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.12.tgz", - "integrity": "sha512-JOOxw49BVZx2/5tW3FqkdjSD/5gXYeVGPDcB0lvap0gLQshkh1Nyel1QazC+wNxus3xPlsYAgqU1BUmrmCvWtw==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.17.11.tgz", + "integrity": "sha512-N9vXqLP3eRL8BqSy8yn4Y98cZI2pZ8fyuHx6lKjiG2WABpT2l01TXdzq5Ma2ZUBzfB7tx5dXVhge8X9u0S70ZQ==", "cpu": [ "x64" ], @@ -3037,9 +3036,9 @@ } }, "node_modules/@eslint-community/eslint-utils": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.3.0.tgz", - "integrity": "sha512-v3oplH6FYCULtFuCeqyuTd9D2WKO937Dxdq+GmHOLL72TTRriLxz2VLlNfkZRsvj6PKnOPAtuT6dwrs/pA5DvA==", + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.2.0.tgz", + "integrity": "sha512-gB8T4H4DEfX2IV9zGDJPOBgP1e/DbfCPDTtEqUMckpvzS1OYtva8JdFYBqMwYk7xAQ429WGF/UPqn8uQ//h2vQ==", "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -3114,24 +3113,25 @@ } }, "node_modules/@floating-ui/core": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.4.tgz", - "integrity": "sha512-SQOeVbMwb1di+mVWWJLpsUTToKfqVNioXys011beCAhyOIFtS+GQoW4EQSneuxzmQKddExDwQ+X0hLl4lJJaSQ==", + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.2.3.tgz", + "integrity": "sha512-upVRtrNZuYNsw+EoxkiBFRPROnU8UTy/u/dZ9U0W14BlemPYODwhhxYXSR2Y9xOnvr1XtptJRWx7gL8Te1qaog==", "dev": true }, "node_modules/@floating-ui/dom": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.5.tgz", - "integrity": "sha512-+sAUfpQ3Frz+VCbPCqj+cZzvEESy3fjSeT/pDWkYCWOBXYNNKZfuVsHuv8/JO2zze8+Eb/Q7a6hZVgzS81fLbQ==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.2.4.tgz", + "integrity": "sha512-4+k+BLhtWj+peCU60gp0+rHeR8+Ohqx6kjJf/lHMnJ8JD5Qj6jytcq1+SZzRwD7rvHKRhR7TDiWWddrNrfwQLg==", "dev": true, "dependencies": { - "@floating-ui/core": "^1.2.4" + "@floating-ui/core": "^1.2.3" } }, "node_modules/@gar/promisify": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", - "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true }, "node_modules/@hapi/b64": { "version": "5.0.0", @@ -3359,7 +3359,8 @@ "node_modules/@isaacs/string-locale-compare": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", - "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==" + "integrity": "sha512-SQ7Kzhh9+D+ZW9MA0zkYv3VXhIDNx+LzM6EJ+/65I3QY+enU6Itte7E5XX7EWrqLW2FN4n06GWzBnPoC3th2aQ==", + "dev": true }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", @@ -4684,6 +4685,10 @@ "resolved": "packages/bump-version-for-cron", "link": true }, + "node_modules/@k8slens/computed-channel": { + "resolved": "packages/technical-features/messaging/computed-channel", + "link": true + }, "node_modules/@k8slens/core": { "resolved": "packages/core", "link": true @@ -4720,6 +4725,22 @@ "resolved": "packages/technical-features/application/legacy-extensions", "link": true }, + "node_modules/@k8slens/messaging": { + "resolved": "packages/technical-features/messaging/agnostic", + "link": true + }, + "node_modules/@k8slens/messaging-fake-bridge": { + "resolved": "packages/technical-features/messaging/message-bridge-fake", + "link": true + }, + "node_modules/@k8slens/messaging-for-main": { + "resolved": "packages/technical-features/messaging/electron/main", + "link": true + }, + "node_modules/@k8slens/messaging-for-renderer": { + "resolved": "packages/technical-features/messaging/electron/renderer", + "link": true + }, "node_modules/@k8slens/node-fetch": { "resolved": "packages/node-fetch", "link": true @@ -4736,6 +4757,10 @@ "resolved": "packages/semver", "link": true }, + "node_modules/@k8slens/startable-stoppable": { + "resolved": "packages/utility-features/startable-stoppable", + "link": true + }, "node_modules/@k8slens/test-utils": { "resolved": "packages/utility-features/test-utils", "link": true @@ -4778,6 +4803,11 @@ "openid-client": "^5.3.0" } }, + "node_modules/@kubernetes/client-node/node_modules/underscore": { + "version": "1.13.6", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", + "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + }, "node_modules/@leichtgewicht/ip-codec": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", @@ -5180,6 +5210,7 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/@npmcli/arborist/-/arborist-5.3.0.tgz", "integrity": "sha512-+rZ9zgL1lnbl8Xbb1NQdMjveOMwj4lIYfcDtyJHHi5x4X8jtR6m8SXooJMZy5vmFVZ8w7A2Bnd/oX9eTuU8w5A==", + "dev": true, "dependencies": { "@isaacs/string-locale-compare": "^1.1.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -5227,6 +5258,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -5238,6 +5270,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -5246,6 +5279,7 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -5260,6 +5294,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -5274,6 +5309,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-2.1.2.tgz", "integrity": "sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==", + "dev": true, "dependencies": { "@gar/promisify": "^1.1.3", "semver": "^7.3.5" @@ -5286,6 +5322,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-3.0.2.tgz", "integrity": "sha512-CAcd08y3DWBJqJDpfuVL0uijlq5oaXaOJEKHKc4wqrjd00gkvTZB+nFuLn+doOOKddaQS9JfqtNoFCO2LCvA3w==", + "dev": true, "dependencies": { "@npmcli/promise-spawn": "^3.0.0", "lru-cache": "^7.4.4", @@ -5305,6 +5342,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -5313,6 +5351,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz", "integrity": "sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw==", + "dev": true, "dependencies": { "npm-bundled": "^1.1.1", "npm-normalize-package-bin": "^1.0.1" @@ -5328,6 +5367,7 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/@npmcli/map-workspaces/-/map-workspaces-2.0.4.tgz", "integrity": "sha512-bMo0aAfwhVwqoVM5UzX1DJnlvVvzDCHae821jv48L1EsrYwfOZChlqWYXEtto/+BkBXetPbEWgau++/brh4oVg==", + "dev": true, "dependencies": { "@npmcli/name-from-folder": "^1.0.1", "glob": "^8.0.1", @@ -5342,6 +5382,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -5350,6 +5391,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -5368,6 +5410,7 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -5379,6 +5422,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/@npmcli/metavuln-calculator/-/metavuln-calculator-3.1.1.tgz", "integrity": "sha512-n69ygIaqAedecLeVH3KnO39M6ZHiJ2dEv5A7DGvcqCB8q17BGUgW8QaanIkbWUo2aYGZqJaOORTLAlIvKjNDKA==", + "dev": true, "dependencies": { "cacache": "^16.0.0", "json-parse-even-better-errors": "^2.3.1", @@ -5394,6 +5438,7 @@ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-2.0.1.tgz", "integrity": "sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==", "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -5406,6 +5451,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -5419,12 +5465,14 @@ "node_modules/@npmcli/name-from-folder": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/@npmcli/name-from-folder/-/name-from-folder-1.0.1.tgz", - "integrity": "sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA==" + "integrity": "sha512-qq3oEfcLFwNfEYOQ8HLimRGKlD8WSeGEdtUa7hmzpR8Sa7haL1KVQrvgO6wqMjhWFFVjgtrh1gIxDz+P8sjUaA==", + "dev": true }, "node_modules/@npmcli/node-gyp": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-2.0.0.tgz", "integrity": "sha512-doNI35wIe3bBaEgrlPfdJPaCpUR89pJWep4Hq3aRdh6gKazIVWfs0jHttvSSoq47ZXgC7h73kDsUl8AoIQUB+A==", + "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -5433,6 +5481,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-2.0.0.tgz", "integrity": "sha512-42jnZ6yl16GzjWSH7vtrmWyJDGVa/LXPdpN2rcUWolFjc9ON2N3uz0qdBbQACfmhuJZ2lbKYtmK5qx68ZPLHMA==", + "dev": true, "dependencies": { "json-parse-even-better-errors": "^2.3.1" }, @@ -5444,6 +5493,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-3.0.0.tgz", "integrity": "sha512-s9SgS+p3a9Eohe68cSI3fi+hpcZUmXq5P7w0kMlAsWVtR7XbK3ptkZqKT2cK1zLDObJ3sR+8P59sJE0w/KTL1g==", + "dev": true, "dependencies": { "infer-owner": "^1.0.4" }, @@ -5455,6 +5505,7 @@ "version": "4.1.7", "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-4.1.7.tgz", "integrity": "sha512-WXr/MyM4tpKA4BotB81NccGAv8B48lNH0gRoILucbcAhTQXLCoi6HflMV3KdXubIqvP9SuLsFn68Z7r4jl+ppw==", + "dev": true, "dependencies": { "@npmcli/node-gyp": "^2.0.0", "@npmcli/promise-spawn": "^3.0.0", @@ -5470,6 +5521,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -5478,6 +5530,7 @@ "version": "10.2.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^16.1.0", @@ -5504,6 +5557,7 @@ "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" }, @@ -5515,6 +5569,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, "dependencies": { "minipass": "^3.1.6", "minipass-sized": "^1.0.3", @@ -5531,6 +5586,7 @@ "version": "9.3.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-9.3.1.tgz", "integrity": "sha512-4Q16ZCqq3g8awk6UplT7AuxQ35XN4R/yf/+wSAwcBUAjg7l58RTactWaP8fIDTi0FzI7YcVLujwExakZlfWkXg==", + "dev": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -5554,6 +5610,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-6.0.0.tgz", "integrity": "sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==", + "dev": true, "dependencies": { "abbrev": "^1.0.0" }, @@ -5568,6 +5625,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -5582,6 +5640,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -5594,21 +5653,22 @@ "node_modules/@npmcli/run-script/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/@nrwl/cli": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/cli/-/cli-15.8.7.tgz", - "integrity": "sha512-G1NEy4jGuZJ/7KjhLQNOe11XmoTgwJS82FW8Tbo4iceq2ItSEbe7bkA8xTSK/AzUixZIMimztb9Oyxw/n1ajGQ==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/cli/-/cli-15.8.6.tgz", + "integrity": "sha512-KrWoYcZgE6woCubPO1QSnwbZAjs2rdV4dotHxR+iRkeHRPAq0D6w83CVo5oP/krfUri2pxwzhnbkgAK1LSPBYg==", "dev": true, "dependencies": { - "nx": "15.8.7" + "nx": "15.8.6" } }, "node_modules/@nrwl/devkit": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-15.8.7.tgz", - "integrity": "sha512-A99nZrA5KN9wRn2uYX2vKByA+t2XEGoZBR5TU/bpXbPYrh92qAHkIJ8ke3ImGQOlzk4iIaZ5Me0k7k1p9Zx4wA==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-15.8.6.tgz", + "integrity": "sha512-yA5hBpeqoIlyEN5lUkejUrmB/5vfg+k6xoT4KhXnmj6bLPDGOYTuixg8k+iYrIAFIRMx0F8zYbYOYzXG3lmvHg==", "dev": true, "dependencies": { "@phenomnomnominal/tsquery": "4.1.1", @@ -5683,9 +5743,9 @@ "dev": true }, "node_modules/@nrwl/nx-darwin-arm64": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-arm64/-/nx-darwin-arm64-15.8.7.tgz", - "integrity": "sha512-+cu8J337gRxUHjz2TGwS/2Oh3yw8d3/T6SoBfvee1DY72VQaeYd8UTz0doOhDtmc/zowvRu7ZVsW0ytNB0jIXQ==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-arm64/-/nx-darwin-arm64-15.8.6.tgz", + "integrity": "sha512-8diQitlyjHxpkWcXNecd6T2ch8fHR7LOMaZg9+qgrt5AypWkEGf+UHMxTSNRObAiBGnoxySa+AL/UKVtpQ203Q==", "cpu": [ "arm64" ], @@ -5699,9 +5759,9 @@ } }, "node_modules/@nrwl/nx-darwin-x64": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-x64/-/nx-darwin-x64-15.8.7.tgz", - "integrity": "sha512-VqHJEP0wgFu1MU0Bo1vKZ5/s7ThRfYkX8SyGUxjVTzR02CrsjC4rNxFoKD8Cc4YkUn44U/F78toGf+i2gRcjSQ==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/nx-darwin-x64/-/nx-darwin-x64-15.8.6.tgz", + "integrity": "sha512-h9/JULzPZTpt6oNpKMZLc1NGDu+CLyx91c8DJUh/hH0Zh/7dS9LFxe9jWeFIdh18iAu7ZAoktK2KJ5YhOrUYhA==", "cpu": [ "x64" ], @@ -5715,9 +5775,9 @@ } }, "node_modules/@nrwl/nx-linux-arm-gnueabihf": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-15.8.7.tgz", - "integrity": "sha512-4F/8awwqPTt7zKQolvjBNrcR1wYicPjGchLOdaqnfMxn/iRRUdh0hD11mEP5zHNv9gZs/nOIvhdBUErNjFkplQ==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-15.8.6.tgz", + "integrity": "sha512-Yp/YjzcIHW+OW4revPRZIt0Px9cKRsOL69FPLlYSxWuR/PD9SPeXWcbo3pKkjnIWIjOL2YT8z5cHiQ3bV1NVfw==", "cpu": [ "arm" ], @@ -5731,9 +5791,9 @@ } }, "node_modules/@nrwl/nx-linux-arm64-gnu": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-15.8.7.tgz", - "integrity": "sha512-3ZTSZx02Vv5emQOpaDROIcLtQucoXAe73zGKYDTXB95mxbOPSjjQJ8Rtx+BeqWq9JQoZZyRcD0qnBkTTy1aLRg==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-15.8.6.tgz", + "integrity": "sha512-b+OenpPhhxqgaG6EFHRLfVGtAU4+UbKqOhv7DLLh5P7tX3RAQAtyrT6tVkfDRFYl6kgEme/I5ZrevcbaGyDO+w==", "cpu": [ "arm64" ], @@ -5747,9 +5807,9 @@ } }, "node_modules/@nrwl/nx-linux-arm64-musl": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-musl/-/nx-linux-arm64-musl-15.8.7.tgz", - "integrity": "sha512-SZxTomiHxAh8El+swbmGSGcaA0vGbHb/rmhFAixo19INu1wBJfD6hjkVJt17h6PyEO7BIYPOpRia6Poxnyv8hA==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-arm64-musl/-/nx-linux-arm64-musl-15.8.6.tgz", + "integrity": "sha512-F9D8moy+lfJQhVrZoY54vDwpigBgxQy4HB9PRmc6Ln9mIk3ouOvKNC99OjUYEO+ensHr9eMpsbghsRCjod//uw==", "cpu": [ "arm64" ], @@ -5763,9 +5823,9 @@ } }, "node_modules/@nrwl/nx-linux-x64-gnu": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-gnu/-/nx-linux-x64-gnu-15.8.7.tgz", - "integrity": "sha512-BlNC6Zz1/x6CFbBFTVrgRGMOPqb7zWh5cOjBVNpoBXYTEth1UXb2r1U+gpuQ4xdUqG+uXoWhy6BHJjqBIjzLJA==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-gnu/-/nx-linux-x64-gnu-15.8.6.tgz", + "integrity": "sha512-an0zD6lKpblexazKssFvcfOx7BuGutwlrzmwScxISPXj5+ly99u+sYclDg2P56YRHYXIuYGBK0c0VWaJ91QIcw==", "cpu": [ "x64" ], @@ -5779,9 +5839,9 @@ } }, "node_modules/@nrwl/nx-linux-x64-musl": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-musl/-/nx-linux-x64-musl-15.8.7.tgz", - "integrity": "sha512-FNYX/IKy8SUbw6bJpvwZrup2YQBYmSJwP6Rw76Vf7c32XHk7uA6AjiPWMIrZCSndXcry8fnwXvR+J2Dnyo82nQ==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/nx-linux-x64-musl/-/nx-linux-x64-musl-15.8.6.tgz", + "integrity": "sha512-LOurlSuLf9LWdjvpHHIsHC0auxgMVrkeOFFCUJ3oVv/dN4uZ0vuNG98XM2E7fPDXDacBZIyKdx34KQlmFfBHsA==", "cpu": [ "x64" ], @@ -5795,9 +5855,9 @@ } }, "node_modules/@nrwl/nx-win32-arm64-msvc": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-15.8.7.tgz", - "integrity": "sha512-sZALEzazjPAeLlw6IbFWsMidCZ4ZM3GKWZZ6rsAqG2y7I9t4nlUPH/y/Isl9MuLBvrBCBXbVnD20wh6EhtuwTw==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-15.8.6.tgz", + "integrity": "sha512-MvH84nLv1tdM96z92abeQd+tguY/zKC22AFHek9PSR1StUQzwwPu6rR7XDn3mggwnkLm11jTUXlk7wdbE5sldQ==", "cpu": [ "arm64" ], @@ -5811,9 +5871,9 @@ } }, "node_modules/@nrwl/nx-win32-x64-msvc": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-x64-msvc/-/nx-win32-x64-msvc-15.8.7.tgz", - "integrity": "sha512-VMdDptI2rqkLQRCvertF29QeA/V/MnFtHbsmVzMCEv5EUfrkHbA5LLxV66LLfngmkDT1FHktffztlsMpbxvhRw==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/nx-win32-x64-msvc/-/nx-win32-x64-msvc-15.8.6.tgz", + "integrity": "sha512-P0Sb4HJCeoeTvPFdUMKljRUIjzso0go36cn1Zpl+Z5CG/nbOvLlbnzh6rg15SRNu9OLWTHNPtyQIvKxjqEDoxg==", "cpu": [ "x64" ], @@ -5827,12 +5887,12 @@ } }, "node_modules/@nrwl/tao": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-15.8.7.tgz", - "integrity": "sha512-wA7QIEh0VwWcyo32Y/xSCTwnQTGcZupe933nResXv8mAb36W8MoR5SXRx+Wdd8fJ1eWlm2tuotIrslhN+lYx/Q==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-15.8.6.tgz", + "integrity": "sha512-dY205cotLiKTV+5BrUlneZEOucDmXiJU4asj1G4vQCf8Nt7awwuLYOmgbsACS27gkopSVV+DPl1zmtkSJX8Cjg==", "dev": true, "dependencies": { - "nx": "15.8.7" + "nx": "15.8.6" }, "bin": { "tao": "index.js" @@ -6581,9 +6641,9 @@ } }, "node_modules/@swc/core": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.41.tgz", - "integrity": "sha512-v6P2dfqJDpZ/7RXPvWge9oI6YgolDM0jtNhQZ2qdXrLBzaWQdDoBGBTJ8KN/nTgGhX3IkNvSB1fafXQ+nVnqAQ==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.3.40.tgz", + "integrity": "sha512-ZQJ+NID24PQkPIHnbO2B68YNQ6aMEyDz6dcsZucpRK4r7+aPqQ2yVLaqFcQU9VcGMyo4JJydmokzyTr1roWPIQ==", "hasInstallScript": true, "engines": { "node": ">=10" @@ -6593,22 +6653,22 @@ "url": "https://opencollective.com/swc" }, "optionalDependencies": { - "@swc/core-darwin-arm64": "1.3.41", - "@swc/core-darwin-x64": "1.3.41", - "@swc/core-linux-arm-gnueabihf": "1.3.41", - "@swc/core-linux-arm64-gnu": "1.3.41", - "@swc/core-linux-arm64-musl": "1.3.41", - "@swc/core-linux-x64-gnu": "1.3.41", - "@swc/core-linux-x64-musl": "1.3.41", - "@swc/core-win32-arm64-msvc": "1.3.41", - "@swc/core-win32-ia32-msvc": "1.3.41", - "@swc/core-win32-x64-msvc": "1.3.41" + "@swc/core-darwin-arm64": "1.3.40", + "@swc/core-darwin-x64": "1.3.40", + "@swc/core-linux-arm-gnueabihf": "1.3.40", + "@swc/core-linux-arm64-gnu": "1.3.40", + "@swc/core-linux-arm64-musl": "1.3.40", + "@swc/core-linux-x64-gnu": "1.3.40", + "@swc/core-linux-x64-musl": "1.3.40", + "@swc/core-win32-arm64-msvc": "1.3.40", + "@swc/core-win32-ia32-msvc": "1.3.40", + "@swc/core-win32-x64-msvc": "1.3.40" } }, "node_modules/@swc/core-darwin-arm64": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.41.tgz", - "integrity": "sha512-D4fybODToO/BvuP35bionDUrSuTVVr8eW+mApr1unOqb3mfiqOrVv0VP2fpWNRYiA+xMq+oBCB6KcGpL60HKWQ==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.3.40.tgz", + "integrity": "sha512-x4JHshTVB2o5xOedLL54/jsKkfUlsMw25tNM5fWkehiKWXlQuxEasl5/roceAFETWm8mEESuL8pWgZaiyTDl4Q==", "cpu": [ "arm64" ], @@ -6621,9 +6681,9 @@ } }, "node_modules/@swc/core-darwin-x64": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.41.tgz", - "integrity": "sha512-0RoVyiPCnylf3TG77C3S86PRSmaq+SaYB4VDLJFz3qcEHz1pfP0LhyskhgX4wjQV1mveDzFEn1BVAuo0eOMwZA==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.3.40.tgz", + "integrity": "sha512-2QaW9HtlvatiQscQACVIyKtj+vAEFEC6Tn+8rqxm8ikYHUD33M/FVXGWEvMLTI7T3P25zjhs+toAlLsjHgfzQQ==", "cpu": [ "x64" ], @@ -6636,9 +6696,9 @@ } }, "node_modules/@swc/core-linux-arm-gnueabihf": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.41.tgz", - "integrity": "sha512-mZW7GeY7Uw1nkKoWpx898ou20oCSt8MR+jAVuAhMjX+G4Zr0WWXYSigWNiRymhR6Q9KhyvoFpMckguSvYWmXsw==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.3.40.tgz", + "integrity": "sha512-cJPgSg8222gezj5Db2S8PNvcALJLokvXqvFjyzRR253SMFFkq9JKWk0uwO3wg8i8jhe78xMB6EO6AteQqFWvCg==", "cpu": [ "arm" ], @@ -6651,9 +6711,9 @@ } }, "node_modules/@swc/core-linux-arm64-gnu": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.41.tgz", - "integrity": "sha512-e91LGn+6KuLFw3sWk5swwGc/dP4tXs0mg3HrhjImRoofU02Bb9aHcj5zgrSO8ZByvDtm/Knn16h1ojxIMOFaxg==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.3.40.tgz", + "integrity": "sha512-s76n4/vpQzV7dpS703m1WnCxyG7OfGk+EeJf+KEl/m6KP7c5MHHOLOf8hpagI/QI1H8jb9j1ADqNu2C7tEUR8Q==", "cpu": [ "arm64" ], @@ -6666,9 +6726,9 @@ } }, "node_modules/@swc/core-linux-arm64-musl": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.41.tgz", - "integrity": "sha512-Q7hmrniLWsQ7zjtImGcjx1tl5/Qxpel+fC+OXTnGvAyyoGssSftIBlXMnqVLteL78zhxIPAzi+gizWAe5RGqrA==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.3.40.tgz", + "integrity": "sha512-aTkeImCq1WrkljAQNnqlbk/1ermotONkBl11GH7Ia+8yhsmgt8ZiNBIi0tJ5UjdfXDtnl58Iek43Vo8LWaPUKA==", "cpu": [ "arm64" ], @@ -6681,9 +6741,9 @@ } }, "node_modules/@swc/core-linux-x64-gnu": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.41.tgz", - "integrity": "sha512-h4sv1sCfZQgRIwmykz8WPqVpbvHb13Qm3SsrbOudhAp2MuzpWzsgMP5hAEpdCP/nWreiCz3aoM6L8JeakRDq0g==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.3.40.tgz", + "integrity": "sha512-ZsfVlzXSXvNZBuK1fCrenoLSLVv0Zk7OdmkAG9cWN3bKkc/ynxO+6njXLEKWfv9bRfDBXhxifyHGOVOQlIFIAA==", "cpu": [ "x64" ], @@ -6696,9 +6756,9 @@ } }, "node_modules/@swc/core-linux-x64-musl": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.41.tgz", - "integrity": "sha512-Z7c26i38378d0NT/dcz8qPSAXm41lqhNzykdhKhI+95mA9m4pskP18T/0I45rmyx1ywifypu+Ip+SXmKeVSPgQ==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.3.40.tgz", + "integrity": "sha512-5GgMuadbd6fhHg/+7W25i+9OQTW4nTMGECias0BNPlcW8nnohzSphpj5jLI/Ub5bWzMwE2hua6e2uiZ17rTySg==", "cpu": [ "x64" ], @@ -6711,9 +6771,9 @@ } }, "node_modules/@swc/core-win32-arm64-msvc": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.41.tgz", - "integrity": "sha512-I0CYnPc+ZGc912YeN0TykIOf/Q7yJQHRwDuhewwD6RkbiSEaVfSux5pAmmdoKw2aGMSq+cwLmgPe9HYLRNz+4w==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.3.40.tgz", + "integrity": "sha512-TqiK28eaK3YOKSp8iESlrrbSzDGRQqM0zR4hvCgfHwL4L1BPh/M0aIMC/vyYh2gqpz2quyNqgi/DxoZ2+WxlUg==", "cpu": [ "arm64" ], @@ -6726,9 +6786,9 @@ } }, "node_modules/@swc/core-win32-ia32-msvc": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.41.tgz", - "integrity": "sha512-EygN4CVDWF29/U2T5fXGfWyLvRbMd2hiUgkciAl7zHuyJ6nKl+kpodqV2A0Wd4sFtSNedU0gQEBEXEe7cqvmsA==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.3.40.tgz", + "integrity": "sha512-PqtCXFs5+ZbrfFe1VZAcCl8k9h47wE65mKDhDvZ9/SQhXxZX2+f5mUGXuH4G5rA0CyijsVpHnpA/5rqE7f2Sxw==", "cpu": [ "ia32" ], @@ -6741,9 +6801,9 @@ } }, "node_modules/@swc/core-win32-x64-msvc": { - "version": "1.3.41", - "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.41.tgz", - "integrity": "sha512-Mfp8qD1hNwWWRy0ISdwQJu1g0UYoVTtuQlO0z3aGbXqL51ew9e56+8j3M1U9i95lXFyWkARgjDCcKkQi+WezyA==", + "version": "1.3.40", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.3.40.tgz", + "integrity": "sha512-73DGsjsJYSzmoRbfomPj5jcQawtK2H0bCDi/1wgfl8NKVOuzrq+PpaTry3lzx+gvTHxUX6mUHV22i7C9ITL74Q==", "cpu": [ "x64" ], @@ -6845,7 +6905,6 @@ "version": "12.1.5", "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-12.1.5.tgz", "integrity": "sha512-OfTXCJUFgjd/digLUuPxa0+/3ZxsQmE7ub9kcbW/wi96Bh3o/p5vrETcBGfP17NWPGqeYYl5LTRpwyGoMC4ysg==", - "dev": true, "dependencies": { "@babel/runtime": "^7.12.5", "@testing-library/dom": "^8.0.0", @@ -6863,7 +6922,6 @@ "version": "8.20.0", "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-8.20.0.tgz", "integrity": "sha512-d9ULIT+a4EXLX3UU8FBjauG9NnsZHkHztXoIcTsOKoOw030fyjheN9svkTULjJxtYag9DZz5Jz5qkWZDPxTFwA==", - "dev": true, "dependencies": { "@babel/code-frame": "^7.10.4", "@babel/runtime": "^7.12.5", @@ -6881,14 +6939,12 @@ "node_modules/@testing-library/react/node_modules/@types/aria-query": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.1.tgz", - "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==", - "dev": true + "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" }, "node_modules/@testing-library/react/node_modules/ansi-styles": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "engines": { "node": ">=10" }, @@ -6900,7 +6956,6 @@ "version": "5.1.3", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", - "dev": true, "dependencies": { "deep-equal": "^2.0.5" } @@ -6909,7 +6964,6 @@ "version": "27.5.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", - "dev": true, "dependencies": { "ansi-regex": "^5.0.1", "ansi-styles": "^5.0.0", @@ -7168,9 +7222,9 @@ "dev": true }, "node_modules/@types/eslint": { - "version": "8.21.3", - "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.3.tgz", - "integrity": "sha512-fa7GkppZVEByMWGbTtE5MbmXWJTVbrjjaS8K6uQj+XtuuUv1fsuPAxhygfqLmsb/Ufb3CV8deFCpiMfAgi00Sw==", + "version": "8.21.2", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.21.2.tgz", + "integrity": "sha512-EMpxUyystd3uZVByZap1DACsMXvb82ypQnGn89e1Y0a+LYu3JJscUd/gqhRsVFDkaD2MIiWo0MT8EfXr3DGRKw==", "dependencies": { "@types/estree": "*", "@types/json-schema": "*" @@ -7616,7 +7670,6 @@ "version": "17.0.19", "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-17.0.19.tgz", "integrity": "sha512-PiYG40pnQRdPHnlf7tZnp0aQ6q9tspYr72vD61saO6zFCybLfMqwUCN0va1/P+86DXn18ZWeW30Bk7xlC5eEAQ==", - "dev": true, "dependencies": { "@types/react": "^17" } @@ -8383,7 +8436,8 @@ "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true }, "node_modules/abort-controller": { "version": "3.0.0", @@ -8536,6 +8590,7 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.3.0.tgz", "integrity": "sha512-7Epl1Blf4Sy37j4v9f9FjICCh4+KAQOyXgHEwlyBiAQLbhKdq/i2QQU3amQalS/wPhdPzDXPL5DMR5bkn+YeWg==", + "dev": true, "dependencies": { "debug": "^4.1.0", "depd": "^2.0.0", @@ -8806,7 +8861,8 @@ "node_modules/aproba": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true }, "node_modules/arch": { "version": "2.2.0", @@ -8832,6 +8888,7 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, "dependencies": { "delegates": "^1.0.0", "readable-stream": "^3.6.0" @@ -8988,7 +9045,8 @@ "node_modules/asap": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", - "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==" + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "dev": true }, "node_modules/asar": { "version": "3.2.0", @@ -9216,9 +9274,9 @@ } }, "node_modules/b4a": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.3.tgz", - "integrity": "sha512-aX6/FqpWQve8VN9kyTExy7GlmwNShvxcCWWD5QVR3ZbRlyBGtCrG5Autu95xxSPH4CRs+5PSV4d7PRnWpmqFlA==" + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.2.tgz", + "integrity": "sha512-YFqjbZ8iqX/wWJVmF1SSOB5TYDwsPd/sZzhSdu2PskElf55PjEe+0MhsEPgoa5eTK1VS/WqJMz9qwIFwZta+3g==" }, "node_modules/babel-jest": { "version": "28.1.3", @@ -9578,6 +9636,7 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/bin-links/-/bin-links-3.0.3.tgz", "integrity": "sha512-zKdnMPWEdh4F5INR07/eBrodC7QrF5JKvqskjz/ZZRXg5YSAZIbn8zGhbhUrElzHBZ2fvEQdOU59RHcTG3GiwA==", + "dev": true, "dependencies": { "cmd-shim": "^5.0.0", "mkdirp-infer-owner": "^2.0.0", @@ -9594,6 +9653,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -9602,6 +9662,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -10039,6 +10100,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, "dependencies": { "semver": "^7.0.0" } @@ -10073,6 +10135,7 @@ "version": "16.1.3", "resolved": "https://registry.npmjs.org/cacache/-/cacache-16.1.3.tgz", "integrity": "sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==", + "dev": true, "dependencies": { "@npmcli/fs": "^2.1.0", "@npmcli/move-file": "^2.0.0", @@ -10101,6 +10164,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -10109,6 +10173,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -10127,6 +10192,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -10135,6 +10201,7 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -10146,6 +10213,7 @@ "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" }, @@ -10157,6 +10225,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -10171,6 +10240,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -10180,6 +10250,7 @@ "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -10199,6 +10270,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -10209,7 +10281,8 @@ "node_modules/cacache/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/cacheable-lookup": { "version": "5.0.4", @@ -10333,9 +10406,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001468", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001468.tgz", - "integrity": "sha512-zgAo8D5kbOyUcRAgSmgyuvBkjrGk5CGYG5TYgFdpQv+ywcyEpo1LOWoG8YmoflGnh+V+UsNuKYedsoYs0hzV5A==", + "version": "1.0.30001466", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001466.tgz", + "integrity": "sha512-ewtFBSfWjEmxUgNBSZItFSmVtvk9zkwkl1OfRZlKA8slltRN+/C/tuGVrF9styXkN36Yu3+SeJ1qkXxDEyNZ5w==", "funding": [ { "type": "opencollective", @@ -10734,6 +10807,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/cmd-shim/-/cmd-shim-5.0.0.tgz", "integrity": "sha512-qkCtZ59BidfEwHltnJwkyVZn+XQojdAySM1D1gSeh11Z4pW1Kpolkyo53L5noc0nrxmIvyFwTmJRo4xs7FFLPw==", + "dev": true, "dependencies": { "mkdirp-infer-owner": "^2.0.0" }, @@ -10807,6 +10881,7 @@ "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, "bin": { "color-support": "bin.js" } @@ -10851,6 +10926,7 @@ "version": "1.6.0", "resolved": "https://registry.npmjs.org/columnify/-/columnify-1.6.0.tgz", "integrity": "sha512-lomjuFZKfM6MSAnV9aCZC9sc0qGbmZdfygNv+nCpqVkSKdCxCklLtd16O0EILGkImHw9ZpHkAnHaB+8Zxq5W6Q==", + "dev": true, "dependencies": { "strip-ansi": "^6.0.1", "wcwidth": "^1.0.0" @@ -10896,7 +10972,8 @@ "node_modules/common-ancestor-path": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/common-ancestor-path/-/common-ancestor-path-1.0.1.tgz", - "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==" + "integrity": "sha512-L3sHRo1pXXEqX8VU28kfgUY+YGsk09hPqZiZmLacNib6XNTCM8ubYeT7ryXQw8asB1sKgcU5lkB7ONug08aB8w==", + "dev": true }, "node_modules/common-path-prefix": { "version": "3.0.0", @@ -11125,7 +11202,8 @@ "node_modules/console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true }, "node_modules/content-disposition": { "version": "0.5.4", @@ -11851,6 +11929,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/debuglog/-/debuglog-1.0.1.tgz", "integrity": "sha512-syBZ+rnAK3EgMsH2aYEOLUW7mZSY9Gb+0wUMCFsZvcmiz+HigA0LOcq/HoQqVuGG+EKykunc7QG2bzrponfaSw==", + "dev": true, "engines": { "node": "*" } @@ -11983,9 +12062,9 @@ } }, "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.0.tgz", + "integrity": "sha512-z2wJZXrmeHdvYJp/Ux55wIjqo81G5Bp4c+oELTW+7ar6SogWHajt5a9gO3s3IDaGSAXjDk0vlQKN3rms8ab3og==", "engines": { "node": ">=0.10.0" } @@ -12159,12 +12238,14 @@ "node_modules/delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "dev": true, "engines": { "node": ">= 0.8" } @@ -12237,6 +12318,7 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/dezalgo/-/dezalgo-1.0.4.tgz", "integrity": "sha512-rXSP0bf+5n0Qonsb+SVVfNfIsimO4HEtmnIpPHY8Q1UCzKlQrDMfdobr8nJOOsRgWCyMRqeSBQzmWUMq7zvVig==", + "dev": true, "dependencies": { "asap": "^2.0.0", "wrappy": "1" @@ -12858,9 +12940,9 @@ } }, "node_modules/electron-to-chromium": { - "version": "1.4.333", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.333.tgz", - "integrity": "sha512-YyE8+GKyGtPEP1/kpvqsdhD6rA/TP1DUFDN4uiU/YI52NzDxmwHkEb3qjId8hLBa5siJvG0sfC3O66501jMruQ==" + "version": "1.4.328", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.328.tgz", + "integrity": "sha512-DE9tTy2PNmy1v55AZAO542ui+MLC2cvINMK4P2LXGsJdput/ThVG9t+QGecPuAZZSgC8XoI+Jh9M1OG9IoNSCw==" }, "node_modules/electron-updater": { "version": "4.6.5", @@ -12981,6 +13063,7 @@ "version": "0.1.13", "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, "optional": true, "dependencies": { "iconv-lite": "^0.6.2" @@ -13057,7 +13140,8 @@ "node_modules/err-code": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true }, "node_modules/errno": { "version": "0.1.8", @@ -13204,9 +13288,9 @@ "peer": true }, "node_modules/esbuild": { - "version": "0.17.12", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.12.tgz", - "integrity": "sha512-bX/zHl7Gn2CpQwcMtRogTTBf9l1nl+H6R8nUbjk+RuKqAE3+8FDulLA+pHvX7aA7Xe07Iwa+CWvy9I8Y2qqPKQ==", + "version": "0.17.11", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.17.11.tgz", + "integrity": "sha512-pAMImyokbWDtnA/ufPxjQg0fYo2DDuzAlqwnDvbXqHLphe+m80eF++perYKVm8LeTuj2zUuFXC+xgSVxyoHUdg==", "dev": true, "hasInstallScript": true, "bin": { @@ -13216,28 +13300,28 @@ "node": ">=12" }, "optionalDependencies": { - "@esbuild/android-arm": "0.17.12", - "@esbuild/android-arm64": "0.17.12", - "@esbuild/android-x64": "0.17.12", - "@esbuild/darwin-arm64": "0.17.12", - "@esbuild/darwin-x64": "0.17.12", - "@esbuild/freebsd-arm64": "0.17.12", - "@esbuild/freebsd-x64": "0.17.12", - "@esbuild/linux-arm": "0.17.12", - "@esbuild/linux-arm64": "0.17.12", - "@esbuild/linux-ia32": "0.17.12", - "@esbuild/linux-loong64": "0.17.12", - "@esbuild/linux-mips64el": "0.17.12", - "@esbuild/linux-ppc64": "0.17.12", - "@esbuild/linux-riscv64": "0.17.12", - "@esbuild/linux-s390x": "0.17.12", - "@esbuild/linux-x64": "0.17.12", - "@esbuild/netbsd-x64": "0.17.12", - "@esbuild/openbsd-x64": "0.17.12", - "@esbuild/sunos-x64": "0.17.12", - "@esbuild/win32-arm64": "0.17.12", - "@esbuild/win32-ia32": "0.17.12", - "@esbuild/win32-x64": "0.17.12" + "@esbuild/android-arm": "0.17.11", + "@esbuild/android-arm64": "0.17.11", + "@esbuild/android-x64": "0.17.11", + "@esbuild/darwin-arm64": "0.17.11", + "@esbuild/darwin-x64": "0.17.11", + "@esbuild/freebsd-arm64": "0.17.11", + "@esbuild/freebsd-x64": "0.17.11", + "@esbuild/linux-arm": "0.17.11", + "@esbuild/linux-arm64": "0.17.11", + "@esbuild/linux-ia32": "0.17.11", + "@esbuild/linux-loong64": "0.17.11", + "@esbuild/linux-mips64el": "0.17.11", + "@esbuild/linux-ppc64": "0.17.11", + "@esbuild/linux-riscv64": "0.17.11", + "@esbuild/linux-s390x": "0.17.11", + "@esbuild/linux-x64": "0.17.11", + "@esbuild/netbsd-x64": "0.17.11", + "@esbuild/openbsd-x64": "0.17.11", + "@esbuild/sunos-x64": "0.17.11", + "@esbuild/win32-arm64": "0.17.11", + "@esbuild/win32-ia32": "0.17.11", + "@esbuild/win32-x64": "0.17.11" } }, "node_modules/esbuild-loader": { @@ -15686,6 +15770,7 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, "dependencies": { "aproba": "^1.0.3 || ^2.0.0", "color-support": "^1.1.3", @@ -16126,9 +16211,9 @@ } }, "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==" }, "node_modules/graceful-readlink": { "version": "1.0.1", @@ -16393,7 +16478,8 @@ "node_modules/has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true }, "node_modules/he": { "version": "1.2.0", @@ -16434,6 +16520,7 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -16445,6 +16532,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -16455,7 +16543,8 @@ "node_modules/hosted-git-info/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/hpack.js": { "version": "2.1.6", @@ -16755,6 +16844,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, "dependencies": { "ms": "^2.0.0" } @@ -16857,6 +16947,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-5.0.1.tgz", "integrity": "sha512-yemi4pMf51WKT7khInJqAvsIGzoqYXblnsz0ql8tM+yi1EKYTY1evX4NAbJrLL/Aanr2HyZeluqU+Oi7MGHokw==", + "dev": true, "dependencies": { "minimatch": "^5.0.1" }, @@ -16868,6 +16959,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -16876,6 +16968,7 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -16980,7 +17073,8 @@ "node_modules/infer-owner": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", - "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==" + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true }, "node_modules/inflight": { "version": "1.0.6", @@ -17005,6 +17099,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/init-package-json/-/init-package-json-3.0.2.tgz", "integrity": "sha512-YhlQPEjNFqlGdzrBfDNRLhvoSgX7iQRgSxgsNknRQ9ITXFT7UMfVMWhBTOh2Y+25lRnGrv5Xz8yZwQ3ACR6T3A==", + "dev": true, "dependencies": { "npm-package-arg": "^9.0.1", "promzard": "^0.3.0", @@ -17022,6 +17117,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -17033,6 +17129,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -17041,6 +17138,7 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -17117,7 +17215,8 @@ "node_modules/ip": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true }, "node_modules/ip-regex": { "version": "4.3.0", @@ -17354,7 +17453,8 @@ "node_modules/is-lambda": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true }, "node_modules/is-map": { "version": "2.0.2", @@ -20317,9 +20417,9 @@ } }, "node_modules/jest-watch-typeahead/node_modules/ansi-escapes": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.1.0.tgz", - "integrity": "sha512-bQyg9bzRntwR/8b89DOEhGwctcwCrbWW/TuqTQnpqpy5Fz3aovcOTj5i8NJV6AHc8OGNdMaqdxAWww8pz2kiKg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.0.0.tgz", + "integrity": "sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw==", "dependencies": { "type-fest": "^3.0.0" }, @@ -20708,9 +20808,9 @@ "integrity": "sha512-1P1OROm/rdubP5aFDSZQILU0vrLCJ4fvHt6EoqHEM+2D/G5MK3bIaymUKLit8Js9gbns5UyJnkP/TZROLw4tUA==" }, "node_modules/joi": { - "version": "17.9.0", - "resolved": "https://registry.npmjs.org/joi/-/joi-17.9.0.tgz", - "integrity": "sha512-PWirKfKoZL3kWHfkGKzdCLGv23c00rI31PKVDMg33b/ANe+bMC/ZPdEnHAoHzn5Hy6BTg3J0A2yRVKzT64e6Xw==", + "version": "17.8.4", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.8.4.tgz", + "integrity": "sha512-jjdRHb5WtL+KgSHvOULQEPPv4kcl+ixd1ybOFQq3rWLgEEqc03QMmilodL0GVJE14U/SQDXkUhQUSZANGDH/AA==", "dependencies": { "@hapi/hoek": "^9.0.0", "@hapi/topo": "^5.0.0", @@ -20880,6 +20980,7 @@ "version": "1.1.4", "resolved": "https://registry.npmjs.org/json-stringify-nice/-/json-stringify-nice-1.1.4.tgz", "integrity": "sha512-5Z5RFW63yxReJ7vANgW6eZFGWaQvnPE3WNmZoOJrSkGju2etKA2L5rrOa1sm877TVTFt57A80BH1bArcmlLfPw==", + "dev": true, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -20920,6 +21021,7 @@ "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "dev": true, "engines": [ "node >= 0.2.0" ] @@ -21128,12 +21230,14 @@ "node_modules/just-diff": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/just-diff/-/just-diff-5.2.0.tgz", - "integrity": "sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw==" + "integrity": "sha512-6ufhP9SHjb7jibNFrNxyFZ6od3g+An6Ai9mhGRvcYe8UJlH0prseN64M+6ZBBUoKYHZsitDP42gAJ8+eVWr3lw==", + "dev": true }, "node_modules/just-diff-apply": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/just-diff-apply/-/just-diff-apply-5.5.0.tgz", - "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==" + "integrity": "sha512-OYTthRfSh55WOItVqwpefPtNt2VdKsq5AnAK6apdtR6yCH8pr0CmSr710J0Mf+WdQy7K/OzMy7K2MgAfdQURDw==", + "dev": true }, "node_modules/keyv": { "version": "4.5.2", @@ -21187,16 +21291,6 @@ "language-subtag-registry": "~0.3.2" } }, - "node_modules/launch-editor": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.0.tgz", - "integrity": "sha512-JpDCcQnyAAzZZaZ7vEiSqL690w7dAEyLao+KC96zBplnYbJS7TYNjvM3M7y3dGz+v7aIsJk3hllWuc0kWAjyRQ==", - "dev": true, - "dependencies": { - "picocolors": "^1.0.0", - "shell-quote": "^1.7.3" - } - }, "node_modules/lazy-cache": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-2.0.2.tgz", @@ -21392,12 +21486,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lerna/node_modules/graceful-fs": { - "version": "4.2.10", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", - "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", - "dev": true - }, "node_modules/lerna/node_modules/inquirer": { "version": "8.2.5", "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-8.2.5.tgz", @@ -21748,6 +21836,7 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/libnpmaccess/-/libnpmaccess-6.0.3.tgz", "integrity": "sha512-4tkfUZprwvih2VUZYMozL7EMKgQ5q9VW2NtRyxWtQWlkLTAWHRklcAvBN49CVqEkhUw7vTX2fNgB5LzgUucgYg==", + "dev": true, "dependencies": { "aproba": "^2.0.0", "minipass": "^3.1.1", @@ -21762,6 +21851,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -21773,6 +21863,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -21781,6 +21872,7 @@ "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" }, @@ -21792,6 +21884,7 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -21805,12 +21898,14 @@ "node_modules/libnpmaccess/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/libnpmpublish": { "version": "6.0.4", "resolved": "https://registry.npmjs.org/libnpmpublish/-/libnpmpublish-6.0.4.tgz", "integrity": "sha512-lvAEYW8mB8QblL6Q/PI/wMzKNvIrF7Kpujf/4fGS/32a2i3jzUXi04TNyIBcK6dQJ34IgywfaKGh+Jq4HYPFmg==", + "dev": true, "dependencies": { "normalize-package-data": "^4.0.0", "npm-package-arg": "^9.0.1", @@ -21826,6 +21921,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -21837,6 +21933,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -21845,6 +21942,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", + "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "is-core-module": "^2.8.1", @@ -21859,6 +21957,7 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -22189,6 +22288,7 @@ "version": "9.1.0", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, "dependencies": { "agentkeepalive": "^4.1.3", "cacache": "^15.2.0", @@ -22215,6 +22315,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, "dependencies": { "@gar/promisify": "^1.0.1", "semver": "^7.3.5" @@ -22225,6 +22326,7 @@ "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, "dependencies": { "mkdirp": "^1.0.4", "rimraf": "^3.0.2" @@ -22237,6 +22339,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, "engines": { "node": ">= 6" } @@ -22245,6 +22348,7 @@ "version": "15.3.0", "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, "dependencies": { "@npmcli/fs": "^1.0.0", "@npmcli/move-file": "^1.0.1", @@ -22273,6 +22377,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, "dependencies": { "@tootallnate/once": "1", "agent-base": "6", @@ -22286,6 +22391,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -22297,6 +22403,7 @@ "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" }, @@ -22308,6 +22415,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -22322,6 +22430,7 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, "dependencies": { "minipass": "^3.1.1" }, @@ -22333,6 +22442,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, "dependencies": { "unique-slug": "^2.0.0" } @@ -22341,6 +22451,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, "dependencies": { "imurmurhash": "^0.1.4" } @@ -22348,7 +22459,8 @@ "node_modules/make-fetch-happen/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/make-plural": { "version": "6.2.2", @@ -22844,9 +22956,9 @@ } }, "node_modules/mini-css-extract-plugin": { - "version": "2.7.5", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.5.tgz", - "integrity": "sha512-9HaR++0mlgom81s95vvNjxkg52n2b5s//3ZTI1EtzFb98awsLSivs2LMsVqnQ3ay0PVhqWcGNyDaTE961FOcjQ==", + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.3.tgz", + "integrity": "sha512-CD9cXeKeXLcnMw8FZdtfrRrLaM7gwCl4nKuKn2YkY2Bw5wdlB8zU2cCzw+w2zS9RFvbrufTBkMCJACNPwqQA0w==", "dependencies": { "schema-utils": "^4.0.0" }, @@ -22961,6 +23073,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -22972,6 +23085,7 @@ "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" }, @@ -22982,12 +23096,14 @@ "node_modules/minipass-collect/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/minipass-fetch": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, "dependencies": { "minipass": "^3.1.0", "minipass-sized": "^1.0.3", @@ -23004,6 +23120,7 @@ "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" }, @@ -23014,12 +23131,14 @@ "node_modules/minipass-fetch/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/minipass-flush": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -23031,6 +23150,7 @@ "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" }, @@ -23041,12 +23161,14 @@ "node_modules/minipass-flush/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/minipass-json-stream": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dev": true, "dependencies": { "jsonparse": "^1.3.1", "minipass": "^3.0.0" @@ -23056,6 +23178,7 @@ "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" }, @@ -23066,12 +23189,14 @@ "node_modules/minipass-json-stream/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/minipass-pipeline": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -23083,6 +23208,7 @@ "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" }, @@ -23093,12 +23219,14 @@ "node_modules/minipass-pipeline/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/minipass-sized": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, "dependencies": { "minipass": "^3.0.0" }, @@ -23110,6 +23238,7 @@ "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" }, @@ -23120,7 +23249,8 @@ "node_modules/minipass-sized/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/minizlib": { "version": "2.1.2", @@ -23207,6 +23337,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz", "integrity": "sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw==", + "dev": true, "dependencies": { "chownr": "^2.0.0", "infer-owner": "^1.0.4", @@ -23474,6 +23605,7 @@ "version": "0.6.3", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, "engines": { "node": ">= 0.6" } @@ -23572,6 +23704,7 @@ "version": "8.4.1", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "dev": true, "dependencies": { "env-paths": "^2.2.0", "glob": "^7.1.4", @@ -23606,6 +23739,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -23725,6 +23859,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, "dependencies": { "abbrev": "1" }, @@ -23944,6 +24079,7 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.2.tgz", "integrity": "sha512-x5DHup0SuyQcmL3s7Rx/YQ8sbw/Hzg0rj48eN0dV7hf5cmQq5PXIeioroH3raV1QC1yh3uTYuMThvEQF3iKgGQ==", + "dev": true, "dependencies": { "npm-normalize-package-bin": "^1.0.1" } @@ -23976,6 +24112,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", "integrity": "sha512-65lUsMI8ztHCxFz5ckCEC44DRvEGdZX5usQFriauxHEwt7upv1FKaQEmAtU0YnOAdwuNWCmk64xYiQABNrEyLA==", + "dev": true, "dependencies": { "semver": "^7.1.1" }, @@ -23986,12 +24123,14 @@ "node_modules/npm-normalize-package-bin": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz", - "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==" + "integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA==", + "dev": true }, "node_modules/npm-package-arg": { "version": "8.1.1", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.1.tgz", "integrity": "sha512-CsP95FhWQDwNqiYS+Q0mZ7FAEDytDZAkNxQqea6IaAFJTAY9Lhhqyl0irU/6PMc7BGfUmnsbHcqxJD7XuVM/rg==", + "dev": true, "dependencies": { "hosted-git-info": "^3.0.6", "semver": "^7.0.0", @@ -24004,12 +24143,14 @@ "node_modules/npm-package-arg/node_modules/builtins": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz", - "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==" + "integrity": "sha512-uYBjakWipfaO/bXI7E8rq6kpwHRZK5cNYrUv2OzZSI/FvmdMyXJ2tG9dKcjEC5YHmHpUAwsargWIZNWdxb/bnQ==", + "dev": true }, "node_modules/npm-package-arg/node_modules/hosted-git-info": { "version": "3.0.8", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-3.0.8.tgz", "integrity": "sha512-aXpmwoOhRBrw6X3j0h5RloK4x1OzsxMPyxqIHyNfSe2pypkVTZFpEiRoSipPEPlMrh0HW/XsjkJ5WgnCirpNUw==", + "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -24021,6 +24162,7 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -24032,6 +24174,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz", "integrity": "sha512-M6w37eVCMMouJ9V/sdPGnC5H4uDr73/+xdq0FBLO3TFFX1+7wiUY6Es328NN+y43tmY+doUdN9g9J21vqB7iLw==", + "dev": true, "dependencies": { "builtins": "^1.0.3" } @@ -24039,12 +24182,14 @@ "node_modules/npm-package-arg/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/npm-packlist": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-5.1.1.tgz", "integrity": "sha512-UfpSvQ5YKwctmodvPPkK6Fwk603aoVsf8AEbmVKAEECrfvL8SSe1A2YIwrJ6xmTHAITKPwwZsWo7WwEbNk0kxw==", + "dev": true, "dependencies": { "glob": "^8.0.1", "ignore-walk": "^5.0.1", @@ -24062,6 +24207,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -24070,6 +24216,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -24088,6 +24235,7 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -24099,6 +24247,7 @@ "version": "7.0.2", "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-7.0.2.tgz", "integrity": "sha512-gk37SyRmlIjvTfcYl6RzDbSmS9Y4TOBXfsPnoYqTHARNgWbyDiCSMLUpmALDj4jjcTZpURiEfsSHJj9k7EV4Rw==", + "dev": true, "dependencies": { "npm-install-checks": "^5.0.0", "npm-normalize-package-bin": "^2.0.0", @@ -24113,6 +24262,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -24124,6 +24274,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -24132,6 +24283,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-2.0.0.tgz", "integrity": "sha512-awzfKUO7v0FscrSpRoogyNm0sajikhBWpU0QMrW09AMi9n1PoKU6WaIqUzuJSQnpciZZmJ/jMZ2Egfmb/9LiWQ==", + "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -24140,6 +24292,7 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -24154,6 +24307,7 @@ "version": "13.3.0", "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-13.3.0.tgz", "integrity": "sha512-10LJQ/1+VhKrZjIuY9I/+gQTvumqqlgnsCufoXETHAPFTS3+M+Z5CFhZRDHGavmJ6rOye3UvNga88vl8n1r6gg==", + "dev": true, "dependencies": { "make-fetch-happen": "^10.0.6", "minipass": "^3.1.6", @@ -24171,6 +24325,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -24182,6 +24337,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -24190,6 +24346,7 @@ "version": "10.2.1", "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-10.2.1.tgz", "integrity": "sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==", + "dev": true, "dependencies": { "agentkeepalive": "^4.2.1", "cacache": "^16.1.0", @@ -24216,6 +24373,7 @@ "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" }, @@ -24227,6 +24385,7 @@ "version": "2.1.2", "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-2.1.2.tgz", "integrity": "sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==", + "dev": true, "dependencies": { "minipass": "^3.1.6", "minipass-sized": "^1.0.3", @@ -24243,6 +24402,7 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -24257,6 +24417,7 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dev": true, "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -24269,7 +24430,8 @@ "node_modules/npm-registry-fetch/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/npm-run-path": { "version": "2.0.2", @@ -26489,6 +26651,7 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, "dependencies": { "are-we-there-yet": "^3.0.0", "console-control-strings": "^1.1.0", @@ -26517,14 +26680,14 @@ "integrity": "sha512-90yv+6538zuvUMnN+zCr8LuV6bPFdq50304114vJYJ8RDyK8D5O9Phpbd6SZWgI7PwzmmfN1upeOJlvybDSgCw==" }, "node_modules/nx": { - "version": "15.8.7", - "resolved": "https://registry.npmjs.org/nx/-/nx-15.8.7.tgz", - "integrity": "sha512-u6p/1gU20WU61orxK7hcXBsVspPHy3X66XVAAakkYcaOBlsJhJrR7Og191qIyjEkqEWmcekiDQVw3D6XfagL4Q==", + "version": "15.8.6", + "resolved": "https://registry.npmjs.org/nx/-/nx-15.8.6.tgz", + "integrity": "sha512-3OsT6HMyyUyRuP07vLr7iuWzqziQvkh/vSfOWQb3PXakm6N1IvaLxF+NuUCtSaBDUACfqoVO4MC7WE2270OrKQ==", "dev": true, "hasInstallScript": true, "dependencies": { - "@nrwl/cli": "15.8.7", - "@nrwl/tao": "15.8.7", + "@nrwl/cli": "15.8.6", + "@nrwl/tao": "15.8.6", "@parcel/watcher": "2.0.4", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "^3.0.0-rc.18", @@ -26563,15 +26726,15 @@ "nx": "bin/nx.js" }, "optionalDependencies": { - "@nrwl/nx-darwin-arm64": "15.8.7", - "@nrwl/nx-darwin-x64": "15.8.7", - "@nrwl/nx-linux-arm-gnueabihf": "15.8.7", - "@nrwl/nx-linux-arm64-gnu": "15.8.7", - "@nrwl/nx-linux-arm64-musl": "15.8.7", - "@nrwl/nx-linux-x64-gnu": "15.8.7", - "@nrwl/nx-linux-x64-musl": "15.8.7", - "@nrwl/nx-win32-arm64-msvc": "15.8.7", - "@nrwl/nx-win32-x64-msvc": "15.8.7" + "@nrwl/nx-darwin-arm64": "15.8.6", + "@nrwl/nx-darwin-x64": "15.8.6", + "@nrwl/nx-linux-arm-gnueabihf": "15.8.6", + "@nrwl/nx-linux-arm64-gnu": "15.8.6", + "@nrwl/nx-linux-arm64-musl": "15.8.6", + "@nrwl/nx-linux-x64-gnu": "15.8.6", + "@nrwl/nx-linux-x64-musl": "15.8.6", + "@nrwl/nx-win32-arm64-msvc": "15.8.6", + "@nrwl/nx-win32-x64-msvc": "15.8.6" }, "peerDependencies": { "@swc-node/register": "^1.4.2", @@ -26603,9 +26766,9 @@ } }, "node_modules/nx/node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.0.tgz", + "integrity": "sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==", "dev": true, "dependencies": { "graceful-fs": "^4.2.0", @@ -27291,6 +27454,7 @@ "version": "13.6.1", "resolved": "https://registry.npmjs.org/pacote/-/pacote-13.6.1.tgz", "integrity": "sha512-L+2BI1ougAPsFjXRyBhcKmfT016NscRFLv6Pz5EiNf1CCFJFU0pSKKQwsZTyAQB+sTuUL4TyFyp6J1Ork3dOqw==", + "dev": true, "dependencies": { "@npmcli/git": "^3.0.0", "@npmcli/installed-package-contents": "^1.0.7", @@ -27325,6 +27489,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -27336,6 +27501,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -27344,6 +27510,7 @@ "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" }, @@ -27355,6 +27522,7 @@ "version": "9.1.2", "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-9.1.2.tgz", "integrity": "sha512-pzd9rLEx4TfNJkovvlBSLGhq31gGu2QDexFPWT19yCDh0JgnRhlBLNo5759N0AJmBk+kQ9Y/hXoLnlgFD+ukmg==", + "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "proc-log": "^2.0.1", @@ -27369,6 +27537,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, "dependencies": { "glob": "^7.1.3" }, @@ -27382,7 +27551,8 @@ "node_modules/pacote/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/pako": { "version": "0.2.9", @@ -27414,6 +27584,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/parse-conflict-json/-/parse-conflict-json-2.0.2.tgz", "integrity": "sha512-jDbRGb00TAPFsKWCpZZOT93SxVP9nONOSgES3AevqRq/CHvavEBvKAjxX9p5Y5F0RZLxH9Ufd9+RwtCsa+lFDA==", + "dev": true, "dependencies": { "json-parse-even-better-errors": "^2.3.1", "just-diff": "^5.0.1", @@ -27534,6 +27705,7 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.6.1.tgz", "integrity": "sha512-OW+5s+7cw6253Q4E+8qQ/u1fVvcJQCJo/VFD8pje+dbJCF1n5ZRMV2AEHbGp+5Q7jxQIYJxkHopnj6nzdGeZLA==", + "dev": true, "dependencies": { "lru-cache": "^7.14.1", "minipass": "^4.0.2" @@ -27549,6 +27721,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -28361,9 +28534,9 @@ } }, "node_modules/prettier": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.5.tgz", - "integrity": "sha512-3gzuxrHbKUePRBB4ZeU08VNkUcqEHaUaouNt0m7LGP4Hti/NuB07C7PPTM/LkWqXoJYJn2McEo5+kxPNrtQkLQ==", + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", + "integrity": "sha512-vIS4Rlc2FNh0BySk3Wkd6xmwxB0FpOndW5fisM5H8hsZSxU2VWVB5CWIkIjWvrHjIhxk2g3bfMKM87zNTrZddw==", "peer": true, "bin": { "prettier": "bin-prettier.js" @@ -28441,6 +28614,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-2.0.1.tgz", "integrity": "sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==", + "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -28470,6 +28644,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-all-reject-late/-/promise-all-reject-late-1.0.1.tgz", "integrity": "sha512-vuf0Lf0lOxyQREH7GDIOUMLS7kz+gs8i6B+Yi8dC68a2sychGrHTJYghMBD6k7eUcH0H5P73EckCA48xijWqXw==", + "dev": true, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -28478,6 +28653,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-call-limit/-/promise-call-limit-1.0.1.tgz", "integrity": "sha512-3+hgaa19jzCGLuSCbieeRsu5C2joKfYn8pY6JAuXFRVfF4IO+L7UPpFWNTeWT9pM7uhskvbPPd/oEOktCn317Q==", + "dev": true, "funding": { "url": "https://github.com/sponsors/isaacs" } @@ -28485,12 +28661,14 @@ "node_modules/promise-inflight": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true }, "node_modules/promise-retry": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -28515,6 +28693,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/promzard/-/promzard-0.3.0.tgz", "integrity": "sha512-JZeYqd7UAcHCwI+sTOeUDYkvEU+1bQ7iE0UT1MgB/tERkAPkesW46MrpIySzODi+owTjZtiF8Ay5j9m60KmMBw==", + "dev": true, "dependencies": { "read": "1" } @@ -28899,6 +29078,16 @@ "react-dom": "^16.13.1 || ^17.0.1" } }, + "node_modules/react-material-ui-carousel/node_modules/@types/react": { + "version": "16.14.35", + "resolved": "https://registry.npmjs.org/@types/react/-/react-16.14.35.tgz", + "integrity": "sha512-NUEiwmSS1XXtmBcsm1NyRRPYjoZF2YTE89/5QiLt5mlGffYK9FQqOKuOLuXNrjPQV04oQgaZG+Yq02ZfHoFyyg==", + "dependencies": { + "@types/prop-types": "*", + "@types/scheduler": "*", + "csstype": "^3.0.2" + } + }, "node_modules/react-material-ui-carousel/node_modules/auto-bind": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/auto-bind/-/auto-bind-2.1.1.tgz", @@ -28910,6 +29099,11 @@ "node": ">=6" } }, + "node_modules/react-material-ui-carousel/node_modules/csstype": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.1.tgz", + "integrity": "sha512-DJR/VvkAvSZW9bTouZue2sSxDwdTN92uHjqeKVm+0dAqdfNykRzQ95tay8aXMBAAPpUiq4Qcug2L7neoRh2Egw==" + }, "node_modules/react-redux": { "version": "7.2.9", "resolved": "https://registry.npmjs.org/react-redux/-/react-redux-7.2.9.tgz", @@ -29010,9 +29204,9 @@ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, "node_modules/react-select": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.1.tgz", - "integrity": "sha512-u/brzm3B6vgI+PtxNyE4/18kXgaf6bn5sOAjKhaQ54EItBfW41SRLH1AJC5fefPnGM4JmMcM51t/HAVCi5GrpQ==", + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/react-select/-/react-select-5.7.0.tgz", + "integrity": "sha512-lJGiMxCa3cqnUr2Jjtg9YHsaytiZqeNOKeibv6WF5zbK/fPegZ1hg3y/9P1RZVLhqBTs0PfqQLKuAACednYGhQ==", "dev": true, "dependencies": { "@babel/runtime": "^7.12.0", @@ -29114,6 +29308,7 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, "dependencies": { "mute-stream": "~0.0.4" }, @@ -29134,6 +29329,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/read-cmd-shim/-/read-cmd-shim-3.0.0.tgz", "integrity": "sha512-KQDVjGqhZk92PPNRj9ZEXEuqg8bUobSKRw+q0YQ3TKI5xkce7bUJobL4Z/OtiEbAAv70yEpYIXp4iQ9L8oPVog==", + "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -29167,6 +29363,7 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-5.0.1.tgz", "integrity": "sha512-MALHuNgYWdGW3gKzuNMuYtcSSZbGQm94fAp16xt8VsYTLBjUSc55bLMKe6gzpWue0Tfi6CBgwCSdDAqutGDhMg==", + "dev": true, "dependencies": { "glob": "^8.0.1", "json-parse-even-better-errors": "^2.3.1", @@ -29181,6 +29378,7 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz", "integrity": "sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ==", + "dev": true, "dependencies": { "json-parse-even-better-errors": "^2.3.0", "npm-normalize-package-bin": "^1.0.1" @@ -29193,6 +29391,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } @@ -29201,6 +29400,7 @@ "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -29219,6 +29419,7 @@ "version": "5.2.1", "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-5.2.1.tgz", "integrity": "sha512-xIcQYMnhcx2Nr4JTjsFmwwnr9vldugPy9uVm0o87bjqqWMv9GaqsTeT+i99wTl0mk1uLxJtHxLb8kymqTENQsw==", + "dev": true, "dependencies": { "lru-cache": "^7.5.1" }, @@ -29230,6 +29431,7 @@ "version": "7.18.3", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "dev": true, "engines": { "node": ">=12" } @@ -29238,6 +29440,7 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -29249,6 +29452,7 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-4.0.1.tgz", "integrity": "sha512-EBk5QKKuocMJhB3BILuKhmaPjI8vNRSpIfO9woLC6NyHVkKKdVEdAO1mrT0ZfxNR1lKwCcTkuZfmGIFdizZ8Pg==", + "dev": true, "dependencies": { "hosted-git-info": "^5.0.0", "is-core-module": "^2.8.1", @@ -29472,6 +29676,7 @@ "resolved": "https://registry.npmjs.org/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz", "integrity": "sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw==", "deprecated": "This functionality has been moved to @npmcli/fs", + "dev": true, "dependencies": { "debuglog": "^1.0.1", "dezalgo": "^1.0.0", @@ -29902,6 +30107,7 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-4.4.0.tgz", "integrity": "sha512-X36S+qpCUR0HjXlkDe4NAOhS//aHH0Z+h8Ckf2auGJk3PTnx5rLmrHkwNdbVQuCSUhOyFrlRvFEllZOYE+yZGQ==", + "dev": true, "dependencies": { "glob": "^9.2.0" }, @@ -29919,14 +30125,16 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, "dependencies": { "balanced-match": "^1.0.0" } }, "node_modules/rimraf/node_modules/glob": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.0.tgz", - "integrity": "sha512-EAZejC7JvnQINayvB/7BJbpZpNOJ8Lrw2OZNEvQxe0vaLn1SuwMcfV7/MNaX8L/T0wmptBFI4YMtDvSBxYDc7w==", + "version": "9.2.1", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.2.1.tgz", + "integrity": "sha512-Pxxgq3W0HyA3XUvSXcFhRSs+43Jsx0ddxcFrbjxNGkL2Ak5BAUBxLqI5G6ADDeCHLfzzXFhe0b1yYcctGmytMA==", + "dev": true, "dependencies": { "fs.realpath": "^1.0.0", "minimatch": "^7.4.1", @@ -29944,6 +30152,7 @@ "version": "7.4.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-7.4.2.tgz", "integrity": "sha512-xy4q7wou3vUoC9k1xGTXc+awNdGaGVHtFUaey8tiX4H1QRc04DZ/rmDFwNm2EBsuYEhAZ6SgMmYf3InGY6OauA==", + "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -30053,9 +30262,9 @@ } }, "node_modules/safe-stable-stringify": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.3.tgz", - "integrity": "sha512-e2bDA2WJT0wxseVd4lsDP4+3ONX6HpMXQa1ZhFQ7SU+GjvORCmShbCMltrtIDfkYhVHrOcPtj+KhmDBdPdZD1g==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.4.2.tgz", + "integrity": "sha512-gMxvPJYhP0O9n2pvcfYfIuYgbledAOJFcqRThtPRmjscaipiwcwPPKLytpVzMkG2HAN87Qmo2d4PtGiri1dSLA==", "engines": { "node": ">=10" } @@ -30075,9 +30284,9 @@ } }, "node_modules/sass": { - "version": "1.59.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.59.3.tgz", - "integrity": "sha512-QCq98N3hX1jfTCoUAsF3eyGuXLsY7BCnCEg9qAact94Yc21npG2/mVOqoDvE0fCbWDqiM4WlcJQla0gWG2YlxQ==", + "version": "1.59.2", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.59.2.tgz", + "integrity": "sha512-jJyO6SmbzkJexF8MUorHx5tAilcgabioYxT/BHbY4+OvoqmbHxsYlrjZ8Adhqcgl6Zqwie0TgMXLCAmPFxXOuw==", "dependencies": { "chokidar": ">=3.0.0 <4.0.0", "immutable": "^4.0.0", @@ -30447,7 +30656,8 @@ "node_modules/set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true }, "node_modules/set-getter": { "version": "0.1.1", @@ -30692,6 +30902,7 @@ "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, "engines": { "node": ">= 6.0.0", "npm": ">= 3.0.0" @@ -30712,6 +30923,7 @@ "version": "2.7.1", "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dev": true, "dependencies": { "ip": "^2.0.0", "smart-buffer": "^4.2.0" @@ -30725,6 +30937,7 @@ "version": "6.2.1", "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "dev": true, "dependencies": { "agent-base": "^6.0.2", "debug": "^4.3.3", @@ -30826,6 +31039,7 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, "dependencies": { "spdx-expression-parse": "^3.0.0", "spdx-license-ids": "^3.0.0" @@ -30834,12 +31048,14 @@ "node_modules/spdx-exceptions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", - "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==" + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true }, "node_modules/spdx-expression-parse": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, "dependencies": { "spdx-exceptions": "^2.1.0", "spdx-license-ids": "^3.0.0" @@ -30848,7 +31064,8 @@ "node_modules/spdx-license-ids": { "version": "3.0.13", "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.13.tgz", - "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==" + "integrity": "sha512-XkD+zwiqXHikFZm4AX/7JSCXA98U5Db4AFd5XUg/+9UNtnH75+Z9KxtpYiJZx36mUDVOwH83pl7yvCer6ewM3w==", + "dev": true }, "node_modules/spdy": { "version": "4.0.2", @@ -30944,6 +31161,7 @@ "version": "9.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-9.0.1.tgz", "integrity": "sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==", + "dev": true, "dependencies": { "minipass": "^3.1.1" }, @@ -30955,6 +31173,7 @@ "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" }, @@ -30965,7 +31184,8 @@ "node_modules/ssri/node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true }, "node_modules/stack-trace": { "version": "0.0.10", @@ -31123,53 +31343,6 @@ "node": ">= 0.8" } }, - "node_modules/stdin-discarder": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.1.0.tgz", - "integrity": "sha512-xhV7w8S+bUwlPTb4bAOUQhv8/cSS5offJuX8GQGq32ONF0ZtDWKfkdomM3HMRA+LhX6um/FZ0COqlwsjD53LeQ==", - "dependencies": { - "bl": "^5.0.0" - }, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/stdin-discarder/node_modules/bl": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", - "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", - "dependencies": { - "buffer": "^6.0.3", - "inherits": "^2.0.4", - "readable-stream": "^3.4.0" - } - }, - "node_modules/stdin-discarder/node_modules/buffer": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", - "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.2.1" - } - }, "node_modules/stop-iteration-iterator": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", @@ -31824,9 +31997,9 @@ } }, "node_modules/tar-stream/node_modules/bl": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.1.tgz", - "integrity": "sha512-zk1P1eAEBHhhB+4NfGxqmuV6NgwECnIoRgsOq2ObdEsmoFVIYzJ/Jjcgaj7JOY/8ekH27bIHSV4Si2T+evqu+Q==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-6.0.0.tgz", + "integrity": "sha512-Ik9BVIMdcWzSOCpzDv2XpQ4rJ4oZBuk3ck6MgiOv0EopdgtohN2uSCrrLlkH1Jf0KnpZZMBA3D0bUMbCdj/jgA==", "dependencies": { "buffer": "^6.0.3", "inherits": "^2.0.4", @@ -32396,6 +32569,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/treeverse/-/treeverse-2.0.0.tgz", "integrity": "sha512-N5gJCkLu1aXccpOTtqV6ddSEi6ZmGkh3hjmbu1IjcavJK4qyOVQmi0myQKM7z5jVGmD68SJoliaVrMmVObhj6A==", + "dev": true, "engines": { "node": "^12.13.0 || ^14.15.0 || >=16.0.0" } @@ -32807,9 +32981,9 @@ "dev": true }, "node_modules/underscore": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.6.tgz", - "integrity": "sha512-+A5Sja4HP1M08MaXya7p5LvjuM7K6q/2EaC0+iovj/wOcMsTzMvDFbasi/oSapiwOlt252IqsKqPjCl7huKS0A==" + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==" }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", @@ -32855,6 +33029,7 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-2.0.1.tgz", "integrity": "sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==", + "dev": true, "dependencies": { "unique-slug": "^3.0.0" }, @@ -32866,6 +33041,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-3.0.0.tgz", "integrity": "sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==", + "dev": true, "dependencies": { "imurmurhash": "^0.1.4" }, @@ -33096,6 +33272,7 @@ "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, "dependencies": { "spdx-correct": "^3.0.0", "spdx-expression-parse": "^3.0.0" @@ -33105,6 +33282,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-4.0.0.tgz", "integrity": "sha512-mzR0L8ZDktZjpX4OB46KT+56MAhl4EIazWP/+G/HPGuvfdaqg4YsCdtOm6U9+LOFyYDoh4dpnpxZRB9MQQns5Q==", + "dev": true, "dependencies": { "builtins": "^5.0.0" }, @@ -33207,7 +33385,8 @@ "node_modules/walk-up-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/walk-up-path/-/walk-up-path-1.0.0.tgz", - "integrity": "sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg==" + "integrity": "sha512-hwj/qMDUEjCU5h0xr90KGCf0tg0/LgJbmOWgrWKYlcJZM7XvquvUJZ0G/HMGr7F7OQMOUuPHWP9JpriinkAlkg==", + "dev": true }, "node_modules/walker": { "version": "1.0.8", @@ -33263,9 +33442,9 @@ } }, "node_modules/webpack": { - "version": "5.76.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.2.tgz", - "integrity": "sha512-Th05ggRm23rVzEOlX8y67NkYCHa9nTNcwHPBhdg+lKG+mtiW7XgggjAeeLnADAe7mLjJ6LUNfgHAuRRh+Z6J7w==", + "version": "5.76.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.76.1.tgz", + "integrity": "sha512-4+YIK4Abzv8172/SGqObnUjaIHjLEuUasz9EwQj/9xmPPkYJy2Mh03Q/lJfSD3YLzbxy5FeTq5Uw0323Oh6SJQ==", "dependencies": { "@types/eslint-scope": "^3.7.3", "@types/estree": "^0.0.51", @@ -33439,9 +33618,9 @@ } }, "node_modules/webpack-dev-server": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.13.1.tgz", - "integrity": "sha512-5tWg00bnWbYgkN+pd5yISQKDejRBYGEw15RaEEslH+zdbNDxxaZvEAO2WulaSaFKb5n3YG8JXsGaDsut1D0xdA==", + "version": "4.11.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.11.1.tgz", + "integrity": "sha512-lILVz9tAUy1zGFwieuaQtYiadImb5M3d+H+L1zDYalYoDl0cksAB1UNyuE5MMWJrG6zR1tXkCP2fitl7yoUJiw==", "dev": true, "dependencies": { "@types/bonjour": "^3.5.9", @@ -33463,7 +33642,6 @@ "html-entities": "^2.3.2", "http-proxy-middleware": "^2.0.3", "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", "open": "^8.0.9", "p-retry": "^4.5.0", "rimraf": "^3.0.2", @@ -33473,7 +33651,7 @@ "sockjs": "^0.3.24", "spdy": "^4.0.2", "webpack-dev-middleware": "^5.3.1", - "ws": "^8.13.0" + "ws": "^8.4.2" }, "bin": { "webpack-dev-server": "bin/webpack-dev-server.js" @@ -33489,9 +33667,6 @@ "webpack": "^4.37.0 || ^5.0.0" }, "peerDependenciesMeta": { - "webpack": { - "optional": true - }, "webpack-cli": { "optional": true } @@ -33737,6 +33912,7 @@ "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, "dependencies": { "string-width": "^1.0.2 || 2 || 3 || 4" } @@ -34267,6 +34443,7 @@ }, "devDependencies": { "@async-fn/jest": "1.6.4", + "@k8slens/messaging-fake-bridge": "^1.0.0-alpha.1", "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", "@material-ui/lab": "^4.0.0-alpha.60", @@ -34403,7 +34580,11 @@ "@k8slens/application": "^6.5.0-alpha.0", "@k8slens/application-for-electron-main": "^6.5.0-alpha.0", "@k8slens/legacy-extensions": "^1.0.0-alpha.0", + "@k8slens/messaging": "^1.0.0-alpha.1", + "@k8slens/messaging-for-main": "^1.0.0-alpha.1", + "@k8slens/messaging-for-renderer": "^1.0.0-alpha.1", "@k8slens/run-many": "^1.0.0-alpha.1", + "@k8slens/startable-stoppable": "^1.0.0-alpha.1", "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", "@types/byline": "^4.2.33", @@ -35073,9 +35254,9 @@ "integrity": "sha512-XTIieEY+gvJ39ChLcB4If5zHtPxt3Syj5rgZR+e1ctpmK8NjPf0zFqsz4JpLJT0xla9GFDKjy8Cpu331nrmE1Q==" }, "packages/infrastructure/jest/node_modules/@types/jest": { - "version": "29.5.0", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", - "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", + "version": "29.4.1", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.4.1.tgz", + "integrity": "sha512-zDQSWXG+ZkEvs2zFFMszePhx4euKz+Yt3Gg1P+RHjfJBinTTr6L2DEyovO4V/WrKXuF0Dgn56GWGZPDa6TW9eQ==", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -35971,6 +36152,18 @@ "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, + "packages/infrastructure/jest/node_modules/react": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react/-/react-18.2.0.tgz", + "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", + "peer": true, + "dependencies": { + "loose-envify": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, "packages/infrastructure/jest/node_modules/react-dom": { "version": "18.2.0", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.2.0.tgz", @@ -36132,11 +36325,11 @@ } }, "packages/infrastructure/webpack/node_modules/sass-loader": { - "version": "13.2.1", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.1.tgz", - "integrity": "sha512-VQUrgUa5/waIzMrzyuko3sj5WD9NMsYph91cNICx+OaODbRtLl6To2fswLx8MH2qNxXFqRtpvdPQIa7mE93YOA==", + "version": "13.2.0", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.2.0.tgz", + "integrity": "sha512-JWEp48djQA4nbZxmgC02/Wh0eroSUutulROUusYJO9P9zltRbNN80JCBHqRGzjd4cmZCa/r88xgfkjGD0TXsHg==", "dependencies": { - "klona": "^2.0.6", + "klona": "^2.0.4", "neo-async": "^2.6.2" }, "engines": { @@ -36457,7 +36650,11 @@ "@k8slens/generate-tray-icons": "^6.5.0-alpha.1", "@k8slens/legacy-extension-example": "^1.0.0-alpha.1", "@k8slens/legacy-extensions": "^1.0.0-alpha.1", + "@k8slens/messaging": "^1.0.0-alpha.1", + "@k8slens/messaging-for-main": "^1.0.0-alpha.1", + "@k8slens/messaging-for-renderer": "^1.0.0-alpha.1", "@k8slens/run-many": "^1.0.0-alpha.1", + "@k8slens/startable-stoppable": "^1.0.0-alpha.1", "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", "@ogre-tools/fp": "^15.1.2", @@ -36654,9 +36851,9 @@ "dev": true }, "packages/release-tool/node_modules/ansi-escapes": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.1.0.tgz", - "integrity": "sha512-bQyg9bzRntwR/8b89DOEhGwctcwCrbWW/TuqTQnpqpy5Fz3aovcOTj5i8NJV6AHc8OGNdMaqdxAWww8pz2kiKg==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-6.0.0.tgz", + "integrity": "sha512-IG23inYII3dWlU2EyiAiGj6Bwal5GzsgPMwjYGvc1HPE2dgbj4ZB5ToWBKSquKw74nB3TIuOwaI6/jSULzfgrw==", "dependencies": { "type-fest": "^3.0.0" }, @@ -36689,6 +36886,39 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "packages/release-tool/node_modules/bl": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", + "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==", + "dependencies": { + "buffer": "^6.0.3", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "packages/release-tool/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "packages/release-tool/node_modules/chalk": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.2.0.tgz", @@ -36754,28 +36984,28 @@ } }, "packages/release-tool/node_modules/inquirer": { - "version": "9.1.5", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.1.5.tgz", - "integrity": "sha512-3ygAIh8gcZavV9bj6MTdYddG2zPSYswP808fKS46NOwlF0zZljVpnLCHODDqItWJDbDpLb3aouAxGaJbkxoppA==", + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.1.4.tgz", + "integrity": "sha512-9hiJxE5gkK/cM2d1mTEnuurGTAoHebbkX0BYl3h7iEg7FYfuNIom+nDfBCSWtvSnoSrWCeBxqqBZu26xdlJlXA==", "dependencies": { "ansi-escapes": "^6.0.0", - "chalk": "^5.2.0", + "chalk": "^5.1.2", "cli-cursor": "^4.0.0", "cli-width": "^4.0.0", "external-editor": "^3.0.3", "figures": "^5.0.0", "lodash": "^4.17.21", - "mute-stream": "1.0.0", + "mute-stream": "0.0.8", "ora": "^6.1.2", "run-async": "^2.4.0", - "rxjs": "^7.8.0", + "rxjs": "^7.5.7", "string-width": "^5.1.2", "strip-ansi": "^7.0.1", "through": "^2.3.6", - "wrap-ansi": "^8.1.0" + "wrap-ansi": "^8.0.1" }, "engines": { - "node": ">=14.18.0" + "node": ">=12.0.0" } }, "packages/release-tool/node_modules/is-interactive": { @@ -36815,26 +37045,18 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/release-tool/node_modules/mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "packages/release-tool/node_modules/ora": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-6.2.0.tgz", - "integrity": "sha512-c1qb/1rdE+EFDYiLXh10VY459uMh7DN9zlgd8mZJLoeiPpYllN8eAOiih2Rkah5ywxRm5tHN5C9zPheDq8d1MA==", + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/ora/-/ora-6.1.2.tgz", + "integrity": "sha512-EJQ3NiP5Xo94wJXIzAyOtSb0QEIAUu7m8t6UZ9krbz0vAJqr92JpcK/lEXg91q6B9pEGqrykkd2EQplnifDSBw==", "dependencies": { + "bl": "^5.0.0", "chalk": "^5.0.0", "cli-cursor": "^4.0.0", "cli-spinners": "^2.6.1", "is-interactive": "^2.0.0", "is-unicode-supported": "^1.1.0", "log-symbols": "^5.1.0", - "stdin-discarder": "^0.1.0", "strip-ansi": "^7.0.1", "wcwidth": "^1.0.1" }, @@ -36995,6 +37217,98 @@ "@ogre-tools/injectable": "^15.1.2" } }, + "packages/technical-features/messaging/agnostic": { + "name": "@k8slens/messaging", + "version": "1.0.0-alpha.1", + "license": "MIT", + "devDependencies": { + "@k8slens/eslint-config": "^6.5.0-alpha.1" + }, + "peerDependencies": { + "@k8slens/application": "^6.5.0-alpha.0", + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@k8slens/startable-stoppable": "^1.0.0-alpha.1", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", + "lodash": "^4.17.21", + "mobx": "^6.7.0" + } + }, + "packages/technical-features/messaging/computed-channel": { + "name": "@k8slens/computed-channel", + "version": "1.0.0-alpha.1", + "license": "MIT", + "devDependencies": { + "@k8slens/eslint-config": "^6.5.0-alpha.1", + "@k8slens/messaging-fake-bridge": "^1.0.0-alpha.1", + "type-fest": "^2.14.0" + }, + "peerDependencies": { + "@k8slens/application": "^6.5.0-alpha.0", + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@k8slens/messaging": "^1.0.0-alpha.1", + "@ogre-tools/fp": "^15.1.2", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", + "lodash": "^4.17.21", + "mobx": "^6.8.0" + } + }, + "packages/technical-features/messaging/electron/main": { + "name": "@k8slens/messaging-for-main", + "version": "1.0.0-alpha.1", + "license": "MIT", + "devDependencies": { + "@k8slens/eslint-config": "^6.5.0-alpha.1" + }, + "peerDependencies": { + "@k8slens/application": "^6.5.0-alpha.0", + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@k8slens/messaging": "^1.0.0-alpha.1", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "electron": "^19.1.8", + "lodash": "^4.17.21" + } + }, + "packages/technical-features/messaging/electron/renderer": { + "name": "@k8slens/messaging-for-renderer", + "version": "1.0.0-alpha.1", + "license": "MIT", + "devDependencies": { + "@k8slens/eslint-config": "^6.5.0-alpha.1" + }, + "peerDependencies": { + "@k8slens/application": "^6.5.0-alpha.0", + "@k8slens/messaging": "^1.0.0-alpha.1", + "@k8slens/run-many": "^1.0.0-alpha.1", + "@k8slens/startable-stoppable": "^1.0.0-alpha.1", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "electron": "^19.1.8", + "lodash": "^4.17.21" + } + }, + "packages/technical-features/messaging/message-bridge-fake": { + "name": "@k8slens/messaging-fake-bridge", + "version": "1.0.0-alpha.1", + "license": "MIT", + "devDependencies": { + "@async-fn/jest": "^1.6.4", + "@k8slens/eslint-config": "^6.5.0-alpha.1", + "@k8slens/feature-core": "6.5.0-alpha.1", + "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", + "mobx": "^6.7.0" + }, + "peerDependencies": { + "@k8slens/messaging": "^1.0.0-alpha.1", + "@ogre-tools/fp": "^15.1.2", + "@ogre-tools/injectable": "^15.1.2", + "lodash": "^4.17.21" + } + }, "packages/utility-features/run-many": { "name": "@k8slens/run-many", "version": "1.0.0-alpha.1", @@ -37005,7 +37319,7 @@ "peerDependencies": { "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", - "@ogre-tools/fp": "^15.1.1", + "@ogre-tools/fp": "^15.1.2", "@ogre-tools/injectable": "^15.1.2", "type-fest": "^2.19.0", "typed-emitter": "^1.4.0", @@ -37018,6 +37332,14 @@ "integrity": "sha512-rFT3ak0/2trgvp4yYZo5iKFEPsET7vKydKF+VRCxlQ9bpheehyAJH89dAkaLEq/j/RZXJIqcgsmPJKUP1Z28HA==", "dev": true }, + "packages/utility-features/startable-stoppable": { + "name": "@k8slens/startable-stoppable", + "version": "1.0.0-alpha.1", + "license": "MIT", + "devDependencies": { + "@k8slens/eslint-config": "^6.5.0-alpha.1" + } + }, "packages/utility-features/test-utils": { "name": "@k8slens/test-utils", "version": "1.0.0-alpha.1", @@ -37027,7 +37349,10 @@ }, "peerDependencies": { "@ogre-tools/injectable": "^15.1.2", - "lodash": "^4.17.21" + "@ogre-tools/injectable-react": "^15.1.2", + "@testing-library/react": "^12.1.5", + "lodash": "^4.17.21", + "react": "^17.0.2" } }, "packages/utility-features/utilities": { @@ -37041,7 +37366,8 @@ "@types/react-router": "^5.1.20", "@types/readable-stream": "^2.3.15", "@types/semver": "^7.3.13", - "@types/tar": "^6.1.4" + "@types/tar": "^6.1.4", + "type-fest": "^2.14.0" }, "peerDependencies": { "@astronautlabs/jsonpath": "^1.1.0", diff --git a/package.json b/package.json index bc6c89ab37..0a9f693adb 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "clean:node_modules": "lerna clean -y && rimraf node_modules", "dev": "lerna run dev --stream --skip-nx-cache", "lint": "lerna run lint --stream", + "lint:fix": "lerna run lint:fix --stream", "mkdocs:serve-local": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -it -p 8000:8000 -v ${PWD}:/docs mkdocs-serve-local:latest", "mkdocs:verify": "docker build -t mkdocs-serve-local:latest mkdocs/ && docker run --rm -v ${PWD}:/docs mkdocs-serve-local:latest build --strict", "test:unit": "lerna run --stream test:unit", diff --git a/packages/core/package.json b/packages/core/package.json index 6b4aecf2cc..15c79d774d 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -189,6 +189,7 @@ }, "devDependencies": { "@async-fn/jest": "1.6.4", + "@k8slens/messaging-fake-bridge": "^1.0.0-alpha.1", "@material-ui/core": "^4.12.3", "@material-ui/icons": "^4.11.2", "@material-ui/lab": "^4.0.0-alpha.60", @@ -322,7 +323,11 @@ "@k8slens/application": "^6.5.0-alpha.0", "@k8slens/application-for-electron-main": "^6.5.0-alpha.0", "@k8slens/legacy-extensions": "^1.0.0-alpha.0", + "@k8slens/messaging": "^1.0.0-alpha.1", + "@k8slens/messaging-for-main": "^1.0.0-alpha.1", + "@k8slens/messaging-for-renderer": "^1.0.0-alpha.1", "@k8slens/run-many": "^1.0.0-alpha.1", + "@k8slens/startable-stoppable": "^1.0.0-alpha.1", "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", "@types/byline": "^4.2.33", diff --git a/packages/core/src/common/app-paths/app-paths-channel.ts b/packages/core/src/common/app-paths/app-paths-channel.ts index 4502569d3b..e738b4896a 100644 --- a/packages/core/src/common/app-paths/app-paths-channel.ts +++ b/packages/core/src/common/app-paths/app-paths-channel.ts @@ -3,11 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { AppPaths } from "./app-path-injection-token"; -import type { RequestChannel } from "../utils/channel/request-channel-listener-injection-token"; +import { getRequestChannel } from "@k8slens/messaging"; -export type AppPathsChannel = RequestChannel; - -export const appPathsChannel: AppPathsChannel = { - id: "app-paths", -}; +export const appPathsChannel = getRequestChannel("app-paths"); diff --git a/packages/core/src/common/base-store/base-store.ts b/packages/core/src/common/base-store/base-store.ts index be7abf1293..a1dd26f0f7 100644 --- a/packages/core/src/common/base-store/base-store.ts +++ b/packages/core/src/common/base-store/base-store.ts @@ -15,7 +15,7 @@ import type { GetConfigurationFileModel } from "../get-configuration-file-model/ import type { Logger } from "../logger"; import type { PersistStateToConfig } from "./save-to-file"; import type { GetBasenameOfPath } from "../path/get-basename.injectable"; -import type { EnlistMessageChannelListener } from "../utils/channel/enlist-message-channel-listener-injection-token"; +import type { EnlistMessageChannelListener } from "@k8slens/messaging"; import { toJS } from "../utils"; export interface BaseStoreParams extends Omit, "migrations"> { @@ -108,6 +108,7 @@ export abstract class BaseStore { this.params.syncOptions, ), this.dependencies.enlistMessageChannelListener({ + id: this.displayName, channel: { id: `${this.dependencies.ipcChannelPrefixes.local}:${config.path}`, }, diff --git a/packages/core/src/common/certificate/lens-proxy-certificate-channel.ts b/packages/core/src/common/certificate/lens-proxy-certificate-channel.ts index 7d9652ce5c..9dd339ee65 100644 --- a/packages/core/src/common/certificate/lens-proxy-certificate-channel.ts +++ b/packages/core/src/common/certificate/lens-proxy-certificate-channel.ts @@ -4,6 +4,6 @@ */ import type { SelfSignedCert } from "selfsigned"; -import { getRequestChannel } from "../utils/channel/get-request-channel"; +import { getRequestChannel } from "@k8slens/messaging"; export const lensProxyCertificateChannel = getRequestChannel("request-lens-proxy-certificate"); diff --git a/packages/core/src/common/cluster-store/cluster-store.injectable.ts b/packages/core/src/common/cluster-store/cluster-store.injectable.ts index ddd811c760..79eb02e36c 100644 --- a/packages/core/src/common/cluster-store/cluster-store.injectable.ts +++ b/packages/core/src/common/cluster-store/cluster-store.injectable.ts @@ -16,7 +16,7 @@ import { baseStoreIpcChannelPrefixesInjectionToken } from "../base-store/channel import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../base-store/disable-sync"; import { persistStateToConfigInjectionToken } from "../base-store/save-to-file"; import getBasenameOfPathInjectable from "../path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "../utils/channel/enlist-message-channel-listener-injection-token"; +import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; const clusterStoreInjectable = getInjectable({ id: "cluster-store", diff --git a/packages/core/src/common/cluster/current-cluster-channel.ts b/packages/core/src/common/cluster/current-cluster-channel.ts index 957baa6f9c..c16af7832b 100644 --- a/packages/core/src/common/cluster/current-cluster-channel.ts +++ b/packages/core/src/common/cluster/current-cluster-channel.ts @@ -4,7 +4,7 @@ */ import type { ClusterId } from "../cluster-types"; -import type { MessageChannel } from "../utils/channel/message-channel-listener-injection-token"; +import type { MessageChannel } from "@k8slens/messaging"; export const currentClusterMessageChannel: MessageChannel = { id: "current-visible-cluster", diff --git a/packages/core/src/common/cluster/visibility-channel.ts b/packages/core/src/common/cluster/visibility-channel.ts index 8a1a297ff2..554217a409 100644 --- a/packages/core/src/common/cluster/visibility-channel.ts +++ b/packages/core/src/common/cluster/visibility-channel.ts @@ -4,7 +4,7 @@ */ import type { ClusterId } from "../cluster-types"; -import type { MessageChannel } from "../utils/channel/message-channel-listener-injection-token"; +import type { MessageChannel } from "@k8slens/messaging"; export const clusterVisibilityChannel: MessageChannel = { id: "cluster-visibility", diff --git a/packages/core/src/common/front-end-routing/app-navigation-channel.ts b/packages/core/src/common/front-end-routing/app-navigation-channel.ts index b3d8f02c66..8670fc4953 100644 --- a/packages/core/src/common/front-end-routing/app-navigation-channel.ts +++ b/packages/core/src/common/front-end-routing/app-navigation-channel.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { IpcRendererNavigationEvents } from "../ipc/navigation-events"; -import type { MessageChannel } from "../utils/channel/message-channel-listener-injection-token"; +import type { MessageChannel } from "@k8slens/messaging"; export type AppNavigationChannel = MessageChannel; diff --git a/packages/core/src/common/front-end-routing/cluster-frame-navigation-channel.ts b/packages/core/src/common/front-end-routing/cluster-frame-navigation-channel.ts index 2439f523e2..5f96526da4 100644 --- a/packages/core/src/common/front-end-routing/cluster-frame-navigation-channel.ts +++ b/packages/core/src/common/front-end-routing/cluster-frame-navigation-channel.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { IpcRendererNavigationEvents } from "../ipc/navigation-events"; -import type { MessageChannel } from "../utils/channel/message-channel-listener-injection-token"; +import type { MessageChannel } from "@k8slens/messaging"; export type ClusterFrameNavigationChannel = MessageChannel; diff --git a/packages/core/src/common/helm/add-helm-repository-channel.ts b/packages/core/src/common/helm/add-helm-repository-channel.ts index 258367c7ec..1744192059 100644 --- a/packages/core/src/common/helm/add-helm-repository-channel.ts +++ b/packages/core/src/common/helm/add-helm-repository-channel.ts @@ -3,11 +3,10 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { HelmRepo } from "./helm-repo"; -import type { AsyncResult } from "@k8slens/utilities"; -import type { RequestChannel } from "../utils/channel/request-channel-listener-injection-token"; +import type { Result } from "@k8slens/utilities"; +import { getRequestChannel } from "@k8slens/messaging"; -export type AddHelmRepositoryChannel = RequestChannel>; - -export const addHelmRepositoryChannel: AddHelmRepositoryChannel = { - id: "add-helm-repository-channel", -}; +export const addHelmRepositoryChannel = getRequestChannel< + HelmRepo, + Result +>("add-helm-repository-channel"); diff --git a/packages/core/src/common/helm/get-active-helm-repositories-channel.ts b/packages/core/src/common/helm/get-active-helm-repositories-channel.ts index 2ea5a80030..ba4e0ae956 100644 --- a/packages/core/src/common/helm/get-active-helm-repositories-channel.ts +++ b/packages/core/src/common/helm/get-active-helm-repositories-channel.ts @@ -4,10 +4,9 @@ */ import type { HelmRepo } from "./helm-repo"; import type { AsyncResult } from "@k8slens/utilities"; -import type { RequestChannel } from "../utils/channel/request-channel-listener-injection-token"; +import { getRequestChannel } from "@k8slens/messaging"; -export type GetActiveHelmRepositoriesChannel = RequestChannel>; - -export const getActiveHelmRepositoriesChannel: GetActiveHelmRepositoriesChannel = { - id: "get-helm-active-list-repositories", -}; +export const getActiveHelmRepositoriesChannel = getRequestChannel< + void, + AsyncResult +>("get-helm-active-list-repositories"); diff --git a/packages/core/src/common/helm/remove-helm-repository-channel.ts b/packages/core/src/common/helm/remove-helm-repository-channel.ts index f1189cb580..09c7630f34 100644 --- a/packages/core/src/common/helm/remove-helm-repository-channel.ts +++ b/packages/core/src/common/helm/remove-helm-repository-channel.ts @@ -3,11 +3,10 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { AsyncResult } from "@k8slens/utilities"; -import type { RequestChannel } from "../utils/channel/request-channel-listener-injection-token"; +import { getRequestChannel } from "@k8slens/messaging"; import type { HelmRepo } from "./helm-repo"; -export type RemoveHelmRepositoryChannel = RequestChannel>; - -export const removeHelmRepositoryChannel: RemoveHelmRepositoryChannel = { - id: "remove-helm-repository-channel", -}; +export const removeHelmRepositoryChannel = getRequestChannel< + HelmRepo, + AsyncResult +>("remove-helm-repository-channel"); diff --git a/packages/core/src/common/hotbars/store.injectable.ts b/packages/core/src/common/hotbars/store.injectable.ts index cc15f93bf8..ea25840e11 100644 --- a/packages/core/src/common/hotbars/store.injectable.ts +++ b/packages/core/src/common/hotbars/store.injectable.ts @@ -14,7 +14,7 @@ import { hotbarStoreMigrationInjectionToken } from "./migrations-token"; import getBasenameOfPathInjectable from "../path/get-basename.injectable"; import { baseStoreIpcChannelPrefixesInjectionToken } from "../base-store/channel-prefix"; import { persistStateToConfigInjectionToken } from "../base-store/save-to-file"; -import { enlistMessageChannelListenerInjectionToken } from "../utils/channel/enlist-message-channel-listener-injection-token"; +import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../base-store/disable-sync"; const hotbarStoreInjectable = getInjectable({ diff --git a/packages/core/src/common/kube-helpers/channels.ts b/packages/core/src/common/kube-helpers/channels.ts index b48f9f1f99..c5df4d7358 100644 --- a/packages/core/src/common/kube-helpers/channels.ts +++ b/packages/core/src/common/kube-helpers/channels.ts @@ -4,11 +4,9 @@ */ import { getInjectionToken } from "@ogre-tools/injectable"; -import type { Asyncify } from "type-fest"; -import type { RequestChannelHandler } from "../../main/utils/channel/channel-listeners/listener-tokens"; import type { ClusterId } from "../cluster-types"; -import type { AsyncResult } from "@k8slens/utilities"; -import type { RequestChannel } from "../utils/channel/request-channel-listener-injection-token"; +import type { AsyncResult, Result } from "@k8slens/utilities"; +import { getRequestChannel } from "@k8slens/messaging"; export interface KubectlApplyAllArgs { clusterId: ClusterId; @@ -16,11 +14,12 @@ export interface KubectlApplyAllArgs { extraArgs: string[]; } -export const kubectlApplyAllChannel: RequestChannel> = { - id: "kubectl-apply-all", -}; +export const kubectlApplyAllChannel = getRequestChannel< + KubectlApplyAllArgs, + Result +>("kubectl-apply-all"); -export type KubectlApplyAll = Asyncify>; +export type KubectlApplyAll = (req: KubectlApplyAllArgs) => AsyncResult; export const kubectlApplyAllInjectionToken = getInjectionToken({ id: "kubectl-apply-all", @@ -32,11 +31,12 @@ export interface KubectlDeleteAllArgs { extraArgs: string[]; } -export const kubectlDeleteAllChannel: RequestChannel> = { - id: "kubectl-delete-all", -}; +export const kubectlDeleteAllChannel = getRequestChannel< + KubectlDeleteAllArgs, + Result +>("kubectl-delete-all"); -export type KubectlDeleteAll = Asyncify>; +export type KubectlDeleteAll = (req: KubectlDeleteAllArgs) => AsyncResult; export const kubectlDeleteAllInjectionToken = getInjectionToken({ id: "kubectl-delete-all", diff --git a/packages/core/src/common/root-frame/root-frame-rendered-channel.ts b/packages/core/src/common/root-frame/root-frame-rendered-channel.ts index 060ae8735c..c4dc0cefa6 100644 --- a/packages/core/src/common/root-frame/root-frame-rendered-channel.ts +++ b/packages/core/src/common/root-frame/root-frame-rendered-channel.ts @@ -2,7 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { MessageChannel } from "../utils/channel/message-channel-listener-injection-token"; +import type { MessageChannel } from "@k8slens/messaging"; export type RootFrameHasRenderedChannel = MessageChannel; diff --git a/packages/core/src/common/user-store/user-store.injectable.ts b/packages/core/src/common/user-store/user-store.injectable.ts index 3b45b03b1d..10806007a2 100644 --- a/packages/core/src/common/user-store/user-store.injectable.ts +++ b/packages/core/src/common/user-store/user-store.injectable.ts @@ -16,7 +16,7 @@ import { baseStoreIpcChannelPrefixesInjectionToken } from "../base-store/channel import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../base-store/disable-sync"; import { persistStateToConfigInjectionToken } from "../base-store/save-to-file"; import getBasenameOfPathInjectable from "../path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "../utils/channel/enlist-message-channel-listener-injection-token"; +import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; import userStorePreferenceDescriptorsInjectable from "./preference-descriptors.injectable"; const userStoreInjectable = getInjectable({ diff --git a/packages/core/src/common/utils/channel/channel.test.ts b/packages/core/src/common/utils/channel/channel.test.ts deleted file mode 100644 index bc6043d349..0000000000 --- a/packages/core/src/common/utils/channel/channel.test.ts +++ /dev/null @@ -1,245 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { DiContainer } from "@ogre-tools/injectable"; -import { getInjectable } from "@ogre-tools/injectable"; -import type { SendMessageToChannel } from "./message-to-channel-injection-token"; -import { sendMessageToChannelInjectionToken } from "./message-to-channel-injection-token"; -import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; -import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; -import type { LensWindow } from "../../../main/start-main-application/lens-window/application-window/create-lens-window.injectable"; -import type { MessageChannel } from "./message-channel-listener-injection-token"; -import { messageChannelListenerInjectionToken } from "./message-channel-listener-injection-token"; -import type { RequestFromChannel } from "./request-from-channel-injection-token"; -import { requestFromChannelInjectionToken } from "./request-from-channel-injection-token"; -import type { RequestChannel } from "./request-channel-listener-injection-token"; -import type { AsyncFnMock } from "@async-fn/jest"; -import asyncFn from "@async-fn/jest"; -import { getPromiseStatus } from "@k8slens/test-utils"; -import { runInAction } from "mobx"; -import type { RequestChannelHandler } from "../../../main/utils/channel/channel-listeners/listener-tokens"; -import { - getRequestChannelListenerInjectable, - requestChannelListenerInjectionToken, -} from "../../../main/utils/channel/channel-listeners/listener-tokens"; - -type TestMessageChannel = MessageChannel; -type TestRequestChannel = RequestChannel; - -describe("channel", () => { - describe("messaging from main to renderer, given listener for channel in a window and application has started", () => { - let messageListenerInWindowMock: jest.Mock; - let mainDi: DiContainer; - let messageToChannel: SendMessageToChannel; - let builder: ApplicationBuilder; - - beforeEach(async () => { - builder = getApplicationBuilder(); - - messageListenerInWindowMock = jest.fn(); - - const testChannelListenerInTestWindowInjectable = getInjectable({ - id: "test-channel-listener-in-test-window", - - instantiate: () => ({ - channel: testMessageChannel, - handler: messageListenerInWindowMock, - }), - - injectionToken: messageChannelListenerInjectionToken, - }); - - builder.beforeWindowStart(({ windowDi }) => { - runInAction(() => { - windowDi.register(testChannelListenerInTestWindowInjectable); - }); - }); - - mainDi = builder.mainDi; - - await builder.startHidden(); - - messageToChannel = mainDi.inject(sendMessageToChannelInjectionToken); - }); - - describe("given window is started", () => { - let someWindowFake: LensWindow; - - beforeEach(async () => { - someWindowFake = builder.applicationWindow.create("some-window"); - - await someWindowFake.start(); - }); - - it("when sending message, triggers listener in window", () => { - messageToChannel(testMessageChannel, "some-message"); - - expect(messageListenerInWindowMock).toHaveBeenCalledWith("some-message"); - }); - - it("given window is hidden, when sending message, does not trigger listener in window", () => { - someWindowFake.close(); - - messageToChannel(testMessageChannel, "some-message"); - - expect(messageListenerInWindowMock).not.toHaveBeenCalled(); - }); - }); - - it("given multiple started windows, when sending message, triggers listeners in all windows", async () => { - const someWindowFake = builder.applicationWindow.create("some-window"); - const someOtherWindowFake = builder.applicationWindow.create("some-other-window"); - - await someWindowFake.start(); - await someOtherWindowFake.start(); - - messageToChannel(testMessageChannel, "some-message"); - - expect(messageListenerInWindowMock.mock.calls).toEqual([ - ["some-message"], - ["some-message"], - ]); - }); - }); - - describe("messaging from renderer to main, given listener for channel in a main and application has started", () => { - let messageListenerInMainMock: jest.Mock; - let messageToChannel: SendMessageToChannel; - - beforeEach(async () => { - const applicationBuilder = getApplicationBuilder(); - - messageListenerInMainMock = jest.fn(); - - const testChannelListenerInMainInjectable = getInjectable({ - id: "test-channel-listener-in-main", - - instantiate: () => ({ - channel: testMessageChannel, - handler: messageListenerInMainMock, - }), - - injectionToken: messageChannelListenerInjectionToken, - }); - - applicationBuilder.beforeApplicationStart(({ mainDi }) => { - runInAction(() => { - mainDi.register(testChannelListenerInMainInjectable); - }); - }); - - await applicationBuilder.render(); - - const windowDi = applicationBuilder.applicationWindow.only.di; - - messageToChannel = windowDi.inject(sendMessageToChannelInjectionToken); - }); - - it("when sending message, triggers listener in main", () => { - messageToChannel(testMessageChannel, "some-message"); - - expect(messageListenerInMainMock).toHaveBeenCalledWith("some-message"); - }); - }); - - describe("requesting from main in renderer, given listener for channel in a main and application has started", () => { - let requestListenerInMainMock: AsyncFnMock>; - let requestFromChannel: RequestFromChannel; - - beforeEach(async () => { - const applicationBuilder = getApplicationBuilder(); - - requestListenerInMainMock = asyncFn(); - - const testChannelListenerInMainInjectable = getRequestChannelListenerInjectable({ - channel: testRequestChannel, - handler: () => requestListenerInMainMock, - }); - - applicationBuilder.beforeApplicationStart(({ mainDi }) => { - runInAction(() => { - mainDi.register(testChannelListenerInMainInjectable); - }); - }); - - await applicationBuilder.render(); - - const windowDi = applicationBuilder.applicationWindow.only.di; - - requestFromChannel = windowDi.inject( - requestFromChannelInjectionToken, - ); - }); - - describe("when requesting from channel", () => { - let actualPromise: Promise; - - beforeEach(() => { - actualPromise = requestFromChannel(testRequestChannel, "some-request"); - }); - - it("triggers listener in main", () => { - expect(requestListenerInMainMock).toHaveBeenCalledWith("some-request"); - }); - - it("does not resolve yet", async () => { - const promiseStatus = await getPromiseStatus(actualPromise); - - expect(promiseStatus.fulfilled).toBe(false); - }); - - it("when main resolves with response, resolves with response", async () => { - await requestListenerInMainMock.resolve("some-response"); - - const actual = await actualPromise; - - expect(actual).toBe("some-response"); - }); - }); - }); - - it("when registering multiple handlers for the same channel, throws", async () => { - const applicationBuilder = getApplicationBuilder(); - - const someChannelListenerInjectable = getInjectable({ - id: "some-channel-listener", - - instantiate: () => ({ - channel: testRequestChannel, - handler: () => () => "irrelevant", - }), - - injectionToken: requestChannelListenerInjectionToken, - }); - - const someOtherChannelListenerInjectable = getInjectable({ - id: "some-other-channel-listener", - - instantiate: () => ({ - channel: testRequestChannel, - handler: () => () => "irrelevant", - }), - - injectionToken: requestChannelListenerInjectionToken, - }); - - applicationBuilder.beforeApplicationStart(({ mainDi }) => { - runInAction(() => { - mainDi.register(someChannelListenerInjectable); - mainDi.register(someOtherChannelListenerInjectable); - }); - }); - - await expect(applicationBuilder.render()).rejects.toThrow('Tried to register a multiple channel handlers for "some-request-channel-id", only one handler is supported for a request channel.'); - }); -}); - -const testMessageChannel: TestMessageChannel = { - id: "some-message-channel-id", -}; - -const testRequestChannel: TestRequestChannel = { - id: "some-request-channel-id", -}; - diff --git a/packages/core/src/common/utils/channel/enlist-message-channel-listener-injection-token.ts b/packages/core/src/common/utils/channel/enlist-message-channel-listener-injection-token.ts deleted file mode 100644 index d6db37cea2..0000000000 --- a/packages/core/src/common/utils/channel/enlist-message-channel-listener-injection-token.ts +++ /dev/null @@ -1,13 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectionToken } from "@ogre-tools/injectable"; -import type { Disposer } from "@k8slens/utilities"; -import type { MessageChannel, MessageChannelListener } from "./message-channel-listener-injection-token"; - -export type EnlistMessageChannelListener = (listener: MessageChannelListener>) => Disposer; - -export const enlistMessageChannelListenerInjectionToken = getInjectionToken({ - id: "enlist-message-channel-listener", -}); diff --git a/packages/core/src/common/utils/channel/get-request-channel.ts b/packages/core/src/common/utils/channel/get-request-channel.ts deleted file mode 100644 index 4dc5b4914e..0000000000 --- a/packages/core/src/common/utils/channel/get-request-channel.ts +++ /dev/null @@ -1,9 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { RequestChannel } from "./request-channel-listener-injection-token"; - -export const getRequestChannel = (id: string): RequestChannel => ({ - id, -}); diff --git a/packages/core/src/common/utils/channel/listening-on-message-channels.injectable.ts b/packages/core/src/common/utils/channel/listening-on-message-channels.injectable.ts deleted file mode 100644 index 6ebc9ca7c1..0000000000 --- a/packages/core/src/common/utils/channel/listening-on-message-channels.injectable.ts +++ /dev/null @@ -1,25 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { getStartableStoppable } from "../get-startable-stoppable"; -import { messageChannelListenerInjectionToken } from "./message-channel-listener-injection-token"; -import { enlistMessageChannelListenerInjectionToken } from "./enlist-message-channel-listener-injection-token"; -import { disposer } from "@k8slens/utilities"; - -const listeningOnMessageChannelsInjectable = getInjectable({ - id: "listening-on-message-channels", - - instantiate: (di) => { - const enlistMessageChannelListener = di.inject(enlistMessageChannelListenerInjectionToken); - const messageChannelListeners = di.injectMany(messageChannelListenerInjectionToken); - - return getStartableStoppable("listening-on-channels", () => ( - disposer(messageChannelListeners.map(enlistMessageChannelListener)) - )); - }, -}); - - -export default listeningOnMessageChannelsInjectable; diff --git a/packages/core/src/common/utils/channel/message-channel-listener-injection-token.ts b/packages/core/src/common/utils/channel/message-channel-listener-injection-token.ts deleted file mode 100644 index 5bfc45a82d..0000000000 --- a/packages/core/src/common/utils/channel/message-channel-listener-injection-token.ts +++ /dev/null @@ -1,51 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { DiContainerForInjection } from "@ogre-tools/injectable"; -import { getInjectable, getInjectionToken } from "@ogre-tools/injectable"; - -export interface MessageChannel { - id: string; - _messageSignature?: Message; // only used to mark `Message` as used -} - -export type MessageChannelHandler = Channel extends MessageChannel - ? (message: Message) => void - : never; - -export interface MessageChannelListener { - channel: Channel; - handler: MessageChannelHandler; -} - -export const messageChannelListenerInjectionToken = getInjectionToken>>( - { - id: "message-channel-listener", - }, -); - -export interface GetMessageChannelListenerInfo< - Channel extends MessageChannel, - Message, -> { - id: string; - channel: Channel; - handler: (di: DiContainerForInjection) => MessageChannelHandler; - causesSideEffects?: boolean; -} - -export function getMessageChannelListenerInjectable< - Channel extends MessageChannel, - Message, ->(info: GetMessageChannelListenerInfo) { - return getInjectable({ - id: `${info.channel.id}-listener-${info.id}`, - instantiate: (di) => ({ - channel: info.channel, - handler: info.handler(di), - }), - injectionToken: messageChannelListenerInjectionToken, - causesSideEffects: info.causesSideEffects, - }); -} diff --git a/packages/core/src/common/utils/channel/request-channel-listener-injection-token.ts b/packages/core/src/common/utils/channel/request-channel-listener-injection-token.ts deleted file mode 100644 index 2f0b84a3cc..0000000000 --- a/packages/core/src/common/utils/channel/request-channel-listener-injection-token.ts +++ /dev/null @@ -1,10 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -export interface RequestChannel { - id: string; - _requestSignature?: Request; // used only to mark `Request` as "used" - _responseSignature?: Response; // used only to mark `Response` as "used" -} diff --git a/packages/core/src/common/utils/resolve-system-proxy/resolve-system-proxy-channel.ts b/packages/core/src/common/utils/resolve-system-proxy/resolve-system-proxy-channel.ts index c823a8a8f9..210112c0b7 100644 --- a/packages/core/src/common/utils/resolve-system-proxy/resolve-system-proxy-channel.ts +++ b/packages/core/src/common/utils/resolve-system-proxy/resolve-system-proxy-channel.ts @@ -2,10 +2,8 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { RequestChannel } from "../channel/request-channel-listener-injection-token"; +import { getRequestChannel } from "@k8slens/messaging"; -export type ResolveSystemProxyChannel = RequestChannel; - -export const resolveSystemProxyChannel: ResolveSystemProxyChannel = { - id: "resolve-system-proxy-channel", -}; +export const resolveSystemProxyChannel = getRequestChannel( + "resolve-system-proxy-channel", +); diff --git a/packages/core/src/common/utils/sync-box/channel-listener.injectable.ts b/packages/core/src/common/utils/sync-box/channel-listener.injectable.ts index a97d95d726..482886d178 100644 --- a/packages/core/src/common/utils/sync-box/channel-listener.injectable.ts +++ b/packages/core/src/common/utils/sync-box/channel-listener.injectable.ts @@ -3,13 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { syncBoxChannel } from "./channels"; -import { getMessageChannelListenerInjectable } from "../channel/message-channel-listener-injection-token"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import syncBoxStateInjectable from "./sync-box-state.injectable"; const syncBoxChannelListenerInjectable = getMessageChannelListenerInjectable({ id: "init", channel: syncBoxChannel, - handler: (di) => ({ id, value }) => di.inject(syncBoxStateInjectable, id).set(value), + getHandler: (di) => ({ id, value }) => di.inject(syncBoxStateInjectable, id).set(value), }); export default syncBoxChannelListenerInjectable; diff --git a/packages/core/src/common/utils/sync-box/channels.ts b/packages/core/src/common/utils/sync-box/channels.ts index 4df0462dc3..5178ff013c 100644 --- a/packages/core/src/common/utils/sync-box/channels.ts +++ b/packages/core/src/common/utils/sync-box/channels.ts @@ -2,20 +2,12 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { MessageChannel } from "../channel/message-channel-listener-injection-token"; -import type { RequestChannel } from "../channel/request-channel-listener-injection-token"; +import { getMessageChannel, getRequestChannel } from "@k8slens/messaging"; -export type SyncBoxChannel = MessageChannel<{ id: string; value: any }>; +export const syncBoxChannel = + getMessageChannel<{ id: string; value: any }>("sync-box-channel"); -export const syncBoxChannel: SyncBoxChannel = { - id: "sync-box-channel", -}; - -export type SyncBoxInitialValueChannel = RequestChannel< +export const syncBoxInitialValueChannel = getRequestChannel< void, { id: string; value: any }[] ->; - -export const syncBoxInitialValueChannel: SyncBoxInitialValueChannel = { - id: "sync-box-initial-value-channel", -}; +>("sync-box-initial-value-channel"); diff --git a/packages/core/src/common/utils/sync-box/create-sync-box.injectable.ts b/packages/core/src/common/utils/sync-box/create-sync-box.injectable.ts index 4a01fe71a0..2a142dc573 100644 --- a/packages/core/src/common/utils/sync-box/create-sync-box.injectable.ts +++ b/packages/core/src/common/utils/sync-box/create-sync-box.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import type { IObservableValue } from "mobx"; import { computed } from "mobx"; import { syncBoxChannel } from "./channels"; -import { sendMessageToChannelInjectionToken } from "../channel/message-to-channel-injection-token"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; import syncBoxStateInjectable from "./sync-box-state.injectable"; import type { SyncBox } from "./sync-box-injection-token"; import { toJS } from "../toJS"; diff --git a/packages/core/src/common/utils/sync-box/handler.injectable.ts b/packages/core/src/common/utils/sync-box/handler.injectable.ts deleted file mode 100644 index f520585474..0000000000 --- a/packages/core/src/common/utils/sync-box/handler.injectable.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import type { MessageChannelHandler } from "../channel/message-channel-listener-injection-token"; -import type { SyncBoxChannel } from "./channels"; -import syncBoxStateInjectable from "./sync-box-state.injectable"; - -const syncBoxChannelHandlerInjectable = getInjectable({ - id: "sync-box-channel-handler", - instantiate: (di): MessageChannelHandler => { - const getSyncBoxState = (id: string) => di.inject(syncBoxStateInjectable, id); - - return ({ id, value }) => getSyncBoxState(id)?.set(value); - }, -}); - -export default syncBoxChannelHandlerInjectable; diff --git a/packages/core/src/common/vars/build-semantic-version.injectable.ts b/packages/core/src/common/vars/build-semantic-version.injectable.ts index 2a49327480..402fb9d442 100644 --- a/packages/core/src/common/vars/build-semantic-version.injectable.ts +++ b/packages/core/src/common/vars/build-semantic-version.injectable.ts @@ -7,7 +7,7 @@ import { getInjectionToken } from "@ogre-tools/injectable"; import { SemVer } from "semver"; import type { InitializableState } from "../initializable-state/create"; import { createInitializableState } from "../initializable-state/create"; -import type { RequestChannel } from "../utils/channel/request-channel-listener-injection-token"; +import type { RequestChannel } from "@k8slens/messaging"; export const buildVersionInjectionToken = getInjectionToken>({ id: "build-version-token", diff --git a/packages/core/src/common/weblinks-store/weblink-store.injectable.ts b/packages/core/src/common/weblinks-store/weblink-store.injectable.ts index cf793a2e58..843c8716e5 100644 --- a/packages/core/src/common/weblinks-store/weblink-store.injectable.ts +++ b/packages/core/src/common/weblinks-store/weblink-store.injectable.ts @@ -11,7 +11,7 @@ import { persistStateToConfigInjectionToken } from "../base-store/save-to-file"; import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable"; import loggerInjectable from "../logger.injectable"; import getBasenameOfPathInjectable from "../path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "../utils/channel/enlist-message-channel-listener-injection-token"; +import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; import storeMigrationVersionInjectable from "../vars/store-migration-version.injectable"; import { weblinkStoreMigrationInjectionToken } from "./migration-token"; import { WeblinkStore } from "./weblink-store"; diff --git a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable.ts b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable.ts index 847ae37f03..2295608520 100644 --- a/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable.ts +++ b/packages/core/src/extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable.ts @@ -12,7 +12,7 @@ import { baseStoreIpcChannelPrefixesInjectionToken } from "../../../common/base- import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../../../common/base-store/disable-sync"; import { persistStateToConfigInjectionToken } from "../../../common/base-store/save-to-file"; import getBasenameOfPathInjectable from "../../../common/path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "../../../common/utils/channel/enlist-message-channel-listener-injection-token"; +import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; import ensureHashedDirectoryForExtensionInjectable from "./ensure-hashed-directory-for-extension.injectable"; import { registeredExtensionsInjectable } from "./registered-extensions.injectable"; diff --git a/packages/core/src/extensions/extension-store.ts b/packages/core/src/extensions/extension-store.ts index cf435fb474..fe9cff2a02 100644 --- a/packages/core/src/extensions/extension-store.ts +++ b/packages/core/src/extensions/extension-store.ts @@ -20,7 +20,7 @@ import { baseStoreIpcChannelPrefixesInjectionToken } from "../common/base-store/ import { shouldBaseStoreDisableSyncInIpcListenerInjectionToken } from "../common/base-store/disable-sync"; import { persistStateToConfigInjectionToken } from "../common/base-store/save-to-file"; import getBasenameOfPathInjectable from "../common/path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "../common/utils/channel/enlist-message-channel-listener-injection-token"; +import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; export interface ExtensionStoreParams extends BaseStoreParams { migrations?: Migrations; diff --git a/packages/core/src/extensions/extensions-store/extensions-store.injectable.ts b/packages/core/src/extensions/extensions-store/extensions-store.injectable.ts index 9f5ff83270..9e08a96aac 100644 --- a/packages/core/src/extensions/extensions-store/extensions-store.injectable.ts +++ b/packages/core/src/extensions/extensions-store/extensions-store.injectable.ts @@ -10,7 +10,7 @@ import { persistStateToConfigInjectionToken } from "../../common/base-store/save import getConfigurationFileModelInjectable from "../../common/get-configuration-file-model/get-configuration-file-model.injectable"; import loggerInjectable from "../../common/logger.injectable"; import getBasenameOfPathInjectable from "../../common/path/get-basename.injectable"; -import { enlistMessageChannelListenerInjectionToken } from "../../common/utils/channel/enlist-message-channel-listener-injection-token"; +import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; import storeMigrationVersionInjectable from "../../common/vars/store-migration-version.injectable"; import { ExtensionsStore } from "./extensions-store"; diff --git a/packages/core/src/features/application-menu/main/application-menu-reactivity.injectable.ts b/packages/core/src/features/application-menu/main/application-menu-reactivity.injectable.ts index 80bfd108fd..e5d95bf7d8 100644 --- a/packages/core/src/features/application-menu/main/application-menu-reactivity.injectable.ts +++ b/packages/core/src/features/application-menu/main/application-menu-reactivity.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { autorun } from "mobx"; -import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable"; +import { getStartableStoppable } from "@k8slens/startable-stoppable"; import populateApplicationMenuInjectable from "./populate-application-menu.injectable"; import applicationMenuItemCompositeInjectable from "./application-menu-item-composite.injectable"; diff --git a/packages/core/src/features/application-update/child-features/periodical-checking-of-updates/main/periodical-check-for-updates.injectable.ts b/packages/core/src/features/application-update/child-features/periodical-checking-of-updates/main/periodical-check-for-updates.injectable.ts index 85c687e478..953aa2b45a 100644 --- a/packages/core/src/features/application-update/child-features/periodical-checking-of-updates/main/periodical-check-for-updates.injectable.ts +++ b/packages/core/src/features/application-update/child-features/periodical-checking-of-updates/main/periodical-check-for-updates.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { getStartableStoppable } from "../../../../../common/utils/get-startable-stoppable"; +import { getStartableStoppable } from "@k8slens/startable-stoppable"; import processCheckingForUpdatesInjectable from "../../../main/process-checking-for-updates.injectable"; import withOrphanPromiseInjectable from "../../../../../common/utils/with-orphan-promise/with-orphan-promise.injectable"; diff --git a/packages/core/src/features/application-update/common/restart-and-install-update-channel.ts b/packages/core/src/features/application-update/common/restart-and-install-update-channel.ts index 470debf981..87b8f76cf3 100644 --- a/packages/core/src/features/application-update/common/restart-and-install-update-channel.ts +++ b/packages/core/src/features/application-update/common/restart-and-install-update-channel.ts @@ -2,7 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { MessageChannel } from "../../../common/utils/channel/message-channel-listener-injection-token"; +import type { MessageChannel } from "@k8slens/messaging"; export type RestartAndInstallUpdateChannel = MessageChannel; diff --git a/packages/core/src/features/application-update/main/restart-and-install-update/restart-and-install-update-listener.injectable.ts b/packages/core/src/features/application-update/main/restart-and-install-update/restart-and-install-update-listener.injectable.ts index 940856ad3b..768ad50ffd 100644 --- a/packages/core/src/features/application-update/main/restart-and-install-update/restart-and-install-update-listener.injectable.ts +++ b/packages/core/src/features/application-update/main/restart-and-install-update/restart-and-install-update-listener.injectable.ts @@ -3,13 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { restartAndInstallUpdateChannel } from "../../common/restart-and-install-update-channel"; -import { getMessageChannelListenerInjectable } from "../../../../common/utils/channel/message-channel-listener-injection-token"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import quitAndInstallUpdateInjectable from "../quit-and-install-update.injectable"; const restartAndInstallUpdateListenerInjectable = getMessageChannelListenerInjectable({ id: "restart", channel: restartAndInstallUpdateChannel, - handler: (di) => di.inject(quitAndInstallUpdateInjectable), + getHandler: (di) => di.inject(quitAndInstallUpdateInjectable), }); export default restartAndInstallUpdateListenerInjectable; diff --git a/packages/core/src/features/application-update/main/watch-if-update-should-happen-on-quit/watch-if-update-should-happen-on-quit.injectable.ts b/packages/core/src/features/application-update/main/watch-if-update-should-happen-on-quit/watch-if-update-should-happen-on-quit.injectable.ts index bcad45a0ac..bd949194e6 100644 --- a/packages/core/src/features/application-update/main/watch-if-update-should-happen-on-quit/watch-if-update-should-happen-on-quit.injectable.ts +++ b/packages/core/src/features/application-update/main/watch-if-update-should-happen-on-quit/watch-if-update-should-happen-on-quit.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { autorun } from "mobx"; -import { getStartableStoppable } from "../../../../common/utils/get-startable-stoppable"; +import { getStartableStoppable } from "@k8slens/startable-stoppable"; import setUpdateOnQuitInjectable from "../../../../main/electron-app/features/set-update-on-quit.injectable"; import selectedUpdateChannelInjectable from "../../common/selected-update-channel/selected-update-channel.injectable"; import type { ReleaseChannel, UpdateChannel } from "../../common/update-channels"; diff --git a/packages/core/src/features/application-update/renderer/restart-and-install-update.injectable.ts b/packages/core/src/features/application-update/renderer/restart-and-install-update.injectable.ts index 2502a599a2..d60f8da909 100644 --- a/packages/core/src/features/application-update/renderer/restart-and-install-update.injectable.ts +++ b/packages/core/src/features/application-update/renderer/restart-and-install-update.injectable.ts @@ -4,13 +4,13 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { restartAndInstallUpdateChannel } from "../common/restart-and-install-update-channel"; -import messageToChannelInjectable from "../../../renderer/utils/channel/message-to-channel.injectable"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; const restartAndInstallUpdateInjectable = getInjectable({ id: "restart-and-install-update", instantiate: (di) => { - const messageToChannel = di.inject(messageToChannelInjectable); + const messageToChannel = di.inject(sendMessageToChannelInjectionToken); return () => { messageToChannel(restartAndInstallUpdateChannel); diff --git a/packages/core/src/features/certificate-authorities/common/channel.ts b/packages/core/src/features/certificate-authorities/common/channel.ts index 5fb58ee1ca..c81ba9be44 100644 --- a/packages/core/src/features/certificate-authorities/common/channel.ts +++ b/packages/core/src/features/certificate-authorities/common/channel.ts @@ -2,7 +2,6 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ - -import { getRequestChannel } from "../../../common/utils/channel/get-request-channel"; +import { getRequestChannel } from "@k8slens/messaging"; export const casChannel = getRequestChannel("certificate-authorities"); diff --git a/packages/core/src/features/certificate-authorities/main/channel-handler.global-override-for-injectable.ts b/packages/core/src/features/certificate-authorities/main/channel-handler.global-override-for-injectable.ts index 62882fb49f..a7c52503c5 100644 --- a/packages/core/src/features/certificate-authorities/main/channel-handler.global-override-for-injectable.ts +++ b/packages/core/src/features/certificate-authorities/main/channel-handler.global-override-for-injectable.ts @@ -8,6 +8,7 @@ import { casChannel } from "../common/channel"; import certificateAuthoritiesChannelListenerInjectable from "./channel-handler.injectable"; export default getGlobalOverride(certificateAuthoritiesChannelListenerInjectable, () => ({ + id: "certificate-authorities-channel-listener", channel: casChannel, handler: () => [], })); diff --git a/packages/core/src/features/certificate-authorities/main/channel-handler.injectable.ts b/packages/core/src/features/certificate-authorities/main/channel-handler.injectable.ts index 206a68ba94..d776e9fcce 100644 --- a/packages/core/src/features/certificate-authorities/main/channel-handler.injectable.ts +++ b/packages/core/src/features/certificate-authorities/main/channel-handler.injectable.ts @@ -2,14 +2,15 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getRequestChannelListenerInjectable } from "../../../main/utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import { casChannel } from "../common/channel"; import { globalAgent } from "https"; import { isString } from "@k8slens/utilities"; const certificateAuthoritiesChannelListenerInjectable = getRequestChannelListenerInjectable({ + id: "certificate-authorities-channel-listener", channel: casChannel, - handler: () => () => { + getHandler: () => () => { if (Array.isArray(globalAgent.options.ca)) { return globalAgent.options.ca.filter(isString); } diff --git a/packages/core/src/features/certificate-authorities/renderer/request-system-cas.injectable.ts b/packages/core/src/features/certificate-authorities/renderer/request-system-cas.injectable.ts index e3c840a95a..e9ac074989 100644 --- a/packages/core/src/features/certificate-authorities/renderer/request-system-cas.injectable.ts +++ b/packages/core/src/features/certificate-authorities/renderer/request-system-cas.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { requestFromChannelInjectionToken } from "../../../common/utils/channel/request-from-channel-injection-token"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { casChannel } from "../common/channel"; import { requestSystemCAsInjectionToken } from "../common/request-system-cas-token"; diff --git a/packages/core/src/features/cluster/activation/common/channels.ts b/packages/core/src/features/cluster/activation/common/channels.ts index 3631c4d9b8..55172e75fc 100644 --- a/packages/core/src/features/cluster/activation/common/channels.ts +++ b/packages/core/src/features/cluster/activation/common/channels.ts @@ -4,7 +4,7 @@ */ import type { ClusterId } from "../../../../common/cluster-types"; -import { getRequestChannel } from "../../../../common/utils/channel/get-request-channel"; +import { getRequestChannel } from "@k8slens/messaging"; export interface ActivateCluster { clusterId: ClusterId; diff --git a/packages/core/src/features/cluster/activation/common/request-token.ts b/packages/core/src/features/cluster/activation/common/request-token.ts index 5bee44208f..0abe5775b3 100644 --- a/packages/core/src/features/cluster/activation/common/request-token.ts +++ b/packages/core/src/features/cluster/activation/common/request-token.ts @@ -4,7 +4,7 @@ */ import { getInjectionToken } from "@ogre-tools/injectable"; -import type { ChannelRequester } from "../../../../common/utils/channel/request-from-channel-injection-token"; +import type { ChannelRequester } from "@k8slens/messaging"; import type { activateClusterChannel, deactivateClusterChannel } from "./channels"; export type RequestClusterActivation = ChannelRequester; diff --git a/packages/core/src/features/cluster/activation/main/activate-listener.injectable.ts b/packages/core/src/features/cluster/activation/main/activate-listener.injectable.ts index 4ce22e6311..08b068abef 100644 --- a/packages/core/src/features/cluster/activation/main/activate-listener.injectable.ts +++ b/packages/core/src/features/cluster/activation/main/activate-listener.injectable.ts @@ -2,13 +2,14 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getRequestChannelListenerInjectable } from "../../../../main/utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import { activateClusterChannel } from "../common/channels"; import requestClusterActivationInjectable from "./request-activation.injectable"; const activateClusterRequestChannelListenerInjectable = getRequestChannelListenerInjectable({ + id: "activate-cluster-request-channel-listener", channel: activateClusterChannel, - handler: (di) => di.inject(requestClusterActivationInjectable), + getHandler: (di) => di.inject(requestClusterActivationInjectable), }); export default activateClusterRequestChannelListenerInjectable; diff --git a/packages/core/src/features/cluster/activation/main/deactivate-listener.injectable.ts b/packages/core/src/features/cluster/activation/main/deactivate-listener.injectable.ts index e24ce48ba6..bbfe79a41d 100644 --- a/packages/core/src/features/cluster/activation/main/deactivate-listener.injectable.ts +++ b/packages/core/src/features/cluster/activation/main/deactivate-listener.injectable.ts @@ -2,13 +2,14 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getRequestChannelListenerInjectable } from "../../../../main/utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import { deactivateClusterChannel } from "../common/channels"; import requestClusterDeactivationInjectable from "./request-deactivation.injectable"; const clusterDeactivationRequestChannelListenerInjectable = getRequestChannelListenerInjectable({ + id: "cluster-deactivation-request-channel-listener", channel: deactivateClusterChannel, - handler: (di) => di.inject(requestClusterDeactivationInjectable), + getHandler: (di) => di.inject(requestClusterDeactivationInjectable), }); export default clusterDeactivationRequestChannelListenerInjectable; diff --git a/packages/core/src/features/cluster/activation/renderer/request-activation.injectable.ts b/packages/core/src/features/cluster/activation/renderer/request-activation.injectable.ts index 1677d67792..6609516918 100644 --- a/packages/core/src/features/cluster/activation/renderer/request-activation.injectable.ts +++ b/packages/core/src/features/cluster/activation/renderer/request-activation.injectable.ts @@ -3,14 +3,14 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import requestFromChannelInjectable from "../../../../renderer/utils/channel/request-from-channel.injectable"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { activateClusterChannel } from "../common/channels"; import { requestClusterActivationInjectionToken } from "../common/request-token"; const requestClusterActivationInjectable = getInjectable({ id: "request-cluster-activation", instantiate: (di) => { - const requestFromChannel = di.inject(requestFromChannelInjectable); + const requestFromChannel = di.inject(requestFromChannelInjectionToken); return (req) => requestFromChannel(activateClusterChannel, req); }, diff --git a/packages/core/src/features/cluster/activation/renderer/request-deactivation.injectable.ts b/packages/core/src/features/cluster/activation/renderer/request-deactivation.injectable.ts index 362784e91b..e019b8b615 100644 --- a/packages/core/src/features/cluster/activation/renderer/request-deactivation.injectable.ts +++ b/packages/core/src/features/cluster/activation/renderer/request-deactivation.injectable.ts @@ -3,14 +3,14 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import requestFromChannelInjectable from "../../../../renderer/utils/channel/request-from-channel.injectable"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { deactivateClusterChannel } from "../common/channels"; import { requestClusterDeactivationInjectionToken } from "../common/request-token"; const requestClusterDeactivationInjectable = getInjectable({ id: "request-cluster-deactivation", instantiate: (di) => { - const requestFromChannel = di.inject(requestFromChannelInjectable); + const requestFromChannel = di.inject(requestFromChannelInjectionToken); return (clusterId) => requestFromChannel(deactivateClusterChannel, clusterId); }, diff --git a/packages/core/src/features/cluster/delete-dialog/common/clear-as-deleting-channel.ts b/packages/core/src/features/cluster/delete-dialog/common/clear-as-deleting-channel.ts index bf33a23165..f6bdc1d072 100644 --- a/packages/core/src/features/cluster/delete-dialog/common/clear-as-deleting-channel.ts +++ b/packages/core/src/features/cluster/delete-dialog/common/clear-as-deleting-channel.ts @@ -3,10 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { ClusterId } from "../../../../common/cluster-types"; -import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token"; +import { getRequestChannel } from "@k8slens/messaging"; -export type ClearClusterAsDeletingChannel = RequestChannel; - -export const clearClusterAsDeletingChannel: ClearClusterAsDeletingChannel = { - id: "clear-cluster-as-deleting", -}; +export const clearClusterAsDeletingChannel = getRequestChannel( + "clear-cluster-as-deleting", +); diff --git a/packages/core/src/features/cluster/delete-dialog/common/delete-channel.ts b/packages/core/src/features/cluster/delete-dialog/common/delete-channel.ts index 0e9142fcd3..b3a007b1bd 100644 --- a/packages/core/src/features/cluster/delete-dialog/common/delete-channel.ts +++ b/packages/core/src/features/cluster/delete-dialog/common/delete-channel.ts @@ -3,10 +3,11 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { ClusterId } from "../../../../common/cluster-types"; -import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token"; +import type { RequestChannel } from "@k8slens/messaging"; +import { getRequestChannel } from "@k8slens/messaging"; export type DeleteClusterChannel = RequestChannel; -export const deleteClusterChannel: DeleteClusterChannel = { - id: "delete-cluster", -}; +export const deleteClusterChannel = getRequestChannel( + "delete-cluster", +); diff --git a/packages/core/src/features/cluster/delete-dialog/common/set-as-deleting-channel.ts b/packages/core/src/features/cluster/delete-dialog/common/set-as-deleting-channel.ts index 57ef2e3a8d..7b93b292d5 100644 --- a/packages/core/src/features/cluster/delete-dialog/common/set-as-deleting-channel.ts +++ b/packages/core/src/features/cluster/delete-dialog/common/set-as-deleting-channel.ts @@ -3,10 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { ClusterId } from "../../../../common/cluster-types"; -import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token"; +import { getRequestChannel } from "@k8slens/messaging"; -export type SetClusterAsDeletingChannel = RequestChannel; - -export const setClusterAsDeletingChannel: SetClusterAsDeletingChannel = { - id: "set-cluster-as-deleting", -}; +export const setClusterAsDeletingChannel = getRequestChannel( + "set-cluster-as-deleting", +); diff --git a/packages/core/src/features/cluster/delete-dialog/main/clear-as-deleting-channel-listener.injectable.ts b/packages/core/src/features/cluster/delete-dialog/main/clear-as-deleting-channel-listener.injectable.ts index a8dd2a80b0..a83de06acb 100644 --- a/packages/core/src/features/cluster/delete-dialog/main/clear-as-deleting-channel-listener.injectable.ts +++ b/packages/core/src/features/cluster/delete-dialog/main/clear-as-deleting-channel-listener.injectable.ts @@ -3,12 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import clustersThatAreBeingDeletedInjectable from "../../../../main/cluster/are-being-deleted.injectable"; -import { getRequestChannelListenerInjectable } from "../../../../main/utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import { clearClusterAsDeletingChannel } from "../common/clear-as-deleting-channel"; const clearClusterAsDeletingChannelListenerInjectable = getRequestChannelListenerInjectable({ + id: "clear-cluster-as-deleting-channel-listener", channel: clearClusterAsDeletingChannel, - handler: (di) => { + getHandler: (di) => { const clustersThatAreBeingDeleted = di.inject(clustersThatAreBeingDeletedInjectable); return (clusterId) => { diff --git a/packages/core/src/features/cluster/delete-dialog/main/delete-channel-listener.injectable.ts b/packages/core/src/features/cluster/delete-dialog/main/delete-channel-listener.injectable.ts index 94caf169ba..30d976c59c 100644 --- a/packages/core/src/features/cluster/delete-dialog/main/delete-channel-listener.injectable.ts +++ b/packages/core/src/features/cluster/delete-dialog/main/delete-channel-listener.injectable.ts @@ -10,12 +10,13 @@ import removePathInjectable from "../../../../common/fs/remove.injectable"; import joinPathsInjectable from "../../../../common/path/join-paths.injectable"; import clusterConnectionInjectable from "../../../../main/cluster/cluster-connection.injectable"; import { noop } from "@k8slens/utilities"; -import { getRequestChannelListenerInjectable } from "../../../../main/utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import { deleteClusterChannel } from "../common/delete-channel"; const deleteClusterChannelListenerInjectable = getRequestChannelListenerInjectable({ + id: "delete-cluster-channel-listener", channel: deleteClusterChannel, - handler: (di) => { + getHandler: (di) => { const emitAppEvent = di.inject(emitAppEventInjectable); const clusterStore = di.inject(clusterStoreInjectable); const clusterFrames = di.inject(clusterFramesInjectable); diff --git a/packages/core/src/features/cluster/delete-dialog/main/set-as-deleteing-channel-listener.injectable.ts b/packages/core/src/features/cluster/delete-dialog/main/set-as-deleteing-channel-listener.injectable.ts index f532b4a81f..74bd168723 100644 --- a/packages/core/src/features/cluster/delete-dialog/main/set-as-deleteing-channel-listener.injectable.ts +++ b/packages/core/src/features/cluster/delete-dialog/main/set-as-deleteing-channel-listener.injectable.ts @@ -3,12 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import clustersThatAreBeingDeletedInjectable from "../../../../main/cluster/are-being-deleted.injectable"; -import { getRequestChannelListenerInjectable } from "../../../../main/utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import { setClusterAsDeletingChannel } from "../common/set-as-deleting-channel"; const setClusterAsDeletingChannelHandlerInjectable = getRequestChannelListenerInjectable({ + id: "set-cluster-as-deleting-channel-handler", channel: setClusterAsDeletingChannel, - handler: (di) => { + getHandler: (di) => { const clustersThatAreBeingDeleted = di.inject(clustersThatAreBeingDeletedInjectable); return (clusterId) => { diff --git a/packages/core/src/features/cluster/delete-dialog/renderer/request-clear-as-deleting.injectable.ts b/packages/core/src/features/cluster/delete-dialog/renderer/request-clear-as-deleting.injectable.ts index e476998ca0..1e3125a52a 100644 --- a/packages/core/src/features/cluster/delete-dialog/renderer/request-clear-as-deleting.injectable.ts +++ b/packages/core/src/features/cluster/delete-dialog/renderer/request-clear-as-deleting.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import type { ClusterId } from "../../../../common/cluster-types"; -import requestFromChannelInjectable from "../../../../renderer/utils/channel/request-from-channel.injectable"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { clearClusterAsDeletingChannel } from "../common/clear-as-deleting-channel"; export type RequestClearClusterAsDeleting = (clusterId: ClusterId) => Promise; @@ -12,7 +12,7 @@ export type RequestClearClusterAsDeleting = (clusterId: ClusterId) => Promise { - const requestChannel = di.inject(requestFromChannelInjectable); + const requestChannel = di.inject(requestFromChannelInjectionToken); return (clusterId) => requestChannel(clearClusterAsDeletingChannel, clusterId); }, diff --git a/packages/core/src/features/cluster/delete-dialog/renderer/request-delete.injectable.ts b/packages/core/src/features/cluster/delete-dialog/renderer/request-delete.injectable.ts index c1286e3103..9e415e79d0 100644 --- a/packages/core/src/features/cluster/delete-dialog/renderer/request-delete.injectable.ts +++ b/packages/core/src/features/cluster/delete-dialog/renderer/request-delete.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import type { ClusterId } from "../../../../common/cluster-types"; -import requestFromChannelInjectable from "../../../../renderer/utils/channel/request-from-channel.injectable"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { deleteClusterChannel } from "../common/delete-channel"; export type RequestDeleteCluster = (clusterId: ClusterId) => Promise; @@ -12,7 +12,7 @@ export type RequestDeleteCluster = (clusterId: ClusterId) => Promise; const requestDeleteClusterInjectable = getInjectable({ id: "request-delete-cluster", instantiate: (di): RequestDeleteCluster => { - const requestChannel = di.inject(requestFromChannelInjectable); + const requestChannel = di.inject(requestFromChannelInjectionToken); return (clusterId) => requestChannel(deleteClusterChannel, clusterId); }, diff --git a/packages/core/src/features/cluster/delete-dialog/renderer/request-set-as-deleting.injectable.ts b/packages/core/src/features/cluster/delete-dialog/renderer/request-set-as-deleting.injectable.ts index de3a6393b3..0e86632f89 100644 --- a/packages/core/src/features/cluster/delete-dialog/renderer/request-set-as-deleting.injectable.ts +++ b/packages/core/src/features/cluster/delete-dialog/renderer/request-set-as-deleting.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import type { ClusterId } from "../../../../common/cluster-types"; -import requestFromChannelInjectable from "../../../../renderer/utils/channel/request-from-channel.injectable"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { setClusterAsDeletingChannel } from "../common/set-as-deleting-channel"; export type RequestSetClusterAsDeleting = (clusterId: ClusterId) => Promise; @@ -12,7 +12,7 @@ export type RequestSetClusterAsDeleting = (clusterId: ClusterId) => Promise { - const requestChannel = di.inject(requestFromChannelInjectable); + const requestChannel = di.inject(requestFromChannelInjectionToken); return (clusterId) => requestChannel(setClusterAsDeletingChannel, clusterId); }, diff --git a/packages/core/src/features/cluster/state-sync/common/channels.ts b/packages/core/src/features/cluster/state-sync/common/channels.ts index 7ceeb82f84..66ce718955 100644 --- a/packages/core/src/features/cluster/state-sync/common/channels.ts +++ b/packages/core/src/features/cluster/state-sync/common/channels.ts @@ -4,8 +4,7 @@ */ import type { ClusterId, ClusterState } from "../../../../common/cluster-types"; -import type { MessageChannel } from "../../../../common/utils/channel/message-channel-listener-injection-token"; -import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token"; +import type { MessageChannel, RequestChannel } from "@k8slens/messaging"; export interface ClusterStateSync { clusterId: ClusterId; diff --git a/packages/core/src/features/cluster/state-sync/main/emit-update.injectable.ts b/packages/core/src/features/cluster/state-sync/main/emit-update.injectable.ts index 8cadd32864..4499d2ac66 100644 --- a/packages/core/src/features/cluster/state-sync/main/emit-update.injectable.ts +++ b/packages/core/src/features/cluster/state-sync/main/emit-update.injectable.ts @@ -3,18 +3,16 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { MessageChannelHandler } from "../../../../common/utils/channel/message-channel-listener-injection-token"; -import { sendMessageToChannelInjectionToken } from "../../../../common/utils/channel/message-to-channel-injection-token"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; +import type { ClusterStateSync } from "../common/channels"; import { clusterStateSyncChannel } from "../common/channels"; -export type EmitClusterStateUpdate = MessageChannelHandler; - const emitClusterStateUpdateInjectable = getInjectable({ id: "emit-cluster-state-update", - instantiate: (di): EmitClusterStateUpdate => { + instantiate: (di) => { const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); - return (message) => sendMessageToChannel(clusterStateSyncChannel, message); + return (message: ClusterStateSync) => sendMessageToChannel(clusterStateSyncChannel, message); }, }); diff --git a/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts b/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts index 708f032d48..db65024973 100644 --- a/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts +++ b/packages/core/src/features/cluster/state-sync/main/handle-initial.injectable.ts @@ -3,12 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import clusterStoreInjectable from "../../../../common/cluster-store/cluster-store.injectable"; -import { getRequestChannelListenerInjectable } from "../../../../main/utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import { initialClusterStatesChannel } from "../common/channels"; const handleInitialClusterStateSyncInjectable = getRequestChannelListenerInjectable({ + id: "handle-initial-cluster-state-sync", channel: initialClusterStatesChannel, - handler: (di) => { + getHandler: (di) => { const clusterStore = di.inject(clusterStoreInjectable); return () => clusterStore.clustersList.map(cluster => ({ diff --git a/packages/core/src/features/cluster/state-sync/renderer/listener.injectable.ts b/packages/core/src/features/cluster/state-sync/renderer/listener.injectable.ts index 9863a391e8..a3778d096e 100644 --- a/packages/core/src/features/cluster/state-sync/renderer/listener.injectable.ts +++ b/packages/core/src/features/cluster/state-sync/renderer/listener.injectable.ts @@ -3,13 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import getClusterByIdInjectable from "../../../../common/cluster-store/get-by-id.injectable"; -import { getMessageChannelListenerInjectable } from "../../../../common/utils/channel/message-channel-listener-injection-token"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import { clusterStateSyncChannel } from "../common/channels"; const clusterStateListenerInjectable = getMessageChannelListenerInjectable({ channel: clusterStateSyncChannel, id: "main", - handler: (di) => { + getHandler: (di) => { const getClusterById = di.inject(getClusterByIdInjectable); return ({ clusterId, state }) => getClusterById(clusterId)?.setState(state); diff --git a/packages/core/src/features/cluster/state-sync/renderer/request-initial.injectable.ts b/packages/core/src/features/cluster/state-sync/renderer/request-initial.injectable.ts index 89f72fbcf5..497d2c5aaf 100644 --- a/packages/core/src/features/cluster/state-sync/renderer/request-initial.injectable.ts +++ b/packages/core/src/features/cluster/state-sync/renderer/request-initial.injectable.ts @@ -3,8 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { RequestChannelHandler } from "../../../../main/utils/channel/channel-listeners/listener-tokens"; -import requestFromChannelInjectable from "../../../../renderer/utils/channel/request-from-channel.injectable"; +import type { RequestChannelHandler } from "@k8slens/messaging"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { initialClusterStatesChannel } from "../common/channels"; export type RequestInitialClusterStates = RequestChannelHandler; @@ -12,7 +12,7 @@ export type RequestInitialClusterStates = RequestChannelHandler { - const requestFromChannel = di.inject(requestFromChannelInjectable); + const requestFromChannel = di.inject(requestFromChannelInjectionToken); return () => requestFromChannel(initialClusterStatesChannel); }, diff --git a/packages/core/src/features/extensions/navigate/common/channel.ts b/packages/core/src/features/extensions/navigate/common/channel.ts index 4c6892e6cb..ec7bc967dc 100644 --- a/packages/core/src/features/extensions/navigate/common/channel.ts +++ b/packages/core/src/features/extensions/navigate/common/channel.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { MessageChannel } from "../../../../common/utils/channel/message-channel-listener-injection-token"; +import type { MessageChannel } from "@k8slens/messaging"; export interface NavigateForExtensionArgs { extId: string; diff --git a/packages/core/src/features/extensions/navigate/renderer/listener.injectable.ts b/packages/core/src/features/extensions/navigate/renderer/listener.injectable.ts index fccf0efca6..2397def4f6 100644 --- a/packages/core/src/features/extensions/navigate/renderer/listener.injectable.ts +++ b/packages/core/src/features/extensions/navigate/renderer/listener.injectable.ts @@ -2,15 +2,15 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getMessageChannelListenerInjectable } from "../../../../common/utils/channel/message-channel-listener-injection-token"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import extensionLoaderInjectable from "../../../../extensions/extension-loader/extension-loader.injectable"; import type { LensRendererExtension } from "../../../../extensions/lens-renderer-extension"; import { navigateForExtensionChannel } from "../common/channel"; const navigateForExtensionListenerInjectable = getMessageChannelListenerInjectable({ channel: navigateForExtensionChannel, - id: "main", - handler: (di) => { + id: "renderer", + getHandler: (di) => { const extensionLoader = di.inject(extensionLoaderInjectable); return ({ extId, pageId, params }) => { diff --git a/packages/core/src/features/helm-charts/child-features/preferences/renderer/active-helm-repositories.injectable.ts b/packages/core/src/features/helm-charts/child-features/preferences/renderer/active-helm-repositories.injectable.ts index 7a0d5e6b47..b4195a876f 100644 --- a/packages/core/src/features/helm-charts/child-features/preferences/renderer/active-helm-repositories.injectable.ts +++ b/packages/core/src/features/helm-charts/child-features/preferences/renderer/active-helm-repositories.injectable.ts @@ -5,7 +5,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import { asyncComputed } from "@ogre-tools/injectable-react"; import { getActiveHelmRepositoriesChannel } from "../../../../../common/helm/get-active-helm-repositories-channel"; -import { requestFromChannelInjectionToken } from "../../../../../common/utils/channel/request-from-channel-injection-token"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import showErrorNotificationInjectable from "../../../../../renderer/components/notifications/show-error-notification.injectable"; import helmRepositoriesErrorStateInjectable from "./helm-repositories-error-state.injectable"; import { runInAction } from "mobx"; diff --git a/packages/core/src/features/helm-charts/child-features/preferences/renderer/adding-of-public-helm-repository/select-helm-repository/add-helm-repository.injectable.ts b/packages/core/src/features/helm-charts/child-features/preferences/renderer/adding-of-public-helm-repository/select-helm-repository/add-helm-repository.injectable.ts index 6b39d8dddf..3c2199c490 100644 --- a/packages/core/src/features/helm-charts/child-features/preferences/renderer/adding-of-public-helm-repository/select-helm-repository/add-helm-repository.injectable.ts +++ b/packages/core/src/features/helm-charts/child-features/preferences/renderer/adding-of-public-helm-repository/select-helm-repository/add-helm-repository.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import type { HelmRepo } from "../../../../../../../common/helm/helm-repo"; -import { requestFromChannelInjectionToken } from "../../../../../../../common/utils/channel/request-from-channel-injection-token"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import activeHelmRepositoriesInjectable from "../../active-helm-repositories.injectable"; import showErrorNotificationInjectable from "../../../../../../../renderer/components/notifications/show-error-notification.injectable"; import showSuccessNotificationInjectable from "../../../../../../../renderer/components/notifications/show-success-notification.injectable"; diff --git a/packages/core/src/features/helm-charts/child-features/preferences/renderer/remove-helm-repository.injectable.ts b/packages/core/src/features/helm-charts/child-features/preferences/renderer/remove-helm-repository.injectable.ts index 3aa56a4b04..4af5543c28 100644 --- a/packages/core/src/features/helm-charts/child-features/preferences/renderer/remove-helm-repository.injectable.ts +++ b/packages/core/src/features/helm-charts/child-features/preferences/renderer/remove-helm-repository.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import type { HelmRepo } from "../../../../../common/helm/helm-repo"; -import { requestFromChannelInjectionToken } from "../../../../../common/utils/channel/request-from-channel-injection-token"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import activeHelmRepositoriesInjectable from "./active-helm-repositories.injectable"; import { removeHelmRepositoryChannel } from "../../../../../common/helm/remove-helm-repository-channel"; diff --git a/packages/core/src/features/navigation/reload-page/common/channel.ts b/packages/core/src/features/navigation/reload-page/common/channel.ts index b920067a4d..50cdaa8918 100644 --- a/packages/core/src/features/navigation/reload-page/common/channel.ts +++ b/packages/core/src/features/navigation/reload-page/common/channel.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { MessageChannel } from "../../../../common/utils/channel/message-channel-listener-injection-token"; +import type { MessageChannel } from "@k8slens/messaging"; export type ReloadPageChannel = MessageChannel; diff --git a/packages/core/src/features/navigation/reload-page/renderer/register-listener.global-override-for-injectable.ts b/packages/core/src/features/navigation/reload-page/renderer/register-listener.global-override-for-injectable.ts index 9953ddcbf9..4b9842cf7d 100644 --- a/packages/core/src/features/navigation/reload-page/renderer/register-listener.global-override-for-injectable.ts +++ b/packages/core/src/features/navigation/reload-page/renderer/register-listener.global-override-for-injectable.ts @@ -8,6 +8,7 @@ import { reloadPageChannel } from "../common/channel"; import reloadPageChannelListenerInjectable from "./register-listener.injectable"; export default getGlobalOverride(reloadPageChannelListenerInjectable, () => ({ + id: "reload-page-channel-listener", channel: reloadPageChannel, handler: () => {}, })); diff --git a/packages/core/src/features/navigation/reload-page/renderer/register-listener.injectable.ts b/packages/core/src/features/navigation/reload-page/renderer/register-listener.injectable.ts index a42d818729..f71096bebf 100644 --- a/packages/core/src/features/navigation/reload-page/renderer/register-listener.injectable.ts +++ b/packages/core/src/features/navigation/reload-page/renderer/register-listener.injectable.ts @@ -2,13 +2,13 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getMessageChannelListenerInjectable } from "../../../../common/utils/channel/message-channel-listener-injection-token"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import { reloadPageChannel } from "../common/channel"; const reloadPageChannelListenerInjectable = getMessageChannelListenerInjectable({ id: "handler", channel: reloadPageChannel, - handler: () => () => location.reload(), + getHandler: () => () => location.reload(), causesSideEffects: true, }); diff --git a/packages/core/src/features/path-picking-dialog/common/channel.ts b/packages/core/src/features/path-picking-dialog/common/channel.ts index 98c19b4ad6..c5e8b9386d 100644 --- a/packages/core/src/features/path-picking-dialog/common/channel.ts +++ b/packages/core/src/features/path-picking-dialog/common/channel.ts @@ -4,7 +4,7 @@ */ import type { OpenDialogOptions } from "electron"; -import type { RequestChannel } from "../../../common/utils/channel/request-channel-listener-injection-token"; +import type { RequestChannel } from "@k8slens/messaging"; export type PathPickingResponse = { canceled: true; diff --git a/packages/core/src/features/path-picking-dialog/main/handle-pick-paths.injectable.ts b/packages/core/src/features/path-picking-dialog/main/handle-pick-paths.injectable.ts index d566ac9728..dded293c83 100644 --- a/packages/core/src/features/path-picking-dialog/main/handle-pick-paths.injectable.ts +++ b/packages/core/src/features/path-picking-dialog/main/handle-pick-paths.injectable.ts @@ -4,12 +4,13 @@ */ import askUserForFilePathsInjectable from "../../../main/ipc/ask-user-for-file-paths.injectable"; -import { getRequestChannelListenerInjectable } from "../../../main/utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import { openPathPickingDialogChannel } from "../common/channel"; const openPathPickingDialogListener = getRequestChannelListenerInjectable({ + id: "open-path-picking-dialog", channel: openPathPickingDialogChannel, - handler: (di) => di.inject(askUserForFilePathsInjectable), + getHandler: (di) => di.inject(askUserForFilePathsInjectable), }); export default openPathPickingDialogListener; diff --git a/packages/core/src/features/path-picking-dialog/renderer/pick-paths.injectable.ts b/packages/core/src/features/path-picking-dialog/renderer/pick-paths.injectable.ts index 5dde31f46d..528bffc634 100644 --- a/packages/core/src/features/path-picking-dialog/renderer/pick-paths.injectable.ts +++ b/packages/core/src/features/path-picking-dialog/renderer/pick-paths.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import type { PathPickOpts } from "../../../renderer/components/path-picker"; -import requestFromChannelInjectable from "../../../renderer/utils/channel/request-from-channel.injectable"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { openPathPickingDialogChannel } from "../common/channel"; export type OpenPathPickingDialog = (options: PathPickOpts) => Promise; @@ -12,7 +12,7 @@ export type OpenPathPickingDialog = (options: PathPickOpts) => Promise; const openPathPickingDialogInjectable = getInjectable({ id: "open-path-picking-dialog", instantiate: (di): OpenPathPickingDialog => { - const requestFromChannel = di.inject(requestFromChannelInjectable); + const requestFromChannel = di.inject(requestFromChannelInjectionToken); return async (options) => { const { onPick, onCancel, ...dialogOptions } = options; diff --git a/packages/core/src/features/shell-sync/common/failure-channel.ts b/packages/core/src/features/shell-sync/common/failure-channel.ts index aed25b0da0..268640fe89 100644 --- a/packages/core/src/features/shell-sync/common/failure-channel.ts +++ b/packages/core/src/features/shell-sync/common/failure-channel.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { MessageChannel } from "../../../common/utils/channel/message-channel-listener-injection-token"; +import type { MessageChannel } from "@k8slens/messaging"; export const shellSyncFailedChannel: MessageChannel = { id: "shell-sync-failed-channel", diff --git a/packages/core/src/features/shell-sync/main/emit-failure.injectable.ts b/packages/core/src/features/shell-sync/main/emit-failure.injectable.ts index 5abdfafa52..7dbfb094f2 100644 --- a/packages/core/src/features/shell-sync/main/emit-failure.injectable.ts +++ b/packages/core/src/features/shell-sync/main/emit-failure.injectable.ts @@ -3,16 +3,15 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { MessageChannelSender } from "../../../common/utils/channel/message-to-channel-injection-token"; -import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; import { shellSyncFailedChannel } from "../common/failure-channel"; const emitShellSyncFailedInjectable = getInjectable({ id: "emit-shell-sync-failed", - instantiate: (di): MessageChannelSender => { + instantiate: (di) => { const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); - return (error) => sendMessageToChannel(shellSyncFailedChannel, error); + return (error: string) => sendMessageToChannel(shellSyncFailedChannel, error); }, }); diff --git a/packages/core/src/features/shell-sync/renderer/failure-listener.injectable.ts b/packages/core/src/features/shell-sync/renderer/failure-listener.injectable.ts index 2014397fad..135143b3a6 100644 --- a/packages/core/src/features/shell-sync/renderer/failure-listener.injectable.ts +++ b/packages/core/src/features/shell-sync/renderer/failure-listener.injectable.ts @@ -2,14 +2,14 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getMessageChannelListenerInjectable } from "../../../common/utils/channel/message-channel-listener-injection-token"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import showErrorNotificationInjectable from "../../../renderer/components/notifications/show-error-notification.injectable"; import { shellSyncFailedChannel } from "../common/failure-channel"; const shellSyncFailureListenerInjectable = getMessageChannelListenerInjectable({ id: "notification", channel: shellSyncFailedChannel, - handler: (di) => { + getHandler: (di) => { const showErrorNotification = di.inject(showErrorNotificationInjectable); return (errorMessage) => showErrorNotification(`Failed to sync shell environment: ${errorMessage}`); diff --git a/packages/core/src/features/theme/system-type/common/channels.ts b/packages/core/src/features/theme/system-type/common/channels.ts index 3134f20378..49fb96ef0a 100644 --- a/packages/core/src/features/theme/system-type/common/channels.ts +++ b/packages/core/src/features/theme/system-type/common/channels.ts @@ -3,8 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { MessageChannel } from "../../../../common/utils/channel/message-channel-listener-injection-token"; -import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token"; +import type { MessageChannel, RequestChannel } from "@k8slens/messaging"; export type SystemThemeType = "dark" | "light"; diff --git a/packages/core/src/features/theme/system-type/main/emit-update.injectable.ts b/packages/core/src/features/theme/system-type/main/emit-update.injectable.ts index c085e6615a..d078e81e33 100644 --- a/packages/core/src/features/theme/system-type/main/emit-update.injectable.ts +++ b/packages/core/src/features/theme/system-type/main/emit-update.injectable.ts @@ -3,18 +3,16 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { MessageChannelHandler } from "../../../../common/utils/channel/message-channel-listener-injection-token"; -import { sendMessageToChannelInjectionToken } from "../../../../common/utils/channel/message-to-channel-injection-token"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; +import type { SystemThemeType } from "../common/channels"; import { systemThemeTypeUpdateChannel } from "../common/channels"; -export type EmitSystemThemeTypeUpdate = MessageChannelHandler; - const emitSystemThemeTypeUpdateInjectable = getInjectable({ id: "emit-system-theme-type-update", - instantiate: (di): EmitSystemThemeTypeUpdate => { + instantiate: (di) => { const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); - return (type) => sendMessageToChannel(systemThemeTypeUpdateChannel, type); + return (type: SystemThemeType) => sendMessageToChannel(systemThemeTypeUpdateChannel, type); }, }); diff --git a/packages/core/src/features/theme/system-type/main/handle-initial.injectable.ts b/packages/core/src/features/theme/system-type/main/handle-initial.injectable.ts index 1468b1eeda..7af8a0a069 100644 --- a/packages/core/src/features/theme/system-type/main/handle-initial.injectable.ts +++ b/packages/core/src/features/theme/system-type/main/handle-initial.injectable.ts @@ -4,12 +4,13 @@ */ import operatingSystemThemeInjectable from "../../../../main/theme/operating-system-theme.injectable"; -import { getRequestChannelListenerInjectable } from "../../../../main/utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import { initialSystemThemeTypeChannel } from "../common/channels"; const initialSystemThemeTypeHandler = getRequestChannelListenerInjectable({ + id: "initial-system-theme-type-listener", channel: initialSystemThemeTypeChannel, - handler: (di) => { + getHandler: (di) => { const operatingSystemTheme = di.inject(operatingSystemThemeInjectable); return () => operatingSystemTheme.get(); diff --git a/packages/core/src/features/theme/system-type/renderer/request-initial.injectable.ts b/packages/core/src/features/theme/system-type/renderer/request-initial.injectable.ts index 74fe73cf03..fd84d7f90c 100644 --- a/packages/core/src/features/theme/system-type/renderer/request-initial.injectable.ts +++ b/packages/core/src/features/theme/system-type/renderer/request-initial.injectable.ts @@ -3,8 +3,8 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { RequestChannelHandler } from "../../../../main/utils/channel/channel-listeners/listener-tokens"; -import requestFromChannelInjectable from "../../../../renderer/utils/channel/request-from-channel.injectable"; +import type { RequestChannelHandler } from "@k8slens/messaging"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { initialSystemThemeTypeChannel } from "../common/channels"; export type RequestInitialSystemThemeType = RequestChannelHandler; @@ -12,7 +12,7 @@ export type RequestInitialSystemThemeType = RequestChannelHandler { - const requestFromChannel = di.inject(requestFromChannelInjectable); + const requestFromChannel = di.inject(requestFromChannelInjectionToken); return () => requestFromChannel(initialSystemThemeTypeChannel); }, diff --git a/packages/core/src/features/theme/system-type/renderer/update-listener.injectable.ts b/packages/core/src/features/theme/system-type/renderer/update-listener.injectable.ts index 4eb57c9b85..dac9061c28 100644 --- a/packages/core/src/features/theme/system-type/renderer/update-listener.injectable.ts +++ b/packages/core/src/features/theme/system-type/renderer/update-listener.injectable.ts @@ -2,14 +2,14 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getMessageChannelListenerInjectable } from "../../../../common/utils/channel/message-channel-listener-injection-token"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import systemThemeConfigurationInjectable from "../../../../renderer/themes/system-theme.injectable"; import { systemThemeTypeUpdateChannel } from "../common/channels"; const systemThemeTypeUpdateListenerInjectable = getMessageChannelListenerInjectable({ channel: systemThemeTypeUpdateChannel, id: "main", - handler: (di) => { + getHandler: (di) => { const systemThemeConfiguration = di.inject(systemThemeConfigurationInjectable); return (type) => systemThemeConfiguration.set(type); diff --git a/packages/core/src/jest-after-env.setup.ts b/packages/core/src/jest-after-env.setup.ts index 69b18161a8..df0fcfff4d 100644 --- a/packages/core/src/jest-after-env.setup.ts +++ b/packages/core/src/jest-after-env.setup.ts @@ -4,3 +4,8 @@ */ import "@testing-library/jest-dom"; + +// Note: This is a kludge to prevent "Hooks cannot be defined inside tests" error +// when importing a test util inside a test suite. +import { render } from "@testing-library/react"; +void render; diff --git a/packages/core/src/main/app-paths/app-paths-request-channel-listener.injectable.ts b/packages/core/src/main/app-paths/app-paths-request-channel-listener.injectable.ts index 568d63f1ea..ccf8be5054 100644 --- a/packages/core/src/main/app-paths/app-paths-request-channel-listener.injectable.ts +++ b/packages/core/src/main/app-paths/app-paths-request-channel-listener.injectable.ts @@ -4,11 +4,12 @@ */ import { appPathsChannel } from "../../common/app-paths/app-paths-channel"; import appPathsInjectable from "../../common/app-paths/app-paths.injectable"; -import { getRequestChannelListenerInjectable } from "../utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; const appPathsRequestChannelListenerInjectable = getRequestChannelListenerInjectable({ + id: "app-paths-request-channel-listener", channel: appPathsChannel, - handler: (di) => { + getHandler: (di) => { const appPaths = di.inject(appPathsInjectable); return () => appPaths; diff --git a/packages/core/src/main/build-version/setup-channel.injectable.ts b/packages/core/src/main/build-version/setup-channel.injectable.ts index 05da92db6e..88661c899f 100644 --- a/packages/core/src/main/build-version/setup-channel.injectable.ts +++ b/packages/core/src/main/build-version/setup-channel.injectable.ts @@ -3,12 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { buildVersionChannel } from "../../common/vars/build-semantic-version.injectable"; -import { getRequestChannelListenerInjectable } from "../utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import buildVersionInjectable from "../vars/build-version/build-version.injectable"; const buildVersionChannelListenerInjectable = getRequestChannelListenerInjectable({ + id: "build-version-channel-listener", channel: buildVersionChannel, - handler: (di) => { + getHandler: (di) => { const buildVersion = di.inject(buildVersionInjectable); return () => buildVersion.get(); diff --git a/packages/core/src/main/catalog-sync-to-renderer/catalog-sync-to-renderer.injectable.ts b/packages/core/src/main/catalog-sync-to-renderer/catalog-sync-to-renderer.injectable.ts index cd77332185..a2fe077c1d 100644 --- a/packages/core/src/main/catalog-sync-to-renderer/catalog-sync-to-renderer.injectable.ts +++ b/packages/core/src/main/catalog-sync-to-renderer/catalog-sync-to-renderer.injectable.ts @@ -7,7 +7,7 @@ import { reaction } from "mobx"; import ipcMainInjectionToken from "../../common/ipc/ipc-main-injection-token"; import { catalogInitChannel } from "../../common/ipc/catalog"; import { disposer } from "@k8slens/utilities"; -import { getStartableStoppable } from "../../common/utils/get-startable-stoppable"; +import { getStartableStoppable } from "@k8slens/startable-stoppable"; import catalogEntityRegistryInjectable from "../catalog/entity-registry.injectable"; import catalogSyncBroadcasterInjectable from "./broadcaster.injectable"; import { toJS } from "../../common/utils"; diff --git a/packages/core/src/main/cluster/visibility-handler.injectable.ts b/packages/core/src/main/cluster/visibility-handler.injectable.ts index 31f6ff13ec..ef4277e905 100644 --- a/packages/core/src/main/cluster/visibility-handler.injectable.ts +++ b/packages/core/src/main/cluster/visibility-handler.injectable.ts @@ -3,13 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { clusterVisibilityChannel } from "../../common/cluster/visibility-channel"; -import { getMessageChannelListenerInjectable } from "../../common/utils/channel/message-channel-listener-injection-token"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import visibleClusterInjectable from "./visible-cluster.injectable"; const clusterVisibilityHandlerInjectable = getMessageChannelListenerInjectable({ channel: clusterVisibilityChannel, id: "base", - handler: (di) => { + getHandler: (di) => { const visibleCluster = di.inject(visibleClusterInjectable); return (clusterId) => visibleCluster.set(clusterId); diff --git a/packages/core/src/main/electron-app/features/sync-theme-from-operating-system.injectable.ts b/packages/core/src/main/electron-app/features/sync-theme-from-operating-system.injectable.ts index 818bf938ec..02f0c916b6 100644 --- a/packages/core/src/main/electron-app/features/sync-theme-from-operating-system.injectable.ts +++ b/packages/core/src/main/electron-app/features/sync-theme-from-operating-system.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable"; +import { getStartableStoppable } from "@k8slens/startable-stoppable"; import operatingSystemThemeStateInjectable from "../../theme/operating-system-theme-state.injectable"; import nativeThemeInjectable from "./native-theme.injectable"; import getElectronThemeInjectable from "./get-electron-theme.injectable"; diff --git a/packages/core/src/main/getDiForUnitTesting.ts b/packages/core/src/main/getDiForUnitTesting.ts index 0712f1e128..b374eec1ca 100644 --- a/packages/core/src/main/getDiForUnitTesting.ts +++ b/packages/core/src/main/getDiForUnitTesting.ts @@ -29,6 +29,8 @@ import { setLegacyGlobalDiForExtensionApi, } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; +import { registerFeature } from "@k8slens/feature-core"; +import { messagingFeature, testUtils as messagingTestUtils } from "@k8slens/messaging"; export function getDiForUnitTesting() { const di = createContainer("main"); @@ -36,6 +38,11 @@ export function getDiForUnitTesting() { registerMobX(di); setLegacyGlobalDiForExtensionApi(di, "main"); + runInAction(() => { + registerFeature(di, messagingFeature, messagingTestUtils.messagingFeatureForUnitTesting); + + }); + di.preventSideEffects(); runInAction(() => { diff --git a/packages/core/src/main/helm/repositories/add-helm-repository/add-helm-repository-channel-listener.injectable.ts b/packages/core/src/main/helm/repositories/add-helm-repository/add-helm-repository-channel-listener.injectable.ts index 1c68bf6fd7..d5343b1d4f 100644 --- a/packages/core/src/main/helm/repositories/add-helm-repository/add-helm-repository-channel-listener.injectable.ts +++ b/packages/core/src/main/helm/repositories/add-helm-repository/add-helm-repository-channel-listener.injectable.ts @@ -3,12 +3,14 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { addHelmRepositoryChannel } from "../../../../common/helm/add-helm-repository-channel"; -import { getRequestChannelListenerInjectable } from "../../../utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import addHelmRepositoryInjectable from "./add-helm-repository.injectable"; -const addHelmRepositoryChannelListenerInjectable = getRequestChannelListenerInjectable({ - channel: addHelmRepositoryChannel, - handler: (di) => di.inject(addHelmRepositoryInjectable), -}); +const addHelmRepositoryChannelListenerInjectable = + getRequestChannelListenerInjectable({ + id: "add-helm-repository-channel-listener", + channel: addHelmRepositoryChannel, + getHandler: (di) => di.inject(addHelmRepositoryInjectable), + }); export default addHelmRepositoryChannelListenerInjectable; diff --git a/packages/core/src/main/helm/repositories/add-helm-repository/add-helm-repository.injectable.ts b/packages/core/src/main/helm/repositories/add-helm-repository/add-helm-repository.injectable.ts index 5292f8a662..27272a76f3 100644 --- a/packages/core/src/main/helm/repositories/add-helm-repository/add-helm-repository.injectable.ts +++ b/packages/core/src/main/helm/repositories/add-helm-repository/add-helm-repository.injectable.ts @@ -5,17 +5,16 @@ import { getInjectable } from "@ogre-tools/injectable"; import execHelmInjectable from "../../exec-helm/exec-helm.injectable"; import loggerInjectable from "../../../../common/logger.injectable"; -import type { AddHelmRepositoryChannel } from "../../../../common/helm/add-helm-repository-channel"; -import type { RequestChannelHandler } from "../../../utils/channel/channel-listeners/listener-tokens"; +import type { HelmRepo } from "../../../../common/helm/helm-repo"; const addHelmRepositoryInjectable = getInjectable({ id: "add-helm-repository", - instantiate: (di): RequestChannelHandler => { + instantiate: (di) => { const execHelm = di.inject(execHelmInjectable); const logger = di.inject(loggerInjectable); - return async (repo) => { + return async (repo: HelmRepo) => { const { name, url, @@ -59,12 +58,12 @@ const addHelmRepositoryInjectable = getInjectable({ if (result.callWasSuccessful) { return { - callWasSuccessful: true, + callWasSuccessful: true as const, }; } return { - callWasSuccessful: false, + callWasSuccessful: false as const, error: result.error.stderr || result.error.message, }; }; diff --git a/packages/core/src/main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories-channel-listener.injectable.ts b/packages/core/src/main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories-channel-listener.injectable.ts index 5ef0f2b5a4..a3cd9f2529 100644 --- a/packages/core/src/main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories-channel-listener.injectable.ts +++ b/packages/core/src/main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories-channel-listener.injectable.ts @@ -3,12 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getActiveHelmRepositoriesChannel } from "../../../../common/helm/get-active-helm-repositories-channel"; -import { getRequestChannelListenerInjectable } from "../../../utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import getActiveHelmRepositoriesInjectable from "./get-active-helm-repositories.injectable"; const getActiveHelmRepositoriesChannelListenerInjectable = getRequestChannelListenerInjectable({ + id: "get-active-helm-repositories-channel-listener", channel: getActiveHelmRepositoriesChannel, - handler: (di) => di.inject(getActiveHelmRepositoriesInjectable), + getHandler: (di) => di.inject(getActiveHelmRepositoriesInjectable), }); export default getActiveHelmRepositoriesChannelListenerInjectable; diff --git a/packages/core/src/main/helm/repositories/remove-helm-repository/remove-helm-repository-channel-listener.injectable.ts b/packages/core/src/main/helm/repositories/remove-helm-repository/remove-helm-repository-channel-listener.injectable.ts index 8a4e04b87c..84b147fed1 100644 --- a/packages/core/src/main/helm/repositories/remove-helm-repository/remove-helm-repository-channel-listener.injectable.ts +++ b/packages/core/src/main/helm/repositories/remove-helm-repository/remove-helm-repository-channel-listener.injectable.ts @@ -4,11 +4,12 @@ */ import removeHelmRepositoryInjectable from "./remove-helm-repository.injectable"; import { removeHelmRepositoryChannel } from "../../../../common/helm/remove-helm-repository-channel"; -import { getRequestChannelListenerInjectable } from "../../../utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; const removeHelmRepositoryChannelListenerInjectable = getRequestChannelListenerInjectable({ + id: "remove-helm-repository-channel-listener", channel: removeHelmRepositoryChannel, - handler: (di) => di.inject(removeHelmRepositoryInjectable), + getHandler: (di) => di.inject(removeHelmRepositoryInjectable), }); export default removeHelmRepositoryChannelListenerInjectable; diff --git a/packages/core/src/main/ipc/ask-user-for-file-paths.injectable.ts b/packages/core/src/main/ipc/ask-user-for-file-paths.injectable.ts index f8a0685d7c..3d0326711e 100644 --- a/packages/core/src/main/ipc/ask-user-for-file-paths.injectable.ts +++ b/packages/core/src/main/ipc/ask-user-for-file-paths.injectable.ts @@ -5,7 +5,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import showApplicationWindowInjectable from "../start-main-application/lens-window/show-application-window.injectable"; -import type { RequestChannelHandler } from "../utils/channel/channel-listeners/listener-tokens"; +import type { RequestChannelHandler } from "@k8slens/messaging"; import type { openPathPickingDialogChannel } from "../../features/path-picking-dialog/common/channel"; import showOpenDialogInjectable from "../electron-app/features/show-open-dialog.injectable"; diff --git a/packages/core/src/main/kubectl/apply-all-handler.injectable.ts b/packages/core/src/main/kubectl/apply-all-handler.injectable.ts index 7f62ca14fc..00f58e5e3f 100644 --- a/packages/core/src/main/kubectl/apply-all-handler.injectable.ts +++ b/packages/core/src/main/kubectl/apply-all-handler.injectable.ts @@ -6,11 +6,12 @@ import emitAppEventInjectable from "../../common/app-event-bus/emit-event.inject import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable"; import { kubectlApplyAllChannel } from "../../common/kube-helpers/channels"; import resourceApplierInjectable from "../resource-applier/create-resource-applier.injectable"; -import { getRequestChannelListenerInjectable } from "../utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; const kubectlApplyAllChannelHandlerInjectable = getRequestChannelListenerInjectable({ + id: "kubectl-apply-all-channel-handler-listener", channel: kubectlApplyAllChannel, - handler: (di) => { + getHandler: (di) => { const getClusterById = di.inject(getClusterByIdInjectable); const emitAppEvent = di.inject(emitAppEventInjectable); diff --git a/packages/core/src/main/kubectl/delete-all-handler.injectable.ts b/packages/core/src/main/kubectl/delete-all-handler.injectable.ts index 715eb0caf9..5d207be482 100644 --- a/packages/core/src/main/kubectl/delete-all-handler.injectable.ts +++ b/packages/core/src/main/kubectl/delete-all-handler.injectable.ts @@ -6,11 +6,12 @@ import emitAppEventInjectable from "../../common/app-event-bus/emit-event.inject import getClusterByIdInjectable from "../../common/cluster-store/get-by-id.injectable"; import { kubectlDeleteAllChannel } from "../../common/kube-helpers/channels"; import resourceApplierInjectable from "../resource-applier/create-resource-applier.injectable"; -import { getRequestChannelListenerInjectable } from "../utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; const kubectlDeleteAllChannelHandlerInjectable = getRequestChannelListenerInjectable({ + id: "kubectl-delete-all-channel-handler-listener", channel: kubectlDeleteAllChannel, - handler: (di) => { + getHandler: (di) => { const emitAppEvent = di.inject(emitAppEventInjectable); const getClusterById = di.inject(getClusterByIdInjectable); diff --git a/packages/core/src/main/lens-proxy/lens-proxy-certificate-request-handler.injectable.ts b/packages/core/src/main/lens-proxy/lens-proxy-certificate-request-handler.injectable.ts index 5f6938912a..6f35450273 100644 --- a/packages/core/src/main/lens-proxy/lens-proxy-certificate-request-handler.injectable.ts +++ b/packages/core/src/main/lens-proxy/lens-proxy-certificate-request-handler.injectable.ts @@ -3,12 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { lensProxyCertificateChannel } from "../../common/certificate/lens-proxy-certificate-channel"; -import { getRequestChannelListenerInjectable } from "../utils/channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import lensProxyCertificateInjectable from "../../common/certificate/lens-proxy-certificate.injectable"; const lensProxyCertificateRequestHandlerInjectable = getRequestChannelListenerInjectable({ + id: "lens-proxy-certificate-request-handler-listener", channel: lensProxyCertificateChannel, - handler: (di) => { + getHandler: (di) => { const lensProxyCertificate = di.inject(lensProxyCertificateInjectable).get(); return () => ({ diff --git a/packages/core/src/main/start-main-application/lens-window/current-cluster-frame/listener.injectable.ts b/packages/core/src/main/start-main-application/lens-window/current-cluster-frame/listener.injectable.ts index d29210cda1..11d23e6a4f 100644 --- a/packages/core/src/main/start-main-application/lens-window/current-cluster-frame/listener.injectable.ts +++ b/packages/core/src/main/start-main-application/lens-window/current-cluster-frame/listener.injectable.ts @@ -3,17 +3,17 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { currentClusterMessageChannel } from "../../../../common/cluster/current-cluster-channel"; -import { getMessageChannelListenerInjectable } from "../../../../common/utils/channel/message-channel-listener-injection-token"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import currentClusterFrameClusterIdStateInjectable from "./current-cluster-frame-cluster-id-state.injectable"; -const currentVisibileClusterListenerInjectable = getMessageChannelListenerInjectable({ - id: "current-visibile-cluster", +const currentVisibleClusterListenerInjectable = getMessageChannelListenerInjectable({ + id: "current-visible-cluster", channel: currentClusterMessageChannel, - handler: (di) => { + getHandler: (di) => { const currentClusterFrameState = di.inject(currentClusterFrameClusterIdStateInjectable); return clusterId => currentClusterFrameState.set(clusterId); }, }); -export default currentVisibileClusterListenerInjectable; +export default currentVisibleClusterListenerInjectable; diff --git a/packages/core/src/main/start-main-application/runnables/root-frame-has-rendered/channel-listener.injectable.ts b/packages/core/src/main/start-main-application/runnables/root-frame-has-rendered/channel-listener.injectable.ts index 8b906c79e9..4769c12256 100644 --- a/packages/core/src/main/start-main-application/runnables/root-frame-has-rendered/channel-listener.injectable.ts +++ b/packages/core/src/main/start-main-application/runnables/root-frame-has-rendered/channel-listener.injectable.ts @@ -2,7 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { getMessageChannelListenerInjectable } from "../../../../common/utils/channel/message-channel-listener-injection-token"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; import { rootFrameHasRenderedChannel } from "../../../../common/root-frame/root-frame-rendered-channel"; import { runManyFor } from "@k8slens/run-many"; import { afterRootFrameIsReadyInjectionToken } from "../../runnable-tokens/phases"; @@ -10,7 +10,7 @@ import { afterRootFrameIsReadyInjectionToken } from "../../runnable-tokens/phase const rootFrameRenderedChannelListenerInjectable = getMessageChannelListenerInjectable({ id: "action", channel: rootFrameHasRenderedChannel, - handler: (di) => { + getHandler: (di) => { const runMany = runManyFor(di); return runMany(afterRootFrameIsReadyInjectionToken); diff --git a/packages/core/src/main/tray/menu-icon/reactive.injectable.ts b/packages/core/src/main/tray/menu-icon/reactive.injectable.ts index 8c6d358477..4fbc8c2448 100644 --- a/packages/core/src/main/tray/menu-icon/reactive.injectable.ts +++ b/packages/core/src/main/tray/menu-icon/reactive.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { reaction } from "mobx"; -import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable"; +import { getStartableStoppable } from "@k8slens/startable-stoppable"; import electronTrayInjectable from "../electron-tray/electron-tray.injectable"; import trayIconInjectable from "./tray-icon.injectable"; diff --git a/packages/core/src/main/tray/reactive-tray-menu-items/reactive-tray-menu-items.injectable.ts b/packages/core/src/main/tray/reactive-tray-menu-items/reactive-tray-menu-items.injectable.ts index 378bceafd9..a216675b01 100644 --- a/packages/core/src/main/tray/reactive-tray-menu-items/reactive-tray-menu-items.injectable.ts +++ b/packages/core/src/main/tray/reactive-tray-menu-items/reactive-tray-menu-items.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { getStartableStoppable } from "../../../common/utils/get-startable-stoppable"; +import { getStartableStoppable } from "@k8slens/startable-stoppable"; import { reaction } from "mobx"; import type { MinimalTrayMenuItem } from "../electron-tray/electron-tray.injectable"; import electronTrayInjectable from "../electron-tray/electron-tray.injectable"; diff --git a/packages/core/src/main/utils/channel/channel-listeners/enlist-message-channel-listener.injectable.ts b/packages/core/src/main/utils/channel/channel-listeners/enlist-message-channel-listener.injectable.ts deleted file mode 100644 index db6435ea56..0000000000 --- a/packages/core/src/main/utils/channel/channel-listeners/enlist-message-channel-listener.injectable.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import type { IpcMainEvent } from "electron"; -import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token"; -import ipcMainInjectionToken from "../../../../common/ipc/ipc-main-injection-token"; - -const enlistMessageChannelListenerInjectable = getInjectable({ - id: "enlist-message-channel-listener-for-main", - - instantiate: (di) => { - const ipcMain = di.inject(ipcMainInjectionToken); - - return ({ channel, handler }) => { - const nativeOnCallback = (_: IpcMainEvent, message: unknown) => { - handler(message); - }; - - ipcMain.on(channel.id, nativeOnCallback); - - return () => { - ipcMain.off(channel.id, nativeOnCallback); - }; - }; - }, - - injectionToken: enlistMessageChannelListenerInjectionToken, -}); - -export default enlistMessageChannelListenerInjectable; diff --git a/packages/core/src/main/utils/channel/channel-listeners/listening-on-request-channels.injectable.ts b/packages/core/src/main/utils/channel/channel-listeners/listening-on-request-channels.injectable.ts deleted file mode 100644 index 1e6d0f296c..0000000000 --- a/packages/core/src/main/utils/channel/channel-listeners/listening-on-request-channels.injectable.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { disposer } from "@k8slens/utilities"; -import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token"; -import { getStartableStoppable } from "../../../../common/utils/get-startable-stoppable"; -import enlistRequestChannelListenerInjectable from "./enlist-request-channel-listener.injectable"; -import { requestChannelListenerInjectionToken } from "./listener-tokens"; - -const listeningOnRequestChannelsInjectable = getInjectable({ - id: "listening-on-request-channels", - instantiate: (di) => { - const enlistRequestChannelListener = di.inject(enlistRequestChannelListenerInjectable); - const requestChannelListeners = di.injectMany(requestChannelListenerInjectionToken); - - return getStartableStoppable("listening-on-request-channels", () => { - const seenChannels = new Set>(); - - for (const listener of requestChannelListeners) { - if (seenChannels.has(listener.channel)) { - throw new Error(`Tried to register a multiple channel handlers for "${listener.channel.id}", only one handler is supported for a request channel.`); - } - - seenChannels.add(listener.channel); - } - - return disposer(requestChannelListeners.map(enlistRequestChannelListener)); - }); - }, -}); - -export default listeningOnRequestChannelsInjectable; diff --git a/packages/core/src/main/utils/channel/channel-listeners/start-listening-on-channels.injectable.ts b/packages/core/src/main/utils/channel/channel-listeners/start-listening-on-channels.injectable.ts deleted file mode 100644 index c83425109c..0000000000 --- a/packages/core/src/main/utils/channel/channel-listeners/start-listening-on-channels.injectable.ts +++ /dev/null @@ -1,26 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; -import listeningOnMessageChannelsInjectable from "../../../../common/utils/channel/listening-on-message-channels.injectable"; -import listeningOnRequestChannelsInjectable from "./listening-on-request-channels.injectable"; - -const startListeningOnChannelsInjectable = getInjectable({ - id: "start-listening-on-channels-main", - - instantiate: (di) => ({ - run: () => { - const listeningOnMessageChannels = di.inject(listeningOnMessageChannelsInjectable); - const listeningOnRequestChannels = di.inject(listeningOnRequestChannelsInjectable); - - listeningOnMessageChannels.start(); - listeningOnRequestChannels.start(); - }, - }), - - injectionToken: onLoadOfApplicationInjectionToken, -}); - -export default startListeningOnChannelsInjectable; diff --git a/packages/core/src/main/utils/channel/message-to-channel.injectable.ts b/packages/core/src/main/utils/channel/message-to-channel.injectable.ts deleted file mode 100644 index 392120509d..0000000000 --- a/packages/core/src/main/utils/channel/message-to-channel.injectable.ts +++ /dev/null @@ -1,32 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import type { SendMessageToChannel } from "../../../common/utils/channel/message-to-channel-injection-token"; -import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token"; -import getVisibleWindowsInjectable from "../../start-main-application/lens-window/get-visible-windows.injectable"; -import clusterFramesInjectable from "../../../common/cluster-frames.injectable"; - -const messageToChannelInjectable = getInjectable({ - id: "message-to-channel", - - instantiate: (di) => { - const getVisibleWindows = di.inject(getVisibleWindowsInjectable); - const clusterFrames = di.inject(clusterFramesInjectable); - - return ((channel, data) => { - for (const window of getVisibleWindows()) { - window.send({ channel: channel.id, data }); - - clusterFrames.forEach(frameInfo => { - window.send({ channel: channel.id, data, frameInfo }); - }); - } - }) as SendMessageToChannel; - }, - - injectionToken: sendMessageToChannelInjectionToken, -}); - -export default messageToChannelInjectable; diff --git a/packages/core/src/main/utils/channel/message-to-channel.test.ts b/packages/core/src/main/utils/channel/message-to-channel.test.ts deleted file mode 100644 index 8e544c47dd..0000000000 --- a/packages/core/src/main/utils/channel/message-to-channel.test.ts +++ /dev/null @@ -1,115 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getDiForUnitTesting } from "../../getDiForUnitTesting"; -import getVisibleWindowsInjectable from "../../start-main-application/lens-window/get-visible-windows.injectable"; -import clusterFramesInjectable from "../../../common/cluster-frames.injectable"; -import type { MessageChannel } from "../../../common/utils/channel/message-channel-listener-injection-token"; -import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token"; -import type { DiContainer } from "@ogre-tools/injectable"; -import type { ClusterFrameInfo } from "../../../common/cluster-frames.injectable"; - -describe("message-to-channel", () => { - let di: DiContainer; - let sendToWindowMock: jest.Mock; - - beforeEach(() => { - di = getDiForUnitTesting(); - - sendToWindowMock = jest.fn(); - - di.override(getVisibleWindowsInjectable, () => () => [ - { - id: "some-window", - send: sendToWindowMock, - show: () => {}, - reload: () => {}, - isStarting: false, - start: async () => {}, - close: () => {}, - isVisible: true, - }, - - { - id: "some-other-window", - send: sendToWindowMock, - show: () => {}, - reload: () => {}, - isStarting: false, - start: async () => {}, - close: () => {}, - isVisible: true, - }, - ]); - - di.override( - clusterFramesInjectable, - () => - new Map([ - [ - "some-cluster-id", - { frameId: 42, processId: 84 }, - ], - [ - "some-other-cluster-id", - { frameId: 126, processId: 168 }, - ], - ]), - ); - }); - - describe("when sending message", () => { - beforeEach(() => { - const sendMessageToChannel = di.inject( - sendMessageToChannelInjectionToken, - ); - - sendMessageToChannel(someChannel, 42); - }); - - it("sends to each window and cluster frames", () => { - expect(sendToWindowMock.mock.calls).toEqual([ - [{ channel: "some-channel-id", data: 42 }], - - [ - { - channel: "some-channel-id", - data: 42, - frameInfo: { frameId: 42, processId: 84 }, - }, - ], - - [ - { - channel: "some-channel-id", - data: 42, - frameInfo: { frameId: 126, processId: 168 }, - }, - ], - - [{ channel: "some-channel-id", data: 42 }], - - [ - { - channel: "some-channel-id", - data: 42, - frameInfo: { frameId: 42, processId: 84 }, - }, - ], - - [ - { - channel: "some-channel-id", - data: 42, - frameInfo: { frameId: 126, processId: 168 }, - }, - ], - ]); - }); - }); -}); - -const someChannel: MessageChannel = { - id: "some-channel-id", -}; diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-channel-responder.injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-channel-responder.injectable.ts index a2cd605633..16229a0fb7 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-channel-responder.injectable.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-channel-responder.injectable.ts @@ -3,12 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { resolveSystemProxyChannel } from "../../../common/utils/resolve-system-proxy/resolve-system-proxy-channel"; -import { getRequestChannelListenerInjectable } from "../channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; import resolveSystemProxyInjectable from "./resolve-system-proxy.injectable"; const resolveSystemProxyChannelResponderInjectable = getRequestChannelListenerInjectable({ + id: "resolve-system-proxy-channel-responder-listener", channel: resolveSystemProxyChannel, - handler: (di) => di.inject(resolveSystemProxyInjectable), + getHandler: (di) => di.inject(resolveSystemProxyInjectable), }); export default resolveSystemProxyChannelResponderInjectable; diff --git a/packages/core/src/main/utils/sync-box/sync-box-initial-value-channel-listener.injectable.ts b/packages/core/src/main/utils/sync-box/sync-box-initial-value-channel-listener.injectable.ts index da78d76c36..fafb32e7e9 100644 --- a/packages/core/src/main/utils/sync-box/sync-box-initial-value-channel-listener.injectable.ts +++ b/packages/core/src/main/utils/sync-box/sync-box-initial-value-channel-listener.injectable.ts @@ -4,11 +4,12 @@ */ import { syncBoxInitialValueChannel } from "../../../common/utils/sync-box/channels"; import { syncBoxInjectionToken } from "../../../common/utils/sync-box/sync-box-injection-token"; -import { getRequestChannelListenerInjectable } from "../channel/channel-listeners/listener-tokens"; +import { getRequestChannelListenerInjectable } from "@k8slens/messaging"; const syncBoxInitialValueChannelListenerInjectable = getRequestChannelListenerInjectable({ + id: "sync-box-initial-value-channel-listener", channel: syncBoxInitialValueChannel, - handler: (di) => { + getHandler: (di) => { const syncBoxes = di.injectMany(syncBoxInjectionToken); return () => syncBoxes.map((box) => ({ diff --git a/packages/core/src/renderer/app-paths/setup-app-paths.injectable.ts b/packages/core/src/renderer/app-paths/setup-app-paths.injectable.ts index d80cc668ac..af5c3cebc6 100644 --- a/packages/core/src/renderer/app-paths/setup-app-paths.injectable.ts +++ b/packages/core/src/renderer/app-paths/setup-app-paths.injectable.ts @@ -4,9 +4,9 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import appPathsStateInjectable from "../../common/app-paths/app-paths-state.injectable"; -import { beforeFrameStartsFirstInjectionToken } from "../before-frame-starts/tokens"; import { appPathsChannel } from "../../common/app-paths/app-paths-channel"; -import { requestFromChannelInjectionToken } from "../../common/utils/channel/request-from-channel-injection-token"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; +import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application"; const setupAppPathsInjectable = getInjectable({ id: "setup-app-paths", @@ -21,7 +21,7 @@ const setupAppPathsInjectable = getInjectable({ }, }), - injectionToken: beforeFrameStartsFirstInjectionToken, + injectionToken: beforeApplicationIsLoadingInjectionToken, }); export default setupAppPathsInjectable; diff --git a/packages/core/src/renderer/before-frame-starts/runnables/setup-current-cluster-broadcast.injectable.ts b/packages/core/src/renderer/before-frame-starts/runnables/setup-current-cluster-broadcast.injectable.ts index 0d9c8bc65a..e60eb3fae1 100644 --- a/packages/core/src/renderer/before-frame-starts/runnables/setup-current-cluster-broadcast.injectable.ts +++ b/packages/core/src/renderer/before-frame-starts/runnables/setup-current-cluster-broadcast.injectable.ts @@ -5,7 +5,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import { reaction } from "mobx"; import { currentClusterMessageChannel } from "../../../common/cluster/current-cluster-channel"; -import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; import matchedClusterIdInjectable from "../../navigation/matched-cluster-id.injectable"; import { beforeMainFrameStartsFirstInjectionToken } from "../tokens"; diff --git a/packages/core/src/renderer/certificate/request-lens-proxy-certificate.injectable.ts b/packages/core/src/renderer/certificate/request-lens-proxy-certificate.injectable.ts index e1322096bf..f80911c7a5 100644 --- a/packages/core/src/renderer/certificate/request-lens-proxy-certificate.injectable.ts +++ b/packages/core/src/renderer/certificate/request-lens-proxy-certificate.injectable.ts @@ -4,12 +4,12 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { lensProxyCertificateChannel } from "../../common/certificate/lens-proxy-certificate-channel"; -import requestFromChannelInjectable from "../utils/channel/request-from-channel.injectable"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; const requestLensProxyCertificateInjectable = getInjectable({ id: "request-lens-proxy-certificate", instantiate: (di) => { - const requestFromChannel = di.inject(requestFromChannelInjectable); + const requestFromChannel = di.inject(requestFromChannelInjectionToken); return () => requestFromChannel(lensProxyCertificateChannel); }, diff --git a/packages/core/src/renderer/components/+extensions/attempt-install-by-info.injectable.tsx b/packages/core/src/renderer/components/+extensions/attempt-install-by-info.injectable.tsx index 523a91596e..8f2e5692d1 100644 --- a/packages/core/src/renderer/components/+extensions/attempt-install-by-info.injectable.tsx +++ b/packages/core/src/renderer/components/+extensions/attempt-install-by-info.injectable.tsx @@ -26,6 +26,7 @@ export interface ExtensionInfo { requireConfirmation?: boolean; } +// @ts-ignore interface NpmPackageVersionDescriptor extends PackageJson { dist: { integrity: string; diff --git a/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.ts b/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.ts index 08a49bb496..7420fa680a 100644 --- a/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.ts +++ b/packages/core/src/renderer/components/cluster-manager/cluster-frame-handler.ts @@ -10,7 +10,6 @@ import { onceDefined } from "@k8slens/utilities"; import assert from "assert"; import type { Logger } from "../../../common/logger"; import type { GetClusterById } from "../../../common/cluster-store/get-by-id.injectable"; -import type { EmitClusterVisibility } from "./emit-cluster-visibility.injectable"; import { getClusterFrameUrl } from "../../../common/utils"; export interface LensView { @@ -21,7 +20,7 @@ export interface LensView { interface Dependencies { readonly logger: Logger; getClusterById: GetClusterById; - emitClusterVisibility: EmitClusterVisibility; + emitClusterVisibility: (clusterId: ClusterId | null) => void; } export class ClusterFrameHandler { diff --git a/packages/core/src/renderer/components/cluster-manager/emit-cluster-visibility.injectable.ts b/packages/core/src/renderer/components/cluster-manager/emit-cluster-visibility.injectable.ts index 261582d136..5c941c60e6 100644 --- a/packages/core/src/renderer/components/cluster-manager/emit-cluster-visibility.injectable.ts +++ b/packages/core/src/renderer/components/cluster-manager/emit-cluster-visibility.injectable.ts @@ -3,18 +3,16 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import type { MessageChannelHandler } from "../../../common/utils/channel/message-channel-listener-injection-token"; -import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; import { clusterVisibilityChannel } from "../../../common/cluster/visibility-channel"; - -export type EmitClusterVisibility = MessageChannelHandler; +import type { ClusterId } from "../../../common/cluster-types"; const emitClusterVisibilityInjectable = getInjectable({ id: "emit-cluster-visibility", - instantiate: (di): EmitClusterVisibility => { + instantiate: (di) => { const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); - return (id) => sendMessageToChannel(clusterVisibilityChannel, id); + return (id: ClusterId | null) => sendMessageToChannel(clusterVisibilityChannel, id); }, }); diff --git a/packages/core/src/renderer/components/test-utils/get-application-builder.tsx b/packages/core/src/renderer/components/test-utils/get-application-builder.tsx index 0d202aa1e5..4ae3441e76 100644 --- a/packages/core/src/renderer/components/test-utils/get-application-builder.tsx +++ b/packages/core/src/renderer/components/test-utils/get-application-builder.tsx @@ -29,7 +29,6 @@ import type { MinimalTrayMenuItem } from "../../../main/tray/electron-tray/elect import electronTrayInjectable from "../../../main/tray/electron-tray/electron-tray.injectable"; import { getDiForUnitTesting as getRendererDi } from "../../getDiForUnitTesting"; import { getDiForUnitTesting as getMainDi } from "../../../main/getDiForUnitTesting"; -import { overrideChannels } from "../../../test-utils/channel-fakes/override-channels"; import assert from "assert"; import { openMenu } from "react-select-event"; import userEvent from "@testing-library/user-event"; @@ -40,7 +39,7 @@ import { navigateToRouteInjectionToken } from "../../../common/front-end-routing import type { LensMainExtension } from "../../../extensions/lens-main-extension"; import type { LensExtension } from "../../../extensions/lens-extension"; import extensionInjectable from "../../../extensions/extension-loader/extension/extension.injectable"; -import { renderFor } from "./renderFor"; +import { renderFor } from "@k8slens/test-utils"; import { RootFrame } from "../../frames/root-frame/root-frame"; import { ClusterFrame } from "../../frames/cluster-frame/cluster-frame"; import hostedClusterIdInjectable from "../../cluster-frame-context/hosted-cluster-id.injectable"; @@ -71,6 +70,8 @@ import { registerFeature } from "@k8slens/feature-core"; import { applicationFeatureForElectronMain, testUtils as applicationForElectronTestUtils } from "@k8slens/application-for-electron-main"; import { applicationFeature, startApplicationInjectionToken } from "@k8slens/application"; import { testUsingFakeTime } from "../../../test-utils/use-fake-time"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; +import { getMessageBridgeFake } from "@k8slens/messaging-fake-bridge"; type MainDiCallback = (container: { mainDi: DiContainer }) => void | Promise; type WindowDiCallback = (container: { windowDi: DiContainer }) => void | Promise; @@ -179,7 +180,9 @@ export const getApplicationBuilder = () => { testUsingFakeTime(); - const { overrideForWindow, sendToWindow } = overrideChannels(mainDi); + const messageBridgeFake = getMessageBridgeFake(); + + messageBridgeFake.involve(mainDi); const beforeApplicationStartCallbacks: MainDiCallback[] = []; const afterApplicationStartCallbacks: MainDiCallback[] = []; @@ -229,7 +232,8 @@ export const getApplicationBuilder = () => { const windowDi = getRendererDi(); - overrideForWindow(windowDi, windowId); + messageBridgeFake.involve(windowDi); + overrideFsWithFakes(windowDi); runInAction(() => { @@ -284,8 +288,10 @@ export const getApplicationBuilder = () => { ); }, - send: (arg) => { - sendToWindow(windowId, arg); + send: ({ channel: channelId, data }) => { + const sendMessageToChannel = mainDi.inject(sendMessageToChannelInjectionToken); + + sendMessageToChannel({ id: channelId }, data); }, reload: () => { diff --git a/packages/core/src/renderer/frames/root-frame/broadcast-that-root-frame-is-rendered.injectable.ts b/packages/core/src/renderer/frames/root-frame/broadcast-that-root-frame-is-rendered.injectable.ts index 841d19e002..dd43cbd301 100644 --- a/packages/core/src/renderer/frames/root-frame/broadcast-that-root-frame-is-rendered.injectable.ts +++ b/packages/core/src/renderer/frames/root-frame/broadcast-that-root-frame-is-rendered.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; import { rootFrameHasRenderedChannel } from "../../../common/root-frame/root-frame-rendered-channel"; const broadcastThatRootFrameIsRenderedInjectable = getInjectable({ diff --git a/packages/core/src/renderer/getDiForUnitTesting.tsx b/packages/core/src/renderer/getDiForUnitTesting.tsx index fbee046de2..ec389e1b10 100644 --- a/packages/core/src/renderer/getDiForUnitTesting.tsx +++ b/packages/core/src/renderer/getDiForUnitTesting.tsx @@ -5,7 +5,6 @@ import { noop, chunk } from "lodash/fp"; import { createContainer, isInjectable } from "@ogre-tools/injectable"; -import requestFromChannelInjectable from "./utils/channel/request-from-channel.injectable"; import { getOverrideFsWithFakes } from "../test-utils/override-fs-with-fakes"; import terminalSpawningPoolInjectable from "./components/dock/terminal/terminal-spawning-pool.injectable"; import hostedClusterIdInjectable from "./cluster-frame-context/hosted-cluster-id.injectable"; @@ -18,6 +17,8 @@ import type { GlobalOverride } from "@k8slens/test-utils"; import { setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api"; import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; import { registerInjectableReact } from "@ogre-tools/injectable-react"; +import { registerFeature } from "@k8slens/feature-core"; +import { messagingFeature, testUtils as messagingTestUtils } from "@k8slens/messaging"; export const getDiForUnitTesting = () => { const environment = "renderer"; @@ -27,6 +28,10 @@ export const getDiForUnitTesting = () => { registerInjectableReact(di); setLegacyGlobalDiForExtensionApi(di, environment); + runInAction(() => { + registerFeature(di, messagingFeature, messagingTestUtils.messagingFeatureForUnitTesting); + }); + di.preventSideEffects(); runInAction(() => { @@ -63,8 +68,6 @@ export const getDiForUnitTesting = () => { di.override(requestAnimationFrameInjectable, () => (callback) => callback()); di.override(watchHistoryStateInjectable, () => () => () => {}); - di.override(requestFromChannelInjectable, () => () => Promise.resolve(undefined as never)); - getOverrideFsWithFakes()(di); return di; diff --git a/packages/core/src/renderer/kubectl/apply-all.injectable.ts b/packages/core/src/renderer/kubectl/apply-all.injectable.ts index 989017f9d9..ffc5be14ba 100644 --- a/packages/core/src/renderer/kubectl/apply-all.injectable.ts +++ b/packages/core/src/renderer/kubectl/apply-all.injectable.ts @@ -4,12 +4,12 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { kubectlApplyAllChannel, kubectlApplyAllInjectionToken } from "../../common/kube-helpers/channels"; -import requestFromChannelInjectable from "../utils/channel/request-from-channel.injectable"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; const kubectlApplyAllInjectable = getInjectable({ id: "kubectl-apply-all", instantiate: (di) => { - const requestFromChannel = di.inject(requestFromChannelInjectable); + const requestFromChannel = di.inject(requestFromChannelInjectionToken); return (req) => requestFromChannel(kubectlApplyAllChannel, req); }, diff --git a/packages/core/src/renderer/kubectl/delete-all.injectable.ts b/packages/core/src/renderer/kubectl/delete-all.injectable.ts index 586895c75c..4a3ee05f54 100644 --- a/packages/core/src/renderer/kubectl/delete-all.injectable.ts +++ b/packages/core/src/renderer/kubectl/delete-all.injectable.ts @@ -4,12 +4,12 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { kubectlDeleteAllChannel, kubectlDeleteAllInjectionToken } from "../../common/kube-helpers/channels"; -import requestFromChannelInjectable from "../utils/channel/request-from-channel.injectable"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; const kubectlDeleteAllInjectable = getInjectable({ id: "kubectl-delete-all", instantiate: (di) => { - const requestFromChannel = di.inject(requestFromChannelInjectable); + const requestFromChannel = di.inject(requestFromChannelInjectionToken); return (req) => requestFromChannel(kubectlDeleteAllChannel, req); }, diff --git a/packages/core/src/renderer/navigation/navigation-channel-listener.injectable.ts b/packages/core/src/renderer/navigation/navigation-channel-listener.injectable.ts index 1b33b4fe2c..fbb66689e1 100644 --- a/packages/core/src/renderer/navigation/navigation-channel-listener.injectable.ts +++ b/packages/core/src/renderer/navigation/navigation-channel-listener.injectable.ts @@ -2,25 +2,25 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { InjectionToken } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable"; import currentlyInClusterFrameInjectable from "../routes/currently-in-cluster-frame.injectable"; import { appNavigationChannel } from "../../common/front-end-routing/app-navigation-channel"; import { clusterFrameNavigationChannel } from "../../common/front-end-routing/cluster-frame-navigation-channel"; import focusWindowInjectable from "./focus-window.injectable"; import { navigateToUrlInjectionToken } from "../../common/front-end-routing/navigate-to-url-injection-token"; -import type { MessageChannel, MessageChannelListener } from "../../common/utils/channel/message-channel-listener-injection-token"; -import { messageChannelListenerInjectionToken } from "../../common/utils/channel/message-channel-listener-injection-token"; +import type { MessageChannel, MessageChannelListener } from "@k8slens/messaging"; +import { messageChannelListenerInjectionToken } from "@k8slens/messaging"; const navigationChannelListenerInjectable = getInjectable({ id: "navigation-channel-listener", - instantiate: (di) => { + instantiate: (di): MessageChannelListener> => { const currentlyInClusterFrame = di.inject(currentlyInClusterFrameInjectable); const focusWindow = di.inject(focusWindowInjectable); const navigateToUrl = di.inject(navigateToUrlInjectionToken); return { + id: "navigation-channel-listener", channel: currentlyInClusterFrame ? clusterFrameNavigationChannel : appNavigationChannel, @@ -34,7 +34,8 @@ const navigationChannelListenerInjectable = getInjectable({ }, }; }, - injectionToken: messageChannelListenerInjectionToken as InjectionToken>, void>, + + injectionToken: messageChannelListenerInjectionToken, }); export default navigationChannelListenerInjectable; diff --git a/packages/core/src/renderer/utils/channel/channel-listeners/start-listening-of-channels.injectable.ts b/packages/core/src/renderer/utils/channel/channel-listeners/start-listening-of-channels.injectable.ts deleted file mode 100644 index c11b34e7e3..0000000000 --- a/packages/core/src/renderer/utils/channel/channel-listeners/start-listening-of-channels.injectable.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { beforeFrameStartsSecondInjectionToken } from "../../../before-frame-starts/tokens"; -import listeningOnMessageChannelsInjectable from "../../../../common/utils/channel/listening-on-message-channels.injectable"; - -const startListeningOfChannelsInjectable = getInjectable({ - id: "start-listening-of-channels-renderer", - - instantiate: (di) => ({ - run: () => { - const listeningOfChannels = di.inject(listeningOnMessageChannelsInjectable); - - listeningOfChannels.start(); - }, - }), - - injectionToken: beforeFrameStartsSecondInjectionToken, -}); - -export default startListeningOfChannelsInjectable; diff --git a/packages/core/src/renderer/utils/channel/message-to-channel.injectable.ts b/packages/core/src/renderer/utils/channel/message-to-channel.injectable.ts deleted file mode 100644 index eab7e4ec7f..0000000000 --- a/packages/core/src/renderer/utils/channel/message-to-channel.injectable.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import type { SendMessageToChannel } from "../../../common/utils/channel/message-to-channel-injection-token"; -import { sendMessageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token"; -import sendToMainInjectable from "./send-to-main.injectable"; - -const messageToChannelInjectable = getInjectable({ - id: "message-to-channel", - - instantiate: (di) => { - const sendToMain = di.inject(sendToMainInjectable); - - return ((channel, message) => { - sendToMain(channel.id, message); - }) as SendMessageToChannel; - }, - - injectionToken: sendMessageToChannelInjectionToken, -}); - -export default messageToChannelInjectable; diff --git a/packages/core/src/renderer/utils/channel/request-from-channel.injectable.ts b/packages/core/src/renderer/utils/channel/request-from-channel.injectable.ts deleted file mode 100644 index fd0815b1a3..0000000000 --- a/packages/core/src/renderer/utils/channel/request-from-channel.injectable.ts +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import ipcRendererInjectable from "./ipc-renderer.injectable"; -import type { RequestFromChannel } from "../../../common/utils/channel/request-from-channel-injection-token"; -import { requestFromChannelInjectionToken } from "../../../common/utils/channel/request-from-channel-injection-token"; - -const requestFromChannelInjectable = getInjectable({ - id: "request-from-channel", - - instantiate: (di) => { - const ipcRenderer = di.inject(ipcRendererInjectable); - - return ((channel, request) => ipcRenderer.invoke(channel.id, request)) as RequestFromChannel; - }, - - injectionToken: requestFromChannelInjectionToken, -}); - -export default requestFromChannelInjectable; diff --git a/packages/core/src/renderer/utils/channel/send-to-main.injectable.ts b/packages/core/src/renderer/utils/channel/send-to-main.injectable.ts deleted file mode 100644 index 6eb4540062..0000000000 --- a/packages/core/src/renderer/utils/channel/send-to-main.injectable.ts +++ /dev/null @@ -1,20 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import ipcRendererInjectable from "./ipc-renderer.injectable"; - -const sendToMainInjectable = getInjectable({ - id: "send-to-main", - - instantiate: (di) => { - const ipcRenderer = di.inject(ipcRendererInjectable); - - return (channelId: string, message: any) => { - ipcRenderer.send(channelId, message); - }; - }, -}); - -export default sendToMainInjectable; diff --git a/packages/core/src/renderer/utils/create-storage/initialize-state.injectable.ts b/packages/core/src/renderer/utils/create-storage/initialize-state.injectable.ts index 75d61908cd..804fe4ebf1 100644 --- a/packages/core/src/renderer/utils/create-storage/initialize-state.injectable.ts +++ b/packages/core/src/renderer/utils/create-storage/initialize-state.injectable.ts @@ -11,7 +11,7 @@ import writeJsonFileInjectable from "../../../common/fs/write-json-file.injectab import loggerInjectable from "../../../common/logger.injectable"; import joinPathsInjectable from "../../../common/path/join-paths.injectable"; import setupAppPathsInjectable from "../../app-paths/setup-app-paths.injectable"; -import { beforeFrameStartsFirstInjectionToken } from "../../before-frame-starts/tokens"; +import { beforeApplicationIsLoadingInjectionToken } from "@k8slens/application"; import hostedClusterIdInjectable from "../../cluster-frame-context/hosted-cluster-id.injectable"; import { storageHelperLogPrefix } from "../storage-helper"; import lensLocalStorageStateInjectable from "./state.injectable"; @@ -68,7 +68,7 @@ const initializeStateInjectable = getInjectable({ }, runAfter: setupAppPathsInjectable, }), - injectionToken: beforeFrameStartsFirstInjectionToken, + injectionToken: beforeApplicationIsLoadingInjectionToken, }); export default initializeStateInjectable; diff --git a/packages/core/src/renderer/utils/resolve-proxy/resolve-system-proxy.injectable.ts b/packages/core/src/renderer/utils/resolve-proxy/resolve-system-proxy.injectable.ts index 5468a8c7b7..55cd0d66d5 100644 --- a/packages/core/src/renderer/utils/resolve-proxy/resolve-system-proxy.injectable.ts +++ b/packages/core/src/renderer/utils/resolve-proxy/resolve-system-proxy.injectable.ts @@ -4,14 +4,14 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import { resolveSystemProxyInjectionToken } from "../../../common/utils/resolve-system-proxy/resolve-system-proxy-injection-token"; -import requestFromChannelInjectable from "../channel/request-from-channel.injectable"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { resolveSystemProxyChannel } from "../../../common/utils/resolve-system-proxy/resolve-system-proxy-channel"; const resolveSystemProxyInjectable = getInjectable({ id: "resolve-system-proxy-for-renderer", instantiate: (di) => { - const requestFromChannel = di.inject(requestFromChannelInjectable); + const requestFromChannel = di.inject(requestFromChannelInjectionToken); return async (url) => requestFromChannel(resolveSystemProxyChannel, url); }, diff --git a/packages/core/src/renderer/utils/sync-box/provide-initial-values-for-sync-boxes.injectable.ts b/packages/core/src/renderer/utils/sync-box/provide-initial-values-for-sync-boxes.injectable.ts index aceb20cea4..b4eb648c87 100644 --- a/packages/core/src/renderer/utils/sync-box/provide-initial-values-for-sync-boxes.injectable.ts +++ b/packages/core/src/renderer/utils/sync-box/provide-initial-values-for-sync-boxes.injectable.ts @@ -6,7 +6,7 @@ import { getInjectable } from "@ogre-tools/injectable"; import { beforeFrameStartsSecondInjectionToken } from "../../before-frame-starts/tokens"; import { syncBoxInitialValueChannel } from "../../../common/utils/sync-box/channels"; import createSyncBoxStateInjectable from "../../../common/utils/sync-box/sync-box-state.injectable"; -import { requestFromChannelInjectionToken } from "../../../common/utils/channel/request-from-channel-injection-token"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { runInAction } from "mobx"; import { syncBoxInjectionToken } from "../../../common/utils/sync-box/sync-box-injection-token"; import assert from "assert"; diff --git a/packages/core/src/renderer/vars/build-version/build-version.injectable.ts b/packages/core/src/renderer/vars/build-version/build-version.injectable.ts index a63a4102b0..f9ba5e34b0 100644 --- a/packages/core/src/renderer/vars/build-version/build-version.injectable.ts +++ b/packages/core/src/renderer/vars/build-version/build-version.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { createInitializableState } from "../../../common/initializable-state/create"; -import { requestFromChannelInjectionToken } from "../../../common/utils/channel/request-from-channel-injection-token"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; import { buildVersionChannel, buildVersionInjectionToken } from "../../../common/vars/build-semantic-version.injectable"; const buildVersionInjectable = createInitializableState({ diff --git a/packages/core/src/test-utils/channel-fakes/override-channels.ts b/packages/core/src/test-utils/channel-fakes/override-channels.ts deleted file mode 100644 index 798fcd84af..0000000000 --- a/packages/core/src/test-utils/channel-fakes/override-channels.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { DiContainer } from "@ogre-tools/injectable"; -import type { SendToViewArgs } from "../../main/start-main-application/lens-window/application-window/create-lens-window.injectable"; -import { overrideMessagingFromMainToWindow } from "./override-messaging-from-main-to-window"; -import { overrideMessagingFromWindowToMain } from "./override-messaging-from-window-to-main"; -import { overrideRequestingFromWindowToMain } from "./override-requesting-from-window-to-main"; - -export interface OverrideChannels { - overrideForWindow: (windowDi: DiContainer, windowId: string) => void; - sendToWindow: (windowId: string, args: SendToViewArgs) => void; -} - -export const overrideChannels = (mainDi: DiContainer): OverrideChannels => { - const { overrideEnlistForWindow, sendToWindow } = overrideMessagingFromMainToWindow(); - const overrideMessagingFromWindowToForWindow = overrideMessagingFromWindowToMain(mainDi); - const overrideRequestingFromWindowToMainForWindow = overrideRequestingFromWindowToMain(mainDi); - - return { - overrideForWindow: (windowDi, windowId) => { - overrideEnlistForWindow(windowDi, windowId); - overrideMessagingFromWindowToForWindow(windowDi); - overrideRequestingFromWindowToMainForWindow(windowDi); - }, - sendToWindow, - }; -}; diff --git a/packages/core/src/test-utils/channel-fakes/override-messaging-from-main-to-window.ts b/packages/core/src/test-utils/channel-fakes/override-messaging-from-main-to-window.ts deleted file mode 100644 index 1b69f13016..0000000000 --- a/packages/core/src/test-utils/channel-fakes/override-messaging-from-main-to-window.ts +++ /dev/null @@ -1,79 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { MessageChannelListener } from "../../common/utils/channel/message-channel-listener-injection-token"; -import enlistMessageChannelListenerInjectableInRenderer from "../../renderer/utils/channel/channel-listeners/enlist-message-channel-listener.injectable"; -import type { DiContainer } from "@ogre-tools/injectable"; -import { getOrInsert, getOrInsertSet } from "@k8slens/utilities"; -import type { SendToViewArgs } from "../../main/start-main-application/lens-window/application-window/create-lens-window.injectable"; -import { deserialize, serialize } from "v8"; - -type ListenerSet = Set>; -type WindowListenerMap = Map; -type ListenerFakeMap = Map; - -export interface OverriddenWindowMessaging { - sendToWindow(windowId: string, args: SendToViewArgs): void; - overrideEnlistForWindow(windowDi: DiContainer, windowId: string): void; -} - -export const overrideMessagingFromMainToWindow = (): OverriddenWindowMessaging => { - const messageChannelListenerFakesForRenderer: ListenerFakeMap = new Map(); - - const getWindowListeners = (channelId: string, windowId: string) => { - const channelListeners = getOrInsert( - messageChannelListenerFakesForRenderer, - channelId, - new Map(), - ); - - return getOrInsertSet(channelListeners, windowId); - }; - - return { - overrideEnlistForWindow: (windowDi, windowId) => { - windowDi.override( - enlistMessageChannelListenerInjectableInRenderer, - - () => (listener) => { - const windowListeners = getWindowListeners( - listener.channel.id, - windowId, - ); - - windowListeners.add(listener); - - return () => { - windowListeners.delete(listener); - }; - }, - ); - }, - sendToWindow: (windowId, { channel, data, frameInfo }) => { - try { - data = deserialize(serialize(data)); - } catch (error) { - throw new Error(`Tried to send a message to channel "${channel}" that is not compatible with StructuredClone: ${error}`); - } - - const windowListeners = getWindowListeners(channel, windowId); - - if (frameInfo) { - throw new Error( - `Tried to send message to frame "${frameInfo.frameId}" in process "${frameInfo.processId}" using channel "${channel}" which isn't supported yet.`, - ); - } - - if (windowListeners.size === 0) { - throw new Error( - `Tried to send message to channel "${channel}" but there where no listeners. Current channels with listeners: "${[ - ...messageChannelListenerFakesForRenderer.keys(), - ].join('", "')}"`, - ); - } - - windowListeners.forEach((listener) => listener.handler(data)); - }, - }; -}; diff --git a/packages/core/src/test-utils/channel-fakes/override-messaging-from-window-to-main.ts b/packages/core/src/test-utils/channel-fakes/override-messaging-from-window-to-main.ts deleted file mode 100644 index 8adc35c4d5..0000000000 --- a/packages/core/src/test-utils/channel-fakes/override-messaging-from-window-to-main.ts +++ /dev/null @@ -1,53 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { DiContainer } from "@ogre-tools/injectable"; -import { deserialize, serialize } from "v8"; -import type { MessageChannel, MessageChannelListener } from "../../common/utils/channel/message-channel-listener-injection-token"; -import enlistMessageChannelListenerInjectableInMain from "../../main/utils/channel/channel-listeners/enlist-message-channel-listener.injectable"; -import { getOrInsertSet } from "@k8slens/utilities"; -import sendToMainInjectable from "../../renderer/utils/channel/send-to-main.injectable"; - -export const overrideMessagingFromWindowToMain = (mainDi: DiContainer) => { - const messageChannelListenerFakesForMain = new Map< - string, - Set>> - >(); - - mainDi.override( - enlistMessageChannelListenerInjectableInMain, - - () => (listener) => { - const listeners = getOrInsertSet(messageChannelListenerFakesForMain, listener.channel.id); - - listeners.add(listener); - - return () => { - listeners.delete(listener); - }; - }, - ); - - return (windowDi: DiContainer) => { - windowDi.override(sendToMainInjectable, () => (channelId, message) => { - const listeners = messageChannelListenerFakesForMain.get(channelId); - - if (!listeners || listeners.size === 0) { - throw new Error( - `Tried to send message to channel "${channelId}" but there where no listeners. Current channels with listeners: "${[ - ...messageChannelListenerFakesForMain.keys(), - ].join('", "')}"`, - ); - } - - try { - message = deserialize(serialize(message)); - } catch (error) { - throw new Error(`Tried to send a message to channel "${channelId}" that is not compatible with StructuredClone: ${error}`); - } - - listeners.forEach((listener) => listener.handler(message)); - }); - }; -}; diff --git a/packages/core/src/test-utils/channel-fakes/override-requesting-from-window-to-main.ts b/packages/core/src/test-utils/channel-fakes/override-requesting-from-window-to-main.ts deleted file mode 100644 index 70526bd84c..0000000000 --- a/packages/core/src/test-utils/channel-fakes/override-requesting-from-window-to-main.ts +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { DiContainer } from "@ogre-tools/injectable"; -import { deserialize, serialize } from "v8"; -import type { RequestChannel } from "../../common/utils/channel/request-channel-listener-injection-token"; -import type { RequestFromChannel } from "../../common/utils/channel/request-from-channel-injection-token"; -import enlistRequestChannelListenerInjectableInMain from "../../main/utils/channel/channel-listeners/enlist-request-channel-listener.injectable"; -import type { RequestChannelListener } from "../../main/utils/channel/channel-listeners/listener-tokens"; -import requestFromChannelInjectable from "../../renderer/utils/channel/request-from-channel.injectable"; - -export const overrideRequestingFromWindowToMain = (mainDi: DiContainer) => { - const requestChannelListenerFakesForMain = new Map< - string, - RequestChannelListener> - >(); - - mainDi.override( - enlistRequestChannelListenerInjectableInMain, - - () => (listener) => { - if (requestChannelListenerFakesForMain.has(listener.channel.id)) { - throw new Error( - `Tried to enlist listener for channel "${listener.channel.id}", but it was already enlisted`, - ); - } - - requestChannelListenerFakesForMain.set(listener.channel.id, listener); - - return () => { - requestChannelListenerFakesForMain.delete(listener.channel.id); - }; - }, - ); - - return (windowDi: DiContainer) => { - windowDi.override( - requestFromChannelInjectable, - - () => (async (channel, request) => { - const requestListener = requestChannelListenerFakesForMain.get(channel.id); - - if (!requestListener) { - throw new Error( - `Tried to get value from channel "${channel.id}", but no listeners were registered`, - ); - } - - try { - request = deserialize(serialize(request)); - } catch (error) { - throw new Error(`Tried to request from channel "${channel.id}" with data that is not compatible with StructuredClone: ${error}`); - } - - return requestListener.handler(request); - }) as RequestFromChannel, - ); - }; -}; diff --git a/packages/infrastructure/eslint-config/bin/lint b/packages/infrastructure/eslint-config/bin/lint index 2abf180561..22d262e0cb 100755 --- a/packages/infrastructure/eslint-config/bin/lint +++ b/packages/infrastructure/eslint-config/bin/lint @@ -8,13 +8,7 @@ const shouldDoTheFix = argv.includes('--fix'); try { execSync(`eslint ${shouldDoTheFix ? "--fix " : " "}--ext ts,tsx --max-warnings=0 .`); } catch (error) { - console.log(error.stdout.toString()); -} + console.error(error.stdout.toString()); -try { - const result = execSync(`prettier ${shouldDoTheFix ? "--write" : "--check"} "**/*.{js,ts,tsx}"`); - - console.log(result.toString()); -} catch (error) { - console.log(error.stdout.toString()); + process.exit(1); } diff --git a/packages/infrastructure/eslint-config/eslint-config.js b/packages/infrastructure/eslint-config/eslint-config.js index 561541838d..2e59a31da7 100644 --- a/packages/infrastructure/eslint-config/eslint-config.js +++ b/packages/infrastructure/eslint-config/eslint-config.js @@ -15,6 +15,7 @@ module.exports = { "xss", "no-unsanitized" ], + ignorePatterns: ["dist/*"], rules: { "react/react-in-jsx-scope": 0, "security/detect-object-injection": "off", @@ -125,7 +126,7 @@ module.exports = { "@typescript-eslint/ban-types": "off", "@typescript-eslint/ban-ts-comment": "off", "@typescript-eslint/no-empty-interface": "off", - "@typescript-eslint/no-floating-promises": "error", + "@typescript-eslint/no-floating-promises": "off", "@typescript-eslint/interface-name-prefix": "off", "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/explicit-module-boundary-types": "off", diff --git a/packages/infrastructure/jest/jest-28-resolver.js b/packages/infrastructure/jest/jest-28-resolver.js new file mode 100644 index 0000000000..118a17f09d --- /dev/null +++ b/packages/infrastructure/jest/jest-28-resolver.js @@ -0,0 +1,34 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +module.exports = (path, options) => { + // Call the defaultResolver, so we leverage its cache, error handling, etc. + return options.defaultResolver(path, { + ...options, + // Use packageFilter to process parsed `package.json` before the resolution (see https://www.npmjs.com/package/resolve#resolveid-opts-cb) + packageFilter: pkg => { + // This is a workaround for https://github.com/uuidjs/uuid/pull/616 + // + // jest-environment-jsdom 28+ tries to use browser exports instead of default exports, + // but uuid only offers an ESM browser export and not a CommonJS one. Jest does not yet + // support ESM modules natively, so this causes a Jest error related to trying to parse + // "export" syntax. + // + // This workaround prevents Jest from considering uuid's module-based exports at all; + // it falls back to uuid's CommonJS+node "main" property. + // + // Once we're able to migrate our Jest config to ESM and a browser crypto + // implementation is available for the browser+ESM version of uuid to use (eg, via + // https://github.com/jsdom/jsdom/pull/3352 or a similar polyfill), this can go away. + switch (pkg.name) { + case "uuid": + delete pkg["exports"]; + delete pkg["module"]; + break; + } + + return pkg; + }, + }); +}; diff --git a/packages/infrastructure/jest/monorepo-package-config.js b/packages/infrastructure/jest/monorepo-package-config.js index 6c68fcd8d8..17b24ba342 100644 --- a/packages/infrastructure/jest/monorepo-package-config.js +++ b/packages/infrastructure/jest/monorepo-package-config.js @@ -1,5 +1,9 @@ +const path = require('path'); + module.exports = (rootDir) => { const shared = { + "resolver": path.join(__dirname, "jest-28-resolver.js"), + transform: { "^.+\\.(t|j)sx?$": ["@swc/jest", { cwd: rootDir }], }, @@ -15,6 +19,8 @@ module.exports = (rootDir) => { collectCoverageFrom: [ "/src/**/*.{ts,tsx}", "!/src/**/*.no-coverage.ts", + "!/src/**/test-utils/**/*.{ts,tsx}", + "!/src/**/index.{ts,tsx}", ], moduleNameMapper: { diff --git a/packages/legacy-extension-example/jest.config.js b/packages/legacy-extension-example/jest.config.js index c6074967eb..6d3d6ff231 100644 --- a/packages/legacy-extension-example/jest.config.js +++ b/packages/legacy-extension-example/jest.config.js @@ -1 +1,2 @@ -module.exports = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForNode; +module.exports = + require("@k8slens/jest").monorepoPackageConfig(__dirname).configForNode; diff --git a/packages/legacy-extension-example/package.json b/packages/legacy-extension-example/package.json index 857be916fa..e175eeb1f1 100644 --- a/packages/legacy-extension-example/package.json +++ b/packages/legacy-extension-example/package.json @@ -33,7 +33,6 @@ "clean": "rimraf dist/", "build": "webpack --config webpack.ts", "dev": "webpack --mode=development --watch --config webpack.ts", - "test": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" }, diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index 539f3ecb55..f59563de3f 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -203,7 +203,11 @@ "@k8slens/generate-tray-icons": "^6.5.0-alpha.1", "@k8slens/legacy-extension-example": "^1.0.0-alpha.1", "@k8slens/legacy-extensions": "^1.0.0-alpha.1", + "@k8slens/messaging": "^1.0.0-alpha.1", + "@k8slens/messaging-for-main": "^1.0.0-alpha.1", + "@k8slens/messaging-for-renderer": "^1.0.0-alpha.1", "@k8slens/run-many": "^1.0.0-alpha.1", + "@k8slens/startable-stoppable": "^1.0.0-alpha.1", "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", "@ogre-tools/fp": "^15.1.2", diff --git a/packages/open-lens/src/main/index.ts b/packages/open-lens/src/main/index.ts index 5329be4595..84e187ba5c 100644 --- a/packages/open-lens/src/main/index.ts +++ b/packages/open-lens/src/main/index.ts @@ -10,6 +10,7 @@ import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; import { registerFeature } from "@k8slens/feature-core"; import { applicationFeature, startApplicationInjectionToken } from '@k8slens/application' import { applicationFeatureForElectronMain } from '@k8slens/application-for-electron-main' +import { messagingFeatureForMain } from "@k8slens/messaging-for-main"; const environment = "main"; @@ -20,7 +21,7 @@ registerMobX(di); runInAction(() => { registerLensCore(di, environment); - registerFeature(di, applicationFeature, applicationFeatureForElectronMain); + registerFeature(di, applicationFeature, applicationFeatureForElectronMain, messagingFeatureForMain); try { autoRegister({ diff --git a/packages/open-lens/src/renderer/index.ts b/packages/open-lens/src/renderer/index.ts index 9f0770de26..207fc2265c 100644 --- a/packages/open-lens/src/renderer/index.ts +++ b/packages/open-lens/src/renderer/index.ts @@ -14,6 +14,7 @@ import { import { createContainer } from "@ogre-tools/injectable"; import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; import { registerInjectableReact } from "@ogre-tools/injectable-react"; +import { messagingFeatureForRenderer } from "@k8slens/messaging-for-renderer"; const environment = "renderer"; @@ -23,7 +24,7 @@ runInAction(() => { registerMobX(di); registerInjectableReact(di); registerLensCore(di, environment); - registerFeature(di, applicationFeature); + registerFeature(di, applicationFeature, messagingFeatureForRenderer); autoRegister({ di, diff --git a/packages/technical-features/application/agnostic/index.ts b/packages/technical-features/application/agnostic/index.ts index 239e938cd2..2e5595a816 100644 --- a/packages/technical-features/application/agnostic/index.ts +++ b/packages/technical-features/application/agnostic/index.ts @@ -5,5 +5,5 @@ export * from "./src/start-application/time-slots"; export type { StartApplication } from "./src/start-application/start-application.injectable"; export { startApplicationInjectionToken } from "./src/start-application/start-application.injectable"; -export { applicationInformationToken } from "./src/application-information-token"; -export type { ApplicationInformation } from "./src/application-information-token"; +export { applicationInformationToken } from "./src/application-information-token.no-coverage"; +export type { ApplicationInformation } from "./src/application-information-token.no-coverage"; diff --git a/packages/technical-features/application/agnostic/package.json b/packages/technical-features/application/agnostic/package.json index 78069b1ae6..ab869a87c0 100644 --- a/packages/technical-features/application/agnostic/package.json +++ b/packages/technical-features/application/agnostic/package.json @@ -26,7 +26,7 @@ "scripts": { "build": "webpack", "dev": "webpack --mode=development --watch", - "test": "jest --coverage --runInBand", + "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" }, diff --git a/packages/technical-features/application/agnostic/src/application-information-token.ts b/packages/technical-features/application/agnostic/src/application-information-token.no-coverage.ts similarity index 100% rename from packages/technical-features/application/agnostic/src/application-information-token.ts rename to packages/technical-features/application/agnostic/src/application-information-token.no-coverage.ts diff --git a/packages/technical-features/application/agnostic/src/start-application/start-application.injectable.ts b/packages/technical-features/application/agnostic/src/start-application/start-application.injectable.ts index 895462f08e..87f6d1f7db 100644 --- a/packages/technical-features/application/agnostic/src/start-application/start-application.injectable.ts +++ b/packages/technical-features/application/agnostic/src/start-application/start-application.injectable.ts @@ -4,17 +4,18 @@ import * as timeSlots from "./time-slots"; export type StartApplication = () => Promise; -export const startApplicationInjectionToken = - getInjectionToken({ - id: "start-application-injection-token", - }); +export const startApplicationInjectionToken = getInjectionToken({ + id: "start-application-injection-token", +}); const startApplicationInjectable = getInjectable({ id: "start-application", instantiate: (di): StartApplication => { - const runManyAsync = runManyFor(di) - const beforeApplicationIsLoading = runManyAsync(timeSlots.beforeApplicationIsLoadingInjectionToken); + const runManyAsync = runManyFor(di); + const beforeApplicationIsLoading = runManyAsync( + timeSlots.beforeApplicationIsLoadingInjectionToken, + ); const onLoadOfApplication = runManyAsync(timeSlots.onLoadOfApplicationInjectionToken); const afterApplicationIsLoaded = runManyAsync(timeSlots.afterApplicationIsLoadedInjectionToken); diff --git a/packages/technical-features/application/agnostic/src/start-application/starting-of-application.test.ts b/packages/technical-features/application/agnostic/src/start-application/starting-of-application.test.ts index 69219d4a08..672e3a0f01 100644 --- a/packages/technical-features/application/agnostic/src/start-application/starting-of-application.test.ts +++ b/packages/technical-features/application/agnostic/src/start-application/starting-of-application.test.ts @@ -4,6 +4,7 @@ import { applicationFeature } from "../feature"; import { startApplicationInjectionToken } from "./start-application.injectable"; import * as timeSlots from "./time-slots"; import asyncFn, { AsyncFnMock } from "@async-fn/jest"; +import { getPromiseStatus } from "@k8slens/test-utils"; describe("starting-of-application", () => { let di: DiContainer; @@ -47,10 +48,12 @@ describe("starting-of-application", () => { }); describe("when application is started", () => { + let actualPromise: Promise; + beforeEach(() => { const startApplication = di.inject(startApplicationInjectionToken); - void startApplication(); + actualPromise = startApplication(); }); it("calls runnables registered in before application is loading", () => { @@ -66,10 +69,28 @@ describe("starting-of-application", () => { expect(onLoadOfApplicationMock).toHaveBeenCalled(); }); - it("when runnables in before application is loading resolve, calls runnables registered in after load of application", async () => { - await onLoadOfApplicationMock.resolve(); + describe("when runnables in before application is loading resolve", () => { + beforeEach(async () => { + await onLoadOfApplicationMock.resolve(); + }); - expect(afterApplicationIsLoadedMock).toHaveBeenCalled(); + it("calls runnables registered in after load of application", async () => { + expect(afterApplicationIsLoadedMock).toHaveBeenCalled(); + }); + + it("does not resolve yet", async () => { + const promiseStatus = await getPromiseStatus(actualPromise); + + expect(promiseStatus.fulfilled).toBe(false); + }); + + it("when runnables in after application is loaded resolve, resolves", async () => { + await afterApplicationIsLoadedMock.resolve(); + + const promiseStatus = await getPromiseStatus(actualPromise); + + expect(promiseStatus.fulfilled).toBe(true); + }); }); }); }); diff --git a/packages/technical-features/application/electron-main/index.ts b/packages/technical-features/application/electron-main/index.ts index 238b564a47..da354760c2 100644 --- a/packages/technical-features/application/electron-main/index.ts +++ b/packages/technical-features/application/electron-main/index.ts @@ -1,4 +1,4 @@ -import { overrideSideEffectsWithFakes } from "./src/override-side-effects-with-fakes"; +import { overrideSideEffectsWithFakes } from "./src/test-utils/override-side-effects-with-fakes"; export * from "./src/start-application/time-slots"; diff --git a/packages/technical-features/application/electron-main/package.json b/packages/technical-features/application/electron-main/package.json index 625c23fe93..f32de6f301 100644 --- a/packages/technical-features/application/electron-main/package.json +++ b/packages/technical-features/application/electron-main/package.json @@ -26,7 +26,7 @@ "scripts": { "build": "webpack", "dev": "webpack --mode=development --watch", - "test": "jest --coverage --runInBand", + "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" }, diff --git a/packages/technical-features/application/electron-main/src/override-side-effects-with-fakes.ts b/packages/technical-features/application/electron-main/src/test-utils/override-side-effects-with-fakes.ts similarity index 69% rename from packages/technical-features/application/electron-main/src/override-side-effects-with-fakes.ts rename to packages/technical-features/application/electron-main/src/test-utils/override-side-effects-with-fakes.ts index a795dbd04b..8873bf7f99 100644 --- a/packages/technical-features/application/electron-main/src/override-side-effects-with-fakes.ts +++ b/packages/technical-features/application/electron-main/src/test-utils/override-side-effects-with-fakes.ts @@ -1,5 +1,5 @@ import type { DiContainer } from "@ogre-tools/injectable"; -import whenAppIsReadyInjectable from "./start-application/when-app-is-ready.injectable"; +import whenAppIsReadyInjectable from "../start-application/when-app-is-ready.injectable"; export const overrideSideEffectsWithFakes = (di: DiContainer) => { di.override(whenAppIsReadyInjectable, () => () => Promise.resolve()); diff --git a/packages/technical-features/application/legacy-extensions/jest.config.js b/packages/technical-features/application/legacy-extensions/jest.config.js index c6074967eb..6d3d6ff231 100644 --- a/packages/technical-features/application/legacy-extensions/jest.config.js +++ b/packages/technical-features/application/legacy-extensions/jest.config.js @@ -1 +1,2 @@ -module.exports = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForNode; +module.exports = + require("@k8slens/jest").monorepoPackageConfig(__dirname).configForNode; diff --git a/packages/technical-features/application/legacy-extensions/package.json b/packages/technical-features/application/legacy-extensions/package.json index 5b7c436da5..6e92ca7c02 100644 --- a/packages/technical-features/application/legacy-extensions/package.json +++ b/packages/technical-features/application/legacy-extensions/package.json @@ -26,7 +26,6 @@ "scripts": { "build": "webpack", "dev": "webpack --mode=development --watch", - "test": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" }, diff --git a/packages/technical-features/feature-core/package.json b/packages/technical-features/feature-core/package.json index 59f4186c6d..cabb6e17a0 100644 --- a/packages/technical-features/feature-core/package.json +++ b/packages/technical-features/feature-core/package.json @@ -26,7 +26,7 @@ "scripts": { "build": "webpack", "dev": "webpack --mode=development --watch", - "test": "jest --coverage --runInBand", + "test:unit": "jest --coverage --runInBand", "lint": "lens-lint", "lint:fix": "lens-lint --fix" }, diff --git a/packages/technical-features/messaging/agnostic/.eslintrc.json b/packages/technical-features/messaging/agnostic/.eslintrc.json new file mode 100644 index 0000000000..b15115cb69 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "@k8slens/eslint-config/eslint", + "parserOptions": { + "project": "./tsconfig.json" + } +} diff --git a/packages/technical-features/messaging/agnostic/.prettierrc b/packages/technical-features/messaging/agnostic/.prettierrc new file mode 100644 index 0000000000..edd47b479e --- /dev/null +++ b/packages/technical-features/messaging/agnostic/.prettierrc @@ -0,0 +1 @@ +"@k8slens/eslint-config/prettier" diff --git a/packages/technical-features/messaging/agnostic/index.ts b/packages/technical-features/messaging/agnostic/index.ts new file mode 100644 index 0000000000..75b20812f1 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/index.ts @@ -0,0 +1,2 @@ +export * from "./src/features/actual"; +export * as testUtils from "./src/features/unit-testing"; diff --git a/packages/technical-features/messaging/agnostic/jest.config.js b/packages/technical-features/messaging/agnostic/jest.config.js new file mode 100644 index 0000000000..38d54ab7b6 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/jest.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; diff --git a/packages/technical-features/messaging/agnostic/package.json b/packages/technical-features/messaging/agnostic/package.json new file mode 100644 index 0000000000..085304d4e0 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/package.json @@ -0,0 +1,49 @@ +{ + "name": "@k8slens/messaging", + "private": false, + "version": "1.0.0-alpha.1", + "description": "An abstraction for messaging between Lens environments", + "type": "commonjs", + + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + + "files": [ + "dist" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/lensapp/lens.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "build": "webpack", + "dev": "webpack --mode=development --watch", + "test:unit": "jest --coverage --runInBand", + "lint:fix": "lens-lint --fix", + "lint": "lens-lint" + }, + "peerDependencies": { + "@k8slens/application": "^6.5.0-alpha.0", + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@k8slens/startable-stoppable": "^1.0.0-alpha.1", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", + "lodash": "^4.17.21", + "mobx": "^6.7.0" + }, + + "devDependencies": { + "@k8slens/eslint-config": "^6.5.0-alpha.1" + } +} diff --git a/packages/core/src/common/utils/channel/channel-injection-token.ts b/packages/technical-features/messaging/agnostic/src/features/actual/channel.no-coverage.ts similarity index 52% rename from packages/core/src/common/utils/channel/channel-injection-token.ts rename to packages/technical-features/messaging/agnostic/src/features/actual/channel.no-coverage.ts index 6006290f89..62a2ea1490 100644 --- a/packages/core/src/common/utils/channel/channel-injection-token.ts +++ b/packages/technical-features/messaging/agnostic/src/features/actual/channel.no-coverage.ts @@ -1,12 +1,5 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - - export interface Channel { id: string; _messageTemplate?: MessageTemplate; _returnTemplate?: ReturnTemplate; } - diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/feature.ts b/packages/technical-features/messaging/agnostic/src/features/actual/feature.ts new file mode 100644 index 0000000000..5f302e1bcd --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/actual/feature.ts @@ -0,0 +1,18 @@ +import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration"; +import { applicationFeature } from "@k8slens/application"; +import { getFeature } from "@k8slens/feature-core"; + +export const messagingFeature = getFeature({ + id: "messaging", + + dependencies: [applicationFeature], + + register: (di) => { + autoRegister({ + di, + targetModule: module, + + getRequireContexts: () => [require.context("./", true, /\.injectable\.(ts|tsx)$/)], + }); + }, +}); diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/index.ts b/packages/technical-features/messaging/agnostic/src/features/actual/index.ts new file mode 100644 index 0000000000..e8209f26f0 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/actual/index.ts @@ -0,0 +1,53 @@ +/* c8 ignore next */ +export { messagingFeature } from "./feature"; + +export { getRequestChannel } from "./request/get-request-channel"; +export { getMessageChannel } from "./message/get-message-channel"; + +export { requestFromChannelInjectionToken } from "./request/request-from-channel-injection-token"; + +export type { Channel } from "./channel.no-coverage"; + +export { sendMessageToChannelInjectionToken } from "./message/message-to-channel-injection-token"; +export type { SendMessageToChannel } from "./message/message-to-channel-injection-token"; + +export type { + GetMessageChannelListenerInfo, + MessageChannel, + MessageChannelHandler, + MessageChannelListener, +} from "./message/message-channel-listener-injection-token"; + +export { + messageChannelListenerInjectionToken, + getMessageChannelListenerInjectable, +} from "./message/message-channel-listener-injection-token"; + +export type { + RequestChannel, + RequestChannelHandler, +} from "./request/request-channel-listener-injection-token"; + +export type { + RequestFromChannel, + ChannelRequester, +} from "./request/request-from-channel-injection-token"; + +export type { EnlistMessageChannelListener } from "./message/enlist-message-channel-listener-injection-token"; +export { enlistMessageChannelListenerInjectionToken } from "./message/enlist-message-channel-listener-injection-token"; + +export type { EnlistRequestChannelListener } from "./request/enlist-request-channel-listener-injection-token"; +export { enlistRequestChannelListenerInjectionToken } from "./request/enlist-request-channel-listener-injection-token"; + +export type { ListeningOfChannels } from "./listening-of-channels/listening-of-channels.injectable"; +export { listeningOfChannelsInjectionToken } from "./listening-of-channels/listening-of-channels.injectable"; + +export type { + GetRequestChannelListenerInjectableInfo, + RequestChannelListener, +} from "./request/request-channel-listener-injection-token"; + +export { + getRequestChannelListenerInjectable, + requestChannelListenerInjectionToken, +} from "./request/request-channel-listener-injection-token"; diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/listening-of-channels.injectable.ts b/packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/listening-of-channels.injectable.ts new file mode 100644 index 0000000000..c28d6cbc5a --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/listening-of-channels.injectable.ts @@ -0,0 +1,106 @@ +import { getInjectable, getInjectionToken } from "@ogre-tools/injectable"; +import { enlistMessageChannelListenerInjectionToken } from "../message/enlist-message-channel-listener-injection-token"; + +import { getStartableStoppable, StartableStoppable } from "@k8slens/startable-stoppable"; + +import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx"; +import { IComputedValue, reaction } from "mobx"; + +import { messageChannelListenerInjectionToken } from "../message/message-channel-listener-injection-token"; +import { requestChannelListenerInjectionToken } from "../request/request-channel-listener-injection-token"; +import { enlistRequestChannelListenerInjectionToken } from "../request/enlist-request-channel-listener-injection-token"; +import type { Channel } from "../channel.no-coverage"; + +export type ListeningOfChannels = StartableStoppable; +export const listeningOfChannelsInjectionToken = getInjectionToken({ + id: "listening-of-channels-injection-token", +}); + +const listening = }>( + channelListeners: IComputedValue, + enlistChannelListener: (listener: T) => () => void, + getId: (listener: T) => string, +) => { + const listenerDisposers = new Map void>(); + + const reactionDisposer = reaction( + () => channelListeners.get(), + (newValues, oldValues = []) => { + const addedListeners = newValues.filter( + (newValue) => !oldValues.some((oldValue) => oldValue.id === newValue.id), + ); + + const removedListeners = oldValues.filter( + (oldValue) => !newValues.some((newValue) => newValue.id === oldValue.id), + ); + + addedListeners.forEach((listener) => { + const id = getId(listener); + + if (listenerDisposers.has(id)) { + throw new Error( + `Tried to add listener for channel "${listener.channel.id}" but listener already exists.`, + ); + } + + const disposer = enlistChannelListener(listener); + + listenerDisposers.set(id, disposer); + }); + + removedListeners.forEach((listener) => { + const dispose = listenerDisposers.get(getId(listener)); + + dispose?.(); + + listenerDisposers.delete(getId(listener)); + }); + }, + + { fireImmediately: true }, + ); + + return () => { + reactionDisposer(); + listenerDisposers.forEach((dispose) => dispose()); + }; +}; + +const listeningOfChannelsInjectable = getInjectable({ + id: "listening-of-channels", + + instantiate: (di) => { + const enlistMessageChannelListener = di.inject(enlistMessageChannelListenerInjectionToken); + + const enlistRequestChannelListener = di.inject(enlistRequestChannelListenerInjectionToken); + + const computedInjectMany = di.inject(computedInjectManyInjectable); + + const messageChannelListeners = computedInjectMany(messageChannelListenerInjectionToken); + + const requestChannelListeners = computedInjectMany(requestChannelListenerInjectionToken); + + return getStartableStoppable("listening-of-channels", () => { + const stopListeningOfMessageChannels = listening( + messageChannelListeners, + enlistMessageChannelListener, + (x) => x.id, + ); + + const stopListeningOfRequestChannels = listening( + requestChannelListeners, + enlistRequestChannelListener, + (x) => x.channel.id, + ); + + return () => { + stopListeningOfMessageChannels(); + stopListeningOfRequestChannels(); + }; + }); + }, + + injectionToken: listeningOfChannelsInjectionToken, +}); + +export default listeningOfChannelsInjectable; diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/start-listening-of-channels.injectable.ts b/packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/start-listening-of-channels.injectable.ts new file mode 100644 index 0000000000..eb265b1ca2 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/actual/listening-of-channels/start-listening-of-channels.injectable.ts @@ -0,0 +1,21 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; +import { listeningOfChannelsInjectionToken } from "./listening-of-channels.injectable"; + +const startListeningOfChannelsInjectable = getInjectable({ + id: "start-listening-of-channels", + + instantiate: (di) => { + const listeningOfChannels = di.inject(listeningOfChannelsInjectionToken); + + return { + run: async () => { + await listeningOfChannels.start(); + }, + }; + }, + + injectionToken: onLoadOfApplicationInjectionToken, +}); + +export default startListeningOfChannelsInjectable; diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/message/enlist-message-channel-listener-injection-token.ts b/packages/technical-features/messaging/agnostic/src/features/actual/message/enlist-message-channel-listener-injection-token.ts new file mode 100644 index 0000000000..9ec6f8b93a --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/actual/message/enlist-message-channel-listener-injection-token.ts @@ -0,0 +1,15 @@ +import { getInjectionToken } from "@ogre-tools/injectable"; + +import type { + MessageChannel, + MessageChannelListener, +} from "./message-channel-listener-injection-token"; + +export type EnlistMessageChannelListener = ( + listener: MessageChannelListener>, +) => () => void; + +export const enlistMessageChannelListenerInjectionToken = + getInjectionToken({ + id: "listening-to-a-message-channel", + }); diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/message/get-message-channel.ts b/packages/technical-features/messaging/agnostic/src/features/actual/message/get-message-channel.ts new file mode 100644 index 0000000000..076a7af464 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/actual/message/get-message-channel.ts @@ -0,0 +1,5 @@ +import type { MessageChannel } from "./message-channel-listener-injection-token"; + +export const getMessageChannel = (id: string): MessageChannel => ({ + id, +}); diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/message/message-channel-listener-injection-token.ts b/packages/technical-features/messaging/agnostic/src/features/actual/message/message-channel-listener-injection-token.ts new file mode 100644 index 0000000000..386c9f9e5e --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/actual/message/message-channel-listener-injection-token.ts @@ -0,0 +1,51 @@ +import type { DiContainerForInjection } from "@ogre-tools/injectable"; +import { getInjectable, getInjectionToken } from "@ogre-tools/injectable"; + +export interface MessageChannel { + id: string; + _messageSignature?: Message; +} + +export type ExtraData = { processId: number; frameId: number }; + +export type MessageChannelHandler = Channel extends MessageChannel + ? (message: Message, data: ExtraData) => void + : never; + +export interface MessageChannelListener { + id: string; + channel: Channel; + handler: MessageChannelHandler; +} + +export const messageChannelListenerInjectionToken = getInjectionToken< + MessageChannelListener> +>({ + id: "message-channel-listener", +}); + +export interface GetMessageChannelListenerInfo, Message> { + id: string; + channel: Channel; + getHandler: (di: DiContainerForInjection) => MessageChannelHandler; + causesSideEffects?: boolean; +} + +export const getMessageChannelListenerInjectable = < + Channel extends MessageChannel, + Message, +>( + info: GetMessageChannelListenerInfo, +) => + getInjectable({ + id: `${info.channel.id}-message-listener-${info.id}`, + + instantiate: (di): MessageChannelListener => ({ + id: `${info.channel.id}-message-listener-${info.id}`, + channel: info.channel, + handler: info.getHandler(di), + }), + + injectionToken: messageChannelListenerInjectionToken, + causesSideEffects: info.causesSideEffects, + }); diff --git a/packages/core/src/common/utils/channel/message-to-channel-injection-token.ts b/packages/technical-features/messaging/agnostic/src/features/actual/message/message-to-channel-injection-token.ts similarity index 55% rename from packages/core/src/common/utils/channel/message-to-channel-injection-token.ts rename to packages/technical-features/messaging/agnostic/src/features/actual/message/message-to-channel-injection-token.ts index 3ffd75f4f7..9cb5df4986 100644 --- a/packages/core/src/common/utils/channel/message-to-channel-injection-token.ts +++ b/packages/technical-features/messaging/agnostic/src/features/actual/message/message-to-channel-injection-token.ts @@ -1,7 +1,3 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ import { getInjectionToken } from "@ogre-tools/injectable"; import type { MessageChannel } from "./message-channel-listener-injection-token"; @@ -10,12 +6,6 @@ export interface SendMessageToChannel { (channel: MessageChannel, message: Message): void; } -export type MessageChannelSender = Channel extends MessageChannel - ? () => void - : Channel extends MessageChannel - ? (message: Message) => void - : never; - export const sendMessageToChannelInjectionToken = getInjectionToken({ id: "send-message-to-message-channel", }); diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/request/enlist-request-channel-listener-injection-token.ts b/packages/technical-features/messaging/agnostic/src/features/actual/request/enlist-request-channel-listener-injection-token.ts new file mode 100644 index 0000000000..cdb3ac97d5 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/actual/request/enlist-request-channel-listener-injection-token.ts @@ -0,0 +1,15 @@ +import { getInjectionToken } from "@ogre-tools/injectable"; + +import type { + RequestChannel, + RequestChannelListener, +} from "./request-channel-listener-injection-token"; + +export type EnlistRequestChannelListener = ( + listener: RequestChannelListener>, +) => () => void; + +export const enlistRequestChannelListenerInjectionToken = + getInjectionToken({ + id: "listening-to-a-request-channel", + }); diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/request/get-request-channel.ts b/packages/technical-features/messaging/agnostic/src/features/actual/request/get-request-channel.ts new file mode 100644 index 0000000000..c0ee40bcf4 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/actual/request/get-request-channel.ts @@ -0,0 +1,7 @@ +import type { RequestChannel } from "./request-channel-listener-injection-token"; + +export const getRequestChannel = ( + id: string, +): RequestChannel => ({ + id, +}); diff --git a/packages/core/src/main/utils/channel/channel-listeners/listener-tokens.ts b/packages/technical-features/messaging/agnostic/src/features/actual/request/request-channel-listener-injection-token.ts similarity index 56% rename from packages/core/src/main/utils/channel/channel-listeners/listener-tokens.ts rename to packages/technical-features/messaging/agnostic/src/features/actual/request/request-channel-listener-injection-token.ts index a3cd5af4f4..2ec76ff546 100644 --- a/packages/core/src/main/utils/channel/channel-listeners/listener-tokens.ts +++ b/packages/technical-features/messaging/agnostic/src/features/actual/request/request-channel-listener-injection-token.ts @@ -1,23 +1,28 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - import type { DiContainerForInjection } from "@ogre-tools/injectable"; import { getInjectable, getInjectionToken } from "@ogre-tools/injectable"; -import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token"; -export type RequestChannelHandler = Channel extends RequestChannel +export interface RequestChannel { + id: string; + _requestSignature?: Request; + _responseSignature?: Response; +} + +export type RequestChannelHandler = Channel extends RequestChannel< + infer Request, + infer Response +> ? (req: Request) => Promise | Response : never; export interface RequestChannelListener { + id: string; channel: Channel; handler: RequestChannelHandler; } - -export const requestChannelListenerInjectionToken = getInjectionToken>>( { +export const requestChannelListenerInjectionToken = getInjectionToken< + RequestChannelListener> +>({ id: "request-channel-listener", }); @@ -26,21 +31,26 @@ export interface GetRequestChannelListenerInjectableInfo< Request, Response, > { + id: string; channel: Channel; - handler: (di: DiContainerForInjection) => RequestChannelHandler; + getHandler: (di: DiContainerForInjection) => RequestChannelHandler; } -export function getRequestChannelListenerInjectable< +export const getRequestChannelListenerInjectable = < Channel extends RequestChannel, Request, Response, ->(info: GetRequestChannelListenerInjectableInfo) { - return getInjectable({ - id: `${info.channel.id}-listener`, +>( + info: GetRequestChannelListenerInjectableInfo, +) => + getInjectable({ + id: `${info.channel.id}-request-listener-${info.id}`, + instantiate: (di) => ({ + id: `${info.channel.id}-request-listener-${info.id}`, channel: info.channel, - handler: info.handler(di), + handler: info.getHandler(di), }), + injectionToken: requestChannelListenerInjectionToken, }); -} diff --git a/packages/core/src/common/utils/channel/request-from-channel-injection-token.ts b/packages/technical-features/messaging/agnostic/src/features/actual/request/request-from-channel-injection-token.ts similarity index 53% rename from packages/core/src/common/utils/channel/request-from-channel-injection-token.ts rename to packages/technical-features/messaging/agnostic/src/features/actual/request/request-from-channel-injection-token.ts index 939cc23f9d..194091b588 100644 --- a/packages/core/src/common/utils/channel/request-from-channel-injection-token.ts +++ b/packages/technical-features/messaging/agnostic/src/features/actual/request/request-from-channel-injection-token.ts @@ -1,16 +1,18 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ import { getInjectionToken } from "@ogre-tools/injectable"; import type { RequestChannel } from "./request-channel-listener-injection-token"; export interface RequestFromChannel { - (channel: RequestChannel, request: Request): Promise>; - (channel: RequestChannel): Promise>; + ( + channel: RequestChannel, + request: Request, + ): Promise; + (channel: RequestChannel): Promise; } -export type ChannelRequester = Channel extends RequestChannel +export type ChannelRequester = Channel extends RequestChannel< + infer Request, + infer Response +> ? (req: Request) => Promise> : never; diff --git a/packages/technical-features/messaging/agnostic/src/features/unit-testing/feature.ts b/packages/technical-features/messaging/agnostic/src/features/unit-testing/feature.ts new file mode 100644 index 0000000000..ca6ddd2b2e --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/unit-testing/feature.ts @@ -0,0 +1,18 @@ +import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration"; +import { getFeature } from "@k8slens/feature-core"; +import { messagingFeature } from "../actual/feature"; + +export const messagingFeatureForUnitTesting = getFeature({ + id: "messaging-for-unit-testing", + + dependencies: [messagingFeature], + + register: (di) => { + autoRegister({ + di, + targetModule: module, + + getRequireContexts: () => [require.context("./", true, /\.injectable\.(ts|tsx)$/)], + }); + }, +}); diff --git a/packages/technical-features/messaging/agnostic/src/features/unit-testing/index.ts b/packages/technical-features/messaging/agnostic/src/features/unit-testing/index.ts new file mode 100644 index 0000000000..e0ee8eb25b --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/unit-testing/index.ts @@ -0,0 +1 @@ +export { messagingFeatureForUnitTesting } from "./feature"; diff --git a/packages/technical-features/messaging/agnostic/src/features/unit-testing/test-doubles.injectable.ts b/packages/technical-features/messaging/agnostic/src/features/unit-testing/test-doubles.injectable.ts new file mode 100644 index 0000000000..621e088a4b --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/features/unit-testing/test-doubles.injectable.ts @@ -0,0 +1,31 @@ +import { sendMessageToChannelInjectionToken } from "../actual/message/message-to-channel-injection-token"; +import { enlistMessageChannelListenerInjectionToken } from "../actual/message/enlist-message-channel-listener-injection-token"; +import { requestFromChannelInjectionToken } from "../actual/request/request-from-channel-injection-token"; +import { enlistRequestChannelListenerInjectionToken } from "../actual/request/enlist-request-channel-listener-injection-token"; +import { getInjectable } from "@ogre-tools/injectable"; + +export const sendMessageToChannelStubInjectable = getInjectable({ + id: "send-message-to-channel-stub", + /* c8 ignore next */ + instantiate: () => () => {}, + injectionToken: sendMessageToChannelInjectionToken, +}); + +export const enlistMessageChannelListenerStubInjectable = getInjectable({ + id: "enlist-message-channel-listener-stub", + instantiate: () => () => () => {}, + injectionToken: enlistMessageChannelListenerInjectionToken, +}); + +export const requestFromChannelStubInjectable = getInjectable({ + id: "request-from-channel-stub", + /* c8 ignore next */ + instantiate: () => () => Promise.resolve(), + injectionToken: requestFromChannelInjectionToken, +}); + +export const enlistRequestChannelListenerStubInjectable = getInjectable({ + id: "enlist-request-channel-listener-stub", + instantiate: () => () => () => {}, + injectionToken: enlistRequestChannelListenerInjectionToken, +}); diff --git a/packages/technical-features/messaging/agnostic/src/listening-of-messages.test.ts b/packages/technical-features/messaging/agnostic/src/listening-of-messages.test.ts new file mode 100644 index 0000000000..8dc25fa41e --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/listening-of-messages.test.ts @@ -0,0 +1,169 @@ +import { createContainer, DiContainer, Injectable } from "@ogre-tools/injectable"; + +import { registerFeature } from "@k8slens/feature-core"; +import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; +import { runInAction } from "mobx"; + +import { + EnlistMessageChannelListener, + enlistMessageChannelListenerInjectionToken, +} from "./features/actual/message/enlist-message-channel-listener-injection-token"; + +import { messagingFeatureForUnitTesting } from "./features/unit-testing"; + +import { + getMessageChannelListenerInjectable, + MessageChannel, + MessageChannelListener, +} from "./features/actual/message/message-channel-listener-injection-token"; + +import { listeningOfChannelsInjectionToken } from "./features/actual/listening-of-channels/listening-of-channels.injectable"; + +import { getMessageChannel } from "./features/actual/message/get-message-channel"; +import { applicationFeature, startApplicationInjectionToken } from "@k8slens/application"; + +describe("listening-of-messages", () => { + let di: DiContainer; + let enlistMessageChannelListenerMock: jest.MockedFunction; + let disposeSomeListenerMock: jest.Mock; + let disposeSomeUnrelatedListenerMock: jest.Mock; + + beforeEach(() => { + di = createContainer("irrelevant"); + + registerMobX(di); + + disposeSomeListenerMock = jest.fn(); + disposeSomeUnrelatedListenerMock = jest.fn(); + + enlistMessageChannelListenerMock = jest.fn((listener) => + listener.id === "some-channel-id-message-listener-some-listener" + ? disposeSomeListenerMock + : disposeSomeUnrelatedListenerMock, + ); + + runInAction(() => { + registerFeature(di, applicationFeature, messagingFeatureForUnitTesting); + }); + + di.override(enlistMessageChannelListenerInjectionToken, () => enlistMessageChannelListenerMock); + }); + + describe("given listening of channels has not started yet", () => { + describe("when a new listener gets registered", () => { + let someChannel: MessageChannel; + let someMessageHandler: () => void; + + let someListenerInjectable: Injectable< + MessageChannelListener>, + MessageChannelListener> + >; + + beforeEach(() => { + someChannel = getMessageChannel("some-channel-id"); + + someMessageHandler = () => {}; + + someListenerInjectable = getMessageChannelListenerInjectable({ + id: "some-listener", + channel: someChannel, + getHandler: () => someMessageHandler, + }); + + runInAction(() => { + di.register(someListenerInjectable); + }); + }); + + describe("when application is started", () => { + beforeEach(async () => { + const startApplication = di.inject(startApplicationInjectionToken); + + await startApplication(); + }); + + it("enlists a listener for the channel", () => { + expect(enlistMessageChannelListenerMock).toHaveBeenCalledWith({ + id: "some-channel-id-message-listener-some-listener", + channel: someChannel, + handler: someMessageHandler, + }); + }); + + describe("when another listener gets registered", () => { + let someOtherListenerInjectable: Injectable< + MessageChannelListener>, + MessageChannelListener>, + void + >; + + beforeEach(() => { + const handler = () => someMessageHandler; + + someOtherListenerInjectable = getMessageChannelListenerInjectable({ + id: "some-other-listener", + channel: someChannel, + getHandler: handler, + }); + + enlistMessageChannelListenerMock.mockClear(); + + runInAction(() => { + di.register(someOtherListenerInjectable); + }); + }); + + it("only enlists it as well", () => { + expect(enlistMessageChannelListenerMock.mock.calls).toEqual([ + [ + { + id: "some-channel-id-message-listener-some-other-listener", + channel: someChannel, + handler: someMessageHandler, + }, + ], + ]); + }); + + describe("when one of the listeners gets deregistered", () => { + beforeEach(() => { + runInAction(() => { + di.deregister(someListenerInjectable); + }); + }); + + it("the listener gets disposed", () => { + expect(disposeSomeListenerMock).toHaveBeenCalled(); + }); + + it("the unrelated listener does not get disposed", () => { + expect(disposeSomeUnrelatedListenerMock).not.toHaveBeenCalled(); + }); + + describe("when listening of channels stops", () => { + beforeEach(() => { + const listening = di.inject(listeningOfChannelsInjectionToken); + + listening.stop(); + }); + + it("remaining listeners get disposed", () => { + expect(disposeSomeUnrelatedListenerMock).toHaveBeenCalled(); + }); + + it("when yet another listener gets registered, does not enlist it", () => { + enlistMessageChannelListenerMock.mockClear(); + + runInAction(() => { + di.register(someListenerInjectable); + }); + + expect(enlistMessageChannelListenerMock).not.toHaveBeenCalled(); + }); + }); + }); + }); + }); + }); + }); +}); diff --git a/packages/technical-features/messaging/agnostic/src/listening-of-requests.test.ts b/packages/technical-features/messaging/agnostic/src/listening-of-requests.test.ts new file mode 100644 index 0000000000..e708c983c8 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/src/listening-of-requests.test.ts @@ -0,0 +1,204 @@ +import { createContainer, DiContainer, Injectable } from "@ogre-tools/injectable"; + +import { registerFeature } from "@k8slens/feature-core"; +import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; +import { _resetGlobalState, configure, runInAction } from "mobx"; + +import { + EnlistRequestChannelListener, + enlistRequestChannelListenerInjectionToken, +} from "./features/actual/request/enlist-request-channel-listener-injection-token"; + +import { messagingFeatureForUnitTesting } from "./features/unit-testing"; + +import { + getRequestChannelListenerInjectable, + RequestChannel, + RequestChannelListener, +} from "./features/actual/request/request-channel-listener-injection-token"; + +import { listeningOfChannelsInjectionToken } from "./features/actual/listening-of-channels/listening-of-channels.injectable"; +import { noop } from "lodash/fp"; +import { getRequestChannel } from "./features/actual/request/get-request-channel"; +import { applicationFeature, startApplicationInjectionToken } from "@k8slens/application"; + +describe("listening-of-requests", () => { + let di: DiContainer; + let enlistRequestChannelListenerMock: jest.MockedFunction; + let disposeSomeListenerMock: jest.Mock; + let disposeSomeUnrelatedListenerMock: jest.Mock; + + beforeEach(() => { + configure({ + disableErrorBoundaries: false, + }); + + _resetGlobalState(); + + di = createContainer("irrelevant"); + + registerMobX(di); + + disposeSomeListenerMock = jest.fn(); + disposeSomeUnrelatedListenerMock = jest.fn(); + + enlistRequestChannelListenerMock = jest.fn((listener) => + listener.id === "some-channel-id-request-listener-some-listener" + ? disposeSomeListenerMock + : disposeSomeUnrelatedListenerMock, + ); + + runInAction(() => { + registerFeature(di, applicationFeature, messagingFeatureForUnitTesting); + }); + + di.override(enlistRequestChannelListenerInjectionToken, () => enlistRequestChannelListenerMock); + }); + + describe("given listening of channels has not started yet", () => { + describe("when a new listener gets registered", () => { + let someChannel: RequestChannel; + let someOtherChannel: RequestChannel; + let someRequestHandler: () => string; + + let someListenerInjectable: Injectable< + RequestChannelListener>, + RequestChannelListener> + >; + + beforeEach(() => { + someChannel = getRequestChannel("some-channel-id"); + someOtherChannel = getRequestChannel("some-other-channel-id"); + + someRequestHandler = () => "some-response"; + + someListenerInjectable = getRequestChannelListenerInjectable({ + id: "some-listener", + channel: someChannel, + getHandler: () => someRequestHandler, + }); + + runInAction(() => { + di.register(someListenerInjectable); + }); + }); + + describe("when application is started", () => { + beforeEach(async () => { + const startApplication = di.inject(startApplicationInjectionToken); + + await startApplication(); + }); + + it("enlists a listener for the channel", () => { + expect(enlistRequestChannelListenerMock).toHaveBeenCalledWith({ + id: "some-channel-id-request-listener-some-listener", + channel: someChannel, + handler: someRequestHandler, + }); + }); + + it("when another listener for same channel gets registered, throws", () => { + const originalConsoleWarn = console.warn; + + console.warn = noop; + + configure({ + disableErrorBoundaries: true, + }); + + console.warn = originalConsoleWarn; + + const handler = () => someRequestHandler; + + const someConflictingListenerInjectable = getRequestChannelListenerInjectable({ + id: "some-other-listener", + channel: someChannel, + getHandler: handler, + }); + + expect(() => { + runInAction(() => { + di.register(someConflictingListenerInjectable); + }); + }).toThrow( + 'Tried to add listener for channel "some-channel-id" but listener already exists.', + ); + }); + + describe("when another listener gets registered", () => { + let someOtherListenerInjectable: Injectable< + RequestChannelListener>, + RequestChannelListener> + >; + + beforeEach(() => { + const handler = () => someRequestHandler; + + someOtherListenerInjectable = getRequestChannelListenerInjectable({ + id: "some-other-listener", + channel: someOtherChannel, + getHandler: handler, + }); + + enlistRequestChannelListenerMock.mockClear(); + + runInAction(() => { + di.register(someOtherListenerInjectable); + }); + }); + + it("only enlists it as well", () => { + expect(enlistRequestChannelListenerMock.mock.calls).toEqual([ + [ + { + id: "some-other-channel-id-request-listener-some-other-listener", + channel: someOtherChannel, + handler: someRequestHandler, + }, + ], + ]); + }); + + describe("when one of the listeners gets deregistered", () => { + beforeEach(() => { + runInAction(() => { + di.deregister(someListenerInjectable); + }); + }); + + it("the listener gets disposed", () => { + expect(disposeSomeListenerMock).toHaveBeenCalled(); + }); + + it("the unrelated listener does not get disposed", () => { + expect(disposeSomeUnrelatedListenerMock).not.toHaveBeenCalled(); + }); + + describe("when listening of channels stops", () => { + beforeEach(() => { + const listening = di.inject(listeningOfChannelsInjectionToken); + + listening.stop(); + }); + + it("remaining listeners get disposed", () => { + expect(disposeSomeUnrelatedListenerMock).toHaveBeenCalled(); + }); + + it("when yet another listener gets registered, does not enlist it", () => { + enlistRequestChannelListenerMock.mockClear(); + + runInAction(() => { + di.register(someListenerInjectable); + }); + + expect(enlistRequestChannelListenerMock).not.toHaveBeenCalled(); + }); + }); + }); + }); + }); + }); + }); +}); diff --git a/packages/technical-features/messaging/agnostic/tsconfig.json b/packages/technical-features/messaging/agnostic/tsconfig.json new file mode 100644 index 0000000000..ec29a8f75f --- /dev/null +++ b/packages/technical-features/messaging/agnostic/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@k8slens/typescript/config/base.json", + "include": ["**/*.ts", "**/*.tsx"] +} diff --git a/packages/technical-features/messaging/agnostic/webpack.config.js b/packages/technical-features/messaging/agnostic/webpack.config.js new file mode 100644 index 0000000000..3183f30179 --- /dev/null +++ b/packages/technical-features/messaging/agnostic/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForNode; diff --git a/packages/technical-features/messaging/computed-channel/.eslintrc.json b/packages/technical-features/messaging/computed-channel/.eslintrc.json new file mode 100644 index 0000000000..b15115cb69 --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "@k8slens/eslint-config/eslint", + "parserOptions": { + "project": "./tsconfig.json" + } +} diff --git a/packages/technical-features/messaging/computed-channel/.prettierrc b/packages/technical-features/messaging/computed-channel/.prettierrc new file mode 100644 index 0000000000..edd47b479e --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/.prettierrc @@ -0,0 +1 @@ +"@k8slens/eslint-config/prettier" diff --git a/packages/technical-features/messaging/computed-channel/index.ts b/packages/technical-features/messaging/computed-channel/index.ts new file mode 100644 index 0000000000..4516e0b9a6 --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/index.ts @@ -0,0 +1,12 @@ +export { + computedChannelInjectionToken, + computedChannelObserverInjectionToken, +} from "./src/computed-channel/computed-channel.injectable"; + +export type { + ChannelObserver, + ComputedChannelFactory, + JsonifiableObject, + JsonifiableArray, + Jsonifiable, +} from "./src/computed-channel/computed-channel.injectable"; diff --git a/packages/technical-features/messaging/computed-channel/jest.config.js b/packages/technical-features/messaging/computed-channel/jest.config.js new file mode 100644 index 0000000000..38d54ab7b6 --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/jest.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; diff --git a/packages/technical-features/messaging/computed-channel/package.json b/packages/technical-features/messaging/computed-channel/package.json new file mode 100644 index 0000000000..81c4f80013 --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/package.json @@ -0,0 +1,51 @@ +{ + "name": "@k8slens/computed-channel", + "private": false, + "version": "1.0.0-alpha.1", + "description": "MobX-like computed between channels", + "type": "commonjs", + + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + + "files": [ + "dist" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/lensapp/lens.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "build": "webpack", + "dev": "webpack --mode=development --watch", + "test:unit": "jest --coverage --runInBand", + "lint": "lens-lint", + "lint:fix": "lens-lint --fix" + }, + "peerDependencies": { + "@k8slens/application": "^6.5.0-alpha.0", + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@k8slens/messaging": "^1.0.0-alpha.1", + "@ogre-tools/fp": "^15.1.2", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", + "lodash": "^4.17.21", + "mobx": "^6.8.0" + }, + "devDependencies": { + "@k8slens/eslint-config": "^6.5.0-alpha.1", + "@k8slens/messaging-fake-bridge": "^1.0.0-alpha.1", + "type-fest": "^2.14.0" + } +} diff --git a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel-administration-channel.injectable.ts b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel-administration-channel.injectable.ts new file mode 100644 index 0000000000..b0fdb3c59f --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel-administration-channel.injectable.ts @@ -0,0 +1,64 @@ +import { reaction } from "mobx"; + +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; +import type { JsonPrimitive } from "type-fest"; +import { computedChannelObserverInjectionToken } from "./computed-channel.injectable"; +import { getMessageChannel } from "@k8slens/messaging"; + +export type JsonifiableObject = { [Key in string]?: Jsonifiable } | { toJSON: () => Jsonifiable }; +export type JsonifiableArray = readonly Jsonifiable[]; +export type Jsonifiable = JsonPrimitive | JsonifiableObject | JsonifiableArray; + +export type ComputedChannelAdminMessage = { + channelId: string; + status: "became-observed" | "became-unobserved"; +}; + +export const computedChannelAdministrationChannel = getMessageChannel( + "computed-channel-administration-channel", +); + +export const computedChannelAdministrationListenerInjectable = getMessageChannelListenerInjectable({ + id: "computed-channel-administration", + channel: computedChannelAdministrationChannel, + + getHandler: (di) => { + const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); + + const disposersByChannelId = new Map void>(); + + return (message) => { + if (message.status === "became-observed") { + const result = di + .injectMany(computedChannelObserverInjectionToken) + .find((channelObserver) => channelObserver.channel.id === message.channelId); + + if (result === undefined) { + return; + } + + const disposer = reaction( + () => result.observer.get(), + (observed) => + sendMessageToChannel( + { + id: message.channelId, + }, + + observed, + ), + { + fireImmediately: true, + }, + ); + + disposersByChannelId.set(message.channelId, disposer); + } else { + const disposer = disposersByChannelId.get(message.channelId); + + disposer?.(); + } + }; + }, +}); diff --git a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.injectable.ts b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.injectable.ts new file mode 100644 index 0000000000..03f5a16aab --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.injectable.ts @@ -0,0 +1,110 @@ +import { getInjectable, getInjectionToken } from "@ogre-tools/injectable"; + +import { + _getGlobalState, + computed, + IComputedValue, + observable, + onBecomeObserved, + onBecomeUnobserved, + runInAction, +} from "mobx"; + +import type { MessageChannel } from "@k8slens/messaging"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; +import type { JsonPrimitive } from "type-fest"; +import { computedChannelAdministrationChannel } from "./computed-channel-administration-channel.injectable"; + +export type JsonifiableObject = { [Key in string]?: Jsonifiable } | { toJSON: () => Jsonifiable }; +export type JsonifiableArray = readonly Jsonifiable[]; +export type Jsonifiable = JsonPrimitive | JsonifiableObject | JsonifiableArray; + +export type ComputedChannelFactory = ( + channel: MessageChannel, + pendingValue: T, +) => IComputedValue; + +export const computedChannelInjectionToken = getInjectionToken({ + id: "computed-channel-injection-token", +}); + +export type ChannelObserver = { + channel: MessageChannel; + observer: IComputedValue; +}; + +export const computedChannelObserverInjectionToken = getInjectionToken< + ChannelObserver +>({ + id: "computed-channel-observer", +}); + +const computedChannelInjectable = getInjectable({ + id: "computed-channel", + + instantiate: (di) => { + const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); + + return ((channel, pendingValue) => { + const observableValue = observable.box(pendingValue); + + const computedValue = computed(() => { + const { trackingDerivation } = _getGlobalState(); + + const contextIsReactive = !!trackingDerivation; + + if (!contextIsReactive) { + throw new Error( + `Tried to access value of computed channel "${channel.id}" outside of reactive context. This is not possible, as the value is acquired asynchronously sometime *after* being observed. Not respecting that, the value could be stale.`, + ); + } + + return observableValue.get(); + }); + + const valueReceiverInjectable = getMessageChannelListenerInjectable({ + id: `computed-channel-value-receiver-for-${channel.id}`, + channel, + + getHandler: () => (message) => { + runInAction(() => { + observableValue.set(message); + }); + }, + }); + + runInAction(() => { + di.register(valueReceiverInjectable); + }); + + onBecomeObserved(computedValue, () => { + runInAction(() => { + observableValue.set(pendingValue); + }); + + sendMessageToChannel(computedChannelAdministrationChannel, { + channelId: channel.id, + status: "became-observed", + }); + }); + + onBecomeUnobserved(computedValue, () => { + runInAction(() => { + observableValue.set(pendingValue); + }); + + sendMessageToChannel(computedChannelAdministrationChannel, { + channelId: channel.id, + status: "became-unobserved", + }); + }); + + return computedValue; + }) as ComputedChannelFactory; + }, + + injectionToken: computedChannelInjectionToken, +}); + +export default computedChannelInjectable; diff --git a/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx new file mode 100644 index 0000000000..4736fe22d4 --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/src/computed-channel/computed-channel.test.tsx @@ -0,0 +1,571 @@ +import React from "react"; +import { act } from "@testing-library/react"; +import { createContainer, DiContainer, getInjectable } from "@ogre-tools/injectable"; +import { getMessageBridgeFake, MessageBridgeFake } from "@k8slens/messaging-fake-bridge"; +import { startApplicationInjectionToken } from "@k8slens/application"; +import { + computed, + IComputedValue, + IObservableValue, + observable, + reaction, + runInAction, +} from "mobx"; +import type { MessageChannel } from "@k8slens/messaging"; +import { getMessageChannelListenerInjectable } from "@k8slens/messaging"; +import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; +import { registerFeature } from "@k8slens/feature-core"; +import { testUtils } from "@k8slens/messaging"; +import { + computedChannelInjectionToken, + computedChannelObserverInjectionToken, +} from "./computed-channel.injectable"; +import { runWithThrownMobxReactions, renderFor } from "@k8slens/test-utils"; +import { observer } from "mobx-react"; +import { + computedChannelAdministrationChannel, + ComputedChannelAdminMessage, +} from "./computed-channel-administration-channel.injectable"; +import { computedChannelFeature } from "../feature"; + +const testChannel: MessageChannel = { id: "some-channel-id" }; +const testChannel2: MessageChannel = { id: "some-other-channel-id" }; + +const TestComponent = observer(({ someComputed }: { someComputed: IComputedValue }) => ( +
{someComputed.get()}
+)); + +[{ scenarioIsAsync: true }, { scenarioIsAsync: false }].forEach(({ scenarioIsAsync }) => + describe(`computed-channel, given running message bridge fake as ${ + scenarioIsAsync ? "async" : "sync" + }`, () => { + describe("given multiple dis and a message channel and a channel observer and application has started", () => { + let di1: DiContainer; + let di2: DiContainer; + let latestAdminMessage: ComputedChannelAdminMessage | undefined; + let latestValueMessage: string | undefined; + let messageBridgeFake: MessageBridgeFake; + + beforeEach(async () => { + latestAdminMessage = undefined; + latestValueMessage = undefined; + + di1 = createContainer("some-container-1"); + di2 = createContainer("some-container-2"); + registerMobX(di1); + registerMobX(di2); + + const administrationChannelTestListenerInjectable = getMessageChannelListenerInjectable({ + id: "administration-channel-test-listener", + channel: computedChannelAdministrationChannel, + + getHandler: () => (adminMessage) => { + latestAdminMessage = adminMessage; + }, + }); + + const channelValueTestListenerInjectable = getMessageChannelListenerInjectable({ + id: "test-channel-value-listener", + channel: testChannel, + + getHandler: () => (message) => { + latestValueMessage = message; + }, + }); + + runInAction(() => { + const messagingFeature = testUtils.messagingFeatureForUnitTesting; + + registerFeature(di1, messagingFeature, computedChannelFeature); + registerFeature(di2, messagingFeature, computedChannelFeature); + + di1.register(channelValueTestListenerInjectable); + di2.register(administrationChannelTestListenerInjectable); + }); + + messageBridgeFake = getMessageBridgeFake(); + messageBridgeFake.setAsync(scenarioIsAsync); + messageBridgeFake.involve(di1, di2); + + await Promise.all([ + di1.inject(startApplicationInjectionToken)(), + di2.inject(startApplicationInjectionToken)(), + ]); + }); + + describe("given a channel observer and matching computed channel for the channel in di-2", () => { + let someObservable: IObservableValue; + let computedTestChannel: IComputedValue; + + beforeEach(() => { + someObservable = observable.box("some-initial-value"); + + const channelObserverInjectable = getInjectable({ + id: "some-channel-observer", + + instantiate: () => ({ + channel: testChannel, + observer: computed(() => someObservable.get()), + }), + + injectionToken: computedChannelObserverInjectionToken, + }); + + runInAction(() => { + di2.register(channelObserverInjectable); + }); + + const computedChannel = di1.inject(computedChannelInjectionToken); + + computedTestChannel = computedChannel(testChannel, "some-pending-value"); + }); + + it("there is no admin message yet", () => { + expect(latestAdminMessage).toBeUndefined(); + }); + + describe("when observing the computed value in a component in di-1", () => { + let rendered: any; + + beforeEach(() => { + const render = renderFor(di2); + + rendered = render(); + }); + + const scenarioName = scenarioIsAsync ? "when all messages are propagated" : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioName, () => { + beforeEach((done) => { + if (scenarioIsAsync) { + messageBridgeFake.messagePropagationRecursive(act).then(done); + } else { + done(); + } + }); + + it("renders", () => { + expect(rendered.container).toHaveTextContent("some-initial-value"); + }); + }); + }); + + describe("when observing the computed channel in di-1", () => { + let observedValue: string | undefined; + let stopObserving: () => void; + + beforeEach(() => { + observedValue = undefined; + + stopObserving = reaction( + () => computedTestChannel.get(), + (value) => { + observedValue = value; + }, + + { + fireImmediately: true, + }, + ); + }); + + scenarioIsAsync && + it("computed test channel value is observed as the pending value", () => { + expect(observedValue).toBe("some-pending-value"); + }); + + const scenarioName = scenarioIsAsync + ? "when admin messages are propagated" + : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioName, () => { + beforeEach((done) => { + if (scenarioIsAsync) { + void messageBridgeFake.messagePropagation().then(done); + } else { + done(); + } + }); + + it("administration-message to start observing gets listened", () => { + expect(latestAdminMessage).toEqual({ + channelId: "some-channel-id", + status: "became-observed", + }); + }); + + const scenarioName = scenarioIsAsync + ? "when returning value-messages propagate" + : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioName, () => { + beforeEach((done) => { + if (scenarioIsAsync) { + void messageBridgeFake.messagePropagation().then(done); + } else { + done(); + } + }); + + it("the computed channel value in di-1 matches the value in di-2", () => { + expect(observedValue).toBe("some-initial-value"); + }); + + it("the value gets listened in di-1", () => { + expect(latestValueMessage).toBe("some-initial-value"); + }); + + describe("when the observed value changes", () => { + beforeEach(async () => { + latestValueMessage = undefined; + + runInAction(() => { + someObservable.set("some-new-value"); + }); + }); + + const scenarioName = scenarioIsAsync + ? "when value-messages propagate" + : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioName, () => { + beforeEach((done) => { + if (scenarioIsAsync) { + void messageBridgeFake.messagePropagation().then(done); + } else { + done(); + } + }); + + it("the computed channel value in di-1 changes", () => { + expect(observedValue).toBe("some-new-value"); + }); + + it("the new value gets listened in di-1", () => { + expect(latestValueMessage).toBe("some-new-value"); + }); + }); + }); + + describe("when stopping observation for the channel in di-1", () => { + beforeEach(async () => { + latestValueMessage = undefined; + + stopObserving(); + }); + + const scenarioName = scenarioIsAsync + ? "when admin-messages propagate" + : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioName, () => { + beforeEach((done) => { + if (scenarioIsAsync) { + void messageBridgeFake.messagePropagation().then(done); + } else { + done(); + } + }); + + it("messages administration channel to stop observing", () => { + expect(latestAdminMessage).toEqual({ + channelId: "some-channel-id", + status: "became-unobserved", + }); + }); + + it("no value gets listened in di-1 anymore", () => { + expect(latestValueMessage).toBeUndefined(); + }); + + describe("when the observed value changes", () => { + beforeEach(async () => { + latestValueMessage = undefined; + + runInAction(() => { + someObservable.set("some-new-value-2"); + }); + }); + + it("when accessing the computed value outside of reactive context, throws", () => { + expect(() => { + computedTestChannel.get(); + }).toThrow( + 'Tried to access value of computed channel "some-channel-id" outside of reactive context. This is not possible, as the value is acquired asynchronously sometime *after* being observed. Not respecting that, the value could be stale.', + ); + }); + + it("no value gets listened in di-1 anymore", () => { + expect(latestValueMessage).toBeUndefined(); + }); + + describe("when observing the computed channel again", () => { + beforeEach(() => { + observedValue = undefined; + + reaction( + () => computedTestChannel.get(), + (value) => { + observedValue = value; + }, + + { + fireImmediately: true, + }, + ); + }); + + scenarioIsAsync && + it("computed test channel value is observed as the pending value again", () => { + expect(observedValue).toBe("some-pending-value"); + }); + + const scenarioName = scenarioIsAsync + ? "when admin messages propagate" + : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioName, () => { + beforeEach((done) => { + if (scenarioIsAsync) { + latestAdminMessage = undefined; + + void messageBridgeFake.messagePropagation().then(done); + } else { + done(); + } + }); + + it("administration-message to start observing gets listened again", () => { + expect(latestAdminMessage).toEqual({ + channelId: "some-channel-id", + status: "became-observed", + }); + }); + + scenarioIsAsync && + it("computed test channel value is still observed as the pending value", () => { + expect(observedValue).toBe("some-pending-value"); + }); + + const scenarioTitle = scenarioIsAsync + ? "when value-messages propagate back" + : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioTitle, () => { + beforeEach((done) => { + if (scenarioIsAsync) { + latestValueMessage = undefined; + + void messageBridgeFake.messagePropagation().then(done); + } else { + done(); + } + }); + + it("the computed channel value changes", () => { + expect(observedValue).toBe("some-new-value-2"); + }); + + it("the current value gets listened", () => { + expect(latestValueMessage).toBe("some-new-value-2"); + }); + }); + }); + }); + }); + }); + + it("when accessing the computed value outside of reactive context, throws", () => { + expect(() => { + computedTestChannel.get(); + }).toThrow( + 'Tried to access value of computed channel "some-channel-id" outside of reactive context. This is not possible, as the value is acquired asynchronously sometime *after* being observed. Not respecting that, the value could be stale.', + ); + }); + }); + + it("given observation of unrelated computed channel is stopped, observation of other computed channel still works", async () => { + const someOtherObservable = observable.box(""); + + const channelObserver2Injectable = getInjectable({ + id: "some-channel-observer-2", + + instantiate: () => ({ + channel: testChannel2, + observer: computed(() => someOtherObservable.get()), + }), + + injectionToken: computedChannelObserverInjectionToken, + }); + + runInAction(() => { + di2.register(channelObserver2Injectable); + }); + + const computedChannel = di1.inject(computedChannelInjectionToken); + + computedTestChannel = computedChannel(testChannel2, "some-pending-value"); + + reaction( + () => computedTestChannel.get(), + (value) => { + observedValue = value; + }, + + { + fireImmediately: true, + }, + ); + + scenarioIsAsync && (await messageBridgeFake.messagePropagation()); + + stopObserving(); + + scenarioIsAsync && (await messageBridgeFake.messagePropagation()); + + runInAction(() => { + someOtherObservable.set("some-value"); + }); + + scenarioIsAsync && (await messageBridgeFake.messagePropagation()); + + expect(observedValue).toBe("some-value"); + }); + + describe("when observing the computed channel again", () => { + beforeEach(() => { + latestAdminMessage = undefined; + + reaction( + () => computedTestChannel.get(), + (value) => { + observedValue = value; + }, + + { + fireImmediately: true, + }, + ); + }); + + it("doesn't send second administration message", () => { + expect(latestAdminMessage).toBeUndefined(); + }); + + it("when one of the observations stops, doesn't send administration message to stop observing", async () => { + latestAdminMessage = undefined; + + stopObserving(); + + expect(latestAdminMessage).toBeUndefined(); + }); + }); + + describe("when accessing the computed value outside of reactive context", () => { + let nonReactiveValue: string; + + beforeEach(() => { + latestValueMessage = undefined; + latestAdminMessage = undefined; + + nonReactiveValue = computedTestChannel.get(); + }); + + it("the non reactive value is what ever happens to be the current value from di-2", () => { + expect(nonReactiveValue).toBe("some-initial-value"); + }); + + const scenarioName = scenarioIsAsync + ? "when messages would be propagated" + : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioName, () => { + beforeEach((done) => { + if (scenarioIsAsync) { + void messageBridgeFake.messagePropagation().then(done); + } else { + done(); + } + }); + + it("does not send new value message", () => { + expect(latestValueMessage).toBeUndefined(); + }); + + it("does not send new admin message", () => { + expect(latestAdminMessage).toBeUndefined(); + }); + }); + }); + }); + }); + }); + + it("when accessing the computed value outside of reactive context, throws", () => { + expect(() => { + computedTestChannel.get(); + }).toThrow( + 'Tried to access value of computed channel "some-channel-id" outside of reactive context. This is not possible, as the value is acquired asynchronously sometime *after* being observed. Not respecting that, the value could be stale.', + ); + }); + + it("given duplicate channel observer for the channel is registered, when the computed channel is observer, throws", () => { + const duplicateChannelObserverInjectable = getInjectable({ + id: "some-duplicate-channel-observer", + + instantiate: () => ({ + channel: testChannel, + observer: computed(() => "irrelevant"), + }), + + injectionToken: computedChannelObserverInjectionToken, + }); + + expect(() => { + runWithThrownMobxReactions(() => { + runInAction(() => { + di2.register(duplicateChannelObserverInjectable); + }); + }); + }).toThrow('Tried to register duplicate channel observer for channels "some-channel-id"'); + }); + }); + + describe("given no channel observer but still a computed channel", () => { + let computedTestChannel: IComputedValue; + + beforeEach(() => { + const computedChannel = di1.inject(computedChannelInjectionToken); + + computedTestChannel = computedChannel(testChannel, "some-pending-value"); + }); + + it("when the computed channel is observed, observes as undefined", () => { + let observedValue = "some-value-to-never-be-seen-in-unit-test"; + + reaction( + () => computedTestChannel.get(), + + (value) => { + observedValue = value; + }, + + { + fireImmediately: true, + }, + ); + + expect(observedValue).toBe("some-pending-value"); + }); + }); + }); + }), +); diff --git a/packages/technical-features/messaging/computed-channel/src/computed-channel/duplicate-channel-observer-guard.injectable.ts b/packages/technical-features/messaging/computed-channel/src/computed-channel/duplicate-channel-observer-guard.injectable.ts new file mode 100644 index 0000000000..42f313ec36 --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/src/computed-channel/duplicate-channel-observer-guard.injectable.ts @@ -0,0 +1,42 @@ +import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; +import { pipeline } from "@ogre-tools/fp"; +import { getInjectable } from "@ogre-tools/injectable"; +import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-for-mobx"; +import { filter, groupBy, nth, map, toPairs } from "lodash/fp"; +import { reaction } from "mobx"; +import { computedChannelObserverInjectionToken } from "./computed-channel.injectable"; + +export const duplicateChannelObserverGuardInjectable = getInjectable({ + id: "duplicate-channel-observer-guard", + + instantiate: (di) => { + const computedInjectMany = di.inject(computedInjectManyInjectable); + + return { + run: () => { + reaction( + () => computedInjectMany(computedChannelObserverInjectionToken).get(), + (observers) => { + const duplicateObserverChannelIds = pipeline( + observers, + groupBy((observer) => observer.channel.id), + toPairs, + filter(([, channelObservers]) => channelObservers.length > 1), + map(nth(0)), + ); + + if (duplicateObserverChannelIds.length) { + throw new Error( + `Tried to register duplicate channel observer for channels "${duplicateObserverChannelIds.join( + '", "', + )}"`, + ); + } + }, + ); + }, + }; + }, + + injectionToken: onLoadOfApplicationInjectionToken, +}); diff --git a/packages/technical-features/messaging/computed-channel/src/feature.ts b/packages/technical-features/messaging/computed-channel/src/feature.ts new file mode 100644 index 0000000000..179700edcc --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/src/feature.ts @@ -0,0 +1,18 @@ +import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration"; +import { getFeature } from "@k8slens/feature-core"; +import { messagingFeature } from "@k8slens/messaging"; + +export const computedChannelFeature = getFeature({ + id: "computed-channel", + + dependencies: [messagingFeature], + + register: (di) => { + autoRegister({ + di, + targetModule: module, + + getRequireContexts: () => [require.context("./", true, /\.injectable\.(ts|tsx)$/)], + }); + }, +}); diff --git a/packages/technical-features/messaging/computed-channel/tsconfig.json b/packages/technical-features/messaging/computed-channel/tsconfig.json new file mode 100644 index 0000000000..ec29a8f75f --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@k8slens/typescript/config/base.json", + "include": ["**/*.ts", "**/*.tsx"] +} diff --git a/packages/technical-features/messaging/computed-channel/webpack.config.js b/packages/technical-features/messaging/computed-channel/webpack.config.js new file mode 100644 index 0000000000..3183f30179 --- /dev/null +++ b/packages/technical-features/messaging/computed-channel/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForNode; diff --git a/packages/technical-features/messaging/electron/main/.eslintrc.json b/packages/technical-features/messaging/electron/main/.eslintrc.json new file mode 100644 index 0000000000..b15115cb69 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "@k8slens/eslint-config/eslint", + "parserOptions": { + "project": "./tsconfig.json" + } +} diff --git a/packages/technical-features/messaging/electron/main/.prettierrc b/packages/technical-features/messaging/electron/main/.prettierrc new file mode 100644 index 0000000000..edd47b479e --- /dev/null +++ b/packages/technical-features/messaging/electron/main/.prettierrc @@ -0,0 +1 @@ +"@k8slens/eslint-config/prettier" diff --git a/packages/technical-features/messaging/electron/main/index.ts b/packages/technical-features/messaging/electron/main/index.ts new file mode 100644 index 0000000000..1ff9afff0d --- /dev/null +++ b/packages/technical-features/messaging/electron/main/index.ts @@ -0,0 +1 @@ +export { messagingFeatureForMain } from "./src/feature"; diff --git a/packages/technical-features/messaging/electron/main/jest.config.js b/packages/technical-features/messaging/electron/main/jest.config.js new file mode 100644 index 0000000000..c6074967eb --- /dev/null +++ b/packages/technical-features/messaging/electron/main/jest.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForNode; diff --git a/packages/technical-features/messaging/electron/main/package.json b/packages/technical-features/messaging/electron/main/package.json new file mode 100644 index 0000000000..63d66ea6d0 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/package.json @@ -0,0 +1,47 @@ +{ + "name": "@k8slens/messaging-for-main", + "private": false, + "version": "1.0.0-alpha.1", + "description": "Implementations for 'messaging' in Electron main", + "type": "commonjs", + + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + + "files": [ + "dist" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/lensapp/lens.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "build": "webpack", + "dev": "webpack --mode=development --watch", + "test:unit": "jest --coverage --runInBand", + "lint": "lens-lint", + "lint:fix": "lens-lint --fix" + }, + "peerDependencies": { + "@k8slens/application": "^6.5.0-alpha.0", + "@k8slens/feature-core": "^6.5.0-alpha.0", + "@k8slens/messaging": "^1.0.0-alpha.1", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "electron": "^19.1.8", + "lodash": "^4.17.21" + }, + "devDependencies": { + "@k8slens/eslint-config": "^6.5.0-alpha.1" + } +} diff --git a/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.injectable.ts b/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.injectable.ts new file mode 100644 index 0000000000..5a33ed39d9 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.injectable.ts @@ -0,0 +1,28 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import type { IpcMainEvent } from "electron"; +import ipcMainInjectable from "../ipc-main/ipc-main.injectable"; +import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; + +const enlistMessageChannelListenerInjectable = getInjectable({ + id: "enlist-message-channel-listener", + + instantiate: (di) => { + const ipcMain = di.inject(ipcMainInjectable); + + return ({ channel, handler }) => { + const nativeOnCallback = (nativeEvent: IpcMainEvent, message: unknown) => { + handler(message, { frameId: nativeEvent.frameId, processId: nativeEvent.processId }); + }; + + ipcMain.on(channel.id, nativeOnCallback); + + return () => { + ipcMain.off(channel.id, nativeOnCallback); + }; + }; + }, + + injectionToken: enlistMessageChannelListenerInjectionToken, +}); + +export default enlistMessageChannelListenerInjectable; diff --git a/packages/core/src/main/utils/channel/channel-listeners/enlist-message-channel-listener.test.ts b/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.test.ts similarity index 59% rename from packages/core/src/main/utils/channel/channel-listeners/enlist-message-channel-listener.test.ts rename to packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.test.ts index 2bb5f7b10f..c4385246cd 100644 --- a/packages/core/src/main/utils/channel/channel-listeners/enlist-message-channel-listener.test.ts +++ b/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-message-channel-listener.test.ts @@ -1,12 +1,12 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getDiForUnitTesting } from "../../../getDiForUnitTesting"; import ipcMainInjectable from "../ipc-main/ipc-main.injectable"; -import type { EnlistMessageChannelListener } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token"; -import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token"; import type { IpcMain, IpcMainEvent } from "electron"; +import { + EnlistMessageChannelListener, + enlistMessageChannelListenerInjectionToken, +} from "@k8slens/messaging"; +import { createContainer } from "@ogre-tools/injectable"; +import { registerFeature } from "@k8slens/feature-core"; +import { messagingFeatureForMain } from "../feature"; describe("enlist message channel listener in main", () => { let enlistMessageChannelListener: EnlistMessageChannelListener; @@ -15,7 +15,9 @@ describe("enlist message channel listener in main", () => { let offMock: jest.Mock; beforeEach(() => { - const di = getDiForUnitTesting(); + const di = createContainer("irrelevant"); + + registerFeature(di, messagingFeatureForMain); onMock = jest.fn(); offMock = jest.fn(); @@ -27,9 +29,7 @@ describe("enlist message channel listener in main", () => { di.override(ipcMainInjectable, () => ipcMainStub); - enlistMessageChannelListener = di.inject( - enlistMessageChannelListenerInjectionToken, - ); + enlistMessageChannelListener = di.inject(enlistMessageChannelListenerInjectionToken); }); describe("when called", () => { @@ -40,6 +40,7 @@ describe("enlist message channel listener in main", () => { handlerMock = jest.fn(); disposer = enlistMessageChannelListener({ + id: "some-listener", channel: { id: "some-channel-id" }, handler: handlerMock, }); @@ -50,10 +51,7 @@ describe("enlist message channel listener in main", () => { }); it("registers the listener", () => { - expect(onMock).toHaveBeenCalledWith( - "some-channel-id", - expect.any(Function), - ); + expect(onMock).toHaveBeenCalledWith("some-channel-id", expect.any(Function)); }); it("does not de-register the listener yet", () => { @@ -62,11 +60,11 @@ describe("enlist message channel listener in main", () => { describe("when message arrives", () => { beforeEach(() => { - onMock.mock.calls[0][1]({} as IpcMainEvent, "some-message"); + onMock.mock.calls[0][1]({ frameId: 42, processId: 84 } as IpcMainEvent, "some-message"); }); it("calls the handler with the message", () => { - expect(handlerMock).toHaveBeenCalledWith("some-message"); + expect(handlerMock).toHaveBeenCalledWith("some-message", { frameId: 42, processId: 84 }); }); it("when disposing the listener, de-registers the listener", () => { @@ -77,21 +75,21 @@ describe("enlist message channel listener in main", () => { }); it("given number as message, when message arrives, calls the handler with the message", () => { - onMock.mock.calls[0][1]({} as IpcMainEvent, 42); + onMock.mock.calls[0][1]({ frameId: 42, processId: 84 } as IpcMainEvent, 42); - expect(handlerMock).toHaveBeenCalledWith(42); + expect(handlerMock).toHaveBeenCalledWith(42, { frameId: 42, processId: 84 }); }); it("given boolean as message, when message arrives, calls the handler with the message", () => { - onMock.mock.calls[0][1]({} as IpcMainEvent, true); + onMock.mock.calls[0][1]({ frameId: 42, processId: 84 } as IpcMainEvent, true); - expect(handlerMock).toHaveBeenCalledWith(true); + expect(handlerMock).toHaveBeenCalledWith(true, { frameId: 42, processId: 84 }); }); it("given object as message, when message arrives, calls the handler with the message", () => { - onMock.mock.calls[0][1]({} as IpcMainEvent, { some: "object" }); + onMock.mock.calls[0][1]({ frameId: 42, processId: 84 } as IpcMainEvent, { some: "object" }); - expect(handlerMock).toHaveBeenCalledWith({ some: "object" }); + expect(handlerMock).toHaveBeenCalledWith({ some: "object" }, { frameId: 42, processId: 84 }); }); }); }); diff --git a/packages/core/src/main/utils/channel/channel-listeners/enlist-request-channel-listener.injectable.ts b/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-request-channel-listener.injectable.ts similarity index 53% rename from packages/core/src/main/utils/channel/channel-listeners/enlist-request-channel-listener.injectable.ts rename to packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-request-channel-listener.injectable.ts index 08a600297c..f46976a3f1 100644 --- a/packages/core/src/main/utils/channel/channel-listeners/enlist-request-channel-listener.injectable.ts +++ b/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-request-channel-listener.injectable.ts @@ -1,21 +1,18 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ import { getInjectable } from "@ogre-tools/injectable"; import type { IpcMainInvokeEvent } from "electron"; -import type { Disposer } from "@k8slens/utilities"; -import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token"; -import type { RequestChannelListener } from "./listener-tokens"; -import ipcMainInjectionToken from "../../../../common/ipc/ipc-main-injection-token"; +import ipcMainInjectable from "../ipc-main/ipc-main.injectable"; +import type { RequestChannel, RequestChannelListener } from "@k8slens/messaging"; +import { enlistRequestChannelListenerInjectionToken } from "@k8slens/messaging"; -export type EnlistRequestChannelListener = >(listener: RequestChannelListener) => Disposer; +export type EnlistRequestChannelListener = >( + listener: RequestChannelListener, +) => () => void; const enlistRequestChannelListenerInjectable = getInjectable({ id: "enlist-request-channel-listener-for-main", instantiate: (di): EnlistRequestChannelListener => { - const ipcMain = di.inject(ipcMainInjectionToken); + const ipcMain = di.inject(ipcMainInjectable); return ({ channel, handler }) => { const nativeHandleCallback = (_: IpcMainInvokeEvent, request: unknown) => handler(request); @@ -27,6 +24,8 @@ const enlistRequestChannelListenerInjectable = getInjectable({ }; }; }, + + injectionToken: enlistRequestChannelListenerInjectionToken, }); export default enlistRequestChannelListenerInjectable; diff --git a/packages/core/src/main/utils/channel/channel-listeners/enlist-request-channel-listener.test.ts b/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-request-channel-listener.test.ts similarity index 86% rename from packages/core/src/main/utils/channel/channel-listeners/enlist-request-channel-listener.test.ts rename to packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-request-channel-listener.test.ts index 188a11866b..68672f4e95 100644 --- a/packages/core/src/main/utils/channel/channel-listeners/enlist-request-channel-listener.test.ts +++ b/packages/technical-features/messaging/electron/main/src/channel-listeners/enlist-request-channel-listener.test.ts @@ -1,17 +1,14 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getDiForUnitTesting } from "../../../getDiForUnitTesting"; import ipcMainInjectable from "../ipc-main/ipc-main.injectable"; import type { IpcMain, IpcMainInvokeEvent } from "electron"; -import { getPromiseStatus } from "@k8slens/test-utils"; import type { AsyncFnMock } from "@async-fn/jest"; import asyncFn from "@async-fn/jest"; -import type { RequestChannel } from "../../../../common/utils/channel/request-channel-listener-injection-token"; import type { EnlistRequestChannelListener } from "./enlist-request-channel-listener.injectable"; import enlistRequestChannelListenerInjectable from "./enlist-request-channel-listener.injectable"; -import type { RequestChannelHandler } from "./listener-tokens"; +import type { RequestChannel, RequestChannelHandler } from "@k8slens/messaging"; +import { getPromiseStatus } from "@k8slens/test-utils"; +import { createContainer } from "@ogre-tools/injectable"; +import { registerFeature } from "@k8slens/feature-core"; +import { messagingFeatureForMain } from "../feature"; type TestRequestChannel = RequestChannel; @@ -26,7 +23,9 @@ describe("enlist request channel listener in main", () => { let offMock: jest.Mock; beforeEach(() => { - const di = getDiForUnitTesting(); + const di = createContainer("irrelevant"); + + registerFeature(di, messagingFeatureForMain); handleMock = jest.fn(); offMock = jest.fn(); @@ -49,6 +48,7 @@ describe("enlist request channel listener in main", () => { handlerMock = asyncFn(); disposer = enlistRequestChannelListener({ + id: "some-listener", channel: testRequestChannel, handler: handlerMock, }); @@ -59,10 +59,7 @@ describe("enlist request channel listener in main", () => { }); it("registers the listener", () => { - expect(handleMock).toHaveBeenCalledWith( - "some-channel-id", - expect.any(Function), - ); + expect(handleMock).toHaveBeenCalledWith("some-channel-id", expect.any(Function)); }); it("does not de-register the listener yet", () => { @@ -73,10 +70,7 @@ describe("enlist request channel listener in main", () => { let actualPromise: Promise; beforeEach(() => { - actualPromise = handleMock.mock.calls[0][1]( - {} as IpcMainInvokeEvent, - "some-request", - ); + actualPromise = handleMock.mock.calls[0][1]({} as IpcMainInvokeEvent, "some-request"); }); it("calls the handler with the request", () => { diff --git a/packages/technical-features/messaging/electron/main/src/feature.ts b/packages/technical-features/messaging/electron/main/src/feature.ts new file mode 100644 index 0000000000..250f5ed104 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/src/feature.ts @@ -0,0 +1,18 @@ +import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration"; +import { getFeature } from "@k8slens/feature-core"; +import { messagingFeature } from "@k8slens/messaging"; + +export const messagingFeatureForMain = getFeature({ + id: "messaging-for-main", + + register: (di) => { + autoRegister({ + di, + targetModule: module, + + getRequireContexts: () => [require.context("./", true, /\.injectable\.(ts|tsx)$/)], + }); + }, + + dependencies: [messagingFeature], +}); diff --git a/packages/technical-features/messaging/electron/main/src/ipc-main/ipc-main.injectable.ts b/packages/technical-features/messaging/electron/main/src/ipc-main/ipc-main.injectable.ts new file mode 100644 index 0000000000..fc55a6b414 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/src/ipc-main/ipc-main.injectable.ts @@ -0,0 +1,10 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import { ipcMain } from "electron"; + +const ipcMainInjectable = getInjectable({ + id: "ipc-main", + instantiate: () => ipcMain, + causesSideEffects: true, +}); + +export default ipcMainInjectable; diff --git a/packages/technical-features/messaging/electron/main/src/ipc-main/ipc-main.test.ts b/packages/technical-features/messaging/electron/main/src/ipc-main/ipc-main.test.ts new file mode 100644 index 0000000000..9a3e92c02e --- /dev/null +++ b/packages/technical-features/messaging/electron/main/src/ipc-main/ipc-main.test.ts @@ -0,0 +1,21 @@ +import { createContainer, DiContainer } from "@ogre-tools/injectable"; +import { registerFeature } from "@k8slens/feature-core"; +import ipcMainInjectable from "./ipc-main.injectable"; +import { ipcMain } from "electron"; +import { messagingFeatureForMain } from "../feature"; + +describe("ipc-main", () => { + let di: DiContainer; + + beforeEach(() => { + di = createContainer("irrelevant"); + + registerFeature(di, messagingFeatureForMain); + }); + + it("is the actual IPC-main of Electron", () => { + const actual = di.inject(ipcMainInjectable); + + expect(actual).toBe(ipcMain); + }); +}); diff --git a/packages/technical-features/messaging/electron/main/src/request-from-channel/request-from-channel.injectable.ts b/packages/technical-features/messaging/electron/main/src/request-from-channel/request-from-channel.injectable.ts new file mode 100644 index 0000000000..220daf9fc7 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/src/request-from-channel/request-from-channel.injectable.ts @@ -0,0 +1,23 @@ +/* c8 ignore start */ +import { getInjectable } from "@ogre-tools/injectable"; +import { + RequestChannel, + RequestFromChannel, + requestFromChannelInjectionToken, +} from "@k8slens/messaging"; + +const requestFromChannelInjectable = getInjectable({ + id: "request-from-channel", + + instantiate: () => + ((channel: RequestChannel) => { + throw new Error( + `Tried to request from channel "${channel.id}" but requesting in "main" it's not supported yet`, + ); + }) as unknown as RequestFromChannel, + + injectionToken: requestFromChannelInjectionToken, +}); + +export default requestFromChannelInjectable; +/* c8 ignore stop */ diff --git a/packages/technical-features/messaging/electron/main/src/send-message-to-channel/allow-communication-listener.injectable.ts b/packages/technical-features/messaging/electron/main/src/send-message-to-channel/allow-communication-listener.injectable.ts new file mode 100644 index 0000000000..af74d7a810 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/src/send-message-to-channel/allow-communication-listener.injectable.ts @@ -0,0 +1,21 @@ +import { getMessageChannel, getMessageChannelListenerInjectable } from "@k8slens/messaging"; +import frameIdsInjectable from "./frameIds.injectable"; + +const frameCommunicationAdminChannel = getMessageChannel( + "frame-communication-admin-channel", +); + +const allowCommunicationListenerInjectable = getMessageChannelListenerInjectable({ + id: "allow-communication", + channel: frameCommunicationAdminChannel, + + getHandler: (di) => { + const frameIds = di.inject(frameIdsInjectable); + + return (_, { frameId, processId }) => { + frameIds.add({ frameId, processId }); + }; + }, +}); + +export default allowCommunicationListenerInjectable; diff --git a/packages/technical-features/messaging/electron/main/src/send-message-to-channel/frameIds.injectable.ts b/packages/technical-features/messaging/electron/main/src/send-message-to-channel/frameIds.injectable.ts new file mode 100644 index 0000000000..6dff45afc2 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/src/send-message-to-channel/frameIds.injectable.ts @@ -0,0 +1,8 @@ +import { getInjectable } from "@ogre-tools/injectable"; + +const frameIdsInjectable = getInjectable({ + id: "frame-ids", + instantiate: () => new Set<{ frameId: number; processId: number }>(), +}); + +export default frameIdsInjectable; diff --git a/packages/technical-features/messaging/electron/main/src/send-message-to-channel/get-web-contents.injectable.ts b/packages/technical-features/messaging/electron/main/src/send-message-to-channel/get-web-contents.injectable.ts new file mode 100644 index 0000000000..701c976621 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/src/send-message-to-channel/get-web-contents.injectable.ts @@ -0,0 +1,12 @@ +/* c8 ignore start */ +import { getInjectable } from "@ogre-tools/injectable"; +import { webContents } from "electron"; + +const getWebContentsInjectable = getInjectable({ + id: "web-contents", + instantiate: () => () => webContents.getAllWebContents(), + causesSideEffects: true, +}); + +export default getWebContentsInjectable; +/* c8 ignore stop */ diff --git a/packages/technical-features/messaging/electron/main/src/send-message-to-channel/send-message-to-channel.injectable.test.ts b/packages/technical-features/messaging/electron/main/src/send-message-to-channel/send-message-to-channel.injectable.test.ts new file mode 100644 index 0000000000..5c5a486658 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/src/send-message-to-channel/send-message-to-channel.injectable.test.ts @@ -0,0 +1,121 @@ +import { registerFeature } from "@k8slens/feature-core"; +import { createContainer, DiContainer } from "@ogre-tools/injectable"; +import { messagingFeatureForMain } from "../feature"; +import { getMessageChannel, sendMessageToChannelInjectionToken } from "@k8slens/messaging"; +import getWebContentsInjectable from "./get-web-contents.injectable"; +import type { WebContents } from "electron"; +import allowCommunicationListenerInjectable from "./allow-communication-listener.injectable"; + +const someChannel = getMessageChannel("some-channel"); + +describe("send-message-to-channel", () => { + let di: DiContainer; + + beforeEach(() => { + di = createContainer("irrelevant"); + + registerFeature(di, messagingFeatureForMain); + }); + + it("given no web contents, when sending a message, does not do anything", () => { + di.override(getWebContentsInjectable, () => () => []); + + const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); + + expect(() => sendMessageToChannel(someChannel, "some-message")).not.toThrow(); + }); + + describe("given web content that is alive", () => { + let sendToFrameMock: jest.Mock; + let sendMessageMock: jest.Mock; + + beforeEach(() => { + sendToFrameMock = jest.fn(); + sendMessageMock = jest.fn(); + + di.override(getWebContentsInjectable, () => () => [ + { + send: (...args: any[]) => sendMessageMock("first", ...args), + sendToFrame: (...args: any[]) => sendToFrameMock("first", ...args), + isDestroyed: () => false, + isCrashed: () => false, + } as unknown as WebContents, + { + send: (...args: any[]) => sendMessageMock("second", ...args), + sendToFrame: (...args: any[]) => sendToFrameMock("second", ...args), + isDestroyed: () => false, + isCrashed: () => false, + } as unknown as WebContents, + ]); + }); + + it("when sending message, sends the message to webcontents", () => { + const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); + + sendMessageToChannel(someChannel, "some-message"); + + expect(sendMessageMock.mock.calls).toEqual([ + ["first", "some-channel", "some-message"], + ["second", "some-channel", "some-message"], + ]); + }); + + describe("when multiple renderers inform that they are ready to listen messages", () => { + beforeEach(() => { + const allowCommunicationListener = di.inject(allowCommunicationListenerInjectable); + + allowCommunicationListener.handler(undefined, { frameId: 42, processId: 126 }); + allowCommunicationListener.handler(undefined, { frameId: 84, processId: 168 }); + }); + + describe("when sending a message", () => { + beforeEach(() => { + const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); + + sendMessageToChannel(someChannel, "some-message"); + }); + + it("sends the message to webcontents", () => { + expect(sendMessageMock.mock.calls).toEqual([ + ["first", "some-channel", "some-message"], + ["second", "some-channel", "some-message"], + ]); + }); + + it("sends the message to individual frames in webcontents", () => { + expect(sendToFrameMock.mock.calls).toEqual([ + ["first", [42, 126], "some-channel", "some-message"], + ["first", [84, 168], "some-channel", "some-message"], + + ["second", [42, 126], "some-channel", "some-message"], + ["second", [84, 168], "some-channel", "some-message"], + ]); + }); + }); + }); + }); + + it("given non alive web contents, when sending a message, does not send messages", () => { + const sendToWebContentsMock = jest.fn(); + + di.override(getWebContentsInjectable, () => () => [ + { + send: sendToWebContentsMock, + isDestroyed: () => true, + isCrashed: () => false, + } as unknown as WebContents, + + { + send: sendToWebContentsMock, + isDestroyed: () => false, + isCrashed: () => true, + } as unknown as WebContents, + ]); + + const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); + + sendMessageToChannel(someChannel, "irrelevant"); + + expect(sendToWebContentsMock).not.toHaveBeenCalled(); + }); +}); diff --git a/packages/technical-features/messaging/electron/main/src/send-message-to-channel/send-message-to-channel.injectable.ts b/packages/technical-features/messaging/electron/main/src/send-message-to-channel/send-message-to-channel.injectable.ts new file mode 100644 index 0000000000..e68d8e1577 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/src/send-message-to-channel/send-message-to-channel.injectable.ts @@ -0,0 +1,48 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import { pipeline } from "@ogre-tools/fp"; +import { SendMessageToChannel, sendMessageToChannelInjectionToken } from "@k8slens/messaging"; +import getWebContentsInjectable from "./get-web-contents.injectable"; +import { flatMap, reject } from "lodash/fp"; +import type { WebContents } from "electron"; +import frameIdsInjectable from "./frameIds.injectable"; + +const isDestroyed = (webContent: WebContents) => webContent.isDestroyed(); +const isCrashed = (webContent: WebContents) => webContent.isCrashed(); + +const forEach = + (predicate: (item: T) => void) => + (items: T[]) => + items.forEach(predicate); + +const sendMessageToChannelInjectable = getInjectable({ + id: "send-message-to-channel", + + instantiate: (di) => { + const getWebContents = di.inject(getWebContentsInjectable); + const frameIds = di.inject(frameIdsInjectable); + + return ((channel, message) => { + pipeline( + getWebContents(), + reject(isDestroyed), + reject(isCrashed), + + flatMap((webContent) => [ + (channelId: string, ...args: any[]) => webContent.send(channelId, ...args), + + ...[...frameIds].map(({ frameId, processId }) => (channelId: string, ...args: any[]) => { + webContent.sendToFrame([frameId, processId], channelId, ...args); + }), + ]), + + forEach((send) => { + send(channel.id, message); + }), + ); + }) as SendMessageToChannel; + }, + + injectionToken: sendMessageToChannelInjectionToken, +}); + +export default sendMessageToChannelInjectable; diff --git a/packages/technical-features/messaging/electron/main/tsconfig.json b/packages/technical-features/messaging/electron/main/tsconfig.json new file mode 100644 index 0000000000..1819203dc1 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@k8slens/typescript/config/base.json", + "include": ["**/*.ts"] +} diff --git a/packages/technical-features/messaging/electron/main/webpack.config.js b/packages/technical-features/messaging/electron/main/webpack.config.js new file mode 100644 index 0000000000..3183f30179 --- /dev/null +++ b/packages/technical-features/messaging/electron/main/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForNode; diff --git a/packages/technical-features/messaging/electron/renderer/.eslintrc.json b/packages/technical-features/messaging/electron/renderer/.eslintrc.json new file mode 100644 index 0000000000..b15115cb69 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "@k8slens/eslint-config/eslint", + "parserOptions": { + "project": "./tsconfig.json" + } +} diff --git a/packages/technical-features/messaging/electron/renderer/.prettierrc b/packages/technical-features/messaging/electron/renderer/.prettierrc new file mode 100644 index 0000000000..edd47b479e --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/.prettierrc @@ -0,0 +1 @@ +"@k8slens/eslint-config/prettier" diff --git a/packages/technical-features/messaging/electron/renderer/index.ts b/packages/technical-features/messaging/electron/renderer/index.ts new file mode 100644 index 0000000000..337d473d1f --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/index.ts @@ -0,0 +1 @@ +export { messagingFeatureForRenderer } from "./src/feature"; diff --git a/packages/technical-features/messaging/electron/renderer/jest.config.js b/packages/technical-features/messaging/electron/renderer/jest.config.js new file mode 100644 index 0000000000..c6074967eb --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/jest.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForNode; diff --git a/packages/technical-features/messaging/electron/renderer/package.json b/packages/technical-features/messaging/electron/renderer/package.json new file mode 100644 index 0000000000..dcb9a7a185 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/package.json @@ -0,0 +1,48 @@ +{ + "name": "@k8slens/messaging-for-renderer", + "private": false, + "version": "1.0.0-alpha.1", + "description": "Implementations for 'messaging' in Electron renderer", + "type": "commonjs", + + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + + "files": [ + "dist" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/lensapp/lens.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "build": "webpack", + "dev": "webpack --mode=development --watch", + "test:unit": "jest --coverage --runInBand", + "lint": "lens-lint", + "lint:fix": "lens-lint --fix" + }, + "peerDependencies": { + "@k8slens/application": "^6.5.0-alpha.0", + "@k8slens/messaging": "^1.0.0-alpha.1", + "@k8slens/run-many": "^1.0.0-alpha.1", + "@k8slens/startable-stoppable": "^1.0.0-alpha.1", + "@ogre-tools/injectable": "^15.1.2", + "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", + "electron": "^19.1.8", + "lodash": "^4.17.21" + }, + "devDependencies": { + "@k8slens/eslint-config": "^6.5.0-alpha.1" + } +} diff --git a/packages/technical-features/messaging/electron/renderer/src/allow-communication-to-iframe.injectable.ts b/packages/technical-features/messaging/electron/renderer/src/allow-communication-to-iframe.injectable.ts new file mode 100644 index 0000000000..59abe7f931 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/allow-communication-to-iframe.injectable.ts @@ -0,0 +1,25 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import { onLoadOfApplicationInjectionToken } from "@k8slens/application"; +import { getMessageChannel, sendMessageToChannelInjectionToken } from "@k8slens/messaging"; + +export const frameCommunicationAdminChannel = getMessageChannel( + "frame-communication-admin-channel", +); + +const allowCommunicationToIframeInjectable = getInjectable({ + id: "allow-communication-to-iframe-injectable", + + instantiate: (di) => { + const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); + + return { + run: () => { + sendMessageToChannel(frameCommunicationAdminChannel); + }, + }; + }, + + injectionToken: onLoadOfApplicationInjectionToken, +}); + +export default allowCommunicationToIframeInjectable; diff --git a/packages/technical-features/messaging/electron/renderer/src/allow-communication-to-iframe.test.ts b/packages/technical-features/messaging/electron/renderer/src/allow-communication-to-iframe.test.ts new file mode 100644 index 0000000000..990c6601d9 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/allow-communication-to-iframe.test.ts @@ -0,0 +1,35 @@ +import { createContainer, DiContainer } from "@ogre-tools/injectable"; +import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; +import { startApplicationInjectionToken } from "@k8slens/application"; +import { registerFeature } from "@k8slens/feature-core"; +import { messagingFeatureForRenderer } from "./feature"; +import { runInAction } from "mobx"; +import ipcRendererInjectable from "./ipc/ipc-renderer.injectable"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; +import { frameCommunicationAdminChannel } from "./allow-communication-to-iframe.injectable"; + +describe("allow communication to iframe", () => { + let di: DiContainer; + let sendMessageToChannelMock: jest.Mock; + + beforeEach(() => { + di = createContainer("irrelevant"); + + registerMobX(di); + + runInAction(() => { + registerFeature(di, messagingFeatureForRenderer); + }); + + di.override(ipcRendererInjectable, () => ({ on: () => {} } as unknown)); + + sendMessageToChannelMock = jest.fn(); + di.override(sendMessageToChannelInjectionToken, () => sendMessageToChannelMock); + }); + + it("when application starts, sends message to communication channel to register the frame ID and process ID for further usage", async () => { + await di.inject(startApplicationInjectionToken)(); + + expect(sendMessageToChannelMock).toHaveBeenCalledWith(frameCommunicationAdminChannel); + }); +}); diff --git a/packages/technical-features/messaging/electron/renderer/src/feature.ts b/packages/technical-features/messaging/electron/renderer/src/feature.ts new file mode 100644 index 0000000000..c63092f2e5 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/feature.ts @@ -0,0 +1,18 @@ +import { autoRegister } from "@ogre-tools/injectable-extension-for-auto-registration"; +import { getFeature } from "@k8slens/feature-core"; +import { messagingFeature } from "@k8slens/messaging"; + +export const messagingFeatureForRenderer = getFeature({ + id: "messaging-for-renderer", + + register: (di) => { + autoRegister({ + di, + targetModule: module, + + getRequireContexts: () => [require.context("./", true, /\.injectable\.(ts|tsx)$/)], + }); + }, + + dependencies: [messagingFeature], +}); diff --git a/packages/technical-features/messaging/electron/renderer/src/ipc/ipc-renderer.injectable.ts b/packages/technical-features/messaging/electron/renderer/src/ipc/ipc-renderer.injectable.ts new file mode 100644 index 0000000000..a2ecffac15 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/ipc/ipc-renderer.injectable.ts @@ -0,0 +1,10 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import { ipcRenderer } from "electron"; + +const ipcRendererInjectable = getInjectable({ + id: "ipc-renderer", + instantiate: () => ipcRenderer, + causesSideEffects: true, +}); + +export default ipcRendererInjectable; diff --git a/packages/technical-features/messaging/electron/renderer/src/ipc/ipc-renderer.test.ts b/packages/technical-features/messaging/electron/renderer/src/ipc/ipc-renderer.test.ts new file mode 100644 index 0000000000..e882b5f5aa --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/ipc/ipc-renderer.test.ts @@ -0,0 +1,27 @@ +import { createContainer, DiContainer } from "@ogre-tools/injectable"; +import { registerFeature } from "@k8slens/feature-core"; +import ipcRendererInjectable from "./ipc-renderer.injectable"; +import { messagingFeatureForRenderer } from "../feature"; +import { ipcRenderer } from "electron"; + +describe("ipc-renderer", () => { + let di: DiContainer; + + beforeEach(() => { + di = createContainer("irrelevant"); + + registerFeature(di, messagingFeatureForRenderer); + }); + + it("is not undefined", () => { + const actual = di.inject(ipcRendererInjectable); + + expect(actual).not.toBeUndefined(); + }); + + it("is IPC-renderer of Electron", () => { + const actual = di.inject(ipcRendererInjectable); + + expect(actual).toBe(ipcRenderer); + }); +}); diff --git a/packages/core/src/renderer/utils/channel/channel-listeners/enlist-message-channel-listener.injectable.ts b/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts similarity index 67% rename from packages/core/src/renderer/utils/channel/channel-listeners/enlist-message-channel-listener.injectable.ts rename to packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts index 1e5b14bb40..64e9b1f873 100644 --- a/packages/core/src/renderer/utils/channel/channel-listeners/enlist-message-channel-listener.injectable.ts +++ b/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts @@ -1,11 +1,7 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import ipcRendererInjectable from "../ipc-renderer.injectable"; +import ipcRendererInjectable from "../ipc/ipc-renderer.injectable"; import { getInjectable } from "@ogre-tools/injectable"; import type { IpcRendererEvent } from "electron"; -import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token"; +import { enlistMessageChannelListenerInjectionToken } from "@k8slens/messaging"; const enlistMessageChannelListenerInjectable = getInjectable({ id: "enlist-message-channel-listener-for-renderer", diff --git a/packages/core/src/renderer/utils/channel/channel-listeners/enlist-message-channel-listener.test.ts b/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.test.ts similarity index 73% rename from packages/core/src/renderer/utils/channel/channel-listeners/enlist-message-channel-listener.test.ts rename to packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.test.ts index ac416a568e..dc89c7b3e7 100644 --- a/packages/core/src/renderer/utils/channel/channel-listeners/enlist-message-channel-listener.test.ts +++ b/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.test.ts @@ -1,12 +1,12 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getDiForUnitTesting } from "../../../getDiForUnitTesting"; -import type { EnlistMessageChannelListener } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token"; -import { enlistMessageChannelListenerInjectionToken } from "../../../../common/utils/channel/enlist-message-channel-listener-injection-token"; import type { IpcRendererEvent, IpcRenderer } from "electron"; -import ipcRendererInjectable from "../ipc-renderer.injectable"; +import ipcRendererInjectable from "../ipc/ipc-renderer.injectable"; +import { + EnlistMessageChannelListener, + enlistMessageChannelListenerInjectionToken, +} from "@k8slens/messaging"; +import { createContainer } from "@ogre-tools/injectable"; +import { registerFeature } from "@k8slens/feature-core"; +import { messagingFeatureForRenderer } from "../feature"; describe("enlist message channel listener in renderer", () => { let enlistMessageChannelListener: EnlistMessageChannelListener; @@ -15,7 +15,9 @@ describe("enlist message channel listener in renderer", () => { let offMock: jest.Mock; beforeEach(() => { - const di = getDiForUnitTesting(); + const di = createContainer("irrelevant"); + + registerFeature(di, messagingFeatureForRenderer); onMock = jest.fn(); offMock = jest.fn(); @@ -27,9 +29,7 @@ describe("enlist message channel listener in renderer", () => { di.override(ipcRendererInjectable, () => ipcRendererStub); - enlistMessageChannelListener = di.inject( - enlistMessageChannelListenerInjectionToken, - ); + enlistMessageChannelListener = di.inject(enlistMessageChannelListenerInjectionToken); }); describe("when called", () => { @@ -40,6 +40,7 @@ describe("enlist message channel listener in renderer", () => { handlerMock = jest.fn(); disposer = enlistMessageChannelListener({ + id: "some-listener", channel: { id: "some-channel-id" }, handler: handlerMock, }); @@ -50,10 +51,7 @@ describe("enlist message channel listener in renderer", () => { }); it("registers the listener", () => { - expect(onMock).toHaveBeenCalledWith( - "some-channel-id", - expect.any(Function), - ); + expect(onMock).toHaveBeenCalledWith("some-channel-id", expect.any(Function)); }); it("does not de-register the listener yet", () => { diff --git a/packages/technical-features/messaging/electron/renderer/src/listening-of-requests/enlist-request-channel-listener.injectable.ts b/packages/technical-features/messaging/electron/renderer/src/listening-of-requests/enlist-request-channel-listener.injectable.ts new file mode 100644 index 0000000000..92d6c978fe --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/listening-of-requests/enlist-request-channel-listener.injectable.ts @@ -0,0 +1,18 @@ +/* c8 ignore start */ +import { getInjectable } from "@ogre-tools/injectable"; +import { enlistRequestChannelListenerInjectionToken } from "@k8slens/messaging"; + +const enlistRequestChannelListenerInjectable = getInjectable({ + id: "enlist-request-channel-listener-for-renderer", + + instantiate: () => (listener) => { + throw new Error( + `Tried to enlist request channel "${listener.channel.id}" in "renderer", but requesting it's not supported yet.`, + ); + }, + + injectionToken: enlistRequestChannelListenerInjectionToken, +}); + +export default enlistRequestChannelListenerInjectable; +/* c8 ignore end */ diff --git a/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/invoke-ipc.injectable.ts b/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/invoke-ipc.injectable.ts new file mode 100644 index 0000000000..03329d0c92 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/invoke-ipc.injectable.ts @@ -0,0 +1,10 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import ipcRendererInjectable from "../ipc/ipc-renderer.injectable"; + +const invokeIpcInjectable = getInjectable({ + id: "invoke-ipc", + + instantiate: (di) => di.inject(ipcRendererInjectable).invoke, +}); + +export default invokeIpcInjectable; diff --git a/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/invoke-ipc.test.ts b/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/invoke-ipc.test.ts new file mode 100644 index 0000000000..e54c98616b --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/invoke-ipc.test.ts @@ -0,0 +1,21 @@ +import { createContainer, DiContainer } from "@ogre-tools/injectable"; +import { registerFeature } from "@k8slens/feature-core"; +import { messagingFeatureForRenderer } from "../feature"; +import { ipcRenderer } from "electron"; +import invokeIpcInjectable from "./invoke-ipc.injectable"; + +describe("ipc-renderer", () => { + let di: DiContainer; + + beforeEach(() => { + di = createContainer("irrelevant"); + + registerFeature(di, messagingFeatureForRenderer); + }); + + it("is IPC-renderer invoke of Electron", () => { + const actual = di.inject(invokeIpcInjectable); + + expect(actual).toBe(ipcRenderer.invoke); + }); +}); diff --git a/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/request-from-channel.injectable.ts b/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/request-from-channel.injectable.ts new file mode 100644 index 0000000000..032042198a --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/request-from-channel.injectable.ts @@ -0,0 +1,18 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import type { RequestFromChannel } from "@k8slens/messaging"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; +import invokeIpcInjectable from "./invoke-ipc.injectable"; + +const requestFromChannelInjectable = getInjectable({ + id: "request-from-channel", + + instantiate: (di) => { + const invokeIpc = di.inject(invokeIpcInjectable); + + return ((channel, request) => invokeIpc(channel.id, request)) as RequestFromChannel; + }, + + injectionToken: requestFromChannelInjectionToken, +}); + +export default requestFromChannelInjectable; diff --git a/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/request-from-channel.test.ts b/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/request-from-channel.test.ts new file mode 100644 index 0000000000..930040f117 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/requesting-of-requests/request-from-channel.test.ts @@ -0,0 +1,46 @@ +import { createContainer, DiContainer } from "@ogre-tools/injectable"; +import { registerFeature } from "@k8slens/feature-core"; +import { requestFromChannelInjectionToken } from "@k8slens/messaging"; +import { messagingFeatureForRenderer } from "../feature"; +import type { RequestChannel } from "@k8slens/messaging"; +import invokeIpcInjectable from "./invoke-ipc.injectable"; +import type { AsyncFnMock } from "@async-fn/jest"; +import asyncFn from "@async-fn/jest"; + +describe("request-from-channel", () => { + let di: DiContainer; + let invokeIpcMock: AsyncFnMock<() => Promise>; + + beforeEach(() => { + di = createContainer("irrelevant"); + + registerFeature(di, messagingFeatureForRenderer); + + invokeIpcMock = asyncFn(); + di.override(invokeIpcInjectable, () => invokeIpcMock); + }); + + describe("when called", () => { + let actualPromise: Promise; + + beforeEach(() => { + const requestFromChannel = di.inject(requestFromChannelInjectionToken); + + const someChannel: RequestChannel = { + id: "some-channel-id", + }; + + actualPromise = requestFromChannel(someChannel, "some-request-payload"); + }); + + it("invokes ipcRenderer of Electron", () => { + expect(invokeIpcMock).toHaveBeenCalledWith("some-channel-id", "some-request-payload"); + }); + + it("when invoke resolves with response, resolves with said response", async () => { + await invokeIpcMock.resolve(42); + + expect(await actualPromise).toBe(42); + }); + }); +}); diff --git a/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/message-to-channel.injectable.ts b/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/message-to-channel.injectable.ts new file mode 100644 index 0000000000..469a1548ab --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/message-to-channel.injectable.ts @@ -0,0 +1,19 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import sendToIpcInjectable from "./send-to-ipc.injectable"; +import { SendMessageToChannel, sendMessageToChannelInjectionToken } from "@k8slens/messaging"; + +const messageToChannelInjectable = getInjectable({ + id: "message-to-channel", + + instantiate: (di) => { + const sendToIpc = di.inject(sendToIpcInjectable); + + return ((channel, message) => { + sendToIpc(channel.id, message); + }) as SendMessageToChannel; + }, + + injectionToken: sendMessageToChannelInjectionToken, +}); + +export default messageToChannelInjectable; diff --git a/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/message-to-channel.test.ts b/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/message-to-channel.test.ts new file mode 100644 index 0000000000..07989cf16e --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/message-to-channel.test.ts @@ -0,0 +1,38 @@ +import { createContainer, DiContainer } from "@ogre-tools/injectable"; +import { registerFeature } from "@k8slens/feature-core"; +import { sendMessageToChannelInjectionToken } from "@k8slens/messaging"; +import { messagingFeatureForRenderer } from "../feature"; +import type { MessageChannel } from "@k8slens/messaging"; +import sendToIpcInjectable from "./send-to-ipc.injectable"; +import type { AsyncFnMock } from "@async-fn/jest"; +import asyncFn from "@async-fn/jest"; + +describe("message-from-channel", () => { + let di: DiContainer; + let sendToIpcMock: AsyncFnMock<() => Promise>; + + beforeEach(() => { + di = createContainer("irrelevant"); + + registerFeature(di, messagingFeatureForRenderer); + + sendToIpcMock = asyncFn(); + di.override(sendToIpcInjectable, () => sendToIpcMock); + }); + + describe("when called", () => { + beforeEach(() => { + const sendMessageToChannel = di.inject(sendMessageToChannelInjectionToken); + + const someChannel: MessageChannel = { + id: "some-channel-id", + }; + + sendMessageToChannel(someChannel, 42); + }); + + it("sends to ipcRenderer of Electron", () => { + expect(sendToIpcMock).toHaveBeenCalledWith("some-channel-id", 42); + }); + }); +}); diff --git a/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/send-to-ipc.injectable.ts b/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/send-to-ipc.injectable.ts new file mode 100644 index 0000000000..059dcbe8c2 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/send-to-ipc.injectable.ts @@ -0,0 +1,10 @@ +import { getInjectable } from "@ogre-tools/injectable"; +import ipcRendererInjectable from "../ipc/ipc-renderer.injectable"; + +const sendToIpcInjectable = getInjectable({ + id: "send-to-ipc", + + instantiate: (di) => di.inject(ipcRendererInjectable).send, +}); + +export default sendToIpcInjectable; diff --git a/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/send-to-ipc.test.ts b/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/send-to-ipc.test.ts new file mode 100644 index 0000000000..9d1b2303f5 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/src/sending-of-messages/send-to-ipc.test.ts @@ -0,0 +1,21 @@ +import { createContainer, DiContainer } from "@ogre-tools/injectable"; +import { registerFeature } from "@k8slens/feature-core"; +import { messagingFeatureForRenderer } from "../feature"; +import { ipcRenderer } from "electron"; +import sendToIpcInjectable from "./send-to-ipc.injectable"; + +describe("ipc-renderer", () => { + let di: DiContainer; + + beforeEach(() => { + di = createContainer("irrelevant"); + + registerFeature(di, messagingFeatureForRenderer); + }); + + it("is IPC-renderer send of Electron", () => { + const actual = di.inject(sendToIpcInjectable); + + expect(actual).toBe(ipcRenderer.send); + }); +}); diff --git a/packages/technical-features/messaging/electron/renderer/tsconfig.json b/packages/technical-features/messaging/electron/renderer/tsconfig.json new file mode 100644 index 0000000000..1819203dc1 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@k8slens/typescript/config/base.json", + "include": ["**/*.ts"] +} diff --git a/packages/technical-features/messaging/electron/renderer/webpack.config.js b/packages/technical-features/messaging/electron/renderer/webpack.config.js new file mode 100644 index 0000000000..3183f30179 --- /dev/null +++ b/packages/technical-features/messaging/electron/renderer/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForNode; diff --git a/packages/technical-features/messaging/message-bridge-fake/.eslintrc.json b/packages/technical-features/messaging/message-bridge-fake/.eslintrc.json new file mode 100644 index 0000000000..b15115cb69 --- /dev/null +++ b/packages/technical-features/messaging/message-bridge-fake/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "@k8slens/eslint-config/eslint", + "parserOptions": { + "project": "./tsconfig.json" + } +} diff --git a/packages/technical-features/messaging/message-bridge-fake/.prettierrc b/packages/technical-features/messaging/message-bridge-fake/.prettierrc new file mode 100644 index 0000000000..edd47b479e --- /dev/null +++ b/packages/technical-features/messaging/message-bridge-fake/.prettierrc @@ -0,0 +1 @@ +"@k8slens/eslint-config/prettier" diff --git a/packages/technical-features/messaging/message-bridge-fake/index.ts b/packages/technical-features/messaging/message-bridge-fake/index.ts new file mode 100644 index 0000000000..6b85a40628 --- /dev/null +++ b/packages/technical-features/messaging/message-bridge-fake/index.ts @@ -0,0 +1,3 @@ +export type { MessageBridgeFake } from "./src/get-message-bridge-fake/get-message-bridge-fake"; + +export { getMessageBridgeFake } from "./src/get-message-bridge-fake/get-message-bridge-fake"; diff --git a/packages/technical-features/messaging/message-bridge-fake/jest.config.js b/packages/technical-features/messaging/message-bridge-fake/jest.config.js new file mode 100644 index 0000000000..38d54ab7b6 --- /dev/null +++ b/packages/technical-features/messaging/message-bridge-fake/jest.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; diff --git a/packages/technical-features/messaging/message-bridge-fake/package.json b/packages/technical-features/messaging/message-bridge-fake/package.json new file mode 100644 index 0000000000..6837504a0e --- /dev/null +++ b/packages/technical-features/messaging/message-bridge-fake/package.json @@ -0,0 +1,49 @@ +{ + "name": "@k8slens/messaging-fake-bridge", + "private": false, + "version": "1.0.0-alpha.1", + "description": "Fake implementation to bridge multiple dependency injection containers.", + "type": "commonjs", + + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + + "files": [ + "dist" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/lensapp/lens.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "build": "webpack", + "dev": "webpack --mode=development --watch", + "test:unit": "jest --coverage --runInBand", + "lint:fix": "lens-lint --fix", + "lint": "lens-lint" + }, + "peerDependencies": { + "@k8slens/messaging": "^1.0.0-alpha.1", + "@ogre-tools/fp": "^15.1.2", + "@ogre-tools/injectable": "^15.1.2", + "lodash": "^4.17.21" + }, + + "devDependencies": { + "@async-fn/jest": "^1.6.4", + "@k8slens/feature-core": "6.5.0-alpha.1", + "@k8slens/eslint-config": "^6.5.0-alpha.1", + "@ogre-tools/injectable-extension-for-mobx": "^15.1.2", + "mobx": "^6.7.0" + } +} diff --git a/packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.test.ts b/packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.test.ts new file mode 100644 index 0000000000..e91109df10 --- /dev/null +++ b/packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.test.ts @@ -0,0 +1,397 @@ +import { createContainer, DiContainer, Injectable } from "@ogre-tools/injectable"; +import asyncFn, { AsyncFnMock } from "@async-fn/jest"; +import { registerFeature } from "@k8slens/feature-core"; +import { + getMessageChannel, + getMessageChannelListenerInjectable, + getRequestChannel, + getRequestChannelListenerInjectable, + MessageChannel, + testUtils, + RequestChannel, + requestFromChannelInjectionToken, + sendMessageToChannelInjectionToken, +} from "@k8slens/messaging"; + +import { registerMobX } from "@ogre-tools/injectable-extension-for-mobx"; +import { runInAction } from "mobx"; +import { getPromiseStatus } from "@k8slens/test-utils"; +import { getMessageBridgeFake } from "./get-message-bridge-fake"; +import { startApplicationInjectionToken } from "@k8slens/application"; + +type SomeMessageChannel = MessageChannel; +type SomeRequestChannel = RequestChannel; + +const someMessageChannel: SomeMessageChannel = getMessageChannel("some-message-channel"); +const someRequestChannel: SomeRequestChannel = getRequestChannel("some-request-channel"); +const someOtherRequestChannel: SomeRequestChannel = { + id: "some-other-request-channel", +}; +const someRequestChannelWithoutListeners: SomeRequestChannel = { + id: "some-request-channel-without-listeners", +}; + +[{ scenarioIsAsync: true }, { scenarioIsAsync: false }].forEach(({ scenarioIsAsync }) => + describe(`get-message-bridge-fake, given running as ${ + scenarioIsAsync ? "async" : "sync" + }`, () => { + let messageBridgeFake: any; + + beforeEach(() => { + messageBridgeFake = getMessageBridgeFake(); + }); + + describe("given multiple DIs are involved", () => { + let someDi1: DiContainer; + let someDi2: DiContainer; + let someDiWithoutListeners: DiContainer; + + beforeEach(async () => { + someDi1 = createContainer("some-di-1"); + someDi2 = createContainer("some-di-2"); + + someDiWithoutListeners = createContainer("some-di-3"); + + registerMobX(someDi1); + registerMobX(someDi2); + registerMobX(someDiWithoutListeners); + + runInAction(() => { + const feature = testUtils.messagingFeatureForUnitTesting; + + registerFeature(someDi1, feature); + registerFeature(someDi2, feature); + registerFeature(someDiWithoutListeners, feature); + }); + + messageBridgeFake.involve(someDi1, someDi2, someDiWithoutListeners); + + if (scenarioIsAsync) { + messageBridgeFake.setAsync(scenarioIsAsync); + } + + await Promise.all([ + someDi1.inject(startApplicationInjectionToken)(), + someDi2.inject(startApplicationInjectionToken)(), + someDiWithoutListeners.inject(startApplicationInjectionToken)(), + ]); + }); + + describe("given there are message listeners", () => { + let someHandler1MockInDi1: jest.Mock; + let someHandler1MockInDi2: jest.Mock; + let someHandler2MockInDi2: jest.Mock; + let someListener1InDi2: Injectable; + + beforeEach(() => { + someHandler1MockInDi1 = jest.fn(); + someHandler1MockInDi2 = jest.fn(); + someHandler2MockInDi2 = jest.fn(); + + const someListener1InDi1 = getMessageChannelListenerInjectable({ + id: "some-listener-in-di-1", + channel: someMessageChannel, + getHandler: () => someHandler1MockInDi1, + }); + + someListener1InDi2 = getMessageChannelListenerInjectable({ + id: "some-listener-in-di-2", + channel: someMessageChannel, + getHandler: () => someHandler1MockInDi2, + }); + + const someListener2InDi2 = getMessageChannelListenerInjectable({ + id: "some-listener-2-in-di-2", + channel: someMessageChannel, + getHandler: () => someHandler2MockInDi2, + }); + + runInAction(() => { + someDi1.register(someListener1InDi1); + someDi2.register(someListener1InDi2); + someDi2.register(someListener2InDi2); + }); + }); + + describe("given there is a listener in di-2 that responds to a message with a message", () => { + beforeEach(() => { + const someResponder = getMessageChannelListenerInjectable({ + id: "some-responder-di-2", + channel: someMessageChannel, + + getHandler: (di) => { + const sendMessage = di.inject(sendMessageToChannelInjectionToken); + + return (message) => { + sendMessage(someMessageChannel, `some-response-to: ${message}`); + }; + }, + }); + + runInAction(() => { + someDi2.register(someResponder); + }); + }); + + describe("given a message is sent in di-1", () => { + beforeEach(() => { + const sendMessageToChannelFromDi1 = someDi1.inject( + sendMessageToChannelInjectionToken, + ); + + sendMessageToChannelFromDi1(someMessageChannel, "some-message"); + }); + + const scenarioTitle = scenarioIsAsync + ? "when all message steps are propagated using a wrapper" + : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioTitle, () => { + let someWrapper: jest.Mock; + + beforeEach((done) => { + someWrapper = jest.fn((propagation) => propagation()); + + if (scenarioIsAsync) { + messageBridgeFake.messagePropagationRecursive(someWrapper).then(done); + } else { + done(); + } + }); + + it("the response gets handled in di-1", () => { + expect(someHandler1MockInDi1).toHaveBeenCalledWith( + "some-response-to: some-message", + { + frameId: 42, + processId: 42, + }, + ); + }); + + scenarioIsAsync && + it("the wrapper gets called with the both propagations", () => { + expect(someWrapper).toHaveBeenCalledTimes(2); + }); + }); + + const scenarioName: string = scenarioIsAsync + ? "when all message steps are propagated not using a wrapper" + : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioName, () => { + beforeEach((done) => { + if (scenarioIsAsync) { + messageBridgeFake.messagePropagationRecursive().then(done); + } else { + done(); + } + }); + + it("the response gets handled in di-1", () => { + expect(someHandler1MockInDi1).toHaveBeenCalledWith( + "some-response-to: some-message", + { + frameId: 42, + processId: 42, + }, + ); + }); + }); + }); + }); + + describe("when sending message in a DI", () => { + beforeEach(() => { + const sendMessageToChannelFromDi1 = someDi1.inject(sendMessageToChannelInjectionToken); + + sendMessageToChannelFromDi1(someMessageChannel, "some-message"); + }); + + it("listener in sending DI does not handle the message", () => { + expect(someHandler1MockInDi1).not.toHaveBeenCalled(); + }); + + scenarioIsAsync && + it("listeners in other than sending DIs do not handle the message yet", () => { + expect(someHandler1MockInDi2).not.toHaveBeenCalled(); + expect(someHandler2MockInDi2).not.toHaveBeenCalled(); + }); + + const scenarioName = scenarioIsAsync ? "when messages are propagated" : "immediately"; + + // eslint-disable-next-line jest/valid-title + describe(scenarioName, () => { + beforeEach((done) => { + if (scenarioIsAsync) { + messageBridgeFake.messagePropagation().then(done); + } else { + done(); + } + }); + + it("listeners in other than sending DIs handle the message", () => { + expect(someHandler1MockInDi2).toHaveBeenCalledWith("some-message", { + frameId: 42, + processId: 42, + }); + + expect(someHandler2MockInDi2).toHaveBeenCalledWith("some-message", { + frameId: 42, + processId: 42, + }); + }); + }); + + scenarioIsAsync && + describe("when messages are propagated using a wrapper, such as act() in react testing lib", () => { + let someWrapper: jest.Mock; + + beforeEach(async () => { + someWrapper = jest.fn((observation) => observation()); + + await messageBridgeFake.messagePropagation(someWrapper); + }); + + it("the wrapper gets called with the related propagation", async () => { + expect(someWrapper).toHaveBeenCalledTimes(1); + }); + + it("listeners still handle the message", () => { + expect(someHandler1MockInDi2).toHaveBeenCalledWith("some-message", { + frameId: 42, + processId: 42, + }); + + expect(someHandler2MockInDi2).toHaveBeenCalledWith("some-message", { + frameId: 42, + processId: 42, + }); + }); + }); + }); + + it("given a listener is deregistered, when sending message, deregistered listener does not handle the message", () => { + runInAction(() => { + someDi2.deregister(someListener1InDi2); + }); + + const sendMessageToChannelFromDi1 = someDi1.inject(sendMessageToChannelInjectionToken); + + someHandler1MockInDi2.mockClear(); + + sendMessageToChannelFromDi1(someMessageChannel, "irrelevant"); + + expect(someHandler1MockInDi2).not.toHaveBeenCalled(); + }); + }); + + describe("given there are request listeners", () => { + let someHandler1MockInDi1: AsyncFnMock<(message: string) => Promise>; + + let someHandler1MockInDi2: AsyncFnMock<(message: string) => Promise>; + + let someListener1InDi2: Injectable; + let actualPromise: Promise; + + beforeEach(() => { + someHandler1MockInDi1 = asyncFn(); + someHandler1MockInDi2 = asyncFn(); + + const someListener1InDi1 = getRequestChannelListenerInjectable({ + id: "some-request-listener-in-di-1", + channel: someOtherRequestChannel, + getHandler: () => someHandler1MockInDi1, + }); + + someListener1InDi2 = getRequestChannelListenerInjectable({ + id: "some-request-listener-in-di-2", + channel: someRequestChannel, + getHandler: () => someHandler1MockInDi2, + }); + + runInAction(() => { + someDi1.register(someListener1InDi1); + someDi2.register(someListener1InDi2); + }); + }); + + describe("when requesting from a channel in a DI", () => { + beforeEach(() => { + const requestFromChannelFromDi1 = someDi1.inject(requestFromChannelInjectionToken); + + actualPromise = requestFromChannelFromDi1(someRequestChannel, "some-request"); + }); + + it("listener in requesting DI does not handle the request", () => { + expect(someHandler1MockInDi1).not.toHaveBeenCalled(); + }); + + it("the listener in other than requesting DIs handle the request", () => { + expect(someHandler1MockInDi2).toHaveBeenCalledWith("some-request"); + }); + + it("does not resolve yet", async () => { + const promiseStatus = await getPromiseStatus(actualPromise); + + expect(promiseStatus.fulfilled).toBe(false); + }); + + it("when handle resolves, resolves with response", async () => { + await someHandler1MockInDi2.resolve(42); + + const actual = await actualPromise; + + expect(actual).toBe(42); + }); + }); + + it("given a listener is deregistered, when requesting, deregistered listener does not handle the request", () => { + runInAction(() => { + someDi2.deregister(someListener1InDi2); + }); + + const sendMessageToChannelFromDi1 = someDi1.inject(sendMessageToChannelInjectionToken); + + someHandler1MockInDi2.mockClear(); + + sendMessageToChannelFromDi1(someMessageChannel, "irrelevant"); + + expect(someHandler1MockInDi2).not.toHaveBeenCalled(); + }); + + it("given there are multiple listeners between different DIs for same channel, when requesting, throws", () => { + const someConflictingListenerInjectable = getRequestChannelListenerInjectable({ + id: "conflicting-listener", + channel: someRequestChannel, + getHandler: () => () => 84, + }); + + runInAction(() => { + someDi1.register(someConflictingListenerInjectable); + }); + + const requestFromChannelFromDi2 = someDi2.inject(requestFromChannelInjectionToken); + + return expect(() => + requestFromChannelFromDi2(someRequestChannel, "irrelevant"), + ).rejects.toThrow( + 'Tried to make a request but multiple listeners were discovered for channel "some-request-channel" in multiple DIs.', + ); + }); + + it("when requesting from channel without listener, throws", () => { + const requestFromChannel = someDi1.inject(requestFromChannelInjectionToken); + + return expect(() => + requestFromChannel(someRequestChannelWithoutListeners, "irrelevant"), + ).rejects.toThrow( + 'Tried to make a request but no listeners for channel "some-request-channel-without-listeners" was discovered in any DIs', + ); + }); + }); + }); + }), +); diff --git a/packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.ts b/packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.ts new file mode 100644 index 0000000000..ef8eed6461 --- /dev/null +++ b/packages/technical-features/messaging/message-bridge-fake/src/get-message-bridge-fake/get-message-bridge-fake.ts @@ -0,0 +1,196 @@ +import type { DiContainer } from "@ogre-tools/injectable"; +import type { Channel, MessageChannelHandler, RequestChannelHandler } from "@k8slens/messaging"; + +import { + enlistMessageChannelListenerInjectionToken, + enlistRequestChannelListenerInjectionToken, + RequestFromChannel, + requestFromChannelInjectionToken, + sendMessageToChannelInjectionToken, +} from "@k8slens/messaging"; + +import { pipeline } from "@ogre-tools/fp"; +import { filter, map } from "lodash/fp"; +import asyncFn, { AsyncFnMock } from "@async-fn/jest"; + +export type MessageBridgeFake = { + involve: (...dis: DiContainer[]) => void; + messagePropagation: () => Promise; + messagePropagationRecursive: (callback: any) => any; + setAsync: (value: boolean) => void; +}; + +const overrideMessaging = ({ + di, + messageListenersByDi, + messagePropagationBuffer, + getAsyncModeStatus, +}: { + di: DiContainer; + + messageListenersByDi: Map>>>; + + messagePropagationBuffer: Set<{ resolve: () => Promise }>; + + getAsyncModeStatus: () => boolean; +}) => { + const messageHandlersByChannel = new Map>>(); + + messageListenersByDi.set(di, messageHandlersByChannel); + + di.override(sendMessageToChannelInjectionToken, () => (channel, message) => { + const allOtherDis = [...messageListenersByDi.keys()].filter((x) => x !== di); + + allOtherDis.forEach((otherDi) => { + const listeners = messageListenersByDi.get(otherDi); + + const handlersForChannel = listeners?.get(channel.id); + + if (!handlersForChannel) { + return; + } + + if (getAsyncModeStatus()) { + const resolvableHandlePromise = asyncFn(); + + resolvableHandlePromise().then(() => { + handlersForChannel.forEach((handler) => handler(message, { frameId: 42, processId: 42 })); + }); + + messagePropagationBuffer.add(resolvableHandlePromise); + } else { + handlersForChannel.forEach((handler) => handler(message, { frameId: 42, processId: 42 })); + } + }); + }); + + di.override(enlistMessageChannelListenerInjectionToken, () => (listener) => { + if (!messageHandlersByChannel.has(listener.channel.id)) { + messageHandlersByChannel.set(listener.channel.id, new Set()); + } + + const handlerSet = messageHandlersByChannel.get(listener.channel.id); + + handlerSet?.add(listener.handler); + + return () => { + handlerSet?.delete(listener.handler); + }; + }); +}; + +const overrideRequesting = ({ + di, + requestListenersByDi, +}: { + di: DiContainer; + + requestListenersByDi: Map>>>; +}) => { + const requestHandlersByChannel = new Map>>(); + + requestListenersByDi.set(di, requestHandlersByChannel); + + di.override( + requestFromChannelInjectionToken, + () => + (async (channel, request) => + pipeline( + [...requestListenersByDi.values()], + map((listenersByChannel) => listenersByChannel?.get(channel.id)), + filter((x) => !!x), + + (channelSpecificListeners) => { + if (channelSpecificListeners.length === 0) { + throw new Error( + `Tried to make a request but no listeners for channel "${channel.id}" was discovered in any DIs`, + ); + } + + if (channelSpecificListeners.length > 1) { + throw new Error( + `Tried to make a request but multiple listeners were discovered for channel "${channel.id}" in multiple DIs.`, + ); + } + + const listeners = channelSpecificListeners[0]; + + // eslint-disable-next-line @typescript-eslint/no-non-null-assertion + const [handler] = listeners!; + + return handler; + }, + + async (handler) => handler(request), + )) as RequestFromChannel, + ); + + di.override(enlistRequestChannelListenerInjectionToken, () => (listener) => { + if (!requestHandlersByChannel.has(listener.channel.id)) { + requestHandlersByChannel.set(listener.channel.id, new Set()); + } + + const handlerSet = requestHandlersByChannel.get(listener.channel.id); + + handlerSet?.add(listener.handler); + + return () => { + handlerSet?.delete(listener.handler); + }; + }); +}; + +export const getMessageBridgeFake = (): MessageBridgeFake => { + const messageListenersByDi = new Map< + DiContainer, + Map>> + >(); + + const requestListenersByDi = new Map< + DiContainer, + Map>> + >(); + + const messagePropagationBuffer = new Set void>>(); + + const messagePropagation = async (wrapper: (callback: any) => any = (callback) => callback()) => { + const oldMessages = [...messagePropagationBuffer.values()]; + + messagePropagationBuffer.clear(); + await Promise.all(oldMessages.map((x) => wrapper(x.resolve))); + }; + + const messagePropagationRecursive = async ( + wrapper: (callback: any) => any = (callback) => callback(), + ) => { + while (messagePropagationBuffer.size) { + await messagePropagation(wrapper); + } + }; + + let asyncModeStatus = false; + const getAsyncModeStatus = () => asyncModeStatus; + + return { + involve: (...dis: DiContainer[]) => { + dis.forEach((di) => { + overrideRequesting({ di, requestListenersByDi }); + + overrideMessaging({ + di, + messageListenersByDi, + messagePropagationBuffer, + getAsyncModeStatus, + }); + }); + }, + + messagePropagation, + + messagePropagationRecursive, + + setAsync: (value) => { + asyncModeStatus = value; + }, + }; +}; diff --git a/packages/technical-features/messaging/message-bridge-fake/tsconfig.json b/packages/technical-features/messaging/message-bridge-fake/tsconfig.json new file mode 100644 index 0000000000..ec29a8f75f --- /dev/null +++ b/packages/technical-features/messaging/message-bridge-fake/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@k8slens/typescript/config/base.json", + "include": ["**/*.ts", "**/*.tsx"] +} diff --git a/packages/technical-features/messaging/message-bridge-fake/webpack.config.js b/packages/technical-features/messaging/message-bridge-fake/webpack.config.js new file mode 100644 index 0000000000..3183f30179 --- /dev/null +++ b/packages/technical-features/messaging/message-bridge-fake/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForNode; diff --git a/packages/utility-features/run-many/jest.config.js b/packages/utility-features/run-many/jest.config.js index 23be80353b..05dbeacf60 100644 --- a/packages/utility-features/run-many/jest.config.js +++ b/packages/utility-features/run-many/jest.config.js @@ -1,2 +1,3 @@ -module.exports = - require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; +const config = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; + +module.exports = { ...config, coverageThreshold: undefined }; diff --git a/packages/utility-features/run-many/package.json b/packages/utility-features/run-many/package.json index 1dd0229afd..1fa8af2ba1 100644 --- a/packages/utility-features/run-many/package.json +++ b/packages/utility-features/run-many/package.json @@ -22,12 +22,12 @@ "scripts": { "build": "webpack", "dev": "webpack --mode=development --watch", - "test": "jest --coverage --runInBand" + "test:unit": "jest --coverage --runInBand" }, "peerDependencies": { "@k8slens/test-utils": "^1.0.0-alpha.1", "@k8slens/utilities": "^1.0.0-alpha.1", - "@ogre-tools/fp": "^15.1.1", + "@ogre-tools/fp": "^15.1.2", "@ogre-tools/injectable": "^15.1.2", "type-fest": "^2.19.0", "typed-emitter": "^1.4.0", diff --git a/packages/utility-features/startable-stoppable/.eslintrc.json b/packages/utility-features/startable-stoppable/.eslintrc.json new file mode 100644 index 0000000000..b15115cb69 --- /dev/null +++ b/packages/utility-features/startable-stoppable/.eslintrc.json @@ -0,0 +1,6 @@ +{ + "extends": "@k8slens/eslint-config/eslint", + "parserOptions": { + "project": "./tsconfig.json" + } +} diff --git a/packages/utility-features/startable-stoppable/.prettierrc b/packages/utility-features/startable-stoppable/.prettierrc new file mode 100644 index 0000000000..edd47b479e --- /dev/null +++ b/packages/utility-features/startable-stoppable/.prettierrc @@ -0,0 +1 @@ +"@k8slens/eslint-config/prettier" diff --git a/packages/utility-features/startable-stoppable/index.ts b/packages/utility-features/startable-stoppable/index.ts new file mode 100644 index 0000000000..7f5c07cf47 --- /dev/null +++ b/packages/utility-features/startable-stoppable/index.ts @@ -0,0 +1,3 @@ +export type { StartableStoppable, Starter, Stopper } from "./src/get-startable-stoppable"; + +export { getStartableStoppable } from "./src/get-startable-stoppable"; diff --git a/packages/utility-features/startable-stoppable/jest.config.js b/packages/utility-features/startable-stoppable/jest.config.js new file mode 100644 index 0000000000..38d54ab7b6 --- /dev/null +++ b/packages/utility-features/startable-stoppable/jest.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; diff --git a/packages/utility-features/startable-stoppable/package.json b/packages/utility-features/startable-stoppable/package.json new file mode 100644 index 0000000000..940e1e91b2 --- /dev/null +++ b/packages/utility-features/startable-stoppable/package.json @@ -0,0 +1,38 @@ +{ + "name": "@k8slens/startable-stoppable", + "private": false, + "version": "1.0.0-alpha.1", + "description": "TBD", + "type": "commonjs", + + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + + "files": [ + "build" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/lensapp/lens.git" + }, + "main": "dist/index.js", + "types": "dist/index.d.ts", + "author": { + "name": "OpenLens Authors", + "email": "info@k8slens.dev" + }, + "license": "MIT", + "homepage": "https://github.com/lensapp/lens", + "scripts": { + "build": "webpack", + "dev": "webpack --mode=development --watch", + "test:unit": "jest --coverage --runInBand", + "lint": "lens-lint", + "lint:fix": "lens-lint --fix" + }, + "devDependencies": { + "@k8slens/eslint-config": "^6.5.0-alpha.1" + } +} diff --git a/packages/core/src/common/utils/get-startable-stoppable.test.ts b/packages/utility-features/startable-stoppable/src/get-startable-stoppable.test.ts similarity index 84% rename from packages/core/src/common/utils/get-startable-stoppable.test.ts rename to packages/utility-features/startable-stoppable/src/get-startable-stoppable.test.ts index dc8b24dd43..2ec64eeb95 100644 --- a/packages/core/src/common/utils/get-startable-stoppable.test.ts +++ b/packages/utility-features/startable-stoppable/src/get-startable-stoppable.test.ts @@ -1,7 +1,3 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ import type { StartableStoppable } from "./get-startable-stoppable"; import { getStartableStoppable } from "./get-startable-stoppable"; @@ -25,7 +21,7 @@ describe("getStartableStoppable", () => { }); it("when stopping before ever starting, throws", () => { - expect(() => actual.stop()).toThrow("Tried to stop \"some-id\", but it is already stopped."); + expect(() => actual.stop()).toThrow('Tried to stop "some-id", but it is already stopped.'); }); it("is not started", () => { @@ -45,6 +41,10 @@ describe("getStartableStoppable", () => { expect(actual.started).toBe(true); }); + it("when started again, throws", () => { + expect(() => actual.start()).toThrow('Tried to start "some-id", but it is already started.'); + }); + describe("when stopped", () => { beforeEach(() => { actual.stop(); diff --git a/packages/core/src/common/utils/get-startable-stoppable.ts b/packages/utility-features/startable-stoppable/src/get-startable-stoppable.ts similarity index 86% rename from packages/core/src/common/utils/get-startable-stoppable.ts rename to packages/utility-features/startable-stoppable/src/get-startable-stoppable.ts index 05d8b4d9af..85f0a6336d 100644 --- a/packages/core/src/common/utils/get-startable-stoppable.ts +++ b/packages/utility-features/startable-stoppable/src/get-startable-stoppable.ts @@ -1,8 +1,3 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - export type Stopper = () => void; export type Starter = () => Stopper; diff --git a/packages/utility-features/startable-stoppable/tsconfig.json b/packages/utility-features/startable-stoppable/tsconfig.json new file mode 100644 index 0000000000..1819203dc1 --- /dev/null +++ b/packages/utility-features/startable-stoppable/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "@k8slens/typescript/config/base.json", + "include": ["**/*.ts"] +} diff --git a/packages/utility-features/startable-stoppable/webpack.config.js b/packages/utility-features/startable-stoppable/webpack.config.js new file mode 100644 index 0000000000..3183f30179 --- /dev/null +++ b/packages/utility-features/startable-stoppable/webpack.config.js @@ -0,0 +1 @@ +module.exports = require("@k8slens/webpack").configForNode; diff --git a/packages/utility-features/test-utils/index.ts b/packages/utility-features/test-utils/index.ts index ed5afc6535..aca8fd5f9a 100644 --- a/packages/utility-features/test-utils/index.ts +++ b/packages/utility-features/test-utils/index.ts @@ -2,3 +2,5 @@ export * from "./src/flush-promises"; export * from "./src/get-global-override-for-function"; export * from "./src/get-global-override"; export * from "./src/get-promise-status"; +export * from "./src/render-for"; +export * from "./src/run-with-thrown-mobx-reactions"; diff --git a/packages/utility-features/test-utils/package.json b/packages/utility-features/test-utils/package.json index 0dc5170a07..4336c0682b 100644 --- a/packages/utility-features/test-utils/package.json +++ b/packages/utility-features/test-utils/package.json @@ -21,12 +21,14 @@ "homepage": "https://github.com/lensapp/lens", "scripts": { "build": "webpack", - "dev": "webpack --mode=development --watch", - "test": "jest --coverage --runInBand" + "dev": "webpack --mode=development --watch" }, "peerDependencies": { "@ogre-tools/injectable": "^15.1.2", - "lodash": "^4.17.21" + "@ogre-tools/injectable-react": "^15.1.2", + "@testing-library/react": "^12.1.5", + "lodash": "^4.17.21", + "react": "^17.0.2" }, "devDependencies": { "@types/lodash": "^4.14.191" diff --git a/packages/utility-features/test-utils/src/render-for.tsx b/packages/utility-features/test-utils/src/render-for.tsx new file mode 100644 index 0000000000..2508d70d69 --- /dev/null +++ b/packages/utility-features/test-utils/src/render-for.tsx @@ -0,0 +1,24 @@ +import React from "react"; +import type { RenderResult } from "@testing-library/react"; +import { render as testingLibraryRender } from "@testing-library/react"; +import type { DiContainer } from "@ogre-tools/injectable"; +import { DiContextProvider } from "@ogre-tools/injectable-react"; + +export type DiRender = (ui: React.ReactElement) => RenderResult; + +type DiRenderFor = (di: DiContainer) => DiRender; + +export const renderFor: DiRenderFor = (di) => (ui) => { + const result = testingLibraryRender( + {ui} + ); + + return { + ...result, + + rerender: (ui: React.ReactElement) => + result.rerender( + {ui} + ), + }; +}; diff --git a/packages/utility-features/test-utils/src/run-with-thrown-mobx-reactions.ts b/packages/utility-features/test-utils/src/run-with-thrown-mobx-reactions.ts new file mode 100644 index 0000000000..cc3f7ada23 --- /dev/null +++ b/packages/utility-features/test-utils/src/run-with-thrown-mobx-reactions.ts @@ -0,0 +1,38 @@ +import { noop } from "lodash/fp"; +import { _resetGlobalState, configure } from "mobx"; + +export const runWithThrownMobxReactions = (callback: () => void) => { + const originalConsoleWarn = console.warn; + + console.warn = noop; + + configure({ + disableErrorBoundaries: true, + }); + + console.warn = originalConsoleWarn; + + let error: any; + + try { + callback(); + } catch (e) { + error = e; + } finally { + configure({ + disableErrorBoundaries: false, + }); + + // This is because when disableErrorBoundaries is true, MobX doesn't recover from the thrown + // errors, and its global state starts bleeding between tests making. + _resetGlobalState(); + + if (!error) { + throw new Error( + "Tried to run with thrown MobX reactions but nothing was thrown" + ); + } else { + throw error; + } + } +}; diff --git a/packages/utility-features/utilities/jest.config.js b/packages/utility-features/utilities/jest.config.js index 23be80353b..05dbeacf60 100644 --- a/packages/utility-features/utilities/jest.config.js +++ b/packages/utility-features/utilities/jest.config.js @@ -1,2 +1,3 @@ -module.exports = - require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; +const config = require("@k8slens/jest").monorepoPackageConfig(__dirname).configForReact; + +module.exports = { ...config, coverageThreshold: undefined }; diff --git a/packages/utility-features/utilities/package.json b/packages/utility-features/utilities/package.json index 01c75c4d7c..777907d851 100644 --- a/packages/utility-features/utilities/package.json +++ b/packages/utility-features/utilities/package.json @@ -22,7 +22,7 @@ "scripts": { "build": "webpack", "dev": "webpack --mode=development --watch", - "test": "jest --coverage --runInBand" + "test:unit": "jest --coverage --runInBand" }, "peerDependencies": { "@astronautlabs/jsonpath": "^1.1.0", @@ -47,6 +47,7 @@ "@types/react-router": "^5.1.20", "@types/readable-stream": "^2.3.15", "@types/semver": "^7.3.13", - "@types/tar": "^6.1.4" + "@types/tar": "^6.1.4", + "type-fest": "^2.14.0" } } diff --git a/packages/utility-features/utilities/src/splitArray.test.ts b/packages/utility-features/utilities/src/splitArray.test.ts index 038d4731d8..9a1a2aac59 100644 --- a/packages/utility-features/utilities/src/splitArray.test.ts +++ b/packages/utility-features/utilities/src/splitArray.test.ts @@ -3,62 +3,62 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { bifurcateArray, splitArray } from "../splitArray"; +import { array } from "./array"; describe("split array on element tests", () => { it("empty array", () => { - expect(splitArray([], 10)).toStrictEqual([[], [], false]); + expect(array.split([], 10)).toStrictEqual([[], [], false]); }); it("one element, not in array", () => { - expect(splitArray([1], 10)).toStrictEqual([[1], [], false]); + expect(array.split([1], 10)).toStrictEqual([[1], [], false]); }); it("ten elements, not in array", () => { - expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 10)).toStrictEqual([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [], false]); + expect(array.split([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 10)).toStrictEqual([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9], [], false]); }); it("one elements, in array", () => { - expect(splitArray([1], 1)).toStrictEqual([[], [], true]); + expect(array.split([1], 1)).toStrictEqual([[], [], true]); }); it("ten elements, in front array", () => { - expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 0)).toStrictEqual([[], [1, 2, 3, 4, 5, 6, 7, 8, 9], true]); + expect(array.split([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 0)).toStrictEqual([[], [1, 2, 3, 4, 5, 6, 7, 8, 9], true]); }); it("ten elements, in middle array", () => { - expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 4)).toStrictEqual([[0, 1, 2, 3], [5, 6, 7, 8, 9], true]); + expect(array.split([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 4)).toStrictEqual([[0, 1, 2, 3], [5, 6, 7, 8, 9], true]); }); it("ten elements, in end array", () => { - expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 9)).toStrictEqual([[0, 1, 2, 3, 4, 5, 6, 7, 8], [], true]); + expect(array.split([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 9)).toStrictEqual([[0, 1, 2, 3, 4, 5, 6, 7, 8], [], true]); }); }); describe("bifurcateArray", () => { it("should return tuple of empty arrays from empty array", () => { - const [left, right] = bifurcateArray([], () => true); + const [left, right] = array.bifurcate([], () => true); expect(left).toStrictEqual([]); expect(right).toStrictEqual([]); }); it("should return all true condition returning items in the right array", () => { - const [left, right] = bifurcateArray([1, 2, 3], () => true); + const [left, right] = array.bifurcate([1, 2, 3], () => true); expect(left).toStrictEqual([]); expect(right).toStrictEqual([1, 2, 3]); }); it("should return all false condition returning items in the right array", () => { - const [left, right] = bifurcateArray([1, 2, 3], () => false); + const [left, right] = array.bifurcate([1, 2, 3], () => false); expect(left).toStrictEqual([1, 2, 3]); expect(right).toStrictEqual([]); }); it("should split array as specified", () => { - const [left, right] = bifurcateArray([1, 2, 3], (i) => Boolean(i % 2)); + const [left, right] = array.bifurcate([1, 2, 3], (i) => Boolean(i % 2)); expect(left).toStrictEqual([2]); expect(right).toStrictEqual([1, 3]); diff --git a/packages/utility-features/utilities/src/union-env-path.test.ts b/packages/utility-features/utilities/src/union-env-path.test.ts index ff8ca916d2..10afb9d1d6 100644 --- a/packages/utility-features/utilities/src/union-env-path.test.ts +++ b/packages/utility-features/utilities/src/union-env-path.test.ts @@ -4,7 +4,7 @@ */ import path from "path"; -import { unionPATHs } from "../union-env-path"; +import { unionPATHs } from "./union-env-path"; describe("unionPATHs", () => { it("return the same path if given only one with no double delimiters", () => { From a920f2c057a53e38e6627faf273b2a67d80e749e Mon Sep 17 00:00:00 2001 From: Jari Kolehmainen Date: Tue, 21 Mar 2023 17:07:27 +0200 Subject: [PATCH 09/17] Electron 22.3.3 (#7389) * electron 22.3.3. Signed-off-by: Jari Kolehmainen * fix typo Signed-off-by: Jari Kolehmainen * fix crash on quit Signed-off-by: Jari Kolehmainen * fix sessionData app path Signed-off-by: Jari Kolehmainen * Fix errors after merging new feature Signed-off-by: Sebastian Malton --------- Signed-off-by: Jari Kolehmainen Signed-off-by: Sebastian Malton Co-authored-by: Sebastian Malton --- package-lock.json | 368 ++++-------------- packages/core/package.json | 2 +- .../src/common/app-paths/app-path-names.ts | 2 +- .../src/common/app-paths/app-paths.test.ts | 6 +- .../initialize-sentry-reporting.injectable.ts | 2 +- .../app-paths/setup-app-paths.injectable.ts | 1 + .../resolve-system-proxy-window.injectable.ts | 6 +- packages/open-lens/package.json | 4 +- .../application/electron-main/package.json | 2 +- .../messaging/electron/main/package.json | 2 +- .../messaging/electron/renderer/package.json | 2 +- 11 files changed, 89 insertions(+), 308 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc13b55540..d00efc567c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2099,92 +2099,25 @@ } }, "node_modules/@electron/get": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@electron/get/-/get-1.14.1.tgz", - "integrity": "sha512-BrZYyL/6m0ZXz/lDxy/nlVhQz+WF+iPS6qXolEU8atw7h6v1aYkjwJZ63m+bJMBTxDE66X+r2tPS4a/8C82sZw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@electron/get/-/get-2.0.2.tgz", + "integrity": "sha512-eFZVFoRXb3GFGd7Ak7W4+6jBl9wBtiZ4AaYOse97ej6mKj5tkyO0dUnUChs1IhJZtx1BENo4/p4WUTXpi6vT+g==", "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", - "got": "^9.6.0", + "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "engines": { - "node": ">=8.6" + "node": ">=12" }, "optionalDependencies": { - "global-agent": "^3.0.0", - "global-tunnel-ng": "^2.7.1" + "global-agent": "^3.0.0" } }, - "node_modules/@electron/get/node_modules/@sindresorhus/is": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/is/-/is-0.14.0.tgz", - "integrity": "sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/@electron/get/node_modules/@szmarczak/http-timer": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@szmarczak/http-timer/-/http-timer-1.1.2.tgz", - "integrity": "sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==", - "dependencies": { - "defer-to-connect": "^1.0.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@electron/get/node_modules/cacheable-request": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/cacheable-request/-/cacheable-request-6.1.0.tgz", - "integrity": "sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==", - "dependencies": { - "clone-response": "^1.0.2", - "get-stream": "^5.1.0", - "http-cache-semantics": "^4.0.0", - "keyv": "^3.0.0", - "lowercase-keys": "^2.0.0", - "normalize-url": "^4.1.0", - "responselike": "^1.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@electron/get/node_modules/cacheable-request/node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@electron/get/node_modules/decompress-response": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-3.3.0.tgz", - "integrity": "sha512-BzRPQuY1ip+qDonAOz42gRm/pg9F768C+npV/4JOsxRC2sq+Rlk+Q4ZCAsOhnIaMrgarILY+RMUIvMmmX1qAEA==", - "dependencies": { - "mimic-response": "^1.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/@electron/get/node_modules/defer-to-connect": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/defer-to-connect/-/defer-to-connect-1.1.3.tgz", - "integrity": "sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==" - }, "node_modules/@electron/get/node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", @@ -2198,51 +2131,6 @@ "node": ">=6 <7 || >=8" } }, - "node_modules/@electron/get/node_modules/get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@electron/get/node_modules/got": { - "version": "9.6.0", - "resolved": "https://registry.npmjs.org/got/-/got-9.6.0.tgz", - "integrity": "sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==", - "dependencies": { - "@sindresorhus/is": "^0.14.0", - "@szmarczak/http-timer": "^1.1.2", - "cacheable-request": "^6.0.0", - "decompress-response": "^3.3.0", - "duplexer3": "^0.1.4", - "get-stream": "^4.1.0", - "lowercase-keys": "^1.0.1", - "mimic-response": "^1.0.1", - "p-cancelable": "^1.0.0", - "to-readable-stream": "^1.0.0", - "url-parse-lax": "^3.0.0" - }, - "engines": { - "node": ">=8.6" - } - }, - "node_modules/@electron/get/node_modules/got/node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/@electron/get/node_modules/json-buffer": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.0.tgz", - "integrity": "sha512-CuUqjv0FUZIdXkHPI8MezCnFCdaTAacej1TZYulLoAg1h/PhwkdXFN4V/gzY4g+fMBCOV2xF+rp7t2XD2ns/NQ==" - }, "node_modules/@electron/get/node_modules/jsonfile": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", @@ -2251,55 +2139,6 @@ "graceful-fs": "^4.1.6" } }, - "node_modules/@electron/get/node_modules/keyv": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-3.1.0.tgz", - "integrity": "sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==", - "dependencies": { - "json-buffer": "3.0.0" - } - }, - "node_modules/@electron/get/node_modules/normalize-url": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-4.5.1.tgz", - "integrity": "sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==", - "engines": { - "node": ">=8" - } - }, - "node_modules/@electron/get/node_modules/p-cancelable": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/p-cancelable/-/p-cancelable-1.1.0.tgz", - "integrity": "sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/@electron/get/node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/@electron/get/node_modules/responselike": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/responselike/-/responselike-1.0.2.tgz", - "integrity": "sha512-/Fpe5guzJk1gPqdJLJR5u7eG/gNY4nImjbRDaVWVMRhne55TCmj2i9Q+54PBRfatRC8v/rIiv9BN0pMd9OV5EQ==", - "dependencies": { - "lowercase-keys": "^1.0.0" - } - }, - "node_modules/@electron/get/node_modules/responselike/node_modules/lowercase-keys": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz", - "integrity": "sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/@electron/get/node_modules/semver": { "version": "6.3.0", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", @@ -7977,6 +7816,16 @@ "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==" }, + "node_modules/@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "optional": true, + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "5.55.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.55.0.tgz", @@ -11054,6 +10903,7 @@ "version": "1.6.2", "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, "engines": [ "node >= 0.8" ], @@ -11067,12 +10917,14 @@ "node_modules/concat-stream/node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==" + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true }, "node_modules/concat-stream/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -11087,6 +10939,7 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -11178,7 +11031,7 @@ "version": "1.1.12", "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "devOptional": true, + "dev": true, "dependencies": { "ini": "^1.3.4", "proto-list": "~1.2.1" @@ -12657,11 +12510,6 @@ "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, - "node_modules/duplexer3": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/duplexer3/-/duplexer3-0.1.5.tgz", - "integrity": "sha512-1A8za6ws41LQgv9HrE/66jyC5yuSjQ3L/KOpFtoBilsAK2iA2wuS5rTt1OCzIvtS2V7nVmedsUU+DGRcjBmOYA==" - }, "node_modules/duplexify": { "version": "3.7.1", "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz", @@ -12736,20 +12584,20 @@ } }, "node_modules/electron": { - "version": "19.1.9", - "resolved": "https://registry.npmjs.org/electron/-/electron-19.1.9.tgz", - "integrity": "sha512-XT5LkTzIHB+ZtD3dTmNnKjVBWrDWReCKt9G1uAFLz6uJMEVcIUiYO+fph5pLXETiBw/QZBx8egduMEfIccLx+g==", + "version": "22.3.3", + "resolved": "https://registry.npmjs.org/electron/-/electron-22.3.3.tgz", + "integrity": "sha512-+ZJDVfyhw7J2A46/kGKscktIhzOisTeJKrUBJLXa7PTB+U+cwyoxCBIaIOnDsdicBCX4nAc1mo6YMQjQQdAmgw==", "hasInstallScript": true, "dependencies": { - "@electron/get": "^1.14.1", + "@electron/get": "^2.0.0", "@types/node": "^16.11.26", - "extract-zip": "^1.0.3" + "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" }, "engines": { - "node": ">= 8.6" + "node": ">= 12.20.55" } }, "node_modules/electron-builder": { @@ -13054,7 +12902,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", - "devOptional": true, + "dev": true, "engines": { "node": ">= 0.8" } @@ -15013,42 +14861,46 @@ } }, "node_modules/extract-zip": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-1.7.0.tgz", - "integrity": "sha512-xoh5G1W/PB0/27lXgMQyIhP5DSY/LhoCsOyZgb+6iMmRtCwVBo55uKaMoEYrDCKQhWvqEip5ZPKAc6eFNyf/MA==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", "dependencies": { - "concat-stream": "^1.6.2", - "debug": "^2.6.9", - "mkdirp": "^0.5.4", + "debug": "^4.1.1", + "get-stream": "^5.1.0", "yauzl": "^2.10.0" }, "bin": { "extract-zip": "cli.js" - } - }, - "node_modules/extract-zip/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/extract-zip/node_modules/mkdirp": { - "version": "0.5.6", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", - "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", - "dependencies": { - "minimist": "^1.2.6" }, - "bin": { - "mkdirp": "bin/cmd.js" + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" } }, - "node_modules/extract-zip/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/extract-zip/node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } }, "node_modules/extsprintf": { "version": "1.3.0", @@ -16106,22 +15958,6 @@ "node": ">=10.0" } }, - "node_modules/global-tunnel-ng": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/global-tunnel-ng/-/global-tunnel-ng-2.7.1.tgz", - "integrity": "sha512-4s+DyciWBV0eK148wqXxcmVAbFVPqtc3sEtUE/GTQfuU80rySLcMhUmHKSHI7/LDj8q0gDYI1lIhRRB7ieRAqg==", - "optional": true, - "peer": true, - "dependencies": { - "encodeurl": "^1.0.2", - "lodash": "^4.17.10", - "npm-conf": "^1.1.3", - "tunnel": "^0.0.6" - }, - "engines": { - "node": ">=0.10" - } - }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -24084,30 +23920,6 @@ "npm-normalize-package-bin": "^1.0.1" } }, - "node_modules/npm-conf": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/npm-conf/-/npm-conf-1.1.3.tgz", - "integrity": "sha512-Yic4bZHJOt9RCFbRP3GgpqhScOY4HH3V2P8yBj6CeYq118Qr+BLXqT2JvpJ00mryLESpgOxf5XlFv4ZjXxLScw==", - "optional": true, - "peer": true, - "dependencies": { - "config-chain": "^1.1.11", - "pify": "^3.0.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm-conf/node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "optional": true, - "peer": true, - "engines": { - "node": ">=4" - } - }, "node_modules/npm-install-checks": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-5.0.0.tgz", @@ -28525,14 +28337,6 @@ "node": ">= 0.8.0" } }, - "node_modules/prepend-http": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-2.0.0.tgz", - "integrity": "sha512-ravE6m9Atw9Z/jjttRUZ+clIXogdghyZAuWJ3qEzjT+jI/dL1ifAqhZeC5VHzQp1MSt1+jxKkFNemj/iO7tVUA==", - "engines": { - "node": ">=4" - } - }, "node_modules/prettier": { "version": "2.8.4", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.4.tgz", @@ -28727,7 +28531,7 @@ "version": "1.2.4", "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", "integrity": "sha512-vtK/94akxsTMhe0/cbfpR+syPuszcuwhqVjJq26CuNDgFGj682oRBXOP5MJpv2r7JtE8MsiepGIqvvOTBwn2vA==", - "devOptional": true + "dev": true }, "node_modules/protocols": { "version": "2.0.1", @@ -30131,9 +29935,9 @@ } }, "node_modules/rimraf/node_modules/glob": { - "version": "9.2.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-9.2.1.tgz", - "integrity": "sha512-Pxxgq3W0HyA3XUvSXcFhRSs+43Jsx0ddxcFrbjxNGkL2Ak5BAUBxLqI5G6ADDeCHLfzzXFhe0b1yYcctGmytMA==", + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-9.3.0.tgz", + "integrity": "sha512-EAZejC7JvnQINayvB/7BJbpZpNOJ8Lrw2OZNEvQxe0vaLn1SuwMcfV7/MNaX8L/T0wmptBFI4YMtDvSBxYDc7w==", "dev": true, "dependencies": { "fs.realpath": "^1.0.0", @@ -32431,14 +32235,6 @@ "node": ">=0.10.0" } }, - "node_modules/to-readable-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/to-readable-stream/-/to-readable-stream-1.0.0.tgz", - "integrity": "sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==", - "engines": { - "node": ">=6" - } - }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -32751,16 +32547,6 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" }, - "node_modules/tunnel": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", - "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", - "optional": true, - "peer": true, - "engines": { - "node": ">=0.6.11 <=0.7.0 || >=0.7.3" - } - }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -32846,7 +32632,8 @@ "node_modules/typedarray": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", - "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==" + "integrity": "sha512-/aCDEGatGvZ2BIk+HmLf4ifCJFwvKFNb9/JeZPMulfgFracn9QFcAf5GO8B/mweUjSoblS5In0cWhqpfs/5PQA==", + "dev": true }, "node_modules/typedoc": { "version": "0.23.25", @@ -33170,17 +32957,6 @@ "requires-port": "^1.0.0" } }, - "node_modules/url-parse-lax": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-3.0.0.tgz", - "integrity": "sha512-NjFKA0DidqPa5ciFcSrXnAltTtzz84ogy+NebPvfEgAck0+TNg4UJ4IN+fB7zRZfbgUf0syOo9MDxFkDSMuFaQ==", - "dependencies": { - "prepend-http": "^2.0.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/use-isomorphic-layout-effect": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/use-isomorphic-layout-effect/-/use-isomorphic-layout-effect-1.1.2.tgz", @@ -34511,7 +34287,7 @@ "css-loader": "^6.7.3", "deepdash": "^5.3.9", "dompurify": "^2.4.4", - "electron": "^19.1.9", + "electron": "^22.3.3", "electron-builder": "^23.6.0", "esbuild": "^0.17.8", "esbuild-loader": "^2.21.0", @@ -36698,7 +36474,7 @@ "copy-webpack-plugin": "^11.0.0", "cross-env": "^7.0.3", "css-loader": "^6.7.2", - "electron": "^19.1.9", + "electron": "^22.3.3", "electron-builder": "^23.6.0", "electron-notarize": "^0.3.0", "esbuild-loader": "^2.20.0", @@ -37192,7 +36968,7 @@ "@k8slens/feature-core": "^6.5.0-alpha.0", "@ogre-tools/injectable": "^15.1.2", "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", - "electron": "^19.1.9" + "electron": "^22.3.3" } }, "packages/technical-features/application/legacy-extensions": { @@ -37269,7 +37045,7 @@ "@k8slens/messaging": "^1.0.0-alpha.1", "@ogre-tools/injectable": "^15.1.2", "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", - "electron": "^19.1.8", + "electron": "^22.3.3", "lodash": "^4.17.21" } }, @@ -37287,7 +37063,7 @@ "@k8slens/startable-stoppable": "^1.0.0-alpha.1", "@ogre-tools/injectable": "^15.1.2", "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", - "electron": "^19.1.8", + "electron": "^22.3.3", "lodash": "^4.17.21" } }, diff --git a/packages/core/package.json b/packages/core/package.json index 15c79d774d..42c39d6181 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -257,7 +257,7 @@ "css-loader": "^6.7.3", "deepdash": "^5.3.9", "dompurify": "^2.4.4", - "electron": "^19.1.9", + "electron": "^22.3.3", "electron-builder": "^23.6.0", "esbuild": "^0.17.8", "esbuild-loader": "^2.21.0", diff --git a/packages/core/src/common/app-paths/app-path-names.ts b/packages/core/src/common/app-paths/app-path-names.ts index 8e3d2c440e..b7b829a5e3 100644 --- a/packages/core/src/common/app-paths/app-path-names.ts +++ b/packages/core/src/common/app-paths/app-path-names.ts @@ -11,7 +11,7 @@ export const pathNames: PathName[] = [ "home", "appData", "userData", - "cache", + "sessionData", "temp", "exe", "module", diff --git a/packages/core/src/common/app-paths/app-paths.test.ts b/packages/core/src/common/app-paths/app-paths.test.ts index f847346dad..851ece4390 100644 --- a/packages/core/src/common/app-paths/app-paths.test.ts +++ b/packages/core/src/common/app-paths/app-paths.test.ts @@ -21,7 +21,6 @@ describe("app-paths", () => { const defaultAppPathsStub: AppPaths = { currentApp: "/some-current-app", appData: "/some-app-data", - cache: "/some-cache", crashDumps: "/some-crash-dumps", desktop: "/some-desktop", documents: "/some-documents", @@ -36,6 +35,7 @@ describe("app-paths", () => { temp: "/some-temp", videos: "/some-videos", userData: "/some-irrelevant-user-data", + sessionData: "/some-irrelevant-user-data", // By default this points to userData }; builder.beforeApplicationStart(({ mainDi }) => { @@ -73,7 +73,6 @@ describe("app-paths", () => { expect(actual).toEqual({ currentApp: "/some-current-app", appData: "/some-app-data", - cache: "/some-cache", crashDumps: "/some-crash-dumps", desktop: "/some-desktop", documents: "/some-documents", @@ -88,6 +87,7 @@ describe("app-paths", () => { temp: "/some-temp", videos: "/some-videos", userData: "/some-app-data/some-product-name", + sessionData: "/some-app-data/some-product-name", }); }); @@ -97,7 +97,6 @@ describe("app-paths", () => { expect(actual).toEqual({ currentApp: "/some-current-app", appData: "/some-app-data", - cache: "/some-cache", crashDumps: "/some-crash-dumps", desktop: "/some-desktop", documents: "/some-documents", @@ -112,6 +111,7 @@ describe("app-paths", () => { temp: "/some-temp", videos: "/some-videos", userData: "/some-app-data/some-product-name", + sessionData: "/some-app-data/some-product-name", }); }); }); diff --git a/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts b/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts index 778f959739..677c18a586 100644 --- a/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts +++ b/packages/core/src/common/error-reporting/initialize-sentry-reporting.injectable.ts @@ -13,7 +13,7 @@ import userStoreInjectable from "../user-store/user-store.injectable"; export type InitializeSentryReportingWith = (initSentry: (opts: BrowserOptions | ElectronMainOptions) => void) => void; -const mapProcessName = (type: "browser" | "renderer" | "worker") => type === "browser" ? "main" : type; +const mapProcessName = (type: "browser" | "renderer" | "worker" | "utility") => type === "browser" ? "main" : type; const initializeSentryReportingWithInjectable = getInjectable({ id: "initialize-sentry-reporting-with", diff --git a/packages/core/src/main/app-paths/setup-app-paths.injectable.ts b/packages/core/src/main/app-paths/setup-app-paths.injectable.ts index 34178547c3..255beffae0 100644 --- a/packages/core/src/main/app-paths/setup-app-paths.injectable.ts +++ b/packages/core/src/main/app-paths/setup-app-paths.injectable.ts @@ -34,6 +34,7 @@ const setupAppPathsInjectable = getInjectable({ const appDataPath = getElectronAppPath("appData"); setElectronAppPath("userData", joinPaths(appDataPath, appName)); + setElectronAppPath("sessionData", getElectronAppPath("userData")); const appPaths = pipeline( pathNames, diff --git a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts index 88e4319fa0..baa0da6c39 100644 --- a/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts +++ b/packages/core/src/main/utils/resolve-system-proxy/resolve-system-proxy-window.injectable.ts @@ -8,7 +8,11 @@ import { BrowserWindow } from "electron"; const resolveSystemProxyWindowInjectable = getInjectable({ id: "resolve-system-proxy-window", instantiate: () => { - return new BrowserWindow({ show: false, paintWhenInitiallyHidden: false }); + const window = new BrowserWindow({ show: false }); + + window.hide(); + + return window; }, causesSideEffects: true, }); diff --git a/packages/open-lens/package.json b/packages/open-lens/package.json index f59563de3f..577c1a2a6b 100644 --- a/packages/open-lens/package.json +++ b/packages/open-lens/package.json @@ -96,7 +96,7 @@ }, "build": { "npmRebuild": false, - "electronVersion": "19.1.9", + "electronVersion": "22.3.3", "generateUpdatesFilesForAllChannels": true, "files": [ "static/**/*", @@ -251,7 +251,7 @@ "copy-webpack-plugin": "^11.0.0", "cross-env": "^7.0.3", "css-loader": "^6.7.2", - "electron": "^19.1.9", + "electron": "^22.3.3", "electron-builder": "^23.6.0", "electron-notarize": "^0.3.0", "esbuild-loader": "^2.20.0", diff --git a/packages/technical-features/application/electron-main/package.json b/packages/technical-features/application/electron-main/package.json index f32de6f301..96d649a362 100644 --- a/packages/technical-features/application/electron-main/package.json +++ b/packages/technical-features/application/electron-main/package.json @@ -35,7 +35,7 @@ "@k8slens/feature-core": "^6.5.0-alpha.0", "@ogre-tools/injectable": "^15.1.2", "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", - "electron": "^19.1.9" + "electron": "^22.3.3" }, "devDependencies": { "@async-fn/jest": "^1.6.4", diff --git a/packages/technical-features/messaging/electron/main/package.json b/packages/technical-features/messaging/electron/main/package.json index 63d66ea6d0..ff1a76a7d3 100644 --- a/packages/technical-features/messaging/electron/main/package.json +++ b/packages/technical-features/messaging/electron/main/package.json @@ -38,7 +38,7 @@ "@k8slens/messaging": "^1.0.0-alpha.1", "@ogre-tools/injectable": "^15.1.2", "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", - "electron": "^19.1.8", + "electron": "^22.3.3", "lodash": "^4.17.21" }, "devDependencies": { diff --git a/packages/technical-features/messaging/electron/renderer/package.json b/packages/technical-features/messaging/electron/renderer/package.json index dcb9a7a185..75fcb8e38f 100644 --- a/packages/technical-features/messaging/electron/renderer/package.json +++ b/packages/technical-features/messaging/electron/renderer/package.json @@ -39,7 +39,7 @@ "@k8slens/startable-stoppable": "^1.0.0-alpha.1", "@ogre-tools/injectable": "^15.1.2", "@ogre-tools/injectable-extension-for-auto-registration": "^15.1.2", - "electron": "^19.1.8", + "electron": "^22.3.3", "lodash": "^4.17.21" }, "devDependencies": { From 517e2fe17d07a5e91109ea448db6defb3f65737c Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 21 Mar 2023 11:12:29 -0400 Subject: [PATCH 10/17] Fix type error in new @k8slens/messaging (#7392) * Fix type error in new @k8slens/messaging Signed-off-by: Sebastian Malton * Better fix to conform to tests Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- .../actual/message/message-channel-listener-injection-token.ts | 2 +- .../enlist-message-channel-listener.injectable.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/technical-features/messaging/agnostic/src/features/actual/message/message-channel-listener-injection-token.ts b/packages/technical-features/messaging/agnostic/src/features/actual/message/message-channel-listener-injection-token.ts index 386c9f9e5e..0558bf6598 100644 --- a/packages/technical-features/messaging/agnostic/src/features/actual/message/message-channel-listener-injection-token.ts +++ b/packages/technical-features/messaging/agnostic/src/features/actual/message/message-channel-listener-injection-token.ts @@ -9,7 +9,7 @@ export interface MessageChannel { export type ExtraData = { processId: number; frameId: number }; export type MessageChannelHandler = Channel extends MessageChannel - ? (message: Message, data: ExtraData) => void + ? (message: Message, data?: ExtraData) => void : never; export interface MessageChannelListener { diff --git a/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts b/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts index 64e9b1f873..6948e51073 100644 --- a/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts +++ b/packages/technical-features/messaging/electron/renderer/src/listening-of-messages/enlist-message-channel-listener.injectable.ts @@ -10,7 +10,7 @@ const enlistMessageChannelListenerInjectable = getInjectable({ const ipcRenderer = di.inject(ipcRendererInjectable); return ({ channel, handler }) => { - const nativeCallback = (_: IpcRendererEvent, message: unknown) => { + const nativeCallback = (event: IpcRendererEvent, message: unknown) => { handler(message); }; From 48db54ec9e42b712d97a67b8a8b85f8096e1422d Mon Sep 17 00:00:00 2001 From: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> Date: Tue, 21 Mar 2023 21:04:22 +0200 Subject: [PATCH 11/17] Renderer file logging through IPC (#7300) * Renderer file logging through IPC Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> * Remove pagehide event listener as it may cause UI to freeze Pagehide was needed in cluster frame to better handle main frame close/reload situation. But even empty pagehide listener in cluster frame seems to freeze the UI at least on some situations (multiple clusters open). Beforeunload is not always executed in cluster frame when main frame is reloaded/closed, leaving log files open. To fix that, `stopIpcLoggingInjectable` is introduced to close all log files. Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> * Remove unnecessary formatting changes Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> * Lint fix Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> * Winston logger override Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> * Remove usage of doGeneralOverrides as it has been removed Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> * Update imports to match the new base Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> * Remove unnecessary id Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> * Review improvements Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> * Extract beforeunload listener to injectable Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> * Typo fix Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> --------- Signed-off-by: Sami Tiilikainen <97873007+samitiilikainen@users.noreply.github.com> --- packages/core/src/common/logger.injectable.ts | 11 +- .../common/logger/ipc-file-logger-channel.ts | 24 +++ ...n-logger.global-override-for-injectable.ts | 23 +++ .../src/common/winston-logger.injectable.ts | 18 ++ .../close-ipc-logging-listener.injectable.ts | 21 +++ ...ransport.global-override-for-injectable.ts | 18 ++ .../create-ipc-file-transport.injectable.ts | 28 +++ .../main/logger/file-transport.injectable.ts | 6 +- .../main/logger/ipc-file-logger.injectable.ts | 55 ++++++ .../src/main/logger/ipc-file-logger.test.ts | 160 ++++++++++++++++++ .../logger/ipc-logging-listener.injectable.ts | 39 +++++ .../main/logger/ipc-logging-listener.test.ts | 31 ++++ .../logger/stop-ipc-logging.injectable.ts | 27 +++ .../runnables/listen-unload.injectable.ts | 46 +++++ packages/core/src/renderer/bootstrap.tsx | 4 +- .../init-cluster-frame/init-cluster-frame.ts | 95 +++++------ .../root-frame/init-root-frame.injectable.ts | 10 +- .../logger/close-renderer-log-file-id.test.ts | 56 ++++++ .../close-renderer-log-file.injectable.ts | 28 +++ .../logger/ipc-transport.injectable.ts | 60 +++++++ .../src/renderer/logger/ipc-transport.test.ts | 48 ++++++ .../core/src/renderer/logger/ipc-transport.ts | 41 +++++ .../logger/renderer-log-file-id.injectable.ts | 29 ++++ .../logger/renderer-log-file-id.test.ts | 34 ++++ 24 files changed, 836 insertions(+), 76 deletions(-) create mode 100644 packages/core/src/common/logger/ipc-file-logger-channel.ts create mode 100644 packages/core/src/common/winston-logger.global-override-for-injectable.ts create mode 100644 packages/core/src/common/winston-logger.injectable.ts create mode 100644 packages/core/src/main/logger/close-ipc-logging-listener.injectable.ts create mode 100644 packages/core/src/main/logger/create-ipc-file-transport.global-override-for-injectable.ts create mode 100644 packages/core/src/main/logger/create-ipc-file-transport.injectable.ts create mode 100644 packages/core/src/main/logger/ipc-file-logger.injectable.ts create mode 100644 packages/core/src/main/logger/ipc-file-logger.test.ts create mode 100644 packages/core/src/main/logger/ipc-logging-listener.injectable.ts create mode 100644 packages/core/src/main/logger/ipc-logging-listener.test.ts create mode 100644 packages/core/src/main/logger/stop-ipc-logging.injectable.ts create mode 100644 packages/core/src/renderer/before-frame-starts/runnables/listen-unload.injectable.ts create mode 100644 packages/core/src/renderer/logger/close-renderer-log-file-id.test.ts create mode 100644 packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts create mode 100644 packages/core/src/renderer/logger/ipc-transport.injectable.ts create mode 100644 packages/core/src/renderer/logger/ipc-transport.test.ts create mode 100644 packages/core/src/renderer/logger/ipc-transport.ts create mode 100644 packages/core/src/renderer/logger/renderer-log-file-id.injectable.ts create mode 100644 packages/core/src/renderer/logger/renderer-log-file-id.test.ts diff --git a/packages/core/src/common/logger.injectable.ts b/packages/core/src/common/logger.injectable.ts index bc1c5de71b..e64978e44b 100644 --- a/packages/core/src/common/logger.injectable.ts +++ b/packages/core/src/common/logger.injectable.ts @@ -3,20 +3,13 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { createLogger, format } from "winston"; import type { Logger } from "./logger"; -import { loggerTransportInjectionToken } from "./logger/transports"; +import winstonLoggerInjectable from "./winston-logger.injectable"; const loggerInjectable = getInjectable({ id: "logger", instantiate: (di): Logger => { - const baseLogger = createLogger({ - format: format.combine( - format.splat(), - format.simple(), - ), - transports: di.injectMany(loggerTransportInjectionToken), - }); + const baseLogger = di.inject(winstonLoggerInjectable); return { debug: (message, ...data) => baseLogger.debug(message, ...data), diff --git a/packages/core/src/common/logger/ipc-file-logger-channel.ts b/packages/core/src/common/logger/ipc-file-logger-channel.ts new file mode 100644 index 0000000000..7550f4f314 --- /dev/null +++ b/packages/core/src/common/logger/ipc-file-logger-channel.ts @@ -0,0 +1,24 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { MessageChannel } from "../utils/channel/message-channel-listener-injection-token"; + +export interface IpcFileLogObject { + fileId: string; + entry: { + level: string; + message: string; + internalMessage: string; + }; +} + +export type IpcFileLoggerChannel = MessageChannel; + +export const ipcFileLoggerChannel: IpcFileLoggerChannel = { + id: "ipc-file-logger-channel", +}; + +export const closeIpcFileLoggerChannel: MessageChannel = { + id: "close-ipc-file-logger-channel", +}; diff --git a/packages/core/src/common/winston-logger.global-override-for-injectable.ts b/packages/core/src/common/winston-logger.global-override-for-injectable.ts new file mode 100644 index 0000000000..3d55f914dd --- /dev/null +++ b/packages/core/src/common/winston-logger.global-override-for-injectable.ts @@ -0,0 +1,23 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type winston from "winston"; +import { getGlobalOverride } from "@k8slens/test-utils"; +import { noop } from "@k8slens/utilities"; +import winstonLoggerInjectable from "./winston-logger.injectable"; + +export default getGlobalOverride(winstonLoggerInjectable, () => ({ + log: noop, + add: noop, + remove: noop, + clear: noop, + close: noop, + + warn: noop, + debug: noop, + error: noop, + info: noop, + silly: noop, +}) as winston.Logger); diff --git a/packages/core/src/common/winston-logger.injectable.ts b/packages/core/src/common/winston-logger.injectable.ts new file mode 100644 index 0000000000..481d520fac --- /dev/null +++ b/packages/core/src/common/winston-logger.injectable.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { createLogger, format } from "winston"; +import { loggerTransportInjectionToken } from "./logger/transports"; + +const winstonLoggerInjectable = getInjectable({ + id: "winston-logger", + instantiate: (di) => + createLogger({ + format: format.combine(format.splat(), format.simple()), + transports: di.injectMany(loggerTransportInjectionToken), + }), +}); + +export default winstonLoggerInjectable; diff --git a/packages/core/src/main/logger/close-ipc-logging-listener.injectable.ts b/packages/core/src/main/logger/close-ipc-logging-listener.injectable.ts new file mode 100644 index 0000000000..6870a29c61 --- /dev/null +++ b/packages/core/src/main/logger/close-ipc-logging-listener.injectable.ts @@ -0,0 +1,21 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import ipcFileLoggerInjectable from "./ipc-file-logger.injectable"; +import { getMessageChannelListenerInjectable } from "../../common/utils/channel/message-channel-listener-injection-token"; +import { + closeIpcFileLoggerChannel, +} from "../../common/logger/ipc-file-logger-channel"; + +const closeIpcFileLoggingListenerInjectable = getMessageChannelListenerInjectable({ + id: "close-ipc-file-logging", + channel: closeIpcFileLoggerChannel, + handler: (di) => { + const ipcFileLogger = di.inject(ipcFileLoggerInjectable); + + return (fileId) => ipcFileLogger.close(fileId); + }, +}); + +export default closeIpcFileLoggingListenerInjectable; diff --git a/packages/core/src/main/logger/create-ipc-file-transport.global-override-for-injectable.ts b/packages/core/src/main/logger/create-ipc-file-transport.global-override-for-injectable.ts new file mode 100644 index 0000000000..98fc62da49 --- /dev/null +++ b/packages/core/src/main/logger/create-ipc-file-transport.global-override-for-injectable.ts @@ -0,0 +1,18 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { transports } from "winston"; +import { getGlobalOverride } from "@k8slens/test-utils"; +import { noop } from "@k8slens/utilities"; +import createIpcFileLoggerTransportInjectable from "./create-ipc-file-transport.injectable"; + +export default getGlobalOverride( + createIpcFileLoggerTransportInjectable, + () => () => + ({ + log: noop, + close: noop, + } as typeof transports.File), +); diff --git a/packages/core/src/main/logger/create-ipc-file-transport.injectable.ts b/packages/core/src/main/logger/create-ipc-file-transport.injectable.ts new file mode 100644 index 0000000000..f29e02fc90 --- /dev/null +++ b/packages/core/src/main/logger/create-ipc-file-transport.injectable.ts @@ -0,0 +1,28 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { transports } from "winston"; +import directoryForLogsInjectable from "../../common/app-paths/directory-for-logs.injectable"; + +const createIpcFileLoggerTransportInjectable = getInjectable({ + id: "create-ipc-file-logger-transport", + instantiate: (di) => { + const options = { + dirname: di.inject(directoryForLogsInjectable), + maxsize: 1024 * 1024, + maxFiles: 2, + tailable: true, + }; + + return (fileId: string) => + new transports.File({ + ...options, + filename: `lens-${fileId}.log`, + }); + }, + causesSideEffects: true, +}); + +export default createIpcFileLoggerTransportInjectable; diff --git a/packages/core/src/main/logger/file-transport.injectable.ts b/packages/core/src/main/logger/file-transport.injectable.ts index fcf855eec4..c71b44a2a0 100644 --- a/packages/core/src/main/logger/file-transport.injectable.ts +++ b/packages/core/src/main/logger/file-transport.injectable.ts @@ -7,8 +7,8 @@ import { transports } from "winston"; import directoryForLogsInjectable from "../../common/app-paths/directory-for-logs.injectable"; import { loggerTransportInjectionToken } from "../../common/logger/transports"; -const fileLoggerTranportInjectable = getInjectable({ - id: "file-logger-tranport", +const fileLoggerTransportInjectable = getInjectable({ + id: "file-logger-transport", instantiate: (di) => new transports.File({ handleExceptions: false, level: "debug", @@ -26,4 +26,4 @@ const fileLoggerTranportInjectable = getInjectable({ decorable: false, }); -export default fileLoggerTranportInjectable; +export default fileLoggerTransportInjectable; diff --git a/packages/core/src/main/logger/ipc-file-logger.injectable.ts b/packages/core/src/main/logger/ipc-file-logger.injectable.ts new file mode 100644 index 0000000000..df82ef7c6b --- /dev/null +++ b/packages/core/src/main/logger/ipc-file-logger.injectable.ts @@ -0,0 +1,55 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { getOrInsertWith } from "@k8slens/utilities"; +import type { LogEntry, transports } from "winston"; +import createIpcFileLoggerTransportInjectable from "./create-ipc-file-transport.injectable"; + +export interface IpcFileLogger { + log: (fileLog: { fileId: string; entry: LogEntry }) => void; + close: (fileId: string) => void; + closeAll: () => void; +} + +const ipcFileLoggerInjectable = getInjectable({ + id: "ipc-file-logger", + instantiate: (di): IpcFileLogger => { + const createIpcFileTransport = di.inject(createIpcFileLoggerTransportInjectable); + const fileTransports = new Map(); + + function log({ fileId, entry }: { fileId: string; entry: LogEntry }) { + const transport = getOrInsertWith( + fileTransports, + fileId, + () => createIpcFileTransport(fileId), + ); + + transport?.log?.(entry, () => {}); + } + + function close(fileId: string) { + const transport = fileTransports.get(fileId); + + if (transport) { + transport.close?.(); + fileTransports.delete(fileId); + } + } + + function closeAll() { + for (const fileId of fileTransports.keys()) { + close(fileId); + } + } + + return { + log, + close, + closeAll, + }; + }, +}); + +export default ipcFileLoggerInjectable; diff --git a/packages/core/src/main/logger/ipc-file-logger.test.ts b/packages/core/src/main/logger/ipc-file-logger.test.ts new file mode 100644 index 0000000000..1ff727e200 --- /dev/null +++ b/packages/core/src/main/logger/ipc-file-logger.test.ts @@ -0,0 +1,160 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getDiForUnitTesting } from "../getDiForUnitTesting"; +import createIpcFileLoggerTransportInjectable from "./create-ipc-file-transport.injectable"; +import type { IpcFileLogger } from "./ipc-file-logger.injectable"; +import ipcFileLoggerInjectable from "./ipc-file-logger.injectable"; + +describe("ipc file logger in main", () => { + let logMock: jest.Mock; + let closeMock: jest.Mock; + let createFileTransportMock: jest.Mock; + let logger: IpcFileLogger; + + beforeEach(() => { + logMock = jest.fn(); + closeMock = jest.fn(); + createFileTransportMock = jest.fn(() => ({ + log: logMock, + close: closeMock, + })); + + const di = getDiForUnitTesting(); + + di.override(createIpcFileLoggerTransportInjectable, () => createFileTransportMock); + logger = di.inject(ipcFileLoggerInjectable); + }); + + it("creates a transport for new log file", () => { + logger.log({ + fileId: "some-log-file", + entry: { level: "irrelevant", message: "irrelevant" }, + }); + + expect(createFileTransportMock).toHaveBeenCalledWith("some-log-file"); + }); + + it("uses existing transport for log file", () => { + logger.log({ + fileId: "some-log-file", + entry: { level: "irrelevant", message: "irrelevant" }, + }); + + logger.log({ + fileId: "some-log-file", + entry: { level: "irrelevant", message: "irrelevant" }, + }); + + logger.log({ + fileId: "some-log-file", + entry: { level: "irrelevant", message: "irrelevant" }, + }); + + expect(createFileTransportMock).toHaveBeenCalledTimes(1); + + expect(createFileTransportMock).toHaveBeenCalledWith("some-log-file"); + }); + + it("creates separate transport for each log file", () => { + logger.log({ + fileId: "some-log-file", + entry: { level: "irrelevant", message: "irrelevant" }, + }); + + logger.log({ + fileId: "some-other-log-file", + entry: { level: "irrelevant", message: "irrelevant" }, + }); + + logger.log({ + fileId: "some-yet-another-log-file", + entry: { level: "irrelevant", message: "irrelevant" }, + }); + + expect(createFileTransportMock).toHaveBeenCalledTimes(3); + + expect(createFileTransportMock).toHaveBeenCalledWith("some-log-file"); + + expect(createFileTransportMock).toHaveBeenCalledWith("some-other-log-file"); + + expect(createFileTransportMock).toHaveBeenCalledWith("some-yet-another-log-file"); + }); + + it("logs using file transport", () => { + logger.log({ + fileId: "some-log-file", + entry: { level: "irrelevant", message: "some-log-message" }, + }); + expect(logMock.mock.calls[0][0]).toEqual({ + level: "irrelevant", + message: "some-log-message", + }); + }); + + it("logs to correct files", () => { + const someLogMock = jest.fn(); + const someOthertLogMock = jest.fn(); + + createFileTransportMock.mockImplementation((fileId: string) => { + if (fileId === "some-log-file") { + return { log: someLogMock }; + } + + if (fileId === "some-other-log-file") { + return { log: someOthertLogMock }; + } + + return null; + }); + + logger.log({ + fileId: "some-log-file", + entry: { level: "irrelevant", message: "some-log-message" }, + }); + logger.log({ + fileId: "some-other-log-file", + entry: { level: "irrelevant", message: "some-other-log-message" }, + }); + + expect(someLogMock).toHaveBeenCalledTimes(1); + expect(someLogMock.mock.calls[0][0]).toEqual({ + level: "irrelevant", + message: "some-log-message", + }); + expect(someOthertLogMock).toHaveBeenCalledTimes(1); + expect(someOthertLogMock.mock.calls[0][0]).toEqual({ + level: "irrelevant", + message: "some-other-log-message", + }); + }); + + it("closes transport (to ensure no file handles are left open)", () => { + logger.log({ + fileId: "some-log-file", + entry: { level: "irrelevant", message: "irrelevant" }, + }); + + logger.close("some-log-file"); + + expect(closeMock).toHaveBeenCalled(); + }); + + it("creates a new transport once needed after closing previous", () => { + logger.log({ + fileId: "some-log-file", + entry: { level: "irrelevant", message: "irrelevant" }, + }); + + logger.close("some-log-file"); + + logger.log({ + fileId: "some-log-file", + entry: { level: "irrelevant", message: "irrelevant" }, + }); + + expect(createFileTransportMock).toHaveBeenCalledTimes(2); + expect(logMock).toHaveBeenCalledTimes(2); + }); +}); diff --git a/packages/core/src/main/logger/ipc-logging-listener.injectable.ts b/packages/core/src/main/logger/ipc-logging-listener.injectable.ts new file mode 100644 index 0000000000..3a3748846b --- /dev/null +++ b/packages/core/src/main/logger/ipc-logging-listener.injectable.ts @@ -0,0 +1,39 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import ipcFileLoggerInjectable from "./ipc-file-logger.injectable"; +import { getMessageChannelListenerInjectable } from "../../common/utils/channel/message-channel-listener-injection-token"; +import type { IpcFileLogObject } from "../../common/logger/ipc-file-logger-channel"; +import { ipcFileLoggerChannel } from "../../common/logger/ipc-file-logger-channel"; +import { MESSAGE } from "triple-beam"; + +/** + * Winston uses symbol property for the actual message. + * + * For that to get through IPC, use the internalMessage property instead + */ +export function deserializeLogFromIpc(ipcFileLogObject: IpcFileLogObject) { + const { internalMessage, ...standardEntry } = ipcFileLogObject.entry; + + return { + ...ipcFileLogObject, + entry: { + ...standardEntry, + [MESSAGE]: internalMessage, + }, + }; +} + +const ipcFileLoggingListenerInjectable = getMessageChannelListenerInjectable({ + id: "ipc-file-logging", + channel: ipcFileLoggerChannel, + handler: (di) => { + const logger = di.inject(ipcFileLoggerInjectable); + + return (ipcFileLogObject) => + logger.log(deserializeLogFromIpc(ipcFileLogObject)); + }, +}); + +export default ipcFileLoggingListenerInjectable; diff --git a/packages/core/src/main/logger/ipc-logging-listener.test.ts b/packages/core/src/main/logger/ipc-logging-listener.test.ts new file mode 100644 index 0000000000..55bb64f4c4 --- /dev/null +++ b/packages/core/src/main/logger/ipc-logging-listener.test.ts @@ -0,0 +1,31 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { MESSAGE } from "triple-beam"; +import { deserializeLogFromIpc } from "./ipc-logging-listener.injectable"; + +describe("Ipc log deserialization", () => { + it("fills in the unique symbol message property Winston transports use internally", () => { + const logObject = { + fileId: "irrelevant", + entry: { + level: "irrelevant", + message: "some public message", + internalMessage: "some internal message", + someProperty: "irrelevant", + }, + }; + + expect(deserializeLogFromIpc(logObject)).toEqual({ + entry: { + level: "irrelevant", + message: "some public message", + [MESSAGE]: "some internal message", + someProperty: "irrelevant", + }, + fileId: "irrelevant", + }); + }); +}); diff --git a/packages/core/src/main/logger/stop-ipc-logging.injectable.ts b/packages/core/src/main/logger/stop-ipc-logging.injectable.ts new file mode 100644 index 0000000000..bdb94a412e --- /dev/null +++ b/packages/core/src/main/logger/stop-ipc-logging.injectable.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { beforeQuitOfFrontEndInjectionToken } from "../start-main-application/runnable-tokens/phases"; +import ipcFileLoggerInjectable from "./ipc-file-logger.injectable"; + +const stopIpcLoggingInjectable = getInjectable({ + id: "stop-ipc-logging", + + instantiate: (di) => { + const ipcFileLogger = di.inject(ipcFileLoggerInjectable); + + return { + run: () => { + ipcFileLogger.closeAll(); + + return undefined; + }, + }; + }, + + injectionToken: beforeQuitOfFrontEndInjectionToken, +}); + +export default stopIpcLoggingInjectable; diff --git a/packages/core/src/renderer/before-frame-starts/runnables/listen-unload.injectable.ts b/packages/core/src/renderer/before-frame-starts/runnables/listen-unload.injectable.ts new file mode 100644 index 0000000000..6b6e0e751c --- /dev/null +++ b/packages/core/src/renderer/before-frame-starts/runnables/listen-unload.injectable.ts @@ -0,0 +1,46 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable"; +import { beforeFrameStartsSecondInjectionToken } from "../tokens"; +import loggerInjectable from "../../../common/logger.injectable"; +import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable"; +import frameRoutingIdInjectable from "../../frames/cluster-frame/init-cluster-frame/frame-routing-id/frame-routing-id.injectable"; +import closeRendererLogFileInjectable from "../../logger/close-renderer-log-file.injectable"; +import { unmountComponentAtNode } from "react-dom"; + +const listenUnloadInjectable = getInjectable({ + id: "listen-unload", + instantiate: (di) => ({ + run: () => { + const closeRendererLogFile = di.inject(closeRendererLogFileInjectable); + const isClusterFrame = di.inject(currentlyInClusterFrameInjectable); + const logger = di.inject(loggerInjectable); + + window.addEventListener("beforeunload", () => { + if (isClusterFrame) { + const hostedCluster = di.inject(hostedClusterInjectable); + const frameRoutingId = di.inject(frameRoutingIdInjectable); + + logger.info( + `[CLUSTER-FRAME] Unload dashboard, clusterId=${hostedCluster?.id}, frameId=${frameRoutingId}`, + ); + } else { + logger.info("[ROOT-FRAME]: Unload app"); + } + + closeRendererLogFile(); + const rootElem = document.getElementById("app"); + + if (rootElem) { + unmountComponentAtNode(rootElem); + } + }); + }, + }), + injectionToken: beforeFrameStartsSecondInjectionToken, +}); + +export default listenUnloadInjectable; diff --git a/packages/core/src/renderer/bootstrap.tsx b/packages/core/src/renderer/bootstrap.tsx index a811f07d5c..75439fce13 100644 --- a/packages/core/src/renderer/bootstrap.tsx +++ b/packages/core/src/renderer/bootstrap.tsx @@ -6,7 +6,7 @@ import "./components/app.scss"; import React from "react"; -import { render, unmountComponentAtNode } from "react-dom"; +import { render } from "react-dom"; import { DefaultProps } from "./mui-base-theme"; import { DiContextProvider } from "@ogre-tools/injectable-react"; import type { @@ -43,7 +43,7 @@ export async function bootstrap(di: DiContainerForInjection) { } try { - await initializeApp(() => unmountComponentAtNode(rootElem)); + await initializeApp(); } catch (error) { console.error(`[BOOTSTRAP]: view initialization error: ${error}`, { origin: location.href, diff --git a/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts b/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts index 9bd0a26a3c..9e901a8060 100644 --- a/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts +++ b/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts @@ -22,62 +22,51 @@ interface Dependencies { const logPrefix = "[CLUSTER-FRAME]:"; -export const initClusterFrame = ({ - hostedCluster, - loadExtensions, - catalogEntityRegistry, - frameRoutingId, - emitAppEvent, - logger, - showErrorNotification, -}: Dependencies) => - async (unmountRoot: () => void) => { +export const initClusterFrame = + ({ + hostedCluster, + loadExtensions, + catalogEntityRegistry, + frameRoutingId, + emitAppEvent, + logger, + showErrorNotification, + }: Dependencies) => + async () => { // TODO: Make catalogEntityRegistry already initialized when passed as dependency - catalogEntityRegistry.init(); + catalogEntityRegistry.init(); - logger.info( - `${logPrefix} Init dashboard, clusterId=${hostedCluster.id}, frameId=${frameRoutingId}`, - ); - - await requestSetClusterFrameId(hostedCluster.id); - await when(() => hostedCluster.ready.get()); // cluster.activate() is done at this point - - catalogEntityRegistry.activeEntity = hostedCluster.id; - - // Only load the extensions once the catalog has been populated. - // Note that the Catalog might still have unprocessed entities until the extensions are fully loaded. - when( - () => catalogEntityRegistry.items.get().length > 0, - () => - loadExtensions(), - { - timeout: 15_000, - onError: (error) => { - logger.warn( - "[CLUSTER-FRAME]: error from activeEntity when()", - error, - ); - - showErrorNotification("Failed to get KubernetesCluster for this view. Extensions will not be loaded."); - }, - }, - ); - - setTimeout(() => { - emitAppEvent({ - name: "cluster", - action: "open", - params: { - clusterId: hostedCluster.id, - }, - }); - }); - - window.onbeforeunload = () => { logger.info( - `${logPrefix} Unload dashboard, clusterId=${(hostedCluster.id)}, frameId=${frameRoutingId}`, + `${logPrefix} Init dashboard, clusterId=${hostedCluster.id}, frameId=${frameRoutingId}`, ); - unmountRoot(); + await requestSetClusterFrameId(hostedCluster.id); + await when(() => hostedCluster.ready.get()); // cluster.activate() is done at this point + + catalogEntityRegistry.activeEntity = hostedCluster.id; + + // Only load the extensions once the catalog has been populated. + // Note that the Catalog might still have unprocessed entities until the extensions are fully loaded. + when( + () => catalogEntityRegistry.items.get().length > 0, + () => loadExtensions(), + { + timeout: 15_000, + onError: (error) => { + logger.warn("[CLUSTER-FRAME]: error from activeEntity when()", error); + + showErrorNotification("Failed to get KubernetesCluster for this view. Extensions will not be loaded."); + }, + }, + ); + + setTimeout(() => { + emitAppEvent({ + name: "cluster", + action: "open", + params: { + clusterId: hostedCluster.id, + }, + }); + }); }; - }; diff --git a/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts b/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts index f1e3024d80..e1bedb0c88 100644 --- a/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts +++ b/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts @@ -9,7 +9,6 @@ import lensProtocolRouterRendererInjectable from "../../protocol-handler/lens-pr import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable"; import registerIpcListenersInjectable from "../../ipc/register-ipc-listeners.injectable"; import loadExtensionsInjectable from "../load-extensions.injectable"; -import loggerInjectable from "../../../common/logger.injectable"; import { delay } from "@k8slens/utilities"; import { broadcastMessage } from "../../../common/ipc"; import { bundledExtensionsLoaded } from "../../../common/ipc/extension-handling"; @@ -23,9 +22,8 @@ const initRootFrameInjectable = getInjectable({ const bindProtocolAddRouteHandlers = di.inject(bindProtocolAddRouteHandlersInjectable); const lensProtocolRouterRenderer = di.inject(lensProtocolRouterRendererInjectable); const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); - const logger = di.inject(loggerInjectable); - return async (unmountRoot: () => void) => { + return async () => { catalogEntityRegistry.init(); try { @@ -56,12 +54,6 @@ const initRootFrameInjectable = getInjectable({ window.addEventListener("online", () => broadcastMessage("network:online")); registerIpcListeners(); - - window.addEventListener("beforeunload", () => { - logger.info("[ROOT-FRAME]: Unload app"); - - unmountRoot(); - }); }; }, }); diff --git a/packages/core/src/renderer/logger/close-renderer-log-file-id.test.ts b/packages/core/src/renderer/logger/close-renderer-log-file-id.test.ts new file mode 100644 index 0000000000..1520844c30 --- /dev/null +++ b/packages/core/src/renderer/logger/close-renderer-log-file-id.test.ts @@ -0,0 +1,56 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import winstonLoggerInjectable from "../../common/winston-logger.injectable"; +import { getDiForUnitTesting } from "../getDiForUnitTesting"; +import closeRendererLogFileInjectable from "./close-renderer-log-file.injectable"; +import type { DiContainer } from "@ogre-tools/injectable"; +import type winston from "winston"; +import type { SendMessageToChannel } from "../../common/utils/channel/message-to-channel-injection-token"; +import { sendMessageToChannelInjectionToken } from "../../common/utils/channel/message-to-channel-injection-token"; +import rendererLogFileIdInjectable from "./renderer-log-file-id.injectable"; +import ipcLogTransportInjectable from "./ipc-transport.injectable"; +import type IpcLogTransport from "./ipc-transport"; + +describe("close renderer file logging", () => { + let di: DiContainer; + let sendIpcMock: SendMessageToChannel; + let winstonMock: winston.Logger; + let ipcTransportMock: IpcLogTransport; + + beforeEach(() => { + di = getDiForUnitTesting(); + sendIpcMock = jest.fn(); + winstonMock = { + remove: jest.fn(), + } as any as winston.Logger; + ipcTransportMock = { name: "ipc-renderer-transport" } as IpcLogTransport; + + di.override(winstonLoggerInjectable, () => winstonMock); + di.override(sendMessageToChannelInjectionToken, () => sendIpcMock); + di.override(rendererLogFileIdInjectable, () => "some-log-id"); + di.override(ipcLogTransportInjectable, () => ipcTransportMock); + }); + + it("sends the ipc close message with correct log id", () => { + const closeLog = di.inject(closeRendererLogFileInjectable); + + closeLog(); + + expect(sendIpcMock).toHaveBeenCalledWith( + { id: "close-ipc-file-logger-channel" }, + "some-log-id", + ); + }); + + it("removes the transport to prevent further logging to closed file", () => { + const closeLog = di.inject(closeRendererLogFileInjectable); + + closeLog(); + + expect(winstonMock.remove).toHaveBeenCalledWith({ + name: "ipc-renderer-transport", + }); + }); +}); diff --git a/packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts b/packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts new file mode 100644 index 0000000000..8015708d84 --- /dev/null +++ b/packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts @@ -0,0 +1,28 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import winstonLoggerInjectable from "../../common/winston-logger.injectable"; +import { closeIpcFileLoggerChannel } from "../../common/logger/ipc-file-logger-channel"; +import { sendMessageToChannelInjectionToken } from "../../common/utils/channel/message-to-channel-injection-token"; +import rendererLogFileIdInjectable from "./renderer-log-file-id.injectable"; +import ipcLogTransportInjectable from "./ipc-transport.injectable"; + +const closeRendererLogFileInjectable = getInjectable({ + id: "close-renderer-log-file", + instantiate: (di) => { + const winstonLogger = di.inject(winstonLoggerInjectable); + const ipcLogTransport = di.inject(ipcLogTransportInjectable); + const messageToChannel = di.inject(sendMessageToChannelInjectionToken); + const fileId = di.inject(rendererLogFileIdInjectable); + + + return () => { + messageToChannel(closeIpcFileLoggerChannel, fileId); + winstonLogger.remove(ipcLogTransport); + }; + }, +}); + +export default closeRendererLogFileInjectable; diff --git a/packages/core/src/renderer/logger/ipc-transport.injectable.ts b/packages/core/src/renderer/logger/ipc-transport.injectable.ts new file mode 100644 index 0000000000..45139cd917 --- /dev/null +++ b/packages/core/src/renderer/logger/ipc-transport.injectable.ts @@ -0,0 +1,60 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { loggerTransportInjectionToken } from "../../common/logger/transports"; +import type winston from "winston"; +import { MESSAGE } from "triple-beam"; + +import IpcLogTransport from "./ipc-transport"; +import { sendMessageToChannelInjectionToken } from "../../common/utils/channel/message-to-channel-injection-token"; +import type { + IpcFileLogObject } from "../../common/logger/ipc-file-logger-channel"; +import { + closeIpcFileLoggerChannel, + ipcFileLoggerChannel, +} from "../../common/logger/ipc-file-logger-channel"; +import rendererLogFileIdInjectable from "./renderer-log-file-id.injectable"; + +/** + * Winston uses symbol property for the actual message. + * + * For that to get through IPC, use the internalMessage property instead + */ +function serializeLogForIpc( + fileId: string, + entry: winston.LogEntry, +): IpcFileLogObject { + return { + fileId, + entry: { + level: entry.level, + message: entry.message, + internalMessage: Object.getOwnPropertyDescriptor(entry, MESSAGE)?.value, + }, + }; +} + +const ipcLogTransportInjectable = getInjectable({ + id: "renderer-file-logger-transport", + instantiate: (di) => { + const messageToChannel = di.inject(sendMessageToChannelInjectionToken); + const fileId = di.inject(rendererLogFileIdInjectable); + + return new IpcLogTransport({ + sendIpcLogMessage: (entry) => + messageToChannel( + ipcFileLoggerChannel, + serializeLogForIpc(fileId, entry), + ), + closeIpcLogging: () => + messageToChannel(closeIpcFileLoggerChannel, fileId), + handleExceptions: false, + level: "info", + }); + }, + injectionToken: loggerTransportInjectionToken, +}); + +export default ipcLogTransportInjectable; diff --git a/packages/core/src/renderer/logger/ipc-transport.test.ts b/packages/core/src/renderer/logger/ipc-transport.test.ts new file mode 100644 index 0000000000..931df377c7 --- /dev/null +++ b/packages/core/src/renderer/logger/ipc-transport.test.ts @@ -0,0 +1,48 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { DiContainer } from "@ogre-tools/injectable"; +import type { SendMessageToChannel } from "../../common/utils/channel/message-to-channel-injection-token"; +import { sendMessageToChannelInjectionToken } from "../../common/utils/channel/message-to-channel-injection-token"; +import { getDiForUnitTesting } from "../getDiForUnitTesting"; +import rendererLogFileIdInjectable from "./renderer-log-file-id.injectable"; +import ipcLogTransportInjectable from "./ipc-transport.injectable"; +import { MESSAGE } from "triple-beam"; + +describe("renderer log transport through ipc", () => { + let di: DiContainer; + let sendIpcMock: SendMessageToChannel; + + beforeEach(() => { + sendIpcMock = jest.fn(); + di = getDiForUnitTesting(); + di.override(sendMessageToChannelInjectionToken, () => sendIpcMock); + di.override(rendererLogFileIdInjectable, () => "some-log-id"); + }); + + it("send serialized ipc messages on log", () => { + const logTransport = di.inject(ipcLogTransportInjectable); + + logTransport.log( + { + level: "info", + message: "some log text", + [MESSAGE]: "actual winston log text", + }, + () => {}, + ); + + expect(sendIpcMock).toHaveBeenCalledWith( + { id: "ipc-file-logger-channel" }, + { + entry: { + level: "info", + message: "some log text", + internalMessage: "actual winston log text", + }, + fileId: "some-log-id", + }, + ); + }); +}); diff --git a/packages/core/src/renderer/logger/ipc-transport.ts b/packages/core/src/renderer/logger/ipc-transport.ts new file mode 100644 index 0000000000..a1f6fa819e --- /dev/null +++ b/packages/core/src/renderer/logger/ipc-transport.ts @@ -0,0 +1,41 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { LogEntry } from "winston"; +import type { TransportStreamOptions } from "winston-transport"; +import TransportStream from "winston-transport"; + +interface IpcLogTransportOptions extends TransportStreamOptions { + sendIpcLogMessage: (entry: LogEntry) => void; + closeIpcLogging: () => void; +} + +class IpcLogTransport extends TransportStream { + sendIpcLogMessage: (entry: LogEntry) => void; + closeIpcLogging: () => void; + name = "ipc-renderer-transport"; + + constructor(options: IpcLogTransportOptions) { + const { sendIpcLogMessage, closeIpcLogging, ...winstonOptions } = options; + + super(winstonOptions); + + this.sendIpcLogMessage = sendIpcLogMessage; + this.closeIpcLogging = closeIpcLogging; + } + + log(logEntry: LogEntry, next: () => void) { + setImmediate(() => { + this.emit("logged", logEntry); + }); + this.sendIpcLogMessage(logEntry); + next(); + } + + close() { + this.closeIpcLogging(); + } +} + +export default IpcLogTransport; diff --git a/packages/core/src/renderer/logger/renderer-log-file-id.injectable.ts b/packages/core/src/renderer/logger/renderer-log-file-id.injectable.ts new file mode 100644 index 0000000000..81f4196b08 --- /dev/null +++ b/packages/core/src/renderer/logger/renderer-log-file-id.injectable.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import windowLocationInjectable from "../../common/k8s-api/window-location.injectable"; +import currentlyInClusterFrameInjectable from "../routes/currently-in-cluster-frame.injectable"; +import { getClusterIdFromHost } from "../../common/utils"; + +const rendererLogFileIdInjectable = getInjectable({ + id: "renderer-log-file-id", + instantiate: (di) => { + let frameId: string; + const currentlyInClusterFrame = di.inject(currentlyInClusterFrameInjectable); + + if (currentlyInClusterFrame) { + const { host } = di.inject(windowLocationInjectable); + const clusterId = getClusterIdFromHost(host); + + frameId = `cluster-${clusterId}`; + } else { + frameId = "main"; + } + + return `renderer-${frameId}`; + }, +}); + +export default rendererLogFileIdInjectable; diff --git a/packages/core/src/renderer/logger/renderer-log-file-id.test.ts b/packages/core/src/renderer/logger/renderer-log-file-id.test.ts new file mode 100644 index 0000000000..bd2abf7a63 --- /dev/null +++ b/packages/core/src/renderer/logger/renderer-log-file-id.test.ts @@ -0,0 +1,34 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import windowLocationInjectable from "../../common/k8s-api/window-location.injectable"; +import { getDiForUnitTesting } from "../getDiForUnitTesting"; +import currentlyInClusterFrameInjectable from "../routes/currently-in-cluster-frame.injectable"; +import rendererLogFileIdInjectable from "./renderer-log-file-id.injectable"; + +describe("renderer log file id", () => { + + it("clearly names log for renderer main frame", () => { + const di = getDiForUnitTesting(); + + di.override(currentlyInClusterFrameInjectable, () => false); + + const mainFileId = di.inject(rendererLogFileIdInjectable); + + expect(mainFileId).toBe("renderer-main"); + }); + + it("includes cluster id in renderer log file names", () => { + const di = getDiForUnitTesting(); + + di.override(currentlyInClusterFrameInjectable, () => true); + di.override(windowLocationInjectable, () => ({ + host: "some-cluster.lens.app", + port: "irrelevant", + })); + const clusterFileId = di.inject(rendererLogFileIdInjectable); + + expect(clusterFileId).toBe("renderer-cluster-some-cluster"); + }); +}); From 54093242367717292312df01905d052b66017953 Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 21 Mar 2023 16:13:27 -0400 Subject: [PATCH 12/17] Revert "Renderer file logging through IPC" (#7393) This reverts commit 48db54ec9e42b712d97a67b8a8b85f8096e1422d. --- packages/core/src/common/logger.injectable.ts | 11 +- .../common/logger/ipc-file-logger-channel.ts | 24 --- ...n-logger.global-override-for-injectable.ts | 23 --- .../src/common/winston-logger.injectable.ts | 18 -- .../close-ipc-logging-listener.injectable.ts | 21 --- ...ransport.global-override-for-injectable.ts | 18 -- .../create-ipc-file-transport.injectable.ts | 28 --- .../main/logger/file-transport.injectable.ts | 6 +- .../main/logger/ipc-file-logger.injectable.ts | 55 ------ .../src/main/logger/ipc-file-logger.test.ts | 160 ------------------ .../logger/ipc-logging-listener.injectable.ts | 39 ----- .../main/logger/ipc-logging-listener.test.ts | 31 ---- .../logger/stop-ipc-logging.injectable.ts | 27 --- .../runnables/listen-unload.injectable.ts | 46 ----- packages/core/src/renderer/bootstrap.tsx | 4 +- .../init-cluster-frame/init-cluster-frame.ts | 87 +++++----- .../root-frame/init-root-frame.injectable.ts | 10 +- .../logger/close-renderer-log-file-id.test.ts | 56 ------ .../close-renderer-log-file.injectable.ts | 28 --- .../logger/ipc-transport.injectable.ts | 60 ------- .../src/renderer/logger/ipc-transport.test.ts | 48 ------ .../core/src/renderer/logger/ipc-transport.ts | 41 ----- .../logger/renderer-log-file-id.injectable.ts | 29 ---- .../logger/renderer-log-file-id.test.ts | 34 ---- 24 files changed, 72 insertions(+), 832 deletions(-) delete mode 100644 packages/core/src/common/logger/ipc-file-logger-channel.ts delete mode 100644 packages/core/src/common/winston-logger.global-override-for-injectable.ts delete mode 100644 packages/core/src/common/winston-logger.injectable.ts delete mode 100644 packages/core/src/main/logger/close-ipc-logging-listener.injectable.ts delete mode 100644 packages/core/src/main/logger/create-ipc-file-transport.global-override-for-injectable.ts delete mode 100644 packages/core/src/main/logger/create-ipc-file-transport.injectable.ts delete mode 100644 packages/core/src/main/logger/ipc-file-logger.injectable.ts delete mode 100644 packages/core/src/main/logger/ipc-file-logger.test.ts delete mode 100644 packages/core/src/main/logger/ipc-logging-listener.injectable.ts delete mode 100644 packages/core/src/main/logger/ipc-logging-listener.test.ts delete mode 100644 packages/core/src/main/logger/stop-ipc-logging.injectable.ts delete mode 100644 packages/core/src/renderer/before-frame-starts/runnables/listen-unload.injectable.ts delete mode 100644 packages/core/src/renderer/logger/close-renderer-log-file-id.test.ts delete mode 100644 packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts delete mode 100644 packages/core/src/renderer/logger/ipc-transport.injectable.ts delete mode 100644 packages/core/src/renderer/logger/ipc-transport.test.ts delete mode 100644 packages/core/src/renderer/logger/ipc-transport.ts delete mode 100644 packages/core/src/renderer/logger/renderer-log-file-id.injectable.ts delete mode 100644 packages/core/src/renderer/logger/renderer-log-file-id.test.ts diff --git a/packages/core/src/common/logger.injectable.ts b/packages/core/src/common/logger.injectable.ts index e64978e44b..bc1c5de71b 100644 --- a/packages/core/src/common/logger.injectable.ts +++ b/packages/core/src/common/logger.injectable.ts @@ -3,13 +3,20 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; +import { createLogger, format } from "winston"; import type { Logger } from "./logger"; -import winstonLoggerInjectable from "./winston-logger.injectable"; +import { loggerTransportInjectionToken } from "./logger/transports"; const loggerInjectable = getInjectable({ id: "logger", instantiate: (di): Logger => { - const baseLogger = di.inject(winstonLoggerInjectable); + const baseLogger = createLogger({ + format: format.combine( + format.splat(), + format.simple(), + ), + transports: di.injectMany(loggerTransportInjectionToken), + }); return { debug: (message, ...data) => baseLogger.debug(message, ...data), diff --git a/packages/core/src/common/logger/ipc-file-logger-channel.ts b/packages/core/src/common/logger/ipc-file-logger-channel.ts deleted file mode 100644 index 7550f4f314..0000000000 --- a/packages/core/src/common/logger/ipc-file-logger-channel.ts +++ /dev/null @@ -1,24 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { MessageChannel } from "../utils/channel/message-channel-listener-injection-token"; - -export interface IpcFileLogObject { - fileId: string; - entry: { - level: string; - message: string; - internalMessage: string; - }; -} - -export type IpcFileLoggerChannel = MessageChannel; - -export const ipcFileLoggerChannel: IpcFileLoggerChannel = { - id: "ipc-file-logger-channel", -}; - -export const closeIpcFileLoggerChannel: MessageChannel = { - id: "close-ipc-file-logger-channel", -}; diff --git a/packages/core/src/common/winston-logger.global-override-for-injectable.ts b/packages/core/src/common/winston-logger.global-override-for-injectable.ts deleted file mode 100644 index 3d55f914dd..0000000000 --- a/packages/core/src/common/winston-logger.global-override-for-injectable.ts +++ /dev/null @@ -1,23 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type winston from "winston"; -import { getGlobalOverride } from "@k8slens/test-utils"; -import { noop } from "@k8slens/utilities"; -import winstonLoggerInjectable from "./winston-logger.injectable"; - -export default getGlobalOverride(winstonLoggerInjectable, () => ({ - log: noop, - add: noop, - remove: noop, - clear: noop, - close: noop, - - warn: noop, - debug: noop, - error: noop, - info: noop, - silly: noop, -}) as winston.Logger); diff --git a/packages/core/src/common/winston-logger.injectable.ts b/packages/core/src/common/winston-logger.injectable.ts deleted file mode 100644 index 481d520fac..0000000000 --- a/packages/core/src/common/winston-logger.injectable.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { createLogger, format } from "winston"; -import { loggerTransportInjectionToken } from "./logger/transports"; - -const winstonLoggerInjectable = getInjectable({ - id: "winston-logger", - instantiate: (di) => - createLogger({ - format: format.combine(format.splat(), format.simple()), - transports: di.injectMany(loggerTransportInjectionToken), - }), -}); - -export default winstonLoggerInjectable; diff --git a/packages/core/src/main/logger/close-ipc-logging-listener.injectable.ts b/packages/core/src/main/logger/close-ipc-logging-listener.injectable.ts deleted file mode 100644 index 6870a29c61..0000000000 --- a/packages/core/src/main/logger/close-ipc-logging-listener.injectable.ts +++ /dev/null @@ -1,21 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import ipcFileLoggerInjectable from "./ipc-file-logger.injectable"; -import { getMessageChannelListenerInjectable } from "../../common/utils/channel/message-channel-listener-injection-token"; -import { - closeIpcFileLoggerChannel, -} from "../../common/logger/ipc-file-logger-channel"; - -const closeIpcFileLoggingListenerInjectable = getMessageChannelListenerInjectable({ - id: "close-ipc-file-logging", - channel: closeIpcFileLoggerChannel, - handler: (di) => { - const ipcFileLogger = di.inject(ipcFileLoggerInjectable); - - return (fileId) => ipcFileLogger.close(fileId); - }, -}); - -export default closeIpcFileLoggingListenerInjectable; diff --git a/packages/core/src/main/logger/create-ipc-file-transport.global-override-for-injectable.ts b/packages/core/src/main/logger/create-ipc-file-transport.global-override-for-injectable.ts deleted file mode 100644 index 98fc62da49..0000000000 --- a/packages/core/src/main/logger/create-ipc-file-transport.global-override-for-injectable.ts +++ /dev/null @@ -1,18 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { transports } from "winston"; -import { getGlobalOverride } from "@k8slens/test-utils"; -import { noop } from "@k8slens/utilities"; -import createIpcFileLoggerTransportInjectable from "./create-ipc-file-transport.injectable"; - -export default getGlobalOverride( - createIpcFileLoggerTransportInjectable, - () => () => - ({ - log: noop, - close: noop, - } as typeof transports.File), -); diff --git a/packages/core/src/main/logger/create-ipc-file-transport.injectable.ts b/packages/core/src/main/logger/create-ipc-file-transport.injectable.ts deleted file mode 100644 index f29e02fc90..0000000000 --- a/packages/core/src/main/logger/create-ipc-file-transport.injectable.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { transports } from "winston"; -import directoryForLogsInjectable from "../../common/app-paths/directory-for-logs.injectable"; - -const createIpcFileLoggerTransportInjectable = getInjectable({ - id: "create-ipc-file-logger-transport", - instantiate: (di) => { - const options = { - dirname: di.inject(directoryForLogsInjectable), - maxsize: 1024 * 1024, - maxFiles: 2, - tailable: true, - }; - - return (fileId: string) => - new transports.File({ - ...options, - filename: `lens-${fileId}.log`, - }); - }, - causesSideEffects: true, -}); - -export default createIpcFileLoggerTransportInjectable; diff --git a/packages/core/src/main/logger/file-transport.injectable.ts b/packages/core/src/main/logger/file-transport.injectable.ts index c71b44a2a0..fcf855eec4 100644 --- a/packages/core/src/main/logger/file-transport.injectable.ts +++ b/packages/core/src/main/logger/file-transport.injectable.ts @@ -7,8 +7,8 @@ import { transports } from "winston"; import directoryForLogsInjectable from "../../common/app-paths/directory-for-logs.injectable"; import { loggerTransportInjectionToken } from "../../common/logger/transports"; -const fileLoggerTransportInjectable = getInjectable({ - id: "file-logger-transport", +const fileLoggerTranportInjectable = getInjectable({ + id: "file-logger-tranport", instantiate: (di) => new transports.File({ handleExceptions: false, level: "debug", @@ -26,4 +26,4 @@ const fileLoggerTransportInjectable = getInjectable({ decorable: false, }); -export default fileLoggerTransportInjectable; +export default fileLoggerTranportInjectable; diff --git a/packages/core/src/main/logger/ipc-file-logger.injectable.ts b/packages/core/src/main/logger/ipc-file-logger.injectable.ts deleted file mode 100644 index df82ef7c6b..0000000000 --- a/packages/core/src/main/logger/ipc-file-logger.injectable.ts +++ /dev/null @@ -1,55 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { getOrInsertWith } from "@k8slens/utilities"; -import type { LogEntry, transports } from "winston"; -import createIpcFileLoggerTransportInjectable from "./create-ipc-file-transport.injectable"; - -export interface IpcFileLogger { - log: (fileLog: { fileId: string; entry: LogEntry }) => void; - close: (fileId: string) => void; - closeAll: () => void; -} - -const ipcFileLoggerInjectable = getInjectable({ - id: "ipc-file-logger", - instantiate: (di): IpcFileLogger => { - const createIpcFileTransport = di.inject(createIpcFileLoggerTransportInjectable); - const fileTransports = new Map(); - - function log({ fileId, entry }: { fileId: string; entry: LogEntry }) { - const transport = getOrInsertWith( - fileTransports, - fileId, - () => createIpcFileTransport(fileId), - ); - - transport?.log?.(entry, () => {}); - } - - function close(fileId: string) { - const transport = fileTransports.get(fileId); - - if (transport) { - transport.close?.(); - fileTransports.delete(fileId); - } - } - - function closeAll() { - for (const fileId of fileTransports.keys()) { - close(fileId); - } - } - - return { - log, - close, - closeAll, - }; - }, -}); - -export default ipcFileLoggerInjectable; diff --git a/packages/core/src/main/logger/ipc-file-logger.test.ts b/packages/core/src/main/logger/ipc-file-logger.test.ts deleted file mode 100644 index 1ff727e200..0000000000 --- a/packages/core/src/main/logger/ipc-file-logger.test.ts +++ /dev/null @@ -1,160 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getDiForUnitTesting } from "../getDiForUnitTesting"; -import createIpcFileLoggerTransportInjectable from "./create-ipc-file-transport.injectable"; -import type { IpcFileLogger } from "./ipc-file-logger.injectable"; -import ipcFileLoggerInjectable from "./ipc-file-logger.injectable"; - -describe("ipc file logger in main", () => { - let logMock: jest.Mock; - let closeMock: jest.Mock; - let createFileTransportMock: jest.Mock; - let logger: IpcFileLogger; - - beforeEach(() => { - logMock = jest.fn(); - closeMock = jest.fn(); - createFileTransportMock = jest.fn(() => ({ - log: logMock, - close: closeMock, - })); - - const di = getDiForUnitTesting(); - - di.override(createIpcFileLoggerTransportInjectable, () => createFileTransportMock); - logger = di.inject(ipcFileLoggerInjectable); - }); - - it("creates a transport for new log file", () => { - logger.log({ - fileId: "some-log-file", - entry: { level: "irrelevant", message: "irrelevant" }, - }); - - expect(createFileTransportMock).toHaveBeenCalledWith("some-log-file"); - }); - - it("uses existing transport for log file", () => { - logger.log({ - fileId: "some-log-file", - entry: { level: "irrelevant", message: "irrelevant" }, - }); - - logger.log({ - fileId: "some-log-file", - entry: { level: "irrelevant", message: "irrelevant" }, - }); - - logger.log({ - fileId: "some-log-file", - entry: { level: "irrelevant", message: "irrelevant" }, - }); - - expect(createFileTransportMock).toHaveBeenCalledTimes(1); - - expect(createFileTransportMock).toHaveBeenCalledWith("some-log-file"); - }); - - it("creates separate transport for each log file", () => { - logger.log({ - fileId: "some-log-file", - entry: { level: "irrelevant", message: "irrelevant" }, - }); - - logger.log({ - fileId: "some-other-log-file", - entry: { level: "irrelevant", message: "irrelevant" }, - }); - - logger.log({ - fileId: "some-yet-another-log-file", - entry: { level: "irrelevant", message: "irrelevant" }, - }); - - expect(createFileTransportMock).toHaveBeenCalledTimes(3); - - expect(createFileTransportMock).toHaveBeenCalledWith("some-log-file"); - - expect(createFileTransportMock).toHaveBeenCalledWith("some-other-log-file"); - - expect(createFileTransportMock).toHaveBeenCalledWith("some-yet-another-log-file"); - }); - - it("logs using file transport", () => { - logger.log({ - fileId: "some-log-file", - entry: { level: "irrelevant", message: "some-log-message" }, - }); - expect(logMock.mock.calls[0][0]).toEqual({ - level: "irrelevant", - message: "some-log-message", - }); - }); - - it("logs to correct files", () => { - const someLogMock = jest.fn(); - const someOthertLogMock = jest.fn(); - - createFileTransportMock.mockImplementation((fileId: string) => { - if (fileId === "some-log-file") { - return { log: someLogMock }; - } - - if (fileId === "some-other-log-file") { - return { log: someOthertLogMock }; - } - - return null; - }); - - logger.log({ - fileId: "some-log-file", - entry: { level: "irrelevant", message: "some-log-message" }, - }); - logger.log({ - fileId: "some-other-log-file", - entry: { level: "irrelevant", message: "some-other-log-message" }, - }); - - expect(someLogMock).toHaveBeenCalledTimes(1); - expect(someLogMock.mock.calls[0][0]).toEqual({ - level: "irrelevant", - message: "some-log-message", - }); - expect(someOthertLogMock).toHaveBeenCalledTimes(1); - expect(someOthertLogMock.mock.calls[0][0]).toEqual({ - level: "irrelevant", - message: "some-other-log-message", - }); - }); - - it("closes transport (to ensure no file handles are left open)", () => { - logger.log({ - fileId: "some-log-file", - entry: { level: "irrelevant", message: "irrelevant" }, - }); - - logger.close("some-log-file"); - - expect(closeMock).toHaveBeenCalled(); - }); - - it("creates a new transport once needed after closing previous", () => { - logger.log({ - fileId: "some-log-file", - entry: { level: "irrelevant", message: "irrelevant" }, - }); - - logger.close("some-log-file"); - - logger.log({ - fileId: "some-log-file", - entry: { level: "irrelevant", message: "irrelevant" }, - }); - - expect(createFileTransportMock).toHaveBeenCalledTimes(2); - expect(logMock).toHaveBeenCalledTimes(2); - }); -}); diff --git a/packages/core/src/main/logger/ipc-logging-listener.injectable.ts b/packages/core/src/main/logger/ipc-logging-listener.injectable.ts deleted file mode 100644 index 3a3748846b..0000000000 --- a/packages/core/src/main/logger/ipc-logging-listener.injectable.ts +++ /dev/null @@ -1,39 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import ipcFileLoggerInjectable from "./ipc-file-logger.injectable"; -import { getMessageChannelListenerInjectable } from "../../common/utils/channel/message-channel-listener-injection-token"; -import type { IpcFileLogObject } from "../../common/logger/ipc-file-logger-channel"; -import { ipcFileLoggerChannel } from "../../common/logger/ipc-file-logger-channel"; -import { MESSAGE } from "triple-beam"; - -/** - * Winston uses symbol property for the actual message. - * - * For that to get through IPC, use the internalMessage property instead - */ -export function deserializeLogFromIpc(ipcFileLogObject: IpcFileLogObject) { - const { internalMessage, ...standardEntry } = ipcFileLogObject.entry; - - return { - ...ipcFileLogObject, - entry: { - ...standardEntry, - [MESSAGE]: internalMessage, - }, - }; -} - -const ipcFileLoggingListenerInjectable = getMessageChannelListenerInjectable({ - id: "ipc-file-logging", - channel: ipcFileLoggerChannel, - handler: (di) => { - const logger = di.inject(ipcFileLoggerInjectable); - - return (ipcFileLogObject) => - logger.log(deserializeLogFromIpc(ipcFileLogObject)); - }, -}); - -export default ipcFileLoggingListenerInjectable; diff --git a/packages/core/src/main/logger/ipc-logging-listener.test.ts b/packages/core/src/main/logger/ipc-logging-listener.test.ts deleted file mode 100644 index 55bb64f4c4..0000000000 --- a/packages/core/src/main/logger/ipc-logging-listener.test.ts +++ /dev/null @@ -1,31 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { MESSAGE } from "triple-beam"; -import { deserializeLogFromIpc } from "./ipc-logging-listener.injectable"; - -describe("Ipc log deserialization", () => { - it("fills in the unique symbol message property Winston transports use internally", () => { - const logObject = { - fileId: "irrelevant", - entry: { - level: "irrelevant", - message: "some public message", - internalMessage: "some internal message", - someProperty: "irrelevant", - }, - }; - - expect(deserializeLogFromIpc(logObject)).toEqual({ - entry: { - level: "irrelevant", - message: "some public message", - [MESSAGE]: "some internal message", - someProperty: "irrelevant", - }, - fileId: "irrelevant", - }); - }); -}); diff --git a/packages/core/src/main/logger/stop-ipc-logging.injectable.ts b/packages/core/src/main/logger/stop-ipc-logging.injectable.ts deleted file mode 100644 index bdb94a412e..0000000000 --- a/packages/core/src/main/logger/stop-ipc-logging.injectable.ts +++ /dev/null @@ -1,27 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { beforeQuitOfFrontEndInjectionToken } from "../start-main-application/runnable-tokens/phases"; -import ipcFileLoggerInjectable from "./ipc-file-logger.injectable"; - -const stopIpcLoggingInjectable = getInjectable({ - id: "stop-ipc-logging", - - instantiate: (di) => { - const ipcFileLogger = di.inject(ipcFileLoggerInjectable); - - return { - run: () => { - ipcFileLogger.closeAll(); - - return undefined; - }, - }; - }, - - injectionToken: beforeQuitOfFrontEndInjectionToken, -}); - -export default stopIpcLoggingInjectable; diff --git a/packages/core/src/renderer/before-frame-starts/runnables/listen-unload.injectable.ts b/packages/core/src/renderer/before-frame-starts/runnables/listen-unload.injectable.ts deleted file mode 100644 index 6b6e0e751c..0000000000 --- a/packages/core/src/renderer/before-frame-starts/runnables/listen-unload.injectable.ts +++ /dev/null @@ -1,46 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable"; -import { beforeFrameStartsSecondInjectionToken } from "../tokens"; -import loggerInjectable from "../../../common/logger.injectable"; -import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable"; -import frameRoutingIdInjectable from "../../frames/cluster-frame/init-cluster-frame/frame-routing-id/frame-routing-id.injectable"; -import closeRendererLogFileInjectable from "../../logger/close-renderer-log-file.injectable"; -import { unmountComponentAtNode } from "react-dom"; - -const listenUnloadInjectable = getInjectable({ - id: "listen-unload", - instantiate: (di) => ({ - run: () => { - const closeRendererLogFile = di.inject(closeRendererLogFileInjectable); - const isClusterFrame = di.inject(currentlyInClusterFrameInjectable); - const logger = di.inject(loggerInjectable); - - window.addEventListener("beforeunload", () => { - if (isClusterFrame) { - const hostedCluster = di.inject(hostedClusterInjectable); - const frameRoutingId = di.inject(frameRoutingIdInjectable); - - logger.info( - `[CLUSTER-FRAME] Unload dashboard, clusterId=${hostedCluster?.id}, frameId=${frameRoutingId}`, - ); - } else { - logger.info("[ROOT-FRAME]: Unload app"); - } - - closeRendererLogFile(); - const rootElem = document.getElementById("app"); - - if (rootElem) { - unmountComponentAtNode(rootElem); - } - }); - }, - }), - injectionToken: beforeFrameStartsSecondInjectionToken, -}); - -export default listenUnloadInjectable; diff --git a/packages/core/src/renderer/bootstrap.tsx b/packages/core/src/renderer/bootstrap.tsx index 75439fce13..a811f07d5c 100644 --- a/packages/core/src/renderer/bootstrap.tsx +++ b/packages/core/src/renderer/bootstrap.tsx @@ -6,7 +6,7 @@ import "./components/app.scss"; import React from "react"; -import { render } from "react-dom"; +import { render, unmountComponentAtNode } from "react-dom"; import { DefaultProps } from "./mui-base-theme"; import { DiContextProvider } from "@ogre-tools/injectable-react"; import type { @@ -43,7 +43,7 @@ export async function bootstrap(di: DiContainerForInjection) { } try { - await initializeApp(); + await initializeApp(() => unmountComponentAtNode(rootElem)); } catch (error) { console.error(`[BOOTSTRAP]: view initialization error: ${error}`, { origin: location.href, diff --git a/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts b/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts index 9e901a8060..9bd0a26a3c 100644 --- a/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts +++ b/packages/core/src/renderer/frames/cluster-frame/init-cluster-frame/init-cluster-frame.ts @@ -22,51 +22,62 @@ interface Dependencies { const logPrefix = "[CLUSTER-FRAME]:"; -export const initClusterFrame = - ({ - hostedCluster, - loadExtensions, - catalogEntityRegistry, - frameRoutingId, - emitAppEvent, - logger, - showErrorNotification, - }: Dependencies) => - async () => { +export const initClusterFrame = ({ + hostedCluster, + loadExtensions, + catalogEntityRegistry, + frameRoutingId, + emitAppEvent, + logger, + showErrorNotification, +}: Dependencies) => + async (unmountRoot: () => void) => { // TODO: Make catalogEntityRegistry already initialized when passed as dependency - catalogEntityRegistry.init(); + catalogEntityRegistry.init(); - logger.info( - `${logPrefix} Init dashboard, clusterId=${hostedCluster.id}, frameId=${frameRoutingId}`, - ); + logger.info( + `${logPrefix} Init dashboard, clusterId=${hostedCluster.id}, frameId=${frameRoutingId}`, + ); - await requestSetClusterFrameId(hostedCluster.id); - await when(() => hostedCluster.ready.get()); // cluster.activate() is done at this point + await requestSetClusterFrameId(hostedCluster.id); + await when(() => hostedCluster.ready.get()); // cluster.activate() is done at this point - catalogEntityRegistry.activeEntity = hostedCluster.id; + catalogEntityRegistry.activeEntity = hostedCluster.id; - // Only load the extensions once the catalog has been populated. - // Note that the Catalog might still have unprocessed entities until the extensions are fully loaded. - when( - () => catalogEntityRegistry.items.get().length > 0, - () => loadExtensions(), - { - timeout: 15_000, - onError: (error) => { - logger.warn("[CLUSTER-FRAME]: error from activeEntity when()", error); + // Only load the extensions once the catalog has been populated. + // Note that the Catalog might still have unprocessed entities until the extensions are fully loaded. + when( + () => catalogEntityRegistry.items.get().length > 0, + () => + loadExtensions(), + { + timeout: 15_000, + onError: (error) => { + logger.warn( + "[CLUSTER-FRAME]: error from activeEntity when()", + error, + ); - showErrorNotification("Failed to get KubernetesCluster for this view. Extensions will not be loaded."); - }, + showErrorNotification("Failed to get KubernetesCluster for this view. Extensions will not be loaded."); }, + }, + ); + + setTimeout(() => { + emitAppEvent({ + name: "cluster", + action: "open", + params: { + clusterId: hostedCluster.id, + }, + }); + }); + + window.onbeforeunload = () => { + logger.info( + `${logPrefix} Unload dashboard, clusterId=${(hostedCluster.id)}, frameId=${frameRoutingId}`, ); - setTimeout(() => { - emitAppEvent({ - name: "cluster", - action: "open", - params: { - clusterId: hostedCluster.id, - }, - }); - }); + unmountRoot(); }; + }; diff --git a/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts b/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts index e1bedb0c88..f1e3024d80 100644 --- a/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts +++ b/packages/core/src/renderer/frames/root-frame/init-root-frame.injectable.ts @@ -9,6 +9,7 @@ import lensProtocolRouterRendererInjectable from "../../protocol-handler/lens-pr import catalogEntityRegistryInjectable from "../../api/catalog/entity/registry.injectable"; import registerIpcListenersInjectable from "../../ipc/register-ipc-listeners.injectable"; import loadExtensionsInjectable from "../load-extensions.injectable"; +import loggerInjectable from "../../../common/logger.injectable"; import { delay } from "@k8slens/utilities"; import { broadcastMessage } from "../../../common/ipc"; import { bundledExtensionsLoaded } from "../../../common/ipc/extension-handling"; @@ -22,8 +23,9 @@ const initRootFrameInjectable = getInjectable({ const bindProtocolAddRouteHandlers = di.inject(bindProtocolAddRouteHandlersInjectable); const lensProtocolRouterRenderer = di.inject(lensProtocolRouterRendererInjectable); const catalogEntityRegistry = di.inject(catalogEntityRegistryInjectable); + const logger = di.inject(loggerInjectable); - return async () => { + return async (unmountRoot: () => void) => { catalogEntityRegistry.init(); try { @@ -54,6 +56,12 @@ const initRootFrameInjectable = getInjectable({ window.addEventListener("online", () => broadcastMessage("network:online")); registerIpcListeners(); + + window.addEventListener("beforeunload", () => { + logger.info("[ROOT-FRAME]: Unload app"); + + unmountRoot(); + }); }; }, }); diff --git a/packages/core/src/renderer/logger/close-renderer-log-file-id.test.ts b/packages/core/src/renderer/logger/close-renderer-log-file-id.test.ts deleted file mode 100644 index 1520844c30..0000000000 --- a/packages/core/src/renderer/logger/close-renderer-log-file-id.test.ts +++ /dev/null @@ -1,56 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import winstonLoggerInjectable from "../../common/winston-logger.injectable"; -import { getDiForUnitTesting } from "../getDiForUnitTesting"; -import closeRendererLogFileInjectable from "./close-renderer-log-file.injectable"; -import type { DiContainer } from "@ogre-tools/injectable"; -import type winston from "winston"; -import type { SendMessageToChannel } from "../../common/utils/channel/message-to-channel-injection-token"; -import { sendMessageToChannelInjectionToken } from "../../common/utils/channel/message-to-channel-injection-token"; -import rendererLogFileIdInjectable from "./renderer-log-file-id.injectable"; -import ipcLogTransportInjectable from "./ipc-transport.injectable"; -import type IpcLogTransport from "./ipc-transport"; - -describe("close renderer file logging", () => { - let di: DiContainer; - let sendIpcMock: SendMessageToChannel; - let winstonMock: winston.Logger; - let ipcTransportMock: IpcLogTransport; - - beforeEach(() => { - di = getDiForUnitTesting(); - sendIpcMock = jest.fn(); - winstonMock = { - remove: jest.fn(), - } as any as winston.Logger; - ipcTransportMock = { name: "ipc-renderer-transport" } as IpcLogTransport; - - di.override(winstonLoggerInjectable, () => winstonMock); - di.override(sendMessageToChannelInjectionToken, () => sendIpcMock); - di.override(rendererLogFileIdInjectable, () => "some-log-id"); - di.override(ipcLogTransportInjectable, () => ipcTransportMock); - }); - - it("sends the ipc close message with correct log id", () => { - const closeLog = di.inject(closeRendererLogFileInjectable); - - closeLog(); - - expect(sendIpcMock).toHaveBeenCalledWith( - { id: "close-ipc-file-logger-channel" }, - "some-log-id", - ); - }); - - it("removes the transport to prevent further logging to closed file", () => { - const closeLog = di.inject(closeRendererLogFileInjectable); - - closeLog(); - - expect(winstonMock.remove).toHaveBeenCalledWith({ - name: "ipc-renderer-transport", - }); - }); -}); diff --git a/packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts b/packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts deleted file mode 100644 index 8015708d84..0000000000 --- a/packages/core/src/renderer/logger/close-renderer-log-file.injectable.ts +++ /dev/null @@ -1,28 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import winstonLoggerInjectable from "../../common/winston-logger.injectable"; -import { closeIpcFileLoggerChannel } from "../../common/logger/ipc-file-logger-channel"; -import { sendMessageToChannelInjectionToken } from "../../common/utils/channel/message-to-channel-injection-token"; -import rendererLogFileIdInjectable from "./renderer-log-file-id.injectable"; -import ipcLogTransportInjectable from "./ipc-transport.injectable"; - -const closeRendererLogFileInjectable = getInjectable({ - id: "close-renderer-log-file", - instantiate: (di) => { - const winstonLogger = di.inject(winstonLoggerInjectable); - const ipcLogTransport = di.inject(ipcLogTransportInjectable); - const messageToChannel = di.inject(sendMessageToChannelInjectionToken); - const fileId = di.inject(rendererLogFileIdInjectable); - - - return () => { - messageToChannel(closeIpcFileLoggerChannel, fileId); - winstonLogger.remove(ipcLogTransport); - }; - }, -}); - -export default closeRendererLogFileInjectable; diff --git a/packages/core/src/renderer/logger/ipc-transport.injectable.ts b/packages/core/src/renderer/logger/ipc-transport.injectable.ts deleted file mode 100644 index 45139cd917..0000000000 --- a/packages/core/src/renderer/logger/ipc-transport.injectable.ts +++ /dev/null @@ -1,60 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import { loggerTransportInjectionToken } from "../../common/logger/transports"; -import type winston from "winston"; -import { MESSAGE } from "triple-beam"; - -import IpcLogTransport from "./ipc-transport"; -import { sendMessageToChannelInjectionToken } from "../../common/utils/channel/message-to-channel-injection-token"; -import type { - IpcFileLogObject } from "../../common/logger/ipc-file-logger-channel"; -import { - closeIpcFileLoggerChannel, - ipcFileLoggerChannel, -} from "../../common/logger/ipc-file-logger-channel"; -import rendererLogFileIdInjectable from "./renderer-log-file-id.injectable"; - -/** - * Winston uses symbol property for the actual message. - * - * For that to get through IPC, use the internalMessage property instead - */ -function serializeLogForIpc( - fileId: string, - entry: winston.LogEntry, -): IpcFileLogObject { - return { - fileId, - entry: { - level: entry.level, - message: entry.message, - internalMessage: Object.getOwnPropertyDescriptor(entry, MESSAGE)?.value, - }, - }; -} - -const ipcLogTransportInjectable = getInjectable({ - id: "renderer-file-logger-transport", - instantiate: (di) => { - const messageToChannel = di.inject(sendMessageToChannelInjectionToken); - const fileId = di.inject(rendererLogFileIdInjectable); - - return new IpcLogTransport({ - sendIpcLogMessage: (entry) => - messageToChannel( - ipcFileLoggerChannel, - serializeLogForIpc(fileId, entry), - ), - closeIpcLogging: () => - messageToChannel(closeIpcFileLoggerChannel, fileId), - handleExceptions: false, - level: "info", - }); - }, - injectionToken: loggerTransportInjectionToken, -}); - -export default ipcLogTransportInjectable; diff --git a/packages/core/src/renderer/logger/ipc-transport.test.ts b/packages/core/src/renderer/logger/ipc-transport.test.ts deleted file mode 100644 index 931df377c7..0000000000 --- a/packages/core/src/renderer/logger/ipc-transport.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { DiContainer } from "@ogre-tools/injectable"; -import type { SendMessageToChannel } from "../../common/utils/channel/message-to-channel-injection-token"; -import { sendMessageToChannelInjectionToken } from "../../common/utils/channel/message-to-channel-injection-token"; -import { getDiForUnitTesting } from "../getDiForUnitTesting"; -import rendererLogFileIdInjectable from "./renderer-log-file-id.injectable"; -import ipcLogTransportInjectable from "./ipc-transport.injectable"; -import { MESSAGE } from "triple-beam"; - -describe("renderer log transport through ipc", () => { - let di: DiContainer; - let sendIpcMock: SendMessageToChannel; - - beforeEach(() => { - sendIpcMock = jest.fn(); - di = getDiForUnitTesting(); - di.override(sendMessageToChannelInjectionToken, () => sendIpcMock); - di.override(rendererLogFileIdInjectable, () => "some-log-id"); - }); - - it("send serialized ipc messages on log", () => { - const logTransport = di.inject(ipcLogTransportInjectable); - - logTransport.log( - { - level: "info", - message: "some log text", - [MESSAGE]: "actual winston log text", - }, - () => {}, - ); - - expect(sendIpcMock).toHaveBeenCalledWith( - { id: "ipc-file-logger-channel" }, - { - entry: { - level: "info", - message: "some log text", - internalMessage: "actual winston log text", - }, - fileId: "some-log-id", - }, - ); - }); -}); diff --git a/packages/core/src/renderer/logger/ipc-transport.ts b/packages/core/src/renderer/logger/ipc-transport.ts deleted file mode 100644 index a1f6fa819e..0000000000 --- a/packages/core/src/renderer/logger/ipc-transport.ts +++ /dev/null @@ -1,41 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import type { LogEntry } from "winston"; -import type { TransportStreamOptions } from "winston-transport"; -import TransportStream from "winston-transport"; - -interface IpcLogTransportOptions extends TransportStreamOptions { - sendIpcLogMessage: (entry: LogEntry) => void; - closeIpcLogging: () => void; -} - -class IpcLogTransport extends TransportStream { - sendIpcLogMessage: (entry: LogEntry) => void; - closeIpcLogging: () => void; - name = "ipc-renderer-transport"; - - constructor(options: IpcLogTransportOptions) { - const { sendIpcLogMessage, closeIpcLogging, ...winstonOptions } = options; - - super(winstonOptions); - - this.sendIpcLogMessage = sendIpcLogMessage; - this.closeIpcLogging = closeIpcLogging; - } - - log(logEntry: LogEntry, next: () => void) { - setImmediate(() => { - this.emit("logged", logEntry); - }); - this.sendIpcLogMessage(logEntry); - next(); - } - - close() { - this.closeIpcLogging(); - } -} - -export default IpcLogTransport; diff --git a/packages/core/src/renderer/logger/renderer-log-file-id.injectable.ts b/packages/core/src/renderer/logger/renderer-log-file-id.injectable.ts deleted file mode 100644 index 81f4196b08..0000000000 --- a/packages/core/src/renderer/logger/renderer-log-file-id.injectable.ts +++ /dev/null @@ -1,29 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectable } from "@ogre-tools/injectable"; -import windowLocationInjectable from "../../common/k8s-api/window-location.injectable"; -import currentlyInClusterFrameInjectable from "../routes/currently-in-cluster-frame.injectable"; -import { getClusterIdFromHost } from "../../common/utils"; - -const rendererLogFileIdInjectable = getInjectable({ - id: "renderer-log-file-id", - instantiate: (di) => { - let frameId: string; - const currentlyInClusterFrame = di.inject(currentlyInClusterFrameInjectable); - - if (currentlyInClusterFrame) { - const { host } = di.inject(windowLocationInjectable); - const clusterId = getClusterIdFromHost(host); - - frameId = `cluster-${clusterId}`; - } else { - frameId = "main"; - } - - return `renderer-${frameId}`; - }, -}); - -export default rendererLogFileIdInjectable; diff --git a/packages/core/src/renderer/logger/renderer-log-file-id.test.ts b/packages/core/src/renderer/logger/renderer-log-file-id.test.ts deleted file mode 100644 index bd2abf7a63..0000000000 --- a/packages/core/src/renderer/logger/renderer-log-file-id.test.ts +++ /dev/null @@ -1,34 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import windowLocationInjectable from "../../common/k8s-api/window-location.injectable"; -import { getDiForUnitTesting } from "../getDiForUnitTesting"; -import currentlyInClusterFrameInjectable from "../routes/currently-in-cluster-frame.injectable"; -import rendererLogFileIdInjectable from "./renderer-log-file-id.injectable"; - -describe("renderer log file id", () => { - - it("clearly names log for renderer main frame", () => { - const di = getDiForUnitTesting(); - - di.override(currentlyInClusterFrameInjectable, () => false); - - const mainFileId = di.inject(rendererLogFileIdInjectable); - - expect(mainFileId).toBe("renderer-main"); - }); - - it("includes cluster id in renderer log file names", () => { - const di = getDiForUnitTesting(); - - di.override(currentlyInClusterFrameInjectable, () => true); - di.override(windowLocationInjectable, () => ({ - host: "some-cluster.lens.app", - port: "irrelevant", - })); - const clusterFileId = di.inject(rendererLogFileIdInjectable); - - expect(clusterFileId).toBe("renderer-cluster-some-cluster"); - }); -}); From 8a80607d8516736128dd22bde83d8e3351cb00db Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Tue, 21 Mar 2023 22:00:12 -0400 Subject: [PATCH 13/17] Add behavioural tests for Cluster Menu K8s Resources in Sidebar menu not being shown (#7280) * Add behavioural tests to cover bug fix Signed-off-by: Sebastian Malton * Remove previous fix to fix last test Signed-off-by: Sebastian Malton * More consistent impl of flushPromises Signed-off-by: Sebastian Malton * Fixup tests Signed-off-by: Sebastian Malton * Remove ContextHandler test (dead code) Signed-off-by: Sebastian Malton * Fix PrometheusHandler describe text Signed-off-by: Sebastian Malton * Fix type errors Signed-off-by: Sebastian Malton * Add useful case test-utils helper Signed-off-by: Sebastian Malton * Rename file to match token Signed-off-by: Sebastian Malton * Cleanup tests to fix type errors and use tables Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- .../authorization-review.injectable.ts | 50 -- .../create-authorization-api.injectable.ts | 16 + .../common/cluster/create-can-i.injectable.ts | 42 ++ .../cluster/create-core-api.injectable.ts | 16 + ...t-namespace-list-permissions.injectable.ts | 57 ++ .../cluster/list-namespaces.injectable.ts | 20 +- ...t-namespace-list-permissions.injectable.ts | 72 -- ...request-namespace-list-permissions.test.ts | 501 ++++++-------- .../fs/copy.global-override-for-injectable.ts | 11 - .../lstat.global-override-for-injectable.ts | 11 - ...irectory.global-override-for-injectable.ts | 11 - .../remove.global-override-for-injectable.ts | 11 - ...ite-file.global-override-for-injectable.ts | 11 - .../refresh-accessibility-technical.test.ts | 637 ++++++++++++++++++ .../core/src/main/__test__/cluster.test.ts | 12 +- .../src/main/__test__/context-handler.test.ts | 203 ------ .../src/main/__test__/kube-auth-proxy.test.ts | 4 +- .../main/__test__/prometheus-handler.test.ts | 2 +- ...-versions.ts => api-versions-requester.ts} | 7 +- .../cluster/cluster-connection.injectable.ts | 34 +- .../kube-auth-proxy-server.injectable.ts | 2 +- .../request-api-resources.injectable.ts | 8 +- .../request-core-api-versions.injectable.ts | 39 +- ...quest-kube-api-resources-for.injectable.ts | 2 +- ...equest-non-core-api-versions.injectable.ts | 45 +- .../request-non-core-api-versions.test.ts | 8 +- .../create-kube-auth-proxy.injectable.ts | 11 +- .../main/kube-auth-proxy/kube-auth-proxy.ts | 3 +- .../kubeconfig-manager/kubeconfig-manager.ts | 2 +- packages/core/src/test-utils/cast.ts | 6 + .../core/src/test-utils/mock-interface.ts | 17 + .../test-utils/src/flush-promises.ts | 7 +- 32 files changed, 1104 insertions(+), 774 deletions(-) delete mode 100644 packages/core/src/common/cluster/authorization-review.injectable.ts create mode 100644 packages/core/src/common/cluster/create-authorization-api.injectable.ts create mode 100644 packages/core/src/common/cluster/create-can-i.injectable.ts create mode 100644 packages/core/src/common/cluster/create-core-api.injectable.ts create mode 100644 packages/core/src/common/cluster/create-request-namespace-list-permissions.injectable.ts delete mode 100644 packages/core/src/common/cluster/request-namespace-list-permissions.injectable.ts delete mode 100644 packages/core/src/common/fs/copy.global-override-for-injectable.ts delete mode 100644 packages/core/src/common/fs/lstat.global-override-for-injectable.ts delete mode 100644 packages/core/src/common/fs/read-directory.global-override-for-injectable.ts delete mode 100644 packages/core/src/common/fs/remove.global-override-for-injectable.ts delete mode 100644 packages/core/src/common/fs/write-file.global-override-for-injectable.ts create mode 100644 packages/core/src/features/cluster/refresh-accessibility-technical.test.ts delete mode 100644 packages/core/src/main/__test__/context-handler.test.ts rename packages/core/src/main/cluster/{request-api-versions.ts => api-versions-requester.ts} (64%) create mode 100644 packages/core/src/test-utils/cast.ts create mode 100644 packages/core/src/test-utils/mock-interface.ts diff --git a/packages/core/src/common/cluster/authorization-review.injectable.ts b/packages/core/src/common/cluster/authorization-review.injectable.ts deleted file mode 100644 index 3352423377..0000000000 --- a/packages/core/src/common/cluster/authorization-review.injectable.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { KubeConfig, V1ResourceAttributes } from "@kubernetes/client-node"; -import { AuthorizationV1Api } from "@kubernetes/client-node"; -import { getInjectable } from "@ogre-tools/injectable"; -import loggerInjectable from "../logger.injectable"; - -/** - * Requests the permissions for actions on the kube cluster - * @param resourceAttributes The descriptor of the action that is desired to be known if it is allowed - * @returns `true` if the actions described are allowed - */ -export type CanI = (resourceAttributes: V1ResourceAttributes) => Promise; - -/** - * @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster - */ -export type CreateAuthorizationReview = (proxyConfig: KubeConfig) => CanI; - -const createAuthorizationReviewInjectable = getInjectable({ - id: "authorization-review", - instantiate: (di): CreateAuthorizationReview => { - const logger = di.inject(loggerInjectable); - - return (proxyConfig) => { - const api = proxyConfig.makeApiClient(AuthorizationV1Api); - - return async (resourceAttributes: V1ResourceAttributes): Promise => { - try { - const { body } = await api.createSelfSubjectAccessReview({ - apiVersion: "authorization.k8s.io/v1", - kind: "SelfSubjectAccessReview", - spec: { resourceAttributes }, - }); - - return body.status?.allowed ?? false; - } catch (error) { - logger.error(`[AUTHORIZATION-REVIEW]: failed to create access review: ${error}`, { resourceAttributes }); - - return false; - } - }; - }; - }, -}); - -export default createAuthorizationReviewInjectable; diff --git a/packages/core/src/common/cluster/create-authorization-api.injectable.ts b/packages/core/src/common/cluster/create-authorization-api.injectable.ts new file mode 100644 index 0000000000..c0658a4a34 --- /dev/null +++ b/packages/core/src/common/cluster/create-authorization-api.injectable.ts @@ -0,0 +1,16 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { AuthorizationV1Api } from "@kubernetes/client-node"; +import type { KubeConfig } from "@kubernetes/client-node"; +import { getInjectable } from "@ogre-tools/injectable"; + +export type CreateAuthorizationApi = (config: KubeConfig) => AuthorizationV1Api; + +const createAuthorizationApiInjectable = getInjectable({ + id: "create-authorization-api", + instantiate: (): CreateAuthorizationApi => (config) => config.makeApiClient(AuthorizationV1Api), +}); + +export default createAuthorizationApiInjectable; diff --git a/packages/core/src/common/cluster/create-can-i.injectable.ts b/packages/core/src/common/cluster/create-can-i.injectable.ts new file mode 100644 index 0000000000..59d30dbe77 --- /dev/null +++ b/packages/core/src/common/cluster/create-can-i.injectable.ts @@ -0,0 +1,42 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { AuthorizationV1Api, V1ResourceAttributes } from "@kubernetes/client-node"; +import { getInjectable } from "@ogre-tools/injectable"; +import loggerInjectable from "../logger.injectable"; + +/** + * Requests the permissions for actions on the kube cluster + * @param resourceAttributes The descriptor of the action that is desired to be known if it is allowed + * @returns `true` if the actions described are allowed + */ +export type CanI = (resourceAttributes: V1ResourceAttributes) => Promise; + +export type CreateCanI = (api: AuthorizationV1Api) => CanI; + +const createCanIInjectable = getInjectable({ + id: "create-can-i", + instantiate: (di): CreateCanI => { + const logger = di.inject(loggerInjectable); + + return (api) => async (resourceAttributes: V1ResourceAttributes): Promise => { + try { + const { body } = await api.createSelfSubjectAccessReview({ + apiVersion: "authorization.k8s.io/v1", + kind: "SelfSubjectAccessReview", + spec: { resourceAttributes }, + }); + + return body.status?.allowed ?? false; + } catch (error) { + logger.error(`[AUTHORIZATION-REVIEW]: failed to create access review: ${error}`, { resourceAttributes }); + + return false; + } + }; + }, +}); + +export default createCanIInjectable; diff --git a/packages/core/src/common/cluster/create-core-api.injectable.ts b/packages/core/src/common/cluster/create-core-api.injectable.ts new file mode 100644 index 0000000000..2389b12478 --- /dev/null +++ b/packages/core/src/common/cluster/create-core-api.injectable.ts @@ -0,0 +1,16 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { KubeConfig } from "@kubernetes/client-node"; +import { CoreV1Api } from "@kubernetes/client-node"; +import { getInjectable } from "@ogre-tools/injectable"; + +export type CreateCoreApi = (config: KubeConfig) => CoreV1Api; + +const createCoreApiInjectable = getInjectable({ + id: "create-core-api", + instantiate: (): CreateCoreApi => config => config.makeApiClient(CoreV1Api), +}); + +export default createCoreApiInjectable; diff --git a/packages/core/src/common/cluster/create-request-namespace-list-permissions.injectable.ts b/packages/core/src/common/cluster/create-request-namespace-list-permissions.injectable.ts new file mode 100644 index 0000000000..b3e8875dc1 --- /dev/null +++ b/packages/core/src/common/cluster/create-request-namespace-list-permissions.injectable.ts @@ -0,0 +1,57 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { AuthorizationV1Api } from "@kubernetes/client-node"; +import { getInjectable } from "@ogre-tools/injectable"; +import loggerInjectable from "../logger.injectable"; +import type { KubeApiResource } from "../rbac"; + +export type CanListResource = (resource: KubeApiResource) => boolean; + +/** + * Requests the permissions for actions on the kube cluster + * @param namespace The namespace of the resources + */ +export type RequestNamespaceListPermissions = (namespace: string) => Promise; + +export type CreateRequestNamespaceListPermissions = (api: AuthorizationV1Api) => RequestNamespaceListPermissions; + +const createRequestNamespaceListPermissionsInjectable = getInjectable({ + id: "create-request-namespace-list-permissions", + instantiate: (di): CreateRequestNamespaceListPermissions => { + const logger = di.inject(loggerInjectable); + + return (api) => async (namespace) => { + try { + const { body: { status }} = await api.createSelfSubjectRulesReview({ + apiVersion: "authorization.k8s.io/v1", + kind: "SelfSubjectRulesReview", + spec: { namespace }, + }); + + if (!status || status.incomplete) { + logger.warn(`[AUTHORIZATION-NAMESPACE-REVIEW]: allowing all resources in namespace="${namespace}" due to incomplete SelfSubjectRulesReview: ${status?.evaluationError}`); + + return () => true; + } + + const { resourceRules } = status; + + return (resource) => ( + resourceRules + .filter(({ apiGroups = ["*"] }) => apiGroups.includes("*") || apiGroups.includes(resource.group)) + .filter(({ resources = ["*"] }) => resources.includes("*") || resources.includes(resource.apiName)) + .some(({ verbs }) => verbs.includes("*") || verbs.includes("list")) + ); + } catch (error) { + logger.error(`[AUTHORIZATION-NAMESPACE-REVIEW]: failed to create subject rules review`, { namespace, error }); + + return () => true; + } + }; + }, +}); + +export default createRequestNamespaceListPermissionsInjectable; diff --git a/packages/core/src/common/cluster/list-namespaces.injectable.ts b/packages/core/src/common/cluster/list-namespaces.injectable.ts index 363a10abb1..04acb0671b 100644 --- a/packages/core/src/common/cluster/list-namespaces.injectable.ts +++ b/packages/core/src/common/cluster/list-namespaces.injectable.ts @@ -2,27 +2,21 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { KubeConfig } from "@kubernetes/client-node"; -import { CoreV1Api } from "@kubernetes/client-node"; +import type { CoreV1Api } from "@kubernetes/client-node"; import { getInjectable } from "@ogre-tools/injectable"; import { isDefined } from "@k8slens/utilities"; export type ListNamespaces = () => Promise; - -export type CreateListNamespaces = (config: KubeConfig) => ListNamespaces; +export type CreateListNamespaces = (api: CoreV1Api) => ListNamespaces; const createListNamespacesInjectable = getInjectable({ id: "create-list-namespaces", - instantiate: (): CreateListNamespaces => (config) => { - const coreApi = config.makeApiClient(CoreV1Api); + instantiate: (): CreateListNamespaces => (api) => async () => { + const { body: { items }} = await api.listNamespace(); - return async () => { - const { body: { items }} = await coreApi.listNamespace(); - - return items - .map(ns => ns.metadata?.name) - .filter(isDefined); - }; + return items + .map(ns => ns.metadata?.name) + .filter(isDefined); }, }); diff --git a/packages/core/src/common/cluster/request-namespace-list-permissions.injectable.ts b/packages/core/src/common/cluster/request-namespace-list-permissions.injectable.ts deleted file mode 100644 index 4b1aadeee6..0000000000 --- a/packages/core/src/common/cluster/request-namespace-list-permissions.injectable.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import type { KubeConfig } from "@kubernetes/client-node"; -import { AuthorizationV1Api } from "@kubernetes/client-node"; -import { getInjectable } from "@ogre-tools/injectable"; -import loggerInjectable from "../logger.injectable"; -import type { KubeApiResource } from "../rbac"; - -export type CanListResource = (resource: KubeApiResource) => boolean; - -/** - * Requests the permissions for actions on the kube cluster - * @param namespace The namespace of the resources - */ -export type RequestNamespaceListPermissions = (namespace: string) => Promise; - -/** - * @param proxyConfig This config's `currentContext` field must be set, and will be used as the target cluster - */ -export type RequestNamespaceListPermissionsFor = (proxyConfig: KubeConfig) => RequestNamespaceListPermissions; - -const requestNamespaceListPermissionsForInjectable = getInjectable({ - id: "request-namespace-list-permissions-for", - instantiate: (di): RequestNamespaceListPermissionsFor => { - const logger = di.inject(loggerInjectable); - - return (proxyConfig) => { - const api = proxyConfig.makeApiClient(AuthorizationV1Api); - - return async (namespace) => { - try { - const { body: { status }} = await api.createSelfSubjectRulesReview({ - apiVersion: "authorization.k8s.io/v1", - kind: "SelfSubjectRulesReview", - spec: { namespace }, - }); - - if (!status || status.incomplete) { - logger.warn(`[AUTHORIZATION-NAMESPACE-REVIEW]: allowing all resources in namespace="${namespace}" due to incomplete SelfSubjectRulesReview: ${status?.evaluationError}`); - - return () => true; - } - - const { resourceRules } = status; - - return (resource) => { - const rules = resourceRules.filter(({ - apiGroups = ["*"], - resources = ["*"], - }) => { - const isAboutRelevantApiGroup = apiGroups.includes("*") || apiGroups.includes(resource.group); - const isAboutResource = resources.includes("*") || resources.includes(resource.apiName); - - return isAboutRelevantApiGroup && isAboutResource; - }); - - return rules.some(({ verbs }) => verbs.includes("*") || verbs.includes("list")); - }; - } catch (error) { - logger.error(`[AUTHORIZATION-NAMESPACE-REVIEW]: failed to create subject rules review`, { namespace, error }); - - return () => true; - } - }; - }; - }, -}); - -export default requestNamespaceListPermissionsForInjectable; diff --git a/packages/core/src/common/cluster/request-namespace-list-permissions.test.ts b/packages/core/src/common/cluster/request-namespace-list-permissions.test.ts index c62f69ca8e..194b5ce7e5 100644 --- a/packages/core/src/common/cluster/request-namespace-list-permissions.test.ts +++ b/packages/core/src/common/cluster/request-namespace-list-permissions.test.ts @@ -3,334 +3,225 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { V1SubjectRulesReviewStatus } from "@kubernetes/client-node"; +import type { AsyncFnMock } from "@async-fn/jest"; +import asyncFn from "@async-fn/jest"; +import type { AuthorizationV1Api, V1SubjectRulesReviewStatus } from "@kubernetes/client-node"; import type { DiContainer } from "@ogre-tools/injectable"; +import type { IncomingMessage } from "http"; +import { anyObject } from "jest-mock-extended"; import { getDiForUnitTesting } from "../../main/getDiForUnitTesting"; -import type { RequestNamespaceListPermissionsFor } from "./request-namespace-list-permissions.injectable"; -import requestNamespaceListPermissionsForInjectable from "./request-namespace-list-permissions.injectable"; +import { cast } from "../../test-utils/cast"; +import type { KubeApiResource } from "../rbac"; +import type { RequestNamespaceListPermissions } from "./create-request-namespace-list-permissions.injectable"; +import createRequestNamespaceListPermissionsInjectable from "./create-request-namespace-list-permissions.injectable"; -const createStubProxyConfig = (statusResponse: Promise<{ body: { status: V1SubjectRulesReviewStatus }}>) => ({ - makeApiClient: () => ({ - createSelfSubjectRulesReview: (): Promise<{ body: { status: V1SubjectRulesReviewStatus }}> => statusResponse, - }), -}); +interface TestCase { + description: string; + status: V1SubjectRulesReviewStatus; + expected: boolean; +} describe("requestNamespaceListPermissions", () => { let di: DiContainer; - let requestNamespaceListPermissions: RequestNamespaceListPermissionsFor; + let createSelfSubjectRulesReviewMock: AsyncFnMock; + let requestNamespaceListPermissions: RequestNamespaceListPermissions; beforeEach(() => { di = getDiForUnitTesting(); - requestNamespaceListPermissions = di.inject(requestNamespaceListPermissionsForInjectable); + + const createRequestNamespaceListPermissions = di.inject(createRequestNamespaceListPermissionsInjectable); + + createSelfSubjectRulesReviewMock = asyncFn(); + + requestNamespaceListPermissions = createRequestNamespaceListPermissions(cast({ + createSelfSubjectRulesReview: createSelfSubjectRulesReviewMock, + })); }); - describe("when api returns incomplete data", () => { - it("returns truthy function", async () => { - const requestPermissions = requestNamespaceListPermissions(createStubProxyConfig( - new Promise((resolve) => resolve({ - body: { - status: { - incomplete: true, - resourceRules: [], - nonResourceRules: [], - }, - }, - })), - ) as any); + describe("when a request for list permissions in a namespace has been started", () => { + let request: ReturnType; - const permissionCheck = await requestPermissions("irrelevant-namespace"); - - expect(permissionCheck({ - apiName: "pods", - group: "", - kind: "Pod", - namespaced: true, - })).toBeTruthy(); + beforeEach(() => { + request = requestNamespaceListPermissions("irrelevant-namespace"); }); - }); - describe("when api rejects", () => { - it("returns truthy function", async () => { - const requestPermissions = requestNamespaceListPermissions(createStubProxyConfig( - new Promise((resolve, reject) => reject("unknown error")), - ) as any); - - const permissionCheck = await requestPermissions("irrelevant-namespace"); - - expect(permissionCheck({ - apiName: "pods", - group: "", - kind: "Pod", - namespaced: true, - })).toBeTruthy(); + it("should request the creation of a SelfSubjectRulesReview", () => { + expect(createSelfSubjectRulesReviewMock).toBeCalledWith(anyObject({ + spec: { + namespace: "irrelevant-namespace", + }, + })); }); - }); - describe("when first resourceRule has all permissions for everything", () => { - it("return truthy function", async () => { - const requestPermissions = requestNamespaceListPermissions(createStubProxyConfig( - new Promise((resolve) => resolve({ - body: { - status: { - incomplete: false, - resourceRules: [ - { - apiGroups: ["*"], - verbs: ["*"], - }, - { - apiGroups: ["*"], - verbs: ["get"], - }, - ], - nonResourceRules: [], + ([ + { + description: "incomplete data", + status: { + incomplete: true, + resourceRules: [], + nonResourceRules: [], + }, + expected: true, + }, + { + description: "first resourceRule has all permissions for everything", + status: { + incomplete: false, + resourceRules: [ + { + apiGroups: ["*"], + verbs: ["*"], }, - }, - })), - ) as any); + { + apiGroups: ["*"], + verbs: ["get"], + }, + ], + nonResourceRules: [], + }, + expected: true, + }, + { + description: "first resourceRule has list permissions for everything", + status: { + incomplete: false, + resourceRules: [ + { + apiGroups: ["*"], + verbs: ["list"], + }, + { + apiGroups: ["*"], + verbs: ["get"], + }, + ], + nonResourceRules: [], + }, + expected: true, + }, + { + description: "first resourceRule has list permissions for asked resource", + status: { + incomplete: false, + resourceRules: [ + { + apiGroups: ["some-api-group"], + resources: ["some-kind"], + verbs: ["list"], + }, + { + apiGroups: ["*"], + verbs: ["get"], + }, + ], + nonResourceRules: [], + }, + expected: true, + }, + { + description: "last resourceRule has all permissions for everything", + status: { + incomplete: false, + resourceRules: [ + { + apiGroups: ["*"], + verbs: ["get"], + }, + { + apiGroups: ["*"], + verbs: ["*"], + }, + ], + nonResourceRules: [], + }, + expected: true, + }, + { + description: "last resourceRule has list permissions for asked resource", + status: { + incomplete: false, + resourceRules: [ + { + apiGroups: ["*"], + verbs: ["get"], + }, + { + apiGroups: ["some-api-group"], + resources: ["some-kind"], + verbs: ["list"], + }, + ], + nonResourceRules: [], + }, + expected: true, + }, + { + description: "resourceRules has matching resource without list verb", + status: { + incomplete: false, + resourceRules: [ + { + apiGroups: ["some-api-group"], + resources: ["some-kind"], + verbs: ["get"], + }, + ], + nonResourceRules: [], + }, + expected: false, + }, + { + description: "resourceRules has no matching resource with list verb", + status: { + incomplete: false, + resourceRules: [ + { + apiGroups: [""], + resources: ["services"], + verbs: ["list"], + }, + ], + nonResourceRules: [], + }, + expected: false, + }, + ] as TestCase[]).forEach(({ description, status, expected }) => { + describe(`when api returns ${description}`, () => { + beforeEach(async () => { + await createSelfSubjectRulesReviewMock.resolve({ + body: { + status, + spec: {}, + }, + response: null as unknown as IncomingMessage, + }); + }); - const permissionCheck = await requestPermissions("irrelevant-namespace"); + it(`allows the request to complete, and 'canListResource' will return ${expected}`, async () => { + const canListResource = await request; - expect(permissionCheck({ - apiName: "pods", - group: "", - kind: "Pod", - namespaced: true, - })).toBeTruthy(); + expect(canListResource(someKubeResource)).toBe(expected); + }); + }); }); - }); - describe("when first resourceRule has list permissions for everything", () => { - it("return truthy function", async () => { - const requestPermissions = requestNamespaceListPermissions(createStubProxyConfig( - new Promise((resolve) => resolve({ - body: { - status: { - incomplete: false, - resourceRules: [ - { - apiGroups: ["*"], - verbs: ["list"], - }, - { - apiGroups: ["*"], - verbs: ["get"], - }, - ], - nonResourceRules: [], - }, - }, - })), - ) as any); + describe("when api rejects", () => { + beforeEach(async () => { + await createSelfSubjectRulesReviewMock.reject(new Error("unknown error")); + }); - const permissionCheck = await requestPermissions("irrelevant-namespace"); + it("allows the request to complete, and 'canListResource' will return true", async () => { + const canListResource = await request; - expect(permissionCheck({ - apiName: "pods", - group: "", - kind: "Pod", - namespaced: true, - })).toBeTruthy(); - }); - }); - - describe("when first resourceRule has list permissions for asked resource", () => { - it("return truthy function", async () => { - const requestPermissions = requestNamespaceListPermissions(createStubProxyConfig( - new Promise((resolve) => resolve({ - body: { - status: { - incomplete: false, - resourceRules: [ - { - apiGroups: [""], - resources: ["pods"], - verbs: ["list"], - }, - { - apiGroups: ["*"], - verbs: ["get"], - }, - ], - nonResourceRules: [], - }, - }, - })), - ) as any); - - const permissionCheck = await requestPermissions("irrelevant-namespace"); - - expect(permissionCheck({ - apiName: "pods", - group: "", - kind: "Pod", - namespaced: true, - })).toBeTruthy(); - }); - }); - - describe("when last resourceRule has all permissions for everything", () => { - it("return truthy function", async () => { - const requestPermissions = requestNamespaceListPermissions(createStubProxyConfig( - new Promise((resolve) => resolve({ - body: { - status: { - incomplete: false, - resourceRules: [ - { - apiGroups: ["*"], - verbs: ["get"], - }, - { - apiGroups: ["*"], - verbs: ["*"], - }, - ], - nonResourceRules: [], - }, - }, - })), - ) as any); - - const permissionCheck = await requestPermissions("irrelevant-namespace"); - - expect(permissionCheck({ - apiName: "pods", - group: "", - kind: "Pod", - namespaced: true, - })).toBeTruthy(); - }); - }); - - describe("when last resourceRule has list permissions for everything", () => { - it("return truthy function", async () => { - const requestPermissions = requestNamespaceListPermissions(createStubProxyConfig( - new Promise((resolve) => resolve({ - body: { - status: { - incomplete: false, - resourceRules: [ - { - apiGroups: ["*"], - verbs: ["get"], - }, - { - apiGroups: ["*"], - verbs: ["list"], - }, - ], - nonResourceRules: [], - }, - }, - })), - ) as any); - - const permissionCheck = await requestPermissions("irrelevant-namespace"); - - expect(permissionCheck({ - apiName: "pods", - group: "", - kind: "Pod", - namespaced: true, - })).toBeTruthy(); - }); - }); - - describe("when last resourceRule has list permissions for asked resource", () => { - it("return truthy function", async () => { - const requestPermissions = requestNamespaceListPermissions(createStubProxyConfig( - new Promise((resolve) => resolve({ - body: { - status: { - incomplete: false, - resourceRules: [ - { - apiGroups: ["*"], - verbs: ["get"], - }, - { - apiGroups: [""], - resources: ["pods"], - verbs: ["list"], - }, - ], - nonResourceRules: [], - }, - }, - })), - ) as any); - - const permissionCheck = await requestPermissions("irrelevant-namespace"); - - expect(permissionCheck({ - apiName: "pods", - group: "", - kind: "Pod", - namespaced: true, - })).toBeTruthy(); - }); - }); - - describe("when resourceRules has matching resource without list verb", () => { - it("return falsy function", async () => { - const requestPermissions = requestNamespaceListPermissions(createStubProxyConfig( - new Promise((resolve) => resolve({ - body: { - status: { - incomplete: false, - resourceRules: [ - { - apiGroups: [""], - resources: ["pods"], - verbs: ["get"], - }, - ], - nonResourceRules: [], - }, - }, - })), - ) as any); - - const permissionCheck = await requestPermissions("irrelevant-namespace"); - - expect(permissionCheck({ - apiName: "pods", - group: "", - kind: "Pod", - namespaced: true, - })).toBeFalsy(); - }); - }); - - describe("when resourceRules has no matching resource with list verb", () => { - it("return falsy function", async () => { - const requestPermissions = requestNamespaceListPermissions(createStubProxyConfig( - new Promise((resolve) => resolve({ - body: { - status: { - incomplete: false, - resourceRules: [ - { - apiGroups: [""], - resources: ["services"], - verbs: ["list"], - }, - ], - nonResourceRules: [], - }, - }, - })), - ) as any); - - const permissionCheck = await requestPermissions("irrelevant-namespace"); - - expect(permissionCheck({ - apiName: "pods", - group: "", - kind: "Pod", - namespaced: true, - })).toBeFalsy(); + expect(canListResource(someKubeResource)).toBe(true); + }); }); }); }); + +const someKubeResource: KubeApiResource = { + apiName: "some-kind", + group: "some-api-group", + kind: "SomeKind", + namespaced: true, +}; diff --git a/packages/core/src/common/fs/copy.global-override-for-injectable.ts b/packages/core/src/common/fs/copy.global-override-for-injectable.ts deleted file mode 100644 index 3799d3b760..0000000000 --- a/packages/core/src/common/fs/copy.global-override-for-injectable.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { getGlobalOverride } from "@k8slens/test-utils"; -import copyInjectable from "./copy.injectable"; - -export default getGlobalOverride(copyInjectable, () => async () => { - throw new Error("tried to copy filepaths without override"); -}); diff --git a/packages/core/src/common/fs/lstat.global-override-for-injectable.ts b/packages/core/src/common/fs/lstat.global-override-for-injectable.ts deleted file mode 100644 index 155fac7451..0000000000 --- a/packages/core/src/common/fs/lstat.global-override-for-injectable.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { getGlobalOverride } from "@k8slens/test-utils"; -import lstatInjectable from "./lstat.injectable"; - -export default getGlobalOverride(lstatInjectable, () => async () => { - throw new Error("tried to lstat a filepath without override"); -}); diff --git a/packages/core/src/common/fs/read-directory.global-override-for-injectable.ts b/packages/core/src/common/fs/read-directory.global-override-for-injectable.ts deleted file mode 100644 index 72d9b523f4..0000000000 --- a/packages/core/src/common/fs/read-directory.global-override-for-injectable.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { getGlobalOverride } from "@k8slens/test-utils"; -import readDirectoryInjectable from "./read-directory.injectable"; - -export default getGlobalOverride(readDirectoryInjectable, () => async () => { - throw new Error("tried to read a directory's content without override"); -}); diff --git a/packages/core/src/common/fs/remove.global-override-for-injectable.ts b/packages/core/src/common/fs/remove.global-override-for-injectable.ts deleted file mode 100644 index 58fb0f9dce..0000000000 --- a/packages/core/src/common/fs/remove.global-override-for-injectable.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { getGlobalOverride } from "@k8slens/test-utils"; -import removePathInjectable from "./remove.injectable"; - -export default getGlobalOverride(removePathInjectable, () => async () => { - throw new Error("tried to remove path without override"); -}); diff --git a/packages/core/src/common/fs/write-file.global-override-for-injectable.ts b/packages/core/src/common/fs/write-file.global-override-for-injectable.ts deleted file mode 100644 index e87f648305..0000000000 --- a/packages/core/src/common/fs/write-file.global-override-for-injectable.ts +++ /dev/null @@ -1,11 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { getGlobalOverride } from "@k8slens/test-utils"; -import writeFileInjectable from "./write-file.injectable"; - -export default getGlobalOverride(writeFileInjectable, () => async () => { - throw new Error("tried to write file without override"); -}); diff --git a/packages/core/src/features/cluster/refresh-accessibility-technical.test.ts b/packages/core/src/features/cluster/refresh-accessibility-technical.test.ts new file mode 100644 index 0000000000..73ff6151b9 --- /dev/null +++ b/packages/core/src/features/cluster/refresh-accessibility-technical.test.ts @@ -0,0 +1,637 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { AsyncFnMock } from "@async-fn/jest"; +import asyncFn from "@async-fn/jest"; +import type { AuthorizationV1Api, CoreV1Api, V1APIGroupList, V1APIVersions, V1NamespaceList, V1SelfSubjectAccessReview, V1SelfSubjectRulesReview } from "@kubernetes/client-node"; +import clusterStoreInjectable from "../../common/cluster-store/cluster-store.injectable"; +import type { Cluster } from "../../common/cluster/cluster"; +import createAuthorizationApiInjectable from "../../common/cluster/create-authorization-api.injectable"; +import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable"; +import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; +import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; +import broadcastMessageInjectable from "../../common/ipc/broadcast-message.injectable"; +import type { PartialDeep } from "type-fest"; +import { anyObject } from "jest-mock-extended"; +import createCoreApiInjectable from "../../common/cluster/create-core-api.injectable"; +import type { K8sRequest } from "../../main/k8s-request.injectable"; +import k8sRequestInjectable from "../../main/k8s-request.injectable"; +import type { DetectClusterMetadata } from "../../main/cluster-detectors/detect-cluster-metadata.injectable"; +import detectClusterMetadataInjectable from "../../main/cluster-detectors/detect-cluster-metadata.injectable"; +import type { ClusterConnection } from "../../main/cluster/cluster-connection.injectable"; +import clusterConnectionInjectable from "../../main/cluster/cluster-connection.injectable"; +import type { KubeAuthProxy } from "../../main/kube-auth-proxy/create-kube-auth-proxy.injectable"; +import createKubeAuthProxyInjectable from "../../main/kube-auth-proxy/create-kube-auth-proxy.injectable"; +import type { Mocked } from "../../test-utils/mock-interface"; +import { flushPromises } from "@k8slens/test-utils"; + +describe("Refresh Cluster Accessibility Technical Tests", () => { + let builder: ApplicationBuilder; + let createSelfSubjectRulesReviewMock: AsyncFnMock; + let createSelfSubjectAccessReviewMock: AsyncFnMock; + let listNamespaceMock: AsyncFnMock; + let k8sRequestMock: AsyncFnMock; + let detectClusterMetadataMock: AsyncFnMock; + let kubeAuthProxyMock: Mocked; + + beforeEach(async () => { + builder = getApplicationBuilder(); + + const mainDi = builder.mainDi; + + mainDi.override(broadcastMessageInjectable, () => async () => {}); + + kubeAuthProxyMock = { + apiPrefix: "/some-api-prefix", + port: 0, + exit: jest.fn(), + run: asyncFn(), + }; + mainDi.override(createKubeAuthProxyInjectable, () => () => kubeAuthProxyMock); + + detectClusterMetadataMock = asyncFn(); + mainDi.override(detectClusterMetadataInjectable, () => detectClusterMetadataMock); + + k8sRequestMock = asyncFn(); + mainDi.override(k8sRequestInjectable, () => k8sRequestMock); + + createSelfSubjectRulesReviewMock = asyncFn(); + createSelfSubjectAccessReviewMock = asyncFn(); + mainDi.override(createAuthorizationApiInjectable, () => () => ({ + createSelfSubjectRulesReview: createSelfSubjectRulesReviewMock, + createSelfSubjectAccessReview: createSelfSubjectAccessReviewMock, + } as any)); + + listNamespaceMock = asyncFn(); + mainDi.override(createCoreApiInjectable, () => () => ({ + listNamespace: listNamespaceMock, + } as any)); + + await builder.render(); + }); + + describe("given a cluster with no configured preferences", () => { + let cluster: Cluster; + let clusterConnection: ClusterConnection; + let refreshPromise: Promise; + + beforeEach(async () => { + const mainDi = builder.mainDi; + const clusterStore = mainDi.inject(clusterStoreInjectable); + const writeJsonFile = mainDi.inject(writeJsonFileInjectable); + + await writeJsonFile("/some-kube-config-path", { + apiVersion: "v1", + kind: "Config", + clusters: [{ + name: "some-cluster-name", + cluster: { + server: "https://localhost:8989", + }, + }], + users: [{ + name: "some-user-name", + }], + contexts: [{ + name: "some-cluster-context", + context: { + user: "some-user-name", + cluster: "some-cluster-name", + }, + }], + }); + + clusterStore.addCluster({ + contextName: "some-cluster-context", + id: "some-cluster-id", + kubeConfigPath: "/some-kube-config-path", + }); + + cluster = clusterStore.getById("some-cluster-id") ?? (() => { throw new Error("missing cluster"); })(); + clusterConnection = mainDi.inject(clusterConnectionInjectable, cluster); + refreshPromise = clusterConnection.refreshAccessibilityAndMetadata(); + }); + + it("starts kubeAuthProxy", () => { + expect(kubeAuthProxyMock.run).toBeCalled(); + }); + + describe("when kubeAuthProxy has started running and its port is found", () => { + beforeEach(async () => { + kubeAuthProxyMock.port = 1235; + await kubeAuthProxyMock.run.resolve(); + await flushPromises(); + }); + + it("requests if cluster has admin permissions", async () => { + expect(createSelfSubjectAccessReviewMock).toBeCalledWith(anyObject({ + spec: { + namespace: "kube-system", + resource: "*", + verb: "create", + }, + })); + }); + + describe.each([ true, false ])("when cluster admin request resolves to %p", (isAdmin) => { + beforeEach(async () => { + await createSelfSubjectAccessReviewMock.resolve({ + body: { + status: { + allowed: isAdmin, + }, + } as PartialDeep, + } as any); + }); + + it("requests if cluster has global watch permissions", () => { + expect(createSelfSubjectAccessReviewMock).toBeCalledWith(anyObject({ + spec: { + verb: "watch", + resource: "*", + }, + })); + }); + + describe.each([ true, false ])("when cluster global watch request resolves with %p", (globalWatch) => { + beforeEach(async () => { + await createSelfSubjectAccessReviewMock.resolve({ + body: { + status: { + allowed: globalWatch, + }, + } as PartialDeep, + } as any); + }); + + it("requests namespaces", () => { + expect(listNamespaceMock).toBeCalled(); + }); + + describe("when list namespaces resolves", () => { + beforeEach(async () => { + await listNamespaceMock.resolve(listNamespaceResponse); + }); + + it("requests core api versions", () => { + expect(k8sRequestMock).toBeCalledWith( + anyObject({ id: "some-cluster-id" }), + "/api", + ); + }); + + describe("when core api versions request resolves", () => { + beforeEach(async () => { + await k8sRequestMock.resolve({ + serverAddressByClientCIDRs: [], + versions: [ + "v1", + ], + } as V1APIVersions); + }); + + it("requests non-core api resource kinds", () => { + expect(k8sRequestMock).toBeCalledWith( + anyObject({ id: "some-cluster-id" }), + "/apis", + ); + }); + + describe("when non-core api resource kinds request resolves", () => { + beforeEach(async () => { + await k8sRequestMock.resolve(nonCoreApiResponse); + }); + + it("requests specific resource kinds in core", () => { + expect(k8sRequestMock).toBeCalledWith( + anyObject({ id: "some-cluster-id" }), + "/api/v1", + ); + }); + + describe("when core specific resource kinds request resolves", () => { + beforeEach(async () => { + await k8sRequestMock.resolve(coreApiKindsResponse); + }); + + it("requests specific resources kinds from the first non-core response", () => { + expect(k8sRequestMock).toBeCalledWith( + anyObject({ id: "some-cluster-id" }), + "/apis/node.k8s.io/v1", + ); + }); + + describe("when first specific resource kinds request resolves", () => { + beforeEach(async () => { + await k8sRequestMock.resolve(nodeK8sIoKindsResponse); + }); + + it("requests specific resources kinds from the second non-core response", () => { + expect(k8sRequestMock).toBeCalledWith( + anyObject({ id: "some-cluster-id" }), + "/apis/discovery.k8s.io/v1", + ); + }); + + describe("when second specific resource kinds request resolves", () => { + beforeEach(async () => { + await k8sRequestMock.resolve(discoveryK8sIoKindsResponse); + }); + + it("requests namespace list permissions for 'default' namespace", () => { + expect(createSelfSubjectRulesReviewMock).toBeCalledWith(anyObject({ + spec: { + namespace: "default", + }, + })); + }); + + describe("when the permissions are incomplete", () => { + beforeEach(async () => { + await createSelfSubjectRulesReviewMock.resolve(defaultIncompletePermissions); + }); + + it("requests namespace list permissions for 'my-namespace' namespace", () => { + expect(createSelfSubjectRulesReviewMock).toBeCalledWith(anyObject({ + spec: { + namespace: "my-namespace", + }, + })); + }); + + describe("when the permissions request for 'my-namespace' resolves as empty", () => { + beforeEach(async () => { + await createSelfSubjectRulesReviewMock.resolve(emptyPermissions); + }); + + it("requests cluster metadata", () => { + expect(detectClusterMetadataMock).toBeCalledWith(anyObject({ id: "some-cluster-id" })); + }); + + describe("when cluster metadata request resolves", () => { + beforeEach(async () => { + await detectClusterMetadataMock.resolve({}); + }); + + it("allows the call to refreshAccessibilityAndMetadata to resolve", async () => { + await refreshPromise; + }); + + it("should have the cluster displaying 'pods'", () => { + expect(cluster.resourcesToShow.has("pods")).toBe(true); + }); + + it("should have the cluster displaying 'namespaces'", () => { + expect(cluster.resourcesToShow.has("namespaces")).toBe(true); + }); + }); + }); + + describe.skip("when the permissions are incomplete", () => {}); + describe.skip("when the permissions resolve to a single entry with 'list' verb", () => {}); + describe.skip("when the permissions resolve to multiple entries with the 'list' verb not on the first entry", () => {}); + }); + + describe("when the permissions resolve to an empty list", () => { + beforeEach(async () => { + await createSelfSubjectRulesReviewMock.resolve(emptyPermissions); + }); + + it("requests namespace list permissions for 'my-namespace' namespace", () => { + expect(createSelfSubjectRulesReviewMock).toBeCalledWith(anyObject({ + spec: { + namespace: "my-namespace", + }, + })); + }); + + describe("when the permissions request for 'my-namespace' resolves as empty", () => { + beforeEach(async () => { + await createSelfSubjectRulesReviewMock.resolve(emptyPermissions); + }); + + it("requests cluster metadata", () => { + expect(detectClusterMetadataMock).toBeCalledWith(anyObject({ id: "some-cluster-id" })); + }); + + describe("when cluster metadata request resolves", () => { + beforeEach(async () => { + await detectClusterMetadataMock.resolve({}); + }); + + it("allows the call to refreshAccessibilityAndMetadata to resolve", async () => { + await refreshPromise; + }); + + it("should have the cluster displaying 'pods'", () => { + expect(cluster.resourcesToShow.has("pods")).toBe(false); + }); + + it("should have the cluster not displaying 'namespaces'", () => { + expect(cluster.resourcesToShow.has("namespaces")).toBe(false); + }); + }); + }); + + describe.skip("when the permissions are incomplete", () => {}); + describe.skip("when the permissions resolve to a single entry with 'list' verb", () => {}); + describe.skip("when the permissions resolve to multiple entries with the 'list' verb not on the first entry", () => {}); + }); + + describe("when the permissions resolve to a single entry with 'list' verb", () => { + beforeEach(async () => { + await createSelfSubjectRulesReviewMock.resolve(defaultSingleListPermissions); + }); + + it("requests namespace list permissions for 'my-namespace' namespace", () => { + expect(createSelfSubjectRulesReviewMock).toBeCalledWith(anyObject({ + spec: { + namespace: "my-namespace", + }, + })); + }); + + describe("when the permissions request for 'my-namespace' resolves as empty", () => { + beforeEach(async () => { + await createSelfSubjectRulesReviewMock.resolve(emptyPermissions); + }); + + it("requests cluster metadata", () => { + expect(detectClusterMetadataMock).toBeCalledWith(anyObject({ id: "some-cluster-id" })); + }); + + describe("when cluster metadata request resolves", () => { + beforeEach(async () => { + await detectClusterMetadataMock.resolve({}); + }); + + it("allows the call to refreshAccessibilityAndMetadata to resolve", async () => { + await refreshPromise; + }); + + it("should have the cluster displaying 'pods'", () => { + expect(cluster.resourcesToShow.has("pods")).toBe(true); + }); + + it("should have the cluster not displaying 'namespaces'", () => { + expect(cluster.resourcesToShow.has("namespaces")).toBe(false); + }); + }); + }); + + describe.skip("when the permissions are incomplete", () => {}); + describe.skip("when the permissions resolve to a single entry with 'list' verb", () => {}); + describe.skip("when the permissions resolve to multiple entries with the 'list' verb not on the first entry", () => {}); + }); + + describe("when the permissions resolve to multiple entries with the 'list' verb not on the first entry", () => { + beforeEach(async () => { + await createSelfSubjectRulesReviewMock.resolve(defaultMultipleListPermissions); + }); + + it("requests namespace list permissions for 'my-namespace' namespace", () => { + expect(createSelfSubjectRulesReviewMock).toBeCalledWith(anyObject({ + spec: { + namespace: "my-namespace", + }, + })); + }); + + describe("when the permissions request for 'my-namespace' resolves as empty", () => { + beforeEach(async () => { + await createSelfSubjectRulesReviewMock.resolve(emptyPermissions); + }); + + it("requests cluster metadata", () => { + expect(detectClusterMetadataMock).toBeCalledWith(anyObject({ id: "some-cluster-id" })); + }); + + describe("when cluster metadata request resolves", () => { + beforeEach(async () => { + await detectClusterMetadataMock.resolve({}); + }); + + it("allows the call to refreshAccessibilityAndMetadata to resolve", async () => { + await refreshPromise; + }); + + it("should have the cluster displaying 'pods'", () => { + expect(cluster.resourcesToShow.has("pods")).toBe(true); + }); + + it("should have the cluster not displaying 'namespaces'", () => { + expect(cluster.resourcesToShow.has("namespaces")).toBe(false); + }); + }); + }); + + describe.skip("when the permissions are incomplete", () => {}); + describe.skip("when the permissions resolve to a single entry with 'list' verb", () => {}); + describe.skip("when the permissions resolve to multiple entries with the 'list' verb not on the first entry", () => {}); + }); + }); + + describe.skip("when second specific resource kinds rejects", () => {}); + }); + }); + + describe.skip("when first specific resource kinds rejects", () => {}); + }); + }); + }); + }); + }); + }); + }); +}); + +const nonCoreApiResponse = { + groups: [ + { + name: "node.k8s.io", + versions: [ + { + groupVersion: "node.k8s.io/v1", + version: "v1", + }, + ], + preferredVersion: { + groupVersion: "node.k8s.io/v1", + version: "v1", + }, + }, + { + name: "discovery.k8s.io", + versions: [ + { + groupVersion: "discovery.k8s.io/v1", + version: "v1", + }, + ], + preferredVersion: { + groupVersion: "discovery.k8s.io/v1", + version: "v1", + }, + }, + ], +} as V1APIGroupList; + +const listNamespaceResponse = { + body: { + items: [ + { + metadata: { + name: "default", + }, + }, + { + metadata: { + name: "my-namespace", + }, + }, + ], + } as PartialDeep, +} as Awaited>; + +const coreApiKindsResponse = { + kind: "APIResourceList", + groupVersion: "v1", + resources: [ + { + name: "namespaces", + singularName: "", + namespaced: false, + kind: "Namespace", + verbs: ["create", "delete", "get", "list", "patch", "update", "watch"], + shortNames: ["ns"], + storageVersionHash: "Q3oi5N2YM8M=", + }, + { + name: "pods", + singularName: "", + namespaced: true, + kind: "Pod", + verbs: [ + "create", + "delete", + "deletecollection", + "get", + "list", + "patch", + "update", + "watch", + ], + shortNames: ["po"], + categories: ["all"], + storageVersionHash: "xPOwRZ+Yhw8=", + }, + { + name: "pods/attach", + singularName: "", + namespaced: true, + kind: "PodAttachOptions", + verbs: ["create", "get"], + }, + ], +}; + +const nodeK8sIoKindsResponse = { + kind: "APIResourceList", + apiVersion: "v1", + groupVersion: "node.k8s.io/v1", + resources: [ + { + name: "runtimeclasses", + singularName: "", + namespaced: false, + kind: "RuntimeClass", + verbs: [ + "create", + "delete", + "deletecollection", + "get", + "list", + "patch", + "update", + "watch", + ], + storageVersionHash: "WQTu1GL3T2Q=", + }, + ], +}; + +const discoveryK8sIoKindsResponse = { + kind: "APIResourceList", + apiVersion: "v1", + groupVersion: "discovery.k8s.io/v1", + resources: [ + { + name: "endpointslices", + singularName: "", + namespaced: true, + kind: "EndpointSlice", + verbs: [ + "create", + "delete", + "deletecollection", + "get", + "list", + "patch", + "update", + "watch", + ], + storageVersionHash: "Nx3SIv6I0mE=", + }, + ], +}; + +type CreateSelfSubjectRulesReviewRes = Awaited>; + +const defaultIncompletePermissions = { + body: { + status: { + incomplete: true, + }, + } as PartialDeep, +} as CreateSelfSubjectRulesReviewRes; + +const emptyPermissions = { + body: { + status: { + resourceRules: [], + }, + } as PartialDeep, +} as CreateSelfSubjectRulesReviewRes; + +const defaultSingleListPermissions = { + body: { + status: { + resourceRules: [{ + apiGroups: [""], + resources: ["pods"], + verbs: ["list"], + }], + }, + } as PartialDeep, +} as CreateSelfSubjectRulesReviewRes; + +const defaultMultipleListPermissions = { + body: { + status: { + resourceRules: [ + { + apiGroups: [""], + resources: ["pods"], + verbs: ["get"], + }, + { + apiGroups: [""], + resources: ["pods"], + verbs: ["list"], + }, + ], + }, + } as PartialDeep, +} as CreateSelfSubjectRulesReviewRes; diff --git a/packages/core/src/main/__test__/cluster.test.ts b/packages/core/src/main/__test__/cluster.test.ts index bb495af847..205a23d5ab 100644 --- a/packages/core/src/main/__test__/cluster.test.ts +++ b/packages/core/src/main/__test__/cluster.test.ts @@ -5,10 +5,6 @@ import { Cluster } from "../../common/cluster/cluster"; import { Kubectl } from "../kubectl/kubectl"; import { getDiForUnitTesting } from "../getDiForUnitTesting"; -import createAuthorizationReviewInjectable from "../../common/cluster/authorization-review.injectable"; -import requestNamespaceListPermissionsForInjectable from "../../common/cluster/request-namespace-list-permissions.injectable"; -import createListNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; -import prometheusHandlerInjectable from "../cluster/prometheus-handler/prometheus-handler.injectable"; import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import directoryForTempInjectable from "../../common/app-paths/directory-for-temp/directory-for-temp.injectable"; import normalizedPlatformInjectable from "../../common/vars/normalized-platform.injectable"; @@ -19,6 +15,10 @@ import clusterConnectionInjectable from "../cluster/cluster-connection.injectabl import kubeconfigManagerInjectable from "../kubeconfig-manager/kubeconfig-manager.injectable"; import type { KubeconfigManager } from "../kubeconfig-manager/kubeconfig-manager"; import broadcastConnectionUpdateInjectable from "../cluster/broadcast-connection-update.injectable"; +import createCanIInjectable from "../../common/cluster/create-can-i.injectable"; +import createRequestNamespaceListPermissionsInjectable from "../../common/cluster/create-request-namespace-list-permissions.injectable"; +import createListNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; +import prometheusHandlerInjectable from "../cluster/prometheus-handler/prometheus-handler.injectable"; describe("create clusters", () => { let cluster: Cluster; @@ -34,8 +34,8 @@ describe("create clusters", () => { di.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64"); di.override(normalizedPlatformInjectable, () => "darwin"); di.override(broadcastConnectionUpdateInjectable, () => async () => {}); - di.override(createAuthorizationReviewInjectable, () => () => () => Promise.resolve(true)); - di.override(requestNamespaceListPermissionsForInjectable, () => () => async () => () => true); + di.override(createCanIInjectable, () => () => () => Promise.resolve(true)); + di.override(createRequestNamespaceListPermissionsInjectable, () => () => async () => () => true); di.override(createListNamespacesInjectable, () => () => () => Promise.resolve([ "default" ])); di.override(prometheusHandlerInjectable, () => ({ getPrometheusDetails: jest.fn(), diff --git a/packages/core/src/main/__test__/context-handler.test.ts b/packages/core/src/main/__test__/context-handler.test.ts deleted file mode 100644 index 61bd12398d..0000000000 --- a/packages/core/src/main/__test__/context-handler.test.ts +++ /dev/null @@ -1,203 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ - -import { getDiForUnitTesting } from "../getDiForUnitTesting"; -import { Cluster } from "../../common/cluster/cluster"; -import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; -import type { DiContainer } from "@ogre-tools/injectable"; -import { getInjectable } from "@ogre-tools/injectable"; -import type { PrometheusProvider } from "../prometheus/provider"; -import { prometheusProviderInjectionToken } from "../prometheus/provider"; -import { runInAction } from "mobx"; -import prometheusHandlerInjectable from "../cluster/prometheus-handler/prometheus-handler.injectable"; -import directoryForTempInjectable from "../../common/app-paths/directory-for-temp/directory-for-temp.injectable"; -import lensProxyPortInjectable from "../lens-proxy/lens-proxy-port.injectable"; -import type { KubeAuthProxy } from "../kube-auth-proxy/kube-auth-proxy"; -import loadProxyKubeconfigInjectable from "../cluster/load-proxy-kubeconfig.injectable"; -import type { KubeConfig } from "@kubernetes/client-node"; - -enum ServiceResult { - Success, - Failure, -} - -const createTestPrometheusProvider = (kind: string, alwaysFail: ServiceResult): PrometheusProvider => ({ - kind, - name: "TestProvider1", - isConfigurable: false, - getQuery: () => { - throw new Error("getQuery is not implemented."); - }, - getPrometheusService: async () => { - switch (alwaysFail) { - case ServiceResult.Success: - return { - kind, - namespace: "default", - port: 7000, - service: "", - }; - case ServiceResult.Failure: - throw new Error("does fail"); - } - }, -}); - -describe("ContextHandler", () => { - let di: DiContainer; - let cluster: Cluster; - - beforeEach(() => { - di = getDiForUnitTesting(); - - di.override(loadProxyKubeconfigInjectable, () => async () => ({ - makeApiClient: () => ({} as any), - } as Partial)); - - di.override(createKubeAuthProxyInjectable, () => () => ({ - run: async () => {}, - } as KubeAuthProxy)); - di.override(directoryForTempInjectable, () => "/some-directory-for-tmp"); - di.inject(lensProxyPortInjectable).set(9968); - - cluster = new Cluster({ - contextName: "some-context-name", - id: "some-cluster-id", - kubeConfigPath: "/some-kubeconfig-path", - }, { - clusterServerUrl: "https://some-website.com", - }); - }); - - describe("getPrometheusService", () => { - it.each([ - [0], - [1], - [2], - [3], - ])("should throw after %d failure(s)", async (failures) => { - runInAction(() => { - for (let i = 0; i < failures; i += 1) { - di.register(getInjectable({ - id: `test-prometheus-provider-failure-${i}`, - injectionToken: prometheusProviderInjectionToken, - instantiate: () => createTestPrometheusProvider(`id_failure_${i}`, ServiceResult.Failure), - })); - } - }); - - expect(() => di.inject(prometheusHandlerInjectable, cluster).getPrometheusDetails()).rejects.toThrowError(); - }); - - it.each([ - [1, 0], - [1, 1], - [1, 2], - [1, 3], - [2, 0], - [2, 1], - [2, 2], - [2, 3], - ])("should pick the first provider of %d success(es) after %d failure(s)", async (successes, failures) => { - runInAction(() => { - for (let i = 0; i < failures; i += 1) { - di.register(getInjectable({ - id: `test-prometheus-provider-failure-${i}`, - injectionToken: prometheusProviderInjectionToken, - instantiate: () => createTestPrometheusProvider(`id_failure_${i}`, ServiceResult.Failure), - })); - } - - for (let i = 0; i < successes; i += 1) { - di.register(getInjectable({ - id: `test-prometheus-provider-success-${i}`, - injectionToken: prometheusProviderInjectionToken, - instantiate: () => createTestPrometheusProvider(`id_success_${i}`, ServiceResult.Success), - })); - } - }); - - const details = await di.inject(prometheusHandlerInjectable, cluster).getPrometheusDetails(); - - expect(details.provider.kind === `id_failure_${failures}`); - }); - - it.each([ - [1, 0], - [1, 1], - [1, 2], - [1, 3], - [2, 0], - [2, 1], - [2, 2], - [2, 3], - ])("should pick the first provider of %d success(es) before %d failure(s)", async (successes, failures) => { - runInAction(() => { - for (let i = 0; i < failures; i += 1) { - di.register(getInjectable({ - id: `test-prometheus-provider-failure-${i}`, - injectionToken: prometheusProviderInjectionToken, - instantiate: () => createTestPrometheusProvider(`id_failure_${i}`, ServiceResult.Failure), - })); - } - - for (let i = 0; i < successes; i += 1) { - di.register(getInjectable({ - id: `test-prometheus-provider-success-${i}`, - injectionToken: prometheusProviderInjectionToken, - instantiate: () => createTestPrometheusProvider(`id_success_${i}`, ServiceResult.Success), - })); - } - }); - - const details = await di.inject(prometheusHandlerInjectable, cluster).getPrometheusDetails(); - - expect(details.provider.kind === "id_failure_0"); - }); - - it.each([ - [1, 0], - [1, 1], - [1, 2], - [1, 3], - [2, 0], - [2, 1], - [2, 2], - [2, 3], - ])("should pick the first provider of %d success(es) between %d failure(s)", async (successes, failures) => { - const beforeSuccesses = Math.floor(successes / 2); - - runInAction(() => { - for (let i = 0; i < beforeSuccesses; i += 1) { - di.register(getInjectable({ - id: `test-prometheus-provider-success-${i}`, - injectionToken: prometheusProviderInjectionToken, - instantiate: () => createTestPrometheusProvider(`id_success_${i}`, ServiceResult.Success), - })); - } - - for (let i = 0; i < failures; i += 1) { - di.register(getInjectable({ - id: `test-prometheus-provider-failure-${i}`, - injectionToken: prometheusProviderInjectionToken, - instantiate: () => createTestPrometheusProvider(`id_failure_${i}`, ServiceResult.Failure), - })); - } - - for (let i = beforeSuccesses; i < successes; i += 1) { - di.register(getInjectable({ - id: `test-prometheus-provider-success-${i}`, - injectionToken: prometheusProviderInjectionToken, - instantiate: () => createTestPrometheusProvider(`id_success_${i}`, ServiceResult.Success), - })); - } - }); - - const details = await di.inject(prometheusHandlerInjectable, cluster).getPrometheusDetails(); - - expect(details.provider.kind === "id_success_0"); - }); - }); -}); diff --git a/packages/core/src/main/__test__/kube-auth-proxy.test.ts b/packages/core/src/main/__test__/kube-auth-proxy.test.ts index 8fa8a175a5..dc4878f806 100644 --- a/packages/core/src/main/__test__/kube-auth-proxy.test.ts +++ b/packages/core/src/main/__test__/kube-auth-proxy.test.ts @@ -5,7 +5,6 @@ import waitUntilPortIsUsedInjectable from "../kube-auth-proxy/wait-until-port-is-used/wait-until-port-is-used.injectable"; import { Cluster } from "../../common/cluster/cluster"; -import type { KubeAuthProxy } from "../kube-auth-proxy/kube-auth-proxy"; import type { ChildProcess } from "child_process"; import { Kubectl } from "../kubectl/kubectl"; import type { DeepMockProxy } from "jest-mock-extended"; @@ -13,6 +12,7 @@ import { mockDeep, mock } from "jest-mock-extended"; import type { Readable } from "stream"; import { EventEmitter } from "stream"; import { getDiForUnitTesting } from "../getDiForUnitTesting"; +import type { CreateKubeAuthProxy, KubeAuthProxy } from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; import spawnInjectable from "../child-process/spawn.injectable"; import directoryForUserDataInjectable from "../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; @@ -29,7 +29,7 @@ import getBasenameOfPathInjectable from "../../common/path/get-basename.injectab const clusterServerUrl = "https://192.168.64.3:8443"; describe("kube auth proxy tests", () => { - let createKubeAuthProxy: (cluster: Cluster, environmentVariables: NodeJS.ProcessEnv) => KubeAuthProxy; + let createKubeAuthProxy: CreateKubeAuthProxy; let spawnMock: jest.Mock; let waitUntilPortIsUsedMock: jest.Mock; let broadcastMessageMock: jest.Mock; diff --git a/packages/core/src/main/__test__/prometheus-handler.test.ts b/packages/core/src/main/__test__/prometheus-handler.test.ts index 59671553bb..74cab1ea74 100644 --- a/packages/core/src/main/__test__/prometheus-handler.test.ts +++ b/packages/core/src/main/__test__/prometheus-handler.test.ts @@ -43,7 +43,7 @@ const createTestPrometheusProvider = (kind: string, alwaysFail: ServiceResult): }, }); -describe("ContextHandler", () => { +describe("PrometheusHandler", () => { let di: DiContainer; let cluster: Cluster; diff --git a/packages/core/src/main/cluster/request-api-versions.ts b/packages/core/src/main/cluster/api-versions-requester.ts similarity index 64% rename from packages/core/src/main/cluster/request-api-versions.ts rename to packages/core/src/main/cluster/api-versions-requester.ts index a9b5074549..0bb2c65f6c 100644 --- a/packages/core/src/main/cluster/request-api-versions.ts +++ b/packages/core/src/main/cluster/api-versions-requester.ts @@ -15,8 +15,11 @@ export interface ClusterData { readonly id: string; } -export type RequestApiVersions = (cluster: ClusterData) => AsyncResult; +export interface ApiVersionsRequester { + request(cluster: ClusterData): AsyncResult; + readonly orderNumber: number; +} -export const requestApiVersionsInjectionToken = getInjectionToken({ +export const apiVersionsRequesterInjectionToken = getInjectionToken({ id: "request-api-versions-token", }); diff --git a/packages/core/src/main/cluster/cluster-connection.injectable.ts b/packages/core/src/main/cluster/cluster-connection.injectable.ts index c5d9a5f165..3f40898fc7 100644 --- a/packages/core/src/main/cluster/cluster-connection.injectable.ts +++ b/packages/core/src/main/cluster/cluster-connection.injectable.ts @@ -6,10 +6,7 @@ import { type KubeConfig, HttpError } from "@kubernetes/client-node"; import { reaction, comparer, runInAction } from "mobx"; import { ClusterStatus } from "../../common/cluster-types"; -import type { CreateAuthorizationReview } from "../../common/cluster/authorization-review.injectable"; -import type { Cluster } from "../../common/cluster/cluster"; import type { CreateListNamespaces } from "../../common/cluster/list-namespaces.injectable"; -import type { RequestNamespaceListPermissionsFor, RequestNamespaceListPermissions } from "../../common/cluster/request-namespace-list-permissions.injectable"; import type { BroadcastMessage } from "../../common/ipc/broadcast-message.injectable"; import { clusterListNamespaceForbiddenChannel } from "../../common/ipc/cluster"; import type { Logger } from "../../common/logger"; @@ -25,7 +22,6 @@ import type { RequestApiResources } from "./request-api-resources.injectable"; import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; import broadcastConnectionUpdateInjectable from "./broadcast-connection-update.injectable"; import broadcastMessageInjectable from "../../common/ipc/broadcast-message.injectable"; -import createAuthorizationReviewInjectable from "../../common/cluster/authorization-review.injectable"; import createListNamespacesInjectable from "../../common/cluster/list-namespaces.injectable"; import kubeAuthProxyServerInjectable from "./kube-auth-proxy-server.injectable"; import loadProxyKubeconfigInjectable from "./load-proxy-kubeconfig.injectable"; @@ -33,21 +29,31 @@ import loggerInjectable from "../../common/logger.injectable"; import prometheusHandlerInjectable from "./prometheus-handler/prometheus-handler.injectable"; import removeProxyKubeconfigInjectable from "./remove-proxy-kubeconfig.injectable"; import requestApiResourcesInjectable from "./request-api-resources.injectable"; -import requestNamespaceListPermissionsForInjectable from "../../common/cluster/request-namespace-list-permissions.injectable"; import type { DetectClusterMetadata } from "../cluster-detectors/detect-cluster-metadata.injectable"; import type { FallibleOnlyClusterMetadataDetector } from "../cluster-detectors/token"; import clusterVersionDetectorInjectable from "../cluster-detectors/cluster-version-detector.injectable"; import detectClusterMetadataInjectable from "../cluster-detectors/detect-cluster-metadata.injectable"; import { replaceObservableObject } from "../../common/utils/replace-observable-object"; +import type { CreateAuthorizationApi } from "../../common/cluster/create-authorization-api.injectable"; +import type { CreateCanI } from "../../common/cluster/create-can-i.injectable"; +import type { CreateRequestNamespaceListPermissions, RequestNamespaceListPermissions } from "../../common/cluster/create-request-namespace-list-permissions.injectable"; +import type { Cluster } from "../../common/cluster/cluster"; +import createAuthorizationApiInjectable from "../../common/cluster/create-authorization-api.injectable"; +import createCanIInjectable from "../../common/cluster/create-can-i.injectable"; +import createRequestNamespaceListPermissionsInjectable from "../../common/cluster/create-request-namespace-list-permissions.injectable"; +import type { CreateCoreApi } from "../../common/cluster/create-core-api.injectable"; +import createCoreApiInjectable from "../../common/cluster/create-core-api.injectable"; interface Dependencies { readonly logger: Logger; readonly prometheusHandler: ClusterPrometheusHandler; readonly kubeAuthProxyServer: KubeAuthProxyServer; readonly clusterVersionDetector: FallibleOnlyClusterMetadataDetector; - createAuthorizationReview: CreateAuthorizationReview; + createCanI: CreateCanI; requestApiResources: RequestApiResources; - requestNamespaceListPermissionsFor: RequestNamespaceListPermissionsFor; + createRequestNamespaceListPermissions: CreateRequestNamespaceListPermissions; + createAuthorizationApi: CreateAuthorizationApi; + createCoreApi: CreateCoreApi; createListNamespaces: CreateListNamespaces; detectClusterMetadata: DetectClusterMetadata; broadcastMessage: BroadcastMessage; @@ -224,8 +230,9 @@ class ClusterConnection { private async refreshAccessibility(): Promise { this.dependencies.logger.info(`[CLUSTER]: refreshAccessibility`, this.cluster.getMeta()); const proxyConfig = await this.dependencies.loadProxyKubeconfig(); - const canI = this.dependencies.createAuthorizationReview(proxyConfig); - const requestNamespaceListPermissions = this.dependencies.requestNamespaceListPermissionsFor(proxyConfig); + const api = this.dependencies.createAuthorizationApi(proxyConfig); + const canI = this.dependencies.createCanI(api); + const requestNamespaceListPermissions = this.dependencies.createRequestNamespaceListPermissions(api); const isAdmin = await canI({ namespace: "kube-system", @@ -360,7 +367,8 @@ class ClusterConnection { } try { - const listNamespaces = this.dependencies.createListNamespaces(proxyConfig); + const api = this.dependencies.createCoreApi(proxyConfig); + const listNamespaces = this.dependencies.createListNamespaces(api); return await listNamespaces(); } catch (error) { @@ -403,13 +411,15 @@ const clusterConnectionInjectable = getInjectable({ prometheusHandler: di.inject(prometheusHandlerInjectable, cluster), broadcastConnectionUpdate: di.inject(broadcastConnectionUpdateInjectable, cluster), broadcastMessage: di.inject(broadcastMessageInjectable), - createAuthorizationReview: di.inject(createAuthorizationReviewInjectable), createListNamespaces: di.inject(createListNamespacesInjectable), detectClusterMetadata: di.inject(detectClusterMetadataInjectable), loadProxyKubeconfig: di.inject(loadProxyKubeconfigInjectable, cluster), removeProxyKubeconfig: di.inject(removeProxyKubeconfigInjectable, cluster), requestApiResources: di.inject(requestApiResourcesInjectable), - requestNamespaceListPermissionsFor: di.inject(requestNamespaceListPermissionsForInjectable), + createAuthorizationApi: di.inject(createAuthorizationApiInjectable), + createCoreApi: di.inject(createCoreApiInjectable), + createCanI: di.inject(createCanIInjectable), + createRequestNamespaceListPermissions: di.inject(createRequestNamespaceListPermissionsInjectable), }, cluster, ), diff --git a/packages/core/src/main/cluster/kube-auth-proxy-server.injectable.ts b/packages/core/src/main/cluster/kube-auth-proxy-server.injectable.ts index 9942c40168..ff70af3a7b 100644 --- a/packages/core/src/main/cluster/kube-auth-proxy-server.injectable.ts +++ b/packages/core/src/main/cluster/kube-auth-proxy-server.injectable.ts @@ -8,7 +8,7 @@ import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; import type { Cluster } from "../../common/cluster/cluster"; import createKubeAuthProxyInjectable from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; import kubeAuthProxyCertificateInjectable from "../kube-auth-proxy/kube-auth-proxy-certificate.injectable"; -import type { KubeAuthProxy } from "../kube-auth-proxy/kube-auth-proxy"; +import type { KubeAuthProxy } from "../kube-auth-proxy/create-kube-auth-proxy.injectable"; export interface KubeAuthProxyServer { getApiTarget(isLongRunningRequest?: boolean): Promise; diff --git a/packages/core/src/main/cluster/request-api-resources.injectable.ts b/packages/core/src/main/cluster/request-api-resources.injectable.ts index d6a21e3ce4..14776bb93a 100644 --- a/packages/core/src/main/cluster/request-api-resources.injectable.ts +++ b/packages/core/src/main/cluster/request-api-resources.injectable.ts @@ -7,11 +7,12 @@ import { getInjectable } from "@ogre-tools/injectable"; import loggerInjectable from "../../common/logger.injectable"; import type { KubeApiResource } from "../../common/rbac"; import type { Cluster } from "../../common/cluster/cluster"; -import { requestApiVersionsInjectionToken } from "./request-api-versions"; +import { apiVersionsRequesterInjectionToken } from "./api-versions-requester"; import { backoffCaller, withConcurrencyLimit } from "@k8slens/utilities"; import requestKubeApiResourcesForInjectable from "./request-kube-api-resources-for.injectable"; import type { AsyncResult } from "@k8slens/utilities"; import broadcastConnectionUpdateInjectable from "./broadcast-connection-update.injectable"; +import { byOrderNumber } from "../../common/utils/composable-responsibilities/orderable/orderable"; export type RequestApiResources = (cluster: Cluster) => AsyncResult; @@ -24,7 +25,8 @@ const requestApiResourcesInjectable = getInjectable({ id: "request-api-resources", instantiate: (di): RequestApiResources => { const logger = di.inject(loggerInjectable); - const apiVersionRequesters = di.injectMany(requestApiVersionsInjectionToken); + const apiVersionRequesters = di.injectMany(apiVersionsRequesterInjectionToken) + .sort(byOrderNumber); const requestKubeApiResourcesFor = di.inject(requestKubeApiResourcesForInjectable); return async (...args) => { @@ -35,7 +37,7 @@ const requestApiResourcesInjectable = getInjectable({ const groupLists: KubeResourceListGroup[] = []; for (const apiVersionRequester of apiVersionRequesters) { - const result = await backoffCaller(() => apiVersionRequester(cluster), { + const result = await backoffCaller(() => apiVersionRequester.request(cluster), { onIntermediateError: (error, attempt) => { broadcastConnectionUpdate({ message: `Failed to list kube API resource kinds, attempt ${attempt}: ${error}`, diff --git a/packages/core/src/main/cluster/request-core-api-versions.injectable.ts b/packages/core/src/main/cluster/request-core-api-versions.injectable.ts index b709eb9356..5b059d6f7f 100644 --- a/packages/core/src/main/cluster/request-core-api-versions.injectable.ts +++ b/packages/core/src/main/cluster/request-core-api-versions.injectable.ts @@ -5,33 +5,36 @@ import type { V1APIVersions } from "@kubernetes/client-node"; import { getInjectable } from "@ogre-tools/injectable"; import k8sRequestInjectable from "../k8s-request.injectable"; -import { requestApiVersionsInjectionToken } from "./request-api-versions"; +import { apiVersionsRequesterInjectionToken } from "./api-versions-requester"; const requestCoreApiVersionsInjectable = getInjectable({ id: "request-core-api-versions", instantiate: (di) => { const k8sRequest = di.inject(k8sRequestInjectable); - return async (cluster) => { - try { - const { versions } = await k8sRequest(cluster, "/api") as V1APIVersions; + return { + request: async (cluster) => { + try { + const { versions } = await k8sRequest(cluster, "/api") as V1APIVersions; - return { - callWasSuccessful: true, - response: versions.map(version => ({ - group: "", - path: `/api/${version}`, - })), - }; - } catch (error) { - return { - callWasSuccessful: false, - error: error as Error, - }; - } + return { + callWasSuccessful: true, + response: versions.map(version => ({ + group: "", + path: `/api/${version}`, + })), + }; + } catch (error) { + return { + callWasSuccessful: false, + error: error as Error, + }; + } + }, + orderNumber: 10, }; }, - injectionToken: requestApiVersionsInjectionToken, + injectionToken: apiVersionsRequesterInjectionToken, }); export default requestCoreApiVersionsInjectable; diff --git a/packages/core/src/main/cluster/request-kube-api-resources-for.injectable.ts b/packages/core/src/main/cluster/request-kube-api-resources-for.injectable.ts index 65e326eed7..80720a9ef1 100644 --- a/packages/core/src/main/cluster/request-kube-api-resources-for.injectable.ts +++ b/packages/core/src/main/cluster/request-kube-api-resources-for.injectable.ts @@ -8,7 +8,7 @@ import type { Cluster } from "../../common/cluster/cluster"; import type { KubeApiResource } from "../../common/rbac"; import type { AsyncResult } from "@k8slens/utilities"; import k8sRequestInjectable from "../k8s-request.injectable"; -import type { KubeResourceListGroup } from "./request-api-versions"; +import type { KubeResourceListGroup } from "./api-versions-requester"; export type RequestKubeApiResources = (grouping: KubeResourceListGroup) => AsyncResult; diff --git a/packages/core/src/main/cluster/request-non-core-api-versions.injectable.ts b/packages/core/src/main/cluster/request-non-core-api-versions.injectable.ts index 84e62f6b80..7e5abbc44d 100644 --- a/packages/core/src/main/cluster/request-non-core-api-versions.injectable.ts +++ b/packages/core/src/main/cluster/request-non-core-api-versions.injectable.ts @@ -6,35 +6,40 @@ import type { V1APIGroupList } from "@kubernetes/client-node"; import { getInjectable } from "@ogre-tools/injectable"; import { iter } from "@k8slens/utilities"; import k8sRequestInjectable from "../k8s-request.injectable"; -import { requestApiVersionsInjectionToken } from "./request-api-versions"; +import { apiVersionsRequesterInjectionToken } from "./api-versions-requester"; const requestNonCoreApiVersionsInjectable = getInjectable({ id: "request-non-core-api-versions", instantiate: (di) => { const k8sRequest = di.inject(k8sRequestInjectable); - return async (cluster) => { - try { - const { groups } = await k8sRequest(cluster, "/apis") as V1APIGroupList; + return { + request: async (cluster) => { + try { + const { groups } = (await k8sRequest(cluster, "/apis")) as V1APIGroupList; - return { - callWasSuccessful: true, - response: iter.chain(groups.values()) - .flatMap(group => group.versions.map(version => ({ - group: group.name, - path: `/apis/${version.groupVersion}`, - }))) - .collect(v => [...v]), - }; - } catch (error) { - return { - callWasSuccessful: false, - error: error as Error, - }; - } + return { + callWasSuccessful: true, + response: iter.chain(groups.values()) + .flatMap((group) => + group.versions.map((version) => ({ + group: group.name, + path: `/apis/${version.groupVersion}`, + })), + ) + .collect((v) => [...v]), + }; + } catch (error) { + return { + callWasSuccessful: false, + error: error as Error, + }; + } + }, + orderNumber: 20, }; }, - injectionToken: requestApiVersionsInjectionToken, + injectionToken: apiVersionsRequesterInjectionToken, }); export default requestNonCoreApiVersionsInjectable; diff --git a/packages/core/src/main/cluster/request-non-core-api-versions.test.ts b/packages/core/src/main/cluster/request-non-core-api-versions.test.ts index c38359b6a5..ca4dcd01b7 100644 --- a/packages/core/src/main/cluster/request-non-core-api-versions.test.ts +++ b/packages/core/src/main/cluster/request-non-core-api-versions.test.ts @@ -10,13 +10,13 @@ import type { DiContainer } from "@ogre-tools/injectable"; import { getDiForUnitTesting } from "../getDiForUnitTesting"; import type { K8sRequest } from "../k8s-request.injectable"; import k8sRequestInjectable from "../k8s-request.injectable"; -import type { RequestApiVersions } from "./request-api-versions"; +import type { ApiVersionsRequester } from "./api-versions-requester"; import requestNonCoreApiVersionsInjectable from "./request-non-core-api-versions.injectable"; describe("requestNonCoreApiVersions", () => { let di: DiContainer; let k8sRequestMock: AsyncFnMock; - let requestNonCoreApiVersions: RequestApiVersions; + let requestNonCoreApiVersions: ApiVersionsRequester; beforeEach(() => { di = getDiForUnitTesting(); @@ -28,10 +28,10 @@ describe("requestNonCoreApiVersions", () => { }); describe("when called", () => { - let versionsRequest: ReturnType; + let versionsRequest: ReturnType; beforeEach(() => { - versionsRequest = requestNonCoreApiVersions({ id: "some-cluster-id" }); + versionsRequest = requestNonCoreApiVersions.request({ id: "some-cluster-id" }); }); it("should request all api groups", () => { diff --git a/packages/core/src/main/kube-auth-proxy/create-kube-auth-proxy.injectable.ts b/packages/core/src/main/kube-auth-proxy/create-kube-auth-proxy.injectable.ts index 56260347bf..fd4acf0d7a 100644 --- a/packages/core/src/main/kube-auth-proxy/create-kube-auth-proxy.injectable.ts +++ b/packages/core/src/main/kube-auth-proxy/create-kube-auth-proxy.injectable.ts @@ -4,7 +4,7 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import type { KubeAuthProxyDependencies } from "./kube-auth-proxy"; -import { KubeAuthProxy } from "./kube-auth-proxy"; +import { KubeAuthProxyImpl } from "./kube-auth-proxy"; import type { Cluster } from "../../common/cluster/cluster"; import spawnInjectable from "../child-process/spawn.injectable"; import kubeAuthProxyCertificateInjectable from "./kube-auth-proxy-certificate.injectable"; @@ -15,6 +15,13 @@ import getPortFromStreamInjectable from "../utils/get-port-from-stream.injectabl import getDirnameOfPathInjectable from "../../common/path/get-dirname.injectable"; import broadcastConnectionUpdateInjectable from "../cluster/broadcast-connection-update.injectable"; +export interface KubeAuthProxy { + readonly apiPrefix: string; + readonly port: number; + run: () => Promise; + exit: () => void; +} + export type CreateKubeAuthProxy = (cluster: Cluster, env: NodeJS.ProcessEnv) => KubeAuthProxy; const createKubeAuthProxyInjectable = getInjectable({ @@ -33,7 +40,7 @@ const createKubeAuthProxyInjectable = getInjectable({ return (cluster, env) => { const clusterUrl = new URL(cluster.apiUrl.get()); - return new KubeAuthProxy({ + return new KubeAuthProxyImpl({ ...dependencies, proxyCert: di.inject(kubeAuthProxyCertificateInjectable, clusterUrl.hostname), broadcastConnectionUpdate: di.inject(broadcastConnectionUpdateInjectable, cluster), diff --git a/packages/core/src/main/kube-auth-proxy/kube-auth-proxy.ts b/packages/core/src/main/kube-auth-proxy/kube-auth-proxy.ts index 9a9b5a249f..160566c3a5 100644 --- a/packages/core/src/main/kube-auth-proxy/kube-auth-proxy.ts +++ b/packages/core/src/main/kube-auth-proxy/kube-auth-proxy.ts @@ -16,6 +16,7 @@ import type { Logger } from "../../common/logger"; import type { WaitUntilPortIsUsed } from "./wait-until-port-is-used/wait-until-port-is-used.injectable"; import type { GetDirnameOfPath } from "../../common/path/get-dirname.injectable"; import type { BroadcastConnectionUpdate } from "../cluster/broadcast-connection-update.injectable"; +import type { KubeAuthProxy } from "./create-kube-auth-proxy.injectable"; const startingServeMatcher = "starting to serve on (?
.+)"; const startingServeRegex = Object.assign(TypedRegEx(startingServeMatcher, "i"), { @@ -33,7 +34,7 @@ export interface KubeAuthProxyDependencies { broadcastConnectionUpdate: BroadcastConnectionUpdate; } -export class KubeAuthProxy { +export class KubeAuthProxyImpl implements KubeAuthProxy { public readonly apiPrefix = `/${randomBytes(8).toString("hex")}`; public get port(): number { diff --git a/packages/core/src/main/kubeconfig-manager/kubeconfig-manager.ts b/packages/core/src/main/kubeconfig-manager/kubeconfig-manager.ts index 9d28306bbf..276692c500 100644 --- a/packages/core/src/main/kubeconfig-manager/kubeconfig-manager.ts +++ b/packages/core/src/main/kubeconfig-manager/kubeconfig-manager.ts @@ -85,7 +85,7 @@ export class KubeconfigManager { return this.tempFilePath = await this.createProxyKubeconfig(); } catch (error) { - throw new Error(`Failed to creat temp config for auth-proxy: ${error}`); + throw new Error(`Failed to create temp config for auth-proxy: ${error}`); } } diff --git a/packages/core/src/test-utils/cast.ts b/packages/core/src/test-utils/cast.ts new file mode 100644 index 0000000000..a3e7329cdd --- /dev/null +++ b/packages/core/src/test-utils/cast.ts @@ -0,0 +1,6 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +export const cast = (data: Partial): T => data as T; diff --git a/packages/core/src/test-utils/mock-interface.ts b/packages/core/src/test-utils/mock-interface.ts new file mode 100644 index 0000000000..e9870282b3 --- /dev/null +++ b/packages/core/src/test-utils/mock-interface.ts @@ -0,0 +1,17 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import type { AsyncFnMock } from "@async-fn/jest"; + +type GetMockedType = + T extends (...args: any[]) => Promise + ? AsyncFnMock + : T extends (...args: any[]) => any + ? jest.MockedFunction + : T; + +export type Mocked = { + -readonly [P in keyof T]: GetMockedType; +}; diff --git a/packages/utility-features/test-utils/src/flush-promises.ts b/packages/utility-features/test-utils/src/flush-promises.ts index c2fdeff99e..fa3271654a 100644 --- a/packages/utility-features/test-utils/src/flush-promises.ts +++ b/packages/utility-features/test-utils/src/flush-promises.ts @@ -2,6 +2,9 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { setImmediate } from "timers"; +import { setImmediate, setTimeout } from "timers/promises"; -export const flushPromises = () => new Promise(setImmediate); +export const flushPromises = async () => { + await setImmediate(); + await setTimeout(5); +}; From 4b1d740d6154d06b655cc106b09b5a39aad2703a Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Wed, 22 Mar 2023 11:51:26 -0400 Subject: [PATCH 14/17] Fix behaviour of auto generated CRD KubeApis and KubeObjectStores (#7384) * Simplify CRD KubeApi registrations - Switch to auto injectable registrations Signed-off-by: Sebastian Malton * Make sure that stores can still be retrieved Signed-off-by: Sebastian Malton * Cleanup get extension fake to simplify impl Signed-off-by: Sebastian Malton * Simplify logic for extensionInjectable Signed-off-by: Sebastian Malton * Fix test in differencing registrator Signed-off-by: Sebastian Malton * Cleanup code style Signed-off-by: Sebastian Malton * Fix some tests Signed-off-by: Sebastian Malton * Fix HPA details tests Signed-off-by: Sebastian Malton --------- Signed-off-by: Sebastian Malton --- .../k8s-api/__tests__/api-manager.test.ts | 90 +++++++++++++++ .../common/k8s-api/api-manager/api-manager.ts | 35 +++++- .../auto-registration-emitter.injectable.ts | 2 - .../k8s-api/api-manager/crd-api-token.ts | 11 ++ ...create-custom-resource-store.injectable.ts | 27 +++++ .../k8s-api/api-manager/manager.injectable.ts | 6 + .../src/common/k8s-api/kube-object.store.ts | 2 +- .../src/common/utils/registrator-helper.ts | 25 +++++ .../extension/extension.injectable.ts | 50 +++------ ...-characters-in-page-registrations.test.tsx | 3 +- ...setup-auto-crd-api-creations.injectable.ts | 53 +++++++++ .../setup-auto-registration.injectable.ts | 52 +-------- .../hpa-details.test.tsx | 16 +++ .../definition.store.injectable.ts | 2 - .../+custom-resources/definition.store.ts | 19 +--- .../test-utils/get-application-builder.tsx | 103 ++++++------------ .../test-utils/get-extension-fake.ts | 8 +- 17 files changed, 315 insertions(+), 189 deletions(-) create mode 100644 packages/core/src/common/k8s-api/api-manager/crd-api-token.ts create mode 100644 packages/core/src/common/k8s-api/api-manager/create-custom-resource-store.injectable.ts create mode 100644 packages/core/src/common/utils/registrator-helper.ts create mode 100644 packages/core/src/renderer/before-frame-starts/runnables/setup-auto-crd-api-creations.injectable.ts diff --git a/packages/core/src/common/k8s-api/__tests__/api-manager.test.ts b/packages/core/src/common/k8s-api/__tests__/api-manager.test.ts index 6ea6327038..48fdb3e544 100644 --- a/packages/core/src/common/k8s-api/__tests__/api-manager.test.ts +++ b/packages/core/src/common/k8s-api/__tests__/api-manager.test.ts @@ -4,6 +4,7 @@ */ import type { DiContainer } from "@ogre-tools/injectable"; +import { getInjectable } from "@ogre-tools/injectable"; import clusterFrameContextForNamespacedResourcesInjectable from "../../../renderer/cluster-frame-context/for-namespaced-resources.injectable"; import hostedClusterInjectable from "../../../renderer/cluster-frame-context/hosted-cluster.injectable"; import { getDiForUnitTesting } from "../../../renderer/getDiForUnitTesting"; @@ -21,6 +22,9 @@ import maybeKubeApiInjectable from "../maybe-kube-api.injectable"; // eslint-disable-next-line no-restricted-imports import { KubeApi as ExternalKubeApi } from "../../../extensions/common-api/k8s-api"; import { Cluster } from "../../cluster/cluster"; +import { runInAction } from "mobx"; +import { customResourceDefinitionApiInjectionToken } from "../api-manager/crd-api-token"; +import assert from "assert"; class TestApi extends KubeApi { protected async checkPreferredVersion() { @@ -117,4 +121,90 @@ describe("ApiManager", () => { }); }); }); + + describe("given than a CRD has a default KubeApi registered for it", () => { + const apiBase = "/apis/aquasecurity.github.io/v1alpha1/vulnerabilityreports"; + + beforeEach(() => { + runInAction(() => { + di.register(getInjectable({ + id: `default-kube-api-for-custom-resource-definition-${apiBase}`, + instantiate: (di) => { + const objectConstructor = class extends KubeObject { + static readonly kind = "VulnerabilityReport"; + static readonly namespaced = true; + static readonly apiBase = apiBase; + }; + + return Object.assign( + new KubeApi({ + logger: di.inject(loggerInjectable), + maybeKubeApi: di.inject(maybeKubeApiInjectable), + }, { objectConstructor }), + { + myField: 1, + }, + ); + }, + injectionToken: customResourceDefinitionApiInjectionToken, + })); + }); + }); + + it("can be retrieved from apiManager", () => { + expect(apiManager.getApi(apiBase)).toMatchObject({ + myField: 1, + }); + }); + + it("can have a default KubeObjectStore instance retrieved for it", () => { + expect(apiManager.getStore(apiBase)).toBeInstanceOf(KubeObjectStore); + }); + + describe("given that an extension registers an api with the same apibase", () => { + beforeEach(() => { + void Object.assign(new ExternalKubeApi({ + objectConstructor: KubeObject, + apiBase, + kind: "VulnerabilityReport", + }), { + myField: 2, + }); + }); + + it("the extension's instance is retrievable instead from apiManager", () => { + expect(apiManager.getApi(apiBase)).toMatchObject({ + myField: 2, + }); + }); + + it("can have a default KubeObjectStore instance retrieved for it", () => { + expect(apiManager.getStore(apiBase)).toBeInstanceOf(KubeObjectStore); + }); + + describe("given that an extension registers a store for the same apibase", () => { + beforeEach(() => { + const api = apiManager.getApi(apiBase); + + assert(api); + + apiManager.registerStore(Object.assign( + new KubeObjectStore({ + context: di.inject(clusterFrameContextForNamespacedResourcesInjectable), + logger: di.inject(loggerInjectable), + }, api), + { + someField: 2, + }, + )); + }); + + it("can gets the custom KubeObjectStore instance instead", () => { + expect(apiManager.getStore(apiBase)).toMatchObject({ + someField: 2, + }); + }); + }); + }); + }); }); diff --git a/packages/core/src/common/k8s-api/api-manager/api-manager.ts b/packages/core/src/common/k8s-api/api-manager/api-manager.ts index f6c2758921..6b60ba8e7a 100644 --- a/packages/core/src/common/k8s-api/api-manager/api-manager.ts +++ b/packages/core/src/common/k8s-api/api-manager/api-manager.ts @@ -10,7 +10,8 @@ import { autorun, action, observable } from "mobx"; import type { KubeApi } from "../kube-api"; import type { KubeObject, ObjectReference } from "../kube-object"; import { parseKubeApi, createKubeApiURL } from "../kube-api-parse"; -import { iter } from "@k8slens/utilities"; +import { getOrInsertWith, iter } from "@k8slens/utilities"; +import type { CreateCustomResourceStore } from "./create-custom-resource-store.injectable"; export type RegisterableStore = Store extends KubeObjectStore ? Store @@ -26,13 +27,15 @@ export type FindApiCallback = (api: KubeApi) => boolean; interface Dependencies { readonly apis: IComputedValue; + readonly crdApis: IComputedValue; readonly stores: IComputedValue; + createCustomResourceStore: CreateCustomResourceStore; } export class ApiManager { private readonly externalApis = observable.array(); private readonly externalStores = observable.array(); - + private readonly defaultCrdStores = observable.map(); private readonly apis = observable.map(); constructor(private readonly dependencies: Dependencies) { @@ -56,6 +59,12 @@ export class ApiManager { } } + for (const crdApi of this.dependencies.crdApis.get()) { + if (!newState.has(crdApi.apiBase)) { + newState.set(crdApi.apiBase, crdApi); + } + } + this.apis.replace(newState); }); } @@ -110,6 +119,16 @@ export class ApiManager { this.externalStores.push(store); } + private apiIsDefaultCrdApi(api: KubeApi): boolean { + for (const crdApi of this.dependencies.crdApis.get()) { + if (crdApi.apiBase === api.apiBase) { + return true; + } + } + + return false; + } + getStore(api: string | undefined): KubeObjectStore | undefined; getStore(api: RegisterableApi): KubeObjectStoreFrom | undefined; /** @@ -130,9 +149,19 @@ export class ApiManager { return undefined; } - return iter.chain(this.dependencies.stores.get().values()) + const defaultResult = iter.chain(this.dependencies.stores.get().values()) .concat(this.externalStores.values()) .find(store => store.api.apiBase === api.apiBase); + + if (defaultResult) { + return defaultResult; + } + + if (this.apiIsDefaultCrdApi(api)) { + return getOrInsertWith(this.defaultCrdStores, api.apiBase, () => this.dependencies.createCustomResourceStore(api)); + } + + return undefined; } lookupApiLink(ref: ObjectReference, parentObject?: KubeObject): string { diff --git a/packages/core/src/common/k8s-api/api-manager/auto-registration-emitter.injectable.ts b/packages/core/src/common/k8s-api/api-manager/auto-registration-emitter.injectable.ts index d9a68a988c..714e9d8952 100644 --- a/packages/core/src/common/k8s-api/api-manager/auto-registration-emitter.injectable.ts +++ b/packages/core/src/common/k8s-api/api-manager/auto-registration-emitter.injectable.ts @@ -5,11 +5,9 @@ import { getInjectable } from "@ogre-tools/injectable"; import EventEmitter from "events"; import type TypedEventEmitter from "typed-emitter"; -import type { CustomResourceDefinition } from "../endpoints"; import type { KubeApi } from "../kube-api"; export interface LegacyAutoRegistration { - customResourceDefinition: (crd: CustomResourceDefinition) => void; kubeApi: (api: KubeApi) => void; } diff --git a/packages/core/src/common/k8s-api/api-manager/crd-api-token.ts b/packages/core/src/common/k8s-api/api-manager/crd-api-token.ts new file mode 100644 index 0000000000..d8f0c918c2 --- /dev/null +++ b/packages/core/src/common/k8s-api/api-manager/crd-api-token.ts @@ -0,0 +1,11 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { getInjectionToken } from "@ogre-tools/injectable"; +import type { KubeApi } from "../kube-api"; + +export const customResourceDefinitionApiInjectionToken = getInjectionToken({ + id: "custom-resource-definition-api-token", +}); diff --git a/packages/core/src/common/k8s-api/api-manager/create-custom-resource-store.injectable.ts b/packages/core/src/common/k8s-api/api-manager/create-custom-resource-store.injectable.ts new file mode 100644 index 0000000000..fbf46e2b42 --- /dev/null +++ b/packages/core/src/common/k8s-api/api-manager/create-custom-resource-store.injectable.ts @@ -0,0 +1,27 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import clusterFrameContextForNamespacedResourcesInjectable from "../../../renderer/cluster-frame-context/for-namespaced-resources.injectable"; +import loggerInjectable from "../../logger.injectable"; +import type { KubeApi } from "../kube-api"; +import type { KubeObject } from "../kube-object"; +import type { KubeObjectStoreDependencies } from "../kube-object.store"; +import { CustomResourceStore } from "./resource.store"; + +export type CreateCustomResourceStore = (api: KubeApi) => CustomResourceStore; + +const createCustomResourceStoreInjectable = getInjectable({ + id: "create-custom-resource-store", + instantiate: (di): CreateCustomResourceStore => { + const deps: KubeObjectStoreDependencies = { + context: di.inject(clusterFrameContextForNamespacedResourcesInjectable), + logger: di.inject(loggerInjectable), + }; + + return (api) => new CustomResourceStore(deps, api); + }, +}); + +export default createCustomResourceStoreInjectable; diff --git a/packages/core/src/common/k8s-api/api-manager/manager.injectable.ts b/packages/core/src/common/k8s-api/api-manager/manager.injectable.ts index f0b61c28b6..2ffd41a296 100644 --- a/packages/core/src/common/k8s-api/api-manager/manager.injectable.ts +++ b/packages/core/src/common/k8s-api/api-manager/manager.injectable.ts @@ -9,6 +9,8 @@ import { computedInjectManyInjectable } from "@ogre-tools/injectable-extension-f import { kubeObjectStoreInjectionToken } from "./kube-object-store-token"; import { kubeApiInjectionToken } from "../kube-api/kube-api-injection-token"; import { computed } from "mobx"; +import { customResourceDefinitionApiInjectionToken } from "./crd-api-token"; +import createCustomResourceStoreInjectable from "./create-custom-resource-store.injectable"; const apiManagerInjectable = getInjectable({ id: "api-manager", @@ -23,6 +25,10 @@ const apiManagerInjectable = getInjectable({ stores: storesAndApisCanBeCreated ? computedInjectMany(kubeObjectStoreInjectionToken) : computed(() => []), + crdApis: storesAndApisCanBeCreated + ? computedInjectMany(customResourceDefinitionApiInjectionToken) + : computed(() => []), + createCustomResourceStore: di.inject(createCustomResourceStoreInjectable), }); }, }); diff --git a/packages/core/src/common/k8s-api/kube-object.store.ts b/packages/core/src/common/k8s-api/kube-object.store.ts index 09b26d4142..fa17fd1f2c 100644 --- a/packages/core/src/common/k8s-api/kube-object.store.ts +++ b/packages/core/src/common/k8s-api/kube-object.store.ts @@ -88,7 +88,7 @@ export interface KubeObjectStoreDependencies { readonly logger: Logger; } -export abstract class KubeObjectStore< +export class KubeObjectStore< K extends KubeObject = KubeObject, A extends KubeApi = KubeApi>, D extends KubeJsonApiDataFor = KubeApiDataFrom, diff --git a/packages/core/src/common/utils/registrator-helper.ts b/packages/core/src/common/utils/registrator-helper.ts new file mode 100644 index 0000000000..4a9cc5c2d2 --- /dev/null +++ b/packages/core/src/common/utils/registrator-helper.ts @@ -0,0 +1,25 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ + +import { iter } from "@k8slens/utilities"; +import type { DiContainerForInjection, Injectable } from "@ogre-tools/injectable"; + +// Register new injectables and deregister removed injectables by id + +export const injectableDifferencingRegistratorWith = (di: DiContainerForInjection) => ( + (rawCurrent: Injectable[], rawPrevious: Injectable[] = []) => { + const current = new Map(rawCurrent.map(inj => [inj.id, inj])); + const previous = new Map(rawPrevious.map(inj => [inj.id, inj])); + const toAdd = iter.chain(current.entries()) + .filter(([id]) => !previous.has(id)) + .collect(entries => new Map(entries)); + const toRemove = iter.chain(previous.entries()) + .filter(([id]) => !current.has(id)) + .collect(entries => new Map(entries)); + + di.deregister(...toRemove.values()); + di.register(...toAdd.values()); + } +); diff --git a/packages/core/src/extensions/extension-loader/extension/extension.injectable.ts b/packages/core/src/extensions/extension-loader/extension/extension.injectable.ts index 07f054d3fd..d54d997d09 100644 --- a/packages/core/src/extensions/extension-loader/extension/extension.injectable.ts +++ b/packages/core/src/extensions/extension-loader/extension/extension.injectable.ts @@ -2,29 +2,18 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { Injectable } from "@ogre-tools/injectable"; import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; -import { difference, find, map } from "lodash"; import { reaction, runInAction } from "mobx"; import { disposer } from "@k8slens/utilities"; import type { LensExtension } from "../../lens-extension"; import { extensionRegistratorInjectionToken } from "../extension-registrator-injection-token"; +import { injectableDifferencingRegistratorWith } from "../../../common/utils/registrator-helper"; export interface Extension { register: () => void; deregister: () => void; } -const idsToInjectables = (ids: string[], injectables: Injectable[]) => ids.map(id => { - const injectable = find(injectables, { id }); - - if (!injectable) { - throw new Error(`Injectable ${id} not found`); - } - - return injectable; -}); - const extensionInjectable = getInjectable({ id: "extension", @@ -35,36 +24,27 @@ const extensionInjectable = getInjectable({ instantiate: (childDi) => { const extensionRegistrators = childDi.injectMany(extensionRegistratorInjectionToken); const reactionDisposer = disposer(); + const injectableDifferencingRegistrator = injectableDifferencingRegistratorWith(childDi); return { register: () => { - extensionRegistrators.forEach((getInjectablesOfExtension) => { - const injectables = getInjectablesOfExtension(instance); + for (const extensionRegistrator of extensionRegistrators) { + const injectables = extensionRegistrator(instance); - reactionDisposer.push( - // injectables is either an array or a computed array, in which case - // we need to update the registered injectables with a reaction every time they change - reaction( - () => Array.isArray(injectables) ? injectables : injectables.get(), - (currentInjectables, previousInjectables = []) => { - // Register new injectables and deregister removed injectables by id - const currentIds = map(currentInjectables, "id"); - const previousIds = map(previousInjectables, "id"); - const idsToAdd = difference(currentIds, previousIds); - const idsToRemove = previousIds.filter(previousId => !currentIds.includes(previousId)); - - if (idsToRemove.length > 0) { - childDi.deregister(...idsToInjectables(idsToRemove, previousInjectables)); - } - - if (idsToAdd.length > 0) { - childDi.register(...idsToInjectables(idsToAdd, currentInjectables)); - } - }, { + if (Array.isArray(injectables)) { + runInAction(() => { + injectableDifferencingRegistrator(injectables); + }); + } else { + reactionDisposer.push(reaction( + () => injectables.get(), + injectableDifferencingRegistrator, + { fireImmediately: true, }, )); - }); + } + } }, deregister: () => { diff --git a/packages/core/src/features/extension-special-characters-in-page-registrations.test.tsx b/packages/core/src/features/extension-special-characters-in-page-registrations.test.tsx index ac038a5743..b9760eba79 100644 --- a/packages/core/src/features/extension-special-characters-in-page-registrations.test.tsx +++ b/packages/core/src/features/extension-special-characters-in-page-registrations.test.tsx @@ -31,8 +31,7 @@ describe("extension special characters in page registrations", () => { describe("when navigating to route with ID having special characters", () => { beforeEach(() => { - const testExtension = - builder.extensions.get("some-extension-id").applicationWindows.only; + const testExtension = builder.extensions.get("some-extension-id").applicationWindows.only; testExtension.navigate("/some-page-id/"); }); diff --git a/packages/core/src/renderer/before-frame-starts/runnables/setup-auto-crd-api-creations.injectable.ts b/packages/core/src/renderer/before-frame-starts/runnables/setup-auto-crd-api-creations.injectable.ts new file mode 100644 index 0000000000..c23a34d767 --- /dev/null +++ b/packages/core/src/renderer/before-frame-starts/runnables/setup-auto-crd-api-creations.injectable.ts @@ -0,0 +1,53 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import { getInjectable } from "@ogre-tools/injectable"; +import { reaction } from "mobx"; +import { customResourceDefinitionApiInjectionToken } from "../../../common/k8s-api/api-manager/crd-api-token"; +import type { CustomResourceDefinition } from "../../../common/k8s-api/endpoints"; +import { KubeApi } from "../../../common/k8s-api/kube-api"; +import { KubeObject } from "../../../common/k8s-api/kube-object"; +import maybeKubeApiInjectable from "../../../common/k8s-api/maybe-kube-api.injectable"; +import loggerInjectable from "../../../common/logger.injectable"; +import { injectableDifferencingRegistratorWith } from "../../../common/utils/registrator-helper"; +import customResourceDefinitionStoreInjectable from "../../components/+custom-resources/definition.store.injectable"; +import { beforeClusterFrameStartsSecondInjectionToken } from "../tokens"; + +const setupAutoCrdApiCreationsInjectable = getInjectable({ + id: "setup-auto-crd-api-creations", + instantiate: (di) => ({ + run: () => { + const customResourceDefinitionStore = di.inject(customResourceDefinitionStoreInjectable); + const injectableDifferencingRegistrator = injectableDifferencingRegistratorWith(di); + + reaction( + () => customResourceDefinitionStore.getItems().map(toCrdApiInjectable), + injectableDifferencingRegistrator, + { + fireImmediately: true, + }, + ); + }, + }), + injectionToken: beforeClusterFrameStartsSecondInjectionToken, +}); + +export default setupAutoCrdApiCreationsInjectable; + +const toCrdApiInjectable = (crd: CustomResourceDefinition) => getInjectable({ + id: `default-kube-api-for-custom-resource-definition-${crd.getResourceApiBase()}`, + instantiate: (di) => { + const objectConstructor = class extends KubeObject { + static readonly kind = crd.getResourceKind(); + static readonly namespaced = crd.isNamespaced(); + static readonly apiBase = crd.getResourceApiBase(); + }; + + return new KubeApi({ + logger: di.inject(loggerInjectable), + maybeKubeApi: di.inject(maybeKubeApiInjectable), + }, { objectConstructor }); + }, + injectionToken: customResourceDefinitionApiInjectionToken, +}); diff --git a/packages/core/src/renderer/before-frame-starts/runnables/setup-auto-registration.injectable.ts b/packages/core/src/renderer/before-frame-starts/runnables/setup-auto-registration.injectable.ts index dbc77a92b8..78b1f90015 100644 --- a/packages/core/src/renderer/before-frame-starts/runnables/setup-auto-registration.injectable.ts +++ b/packages/core/src/renderer/before-frame-starts/runnables/setup-auto-registration.injectable.ts @@ -5,71 +5,22 @@ import { getInjectable } from "@ogre-tools/injectable"; import autoRegistrationEmitterInjectable from "../../../common/k8s-api/api-manager/auto-registration-emitter.injectable"; import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable"; -import { CustomResourceStore } from "../../../common/k8s-api/api-manager/resource.store"; -import type { CustomResourceDefinition } from "../../../common/k8s-api/endpoints"; -import type { KubeApiDependencies } from "../../../common/k8s-api/kube-api"; -import { KubeApi } from "../../../common/k8s-api/kube-api"; -import { KubeObject } from "../../../common/k8s-api/kube-object"; +import type { KubeApi } from "../../../common/k8s-api/kube-api"; import { beforeClusterFrameStartsSecondInjectionToken } from "../tokens"; -import type { KubeObjectStoreDependencies } from "../../../common/k8s-api/kube-object.store"; -import clusterFrameContextForNamespacedResourcesInjectable from "../../cluster-frame-context/for-namespaced-resources.injectable"; -import loggerInjectable from "../../../common/logger.injectable"; -import maybeKubeApiInjectable from "../../../common/k8s-api/maybe-kube-api.injectable"; const setupAutoRegistrationInjectable = getInjectable({ id: "setup-auto-registration", instantiate: (di) => ({ run: () => { const autoRegistrationEmitter = di.inject(autoRegistrationEmitterInjectable); - const beforeApiManagerInitializationCrds: CustomResourceDefinition[] = []; const beforeApiManagerInitializationApis: KubeApi[] = []; - const kubeApiDependencies: KubeApiDependencies = { - logger: di.inject(loggerInjectable), - maybeKubeApi: di.inject(maybeKubeApiInjectable), - }; - const kubeObjectStoreDependencies: KubeObjectStoreDependencies = { - context: di.inject(clusterFrameContextForNamespacedResourcesInjectable), - logger: di.inject(loggerInjectable), - }; let initialized = false; - const autoInitCustomResourceStore = (crd: CustomResourceDefinition) => { - const objectConstructor = class extends KubeObject { - static readonly kind = crd.getResourceKind(); - static readonly namespaced = crd.isNamespaced(); - static readonly apiBase = crd.getResourceApiBase(); - }; - - const api = (() => { - const rawApi = apiManager.getApi(objectConstructor.apiBase); - - if (rawApi) { - return rawApi; - } - - const api = new KubeApi(kubeApiDependencies, { objectConstructor }); - - apiManager.registerApi(api); - - return api; - })(); - - if (!apiManager.getStore(api)) { - apiManager.registerStore(new CustomResourceStore(kubeObjectStoreDependencies, api)); - } - }; const autoInitKubeApi = (api: KubeApi) => { apiManager.registerApi(api); }; autoRegistrationEmitter - .on("customResourceDefinition", (crd) => { - if (initialized) { - autoInitCustomResourceStore(crd); - } else { - beforeApiManagerInitializationCrds.push(crd); - } - }) .on("kubeApi", (api) => { if (initialized) { autoInitKubeApi(api); @@ -81,7 +32,6 @@ const setupAutoRegistrationInjectable = getInjectable({ // NOTE: this MUST happen after the event emitter listeners are registered const apiManager = di.inject(apiManagerInjectable); - beforeApiManagerInitializationCrds.forEach(autoInitCustomResourceStore); beforeApiManagerInitializationApis.forEach(autoInitKubeApi); initialized = true; }, diff --git a/packages/core/src/renderer/components/+config-horizontal-pod-autoscalers/hpa-details.test.tsx b/packages/core/src/renderer/components/+config-horizontal-pod-autoscalers/hpa-details.test.tsx index 48c2183055..aa2d2a3b32 100644 --- a/packages/core/src/renderer/components/+config-horizontal-pod-autoscalers/hpa-details.test.tsx +++ b/packages/core/src/renderer/components/+config-horizontal-pod-autoscalers/hpa-details.test.tsx @@ -4,8 +4,13 @@ */ import type { RenderResult } from "@testing-library/react"; import React from "react"; +import directoryForKubeConfigsInjectable from "../../../common/app-paths/directory-for-kube-configs/directory-for-kube-configs.injectable"; +import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; +import { Cluster } from "../../../common/cluster/cluster"; import { HorizontalPodAutoscaler, HpaMetricType } from "../../../common/k8s-api/endpoints"; +import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable"; import { getDiForUnitTesting } from "../../getDiForUnitTesting"; +import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import type { DiRender } from "../test-utils/renderFor"; import { renderFor } from "../test-utils/renderFor"; import { HpaDetails } from "./hpa-details"; @@ -41,6 +46,17 @@ describe("", () => { beforeEach(() => { const di = getDiForUnitTesting(); + di.override(directoryForUserDataInjectable, () => "/some-user-store-path"); + di.override(directoryForKubeConfigsInjectable, () => "/some-kube-configs"); + di.override(storesAndApisCanBeCreatedInjectable, () => true); + di.override(hostedClusterInjectable, () => new Cluster({ + contextName: "some-context-name", + id: "some-cluster-id", + kubeConfigPath: "/some-path-to-a-kubeconfig", + }, { + clusterServerUrl: "https://localhost:8080", + })); + render = renderFor(di); }); diff --git a/packages/core/src/renderer/components/+custom-resources/definition.store.injectable.ts b/packages/core/src/renderer/components/+custom-resources/definition.store.injectable.ts index f1d8f635b8..dbbd2460aa 100644 --- a/packages/core/src/renderer/components/+custom-resources/definition.store.injectable.ts +++ b/packages/core/src/renderer/components/+custom-resources/definition.store.injectable.ts @@ -4,7 +4,6 @@ */ import { getInjectable } from "@ogre-tools/injectable"; import assert from "assert"; -import autoRegistrationEmitterInjectable from "../../../common/k8s-api/api-manager/auto-registration-emitter.injectable"; import { kubeObjectStoreInjectionToken } from "../../../common/k8s-api/api-manager/kube-object-store-token"; import customResourceDefinitionApiInjectable from "../../../common/k8s-api/endpoints/custom-resource-definition.api.injectable"; import loggerInjectable from "../../../common/logger.injectable"; @@ -20,7 +19,6 @@ const customResourceDefinitionStoreInjectable = getInjectable({ const api = di.inject(customResourceDefinitionApiInjectable); return new CustomResourceDefinitionStore({ - autoRegistration: di.inject(autoRegistrationEmitterInjectable), context: di.inject(clusterFrameContextForClusterScopedResourcesInjectable), logger: di.inject(loggerInjectable), }, api); diff --git a/packages/core/src/renderer/components/+custom-resources/definition.store.ts b/packages/core/src/renderer/components/+custom-resources/definition.store.ts index 310e51709a..78ef3982a9 100644 --- a/packages/core/src/renderer/components/+custom-resources/definition.store.ts +++ b/packages/core/src/renderer/components/+custom-resources/definition.store.ts @@ -3,37 +3,22 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ -import { computed, reaction, makeObservable } from "mobx"; +import { computed, makeObservable } from "mobx"; import type { KubeObjectStoreDependencies, KubeObjectStoreOptions } from "../../../common/k8s-api/kube-object.store"; import { KubeObjectStore } from "../../../common/k8s-api/kube-object.store"; import type { CustomResourceDefinition, CustomResourceDefinitionApi } from "../../../common/k8s-api/endpoints/custom-resource-definition.api"; import type { KubeObject } from "../../../common/k8s-api/kube-object"; -import type TypedEventEmitter from "typed-emitter"; -import type { LegacyAutoRegistration } from "../../../common/k8s-api/api-manager/auto-registration-emitter.injectable"; import autoBind from "auto-bind"; -export interface CustomResourceDefinitionStoreDependencies extends KubeObjectStoreDependencies { - readonly autoRegistration: TypedEventEmitter; -} - export class CustomResourceDefinitionStore extends KubeObjectStore { constructor( - protected readonly dependencies: CustomResourceDefinitionStoreDependencies, + dependencies: KubeObjectStoreDependencies, api: CustomResourceDefinitionApi, opts?: KubeObjectStoreOptions, ) { super(dependencies, api, opts); makeObservable(this); autoBind(this); - - reaction( - () => this.getItems(), - crds => { - for (const crd of crds) { - this.dependencies.autoRegistration.emit("customResourceDefinition", crd); - } - }, - ); } protected sortItems(items: CustomResourceDefinition[]) { diff --git a/packages/core/src/renderer/components/test-utils/get-application-builder.tsx b/packages/core/src/renderer/components/test-utils/get-application-builder.tsx index 4ae3441e76..731c5ba8c7 100644 --- a/packages/core/src/renderer/components/test-utils/get-application-builder.tsx +++ b/packages/core/src/renderer/components/test-utils/get-application-builder.tsx @@ -53,7 +53,7 @@ import { applicationWindowInjectionToken } from "../../../main/start-main-applic import closeAllWindowsInjectable from "../../../main/start-main-application/lens-window/hide-all-windows/close-all-windows.injectable"; import type { LensWindow } from "../../../main/start-main-application/lens-window/application-window/create-lens-window.injectable"; import type { FakeExtensionOptions } from "./get-extension-fake"; -import { getExtensionFakeForMain, getExtensionFakeForRenderer } from "./get-extension-fake"; +import { getMainExtensionFakeWith, getRendererExtensionFakeWith } from "./get-extension-fake"; import namespaceApiInjectable from "../../../common/k8s-api/endpoints/namespace.api.injectable"; import { Namespace } from "../../../common/k8s-api/endpoints"; import { getOverrideFsWithFakes } from "../../../test-utils/override-fs-with-fakes"; @@ -594,49 +594,28 @@ export const getApplicationBuilder = () => { }, enable: (...extensions) => { - builder.afterWindowStart(({ windowDi }) => { - const rendererExtensionInstances = extensions.map((options) => - getExtensionFakeForRenderer( - windowDi, - options.id, - options.name, - options.rendererOptions || {}, - ), - ); + builder.afterWindowStart(action(({ windowDi }) => { + extensions + .map(getRendererExtensionFakeWith(windowDi)) + .forEach(enableExtensionFor(windowDi, rendererExtensionsStateInjectable)); + })); - rendererExtensionInstances.forEach( - enableExtensionFor(windowDi, rendererExtensionsStateInjectable), - ); - }); - - builder.afterApplicationStart(({ mainDi }) => { - const mainExtensionInstances = extensions.map((extension) => - getExtensionFakeForMain(mainDi, extension.id, extension.name, extension.mainOptions || {}), - ); - - runInAction(() => { - mainExtensionInstances.forEach( - enableExtensionFor(mainDi, mainExtensionsStateInjectable), - ); - }); - }); + builder.afterApplicationStart(action(({ mainDi }) => { + extensions + .map(getMainExtensionFakeWith(mainDi)) + .forEach(enableExtensionFor(mainDi, mainExtensionsStateInjectable)); + })); }, disable: (...extensions) => { builder.afterWindowStart(({ windowDi }) => { extensions - .map((ext) => ext.id) - .forEach( - disableExtensionFor(windowDi, rendererExtensionsStateInjectable), - ); + .forEach(disableExtensionFor(windowDi, rendererExtensionsStateInjectable)); }); builder.afterApplicationStart(({ mainDi }) => { extensions - .map((ext) => ext.id) - .forEach( - disableExtensionFor(mainDi, mainExtensionsStateInjectable), - ); + .forEach(disableExtensionFor(mainDi, mainExtensionsStateInjectable)); }); }, }, @@ -835,49 +814,29 @@ const selectOptionFor = (builder: ApplicationBuilder, menuId: string) => (labelT userEvent.click(option); }; -const enableExtensionFor = ( - di: DiContainer, - stateInjectable: Injectable, any, any>, -) => { +function enableExtensionFor(di: DiContainer, stateInjectable: Injectable, any, any>) { const extensionState = di.inject(stateInjectable); - const getExtension = (extension: LensExtension) => - di.inject(extensionInjectable, extension); + return (instance: LensExtension) => { + const extension = di.inject(extensionInjectable, instance); - return (extensionInstance: LensExtension) => { - const extension = getExtension(extensionInstance); - - runInAction(() => { - extension.register(); - extensionState.set(extensionInstance.id, extensionInstance); - }); + extension.register(); + extensionState.set(instance.id, instance); }; -}; +} -const disableExtensionFor = - ( - di: DiContainer, - stateInjectable: Injectable, unknown, void>, - ) => - (id: string) => { - const getExtension = (extension: LensExtension) => - di.inject(extensionInjectable, extension); +function disableExtensionFor(di: DiContainer, stateInjectable: Injectable, unknown, void>) { + return (extension: FakeExtensionOptions) => { + const extensionsState = di.inject(stateInjectable); + const instance = extensionsState.get(extension.id); - const extensionsState = di.inject(stateInjectable); + if (!instance) { + throw new Error(`Tried to disable extension with ID "${extension.id}", but it wasn't enabled`); + } - const instance = extensionsState.get(id); + const injectable = di.inject(extensionInjectable, instance); - if (!instance) { - throw new Error( - `Tried to disable extension with ID "${id}", but it wasn't enabled`, - ); - } - - const injectable = getExtension(instance); - - runInAction(() => { - injectable.deregister(); - - extensionsState.delete(id); - }); - }; + injectable.deregister(); + extensionsState.delete(extension.id); + }; +} diff --git a/packages/core/src/renderer/components/test-utils/get-extension-fake.ts b/packages/core/src/renderer/components/test-utils/get-extension-fake.ts index 8079207daa..675b7e93e2 100644 --- a/packages/core/src/renderer/components/test-utils/get-extension-fake.ts +++ b/packages/core/src/renderer/components/test-utils/get-extension-fake.ts @@ -27,7 +27,7 @@ export interface FakeExtensionOptions { mainOptions?: Partial; } -export const getExtensionFakeForMain = (di: DiContainer, id: string, name: string, options: Partial) => { +export const getMainExtensionFakeWith = (di: DiContainer) => ({ id, name, mainOptions = {}}: FakeExtensionOptions) => { const instance = new TestExtensionMain({ id, absolutePath: "irrelevant", @@ -44,7 +44,7 @@ export const getExtensionFakeForMain = (di: DiContainer, id: string, name: strin manifestPath: "irrelevant", }); - Object.assign(instance, options); + Object.assign(instance, mainOptions); (instance as Writable)[lensExtensionDependencies] = { fileSystemProvisionerStore: di.inject(fileSystemProvisionerStoreInjectable), @@ -56,7 +56,7 @@ export const getExtensionFakeForMain = (di: DiContainer, id: string, name: strin return instance; }; -export const getExtensionFakeForRenderer = (di: DiContainer, id: string, name: string, options: Partial) => { +export const getRendererExtensionFakeWith = (di: DiContainer) => ({ id, name, rendererOptions = {}}: FakeExtensionOptions) => { const instance = new TestExtensionRenderer({ id, absolutePath: "irrelevant", @@ -73,7 +73,7 @@ export const getExtensionFakeForRenderer = (di: DiContainer, id: string, name: s manifestPath: "irrelevant", }); - Object.assign(instance, options); + Object.assign(instance, rendererOptions); (instance as Writable)[lensExtensionDependencies] = { categoryRegistry: di.inject(catalogCategoryRegistryInjectable), From 4a3f08d798dd535b6b6e1749f562c38a715b7acd Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Thu, 23 Mar 2023 11:37:10 +0300 Subject: [PATCH 15/17] Fix Check for updates menu item title capitalisation (#7396) * Check for updates -> Check for Updates Signed-off-by: Alex Andreev * Revert debugging changes Signed-off-by: Alex Andreev * Adding ellipsis to every Check for Updates items Signed-off-by: Alex Andreev --------- Signed-off-by: Alex Andreev --- .../main/check-for-updates-menu-item.injectable.ts | 2 +- .../installing-update-using-tray.test.ts | 8 ++++---- .../tray-items/check-for-updates-tray-item.injectable.ts | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/core/src/features/application-update/child-features/application-update-using-application-menu/main/check-for-updates-menu-item.injectable.ts b/packages/core/src/features/application-update/child-features/application-update-using-application-menu/main/check-for-updates-menu-item.injectable.ts index fe997e62fb..97b9acf9f8 100644 --- a/packages/core/src/features/application-update/child-features/application-update-using-application-menu/main/check-for-updates-menu-item.injectable.ts +++ b/packages/core/src/features/application-update/child-features/application-update-using-application-menu/main/check-for-updates-menu-item.injectable.ts @@ -28,7 +28,7 @@ const checkForUpdatesMenuItemInjectable = getInjectable({ id: "check-for-updates", parentId: isMac ? "mac" : "help", orderNumber: isMac ? 20 : 50, - label: "Check for updates", + label: "Check for Updates...", isShown: updatingIsEnabled, onClick: () => { diff --git a/packages/core/src/features/application-update/child-features/application-update-using-tray/installing-update-using-tray.test.ts b/packages/core/src/features/application-update/child-features/application-update-using-tray/installing-update-using-tray.test.ts index d5caa63149..f18f288469 100644 --- a/packages/core/src/features/application-update/child-features/application-update-using-tray/installing-update-using-tray.test.ts +++ b/packages/core/src/features/application-update/child-features/application-update-using-tray/installing-update-using-tray.test.ts @@ -146,7 +146,7 @@ describe("installing update using tray", () => { it("name of tray item for checking updates indicates that checking is happening", () => { expect( builder.tray.get("check-for-updates")?.label, - ).toBe("Checking for updates..."); + ).toBe("Checking for Updates..."); }); it("user cannot install update yet", () => { @@ -177,7 +177,7 @@ describe("installing update using tray", () => { it("name of tray item for checking updates no longer indicates that checking is happening", () => { expect( builder.tray.get("check-for-updates")?.label, - ).toBe("Check for updates"); + ).toBe("Check for Updates..."); }); it("renders", () => { @@ -241,7 +241,7 @@ describe("installing update using tray", () => { it("name of tray item for checking updates no longer indicates that downloading is happening", () => { expect( builder.tray.get("check-for-updates")?.label, - ).toBe("Check for updates"); + ).toBe("Check for Updates..."); }); it("renders", () => { @@ -269,7 +269,7 @@ describe("installing update using tray", () => { it("name of tray item for checking updates no longer indicates that downloading is happening", () => { expect( builder.tray.get("check-for-updates")?.label, - ).toBe("Check for updates"); + ).toBe("Check for Updates..."); }); it("renders", () => { diff --git a/packages/core/src/features/application-update/child-features/application-update-using-tray/main/tray-items/check-for-updates-tray-item.injectable.ts b/packages/core/src/features/application-update/child-features/application-update-using-tray/main/tray-items/check-for-updates-tray-item.injectable.ts index e904abaa99..3f05ddb71e 100644 --- a/packages/core/src/features/application-update/child-features/application-update-using-tray/main/tray-items/check-for-updates-tray-item.injectable.ts +++ b/packages/core/src/features/application-update/child-features/application-update-using-tray/main/tray-items/check-for-updates-tray-item.injectable.ts @@ -47,10 +47,10 @@ const checkForUpdatesTrayItemInjectable = getInjectable({ } if (checkingForUpdatesState.value.get()) { - return "Checking for updates..."; + return "Checking for Updates..."; } - return "Check for updates"; + return "Check for Updates..."; }), enabled: computed(() => !checkingForUpdatesState.value.get() && !downloadingUpdateState.value.get()), From a0d13e80031c7424607b6c50135ec0e0a49df5ae Mon Sep 17 00:00:00 2001 From: Alex Andreev Date: Thu, 23 Mar 2023 11:40:56 +0300 Subject: [PATCH 16/17] Adding package exporting injection tokens for cluster settings (#7395) * Add clusterIconSettingsComponentInjectionToken Signed-off-by: Alex Andreev * Adding tests for new token Signed-off-by: Alex Andreev * Create cluster-settings package Signed-off-by: Alex Andreev * Fix cluster-settings package build process Signed-off-by: Alex Andreev * Use tolens from @k8slens/cluster-settings Signed-off-by: Alex Andreev * Linter fixes Signed-off-by: Alex Andreev * Remove typescript 5.x.x from cluster-settings package Signed-off-by: Alex Andreev * Adding prepare:test command to package.json Signed-off-by: Alex Andreev * Test small cleanup Signed-off-by: Alex Andreev * Fix getByText check Signed-off-by: Alex Andreev * Clean up Signed-off-by: Alex Andreev * Linter fix Signed-off-by: Alex Andreev --------- Signed-off-by: Alex Andreev --- package-lock.json | 24 ++++++++ packages/cluster-settings/.swcrc | 9 +++ packages/cluster-settings/README.md | 3 + packages/cluster-settings/package.json | 31 ++++++++++ packages/cluster-settings/src/index.ts | 30 ++++++++++ packages/cluster-settings/tsconfig.json | 18 ++++++ packages/core/package.json | 1 + .../__snapshots__/icon-settings.test.tsx.snap | 52 ++++++++++++++++ .../__tests__/icon-settings.test.tsx | 59 ++++++++++++++++++- ...ter-settings-menu-clear-item.injectable.ts | 2 +- .../cluster-settings-menu-injection-token.ts | 17 ------ .../cluster-settings/icon-settings.tsx | 14 ++++- 12 files changed, 237 insertions(+), 23 deletions(-) create mode 100644 packages/cluster-settings/.swcrc create mode 100644 packages/cluster-settings/README.md create mode 100644 packages/cluster-settings/package.json create mode 100644 packages/cluster-settings/src/index.ts create mode 100644 packages/cluster-settings/tsconfig.json delete mode 100644 packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-injection-token.ts diff --git a/package-lock.json b/package-lock.json index d00efc567c..946b5f8168 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4524,6 +4524,10 @@ "resolved": "packages/bump-version-for-cron", "link": true }, + "node_modules/@k8slens/cluster-settings": { + "resolved": "packages/cluster-settings", + "link": true + }, "node_modules/@k8slens/computed-channel": { "resolved": "packages/technical-features/messaging/computed-channel", "link": true @@ -34142,6 +34146,25 @@ "integrity": "sha512-ZOzvDRWp8dCVBmgnkIqYCArgdFOO9YzocZp8Ra25N/RStKiWvMOXHMz+GjSeVNe5TstaTmTWPucGJkDw0XXJWA==", "dev": true }, + "packages/cluster-settings": { + "name": "@k8slens/cluster-settings", + "version": "6.5.0-alpha.1", + "license": "MIT", + "devDependencies": { + "@ogre-tools/injectable": "^15.1.2", + "@swc/cli": "^0.1.61", + "@swc/core": "^1.3.37", + "@types/node": "^16.18.11", + "@types/semver": "^7.3.13", + "rimraf": "^4.1.2" + } + }, + "packages/cluster-settings/node_modules/@types/node": { + "version": "16.18.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-16.18.18.tgz", + "integrity": "sha512-fwGw1uvQAzabxL1pyoknPlJIF2t7+K90uTqynleKRx24n3lYcxWa3+KByLhgkF8GEAK2c7hC8Ki0RkNM5H15jQ==", + "dev": true + }, "packages/core": { "name": "@k8slens/core", "version": "6.5.0-alpha.3", @@ -34150,6 +34173,7 @@ "@astronautlabs/jsonpath": "^1.1.0", "@hapi/call": "^9.0.1", "@hapi/subtext": "^7.1.0", + "@k8slens/cluster-settings": "^6.5.0-alpha.1", "@k8slens/node-fetch": "^6.5.0-alpha.1", "@kubernetes/client-node": "^0.18.1", "@material-ui/styles": "^4.11.5", diff --git a/packages/cluster-settings/.swcrc b/packages/cluster-settings/.swcrc new file mode 100644 index 0000000000..8e7a530f16 --- /dev/null +++ b/packages/cluster-settings/.swcrc @@ -0,0 +1,9 @@ +{ + "$schema": "https://json.schemastore.org/swcrc", + "jsc": { + "parser": { + "syntax": "typescript" + }, + "target": "es2022" + } +} diff --git a/packages/cluster-settings/README.md b/packages/cluster-settings/README.md new file mode 100644 index 0000000000..c3d3b890f4 --- /dev/null +++ b/packages/cluster-settings/README.md @@ -0,0 +1,3 @@ +# Description + +The package exports tokens needed for external configuration of Cluster Settings page. diff --git a/packages/cluster-settings/package.json b/packages/cluster-settings/package.json new file mode 100644 index 0000000000..199347dcf4 --- /dev/null +++ b/packages/cluster-settings/package.json @@ -0,0 +1,31 @@ +{ + "name": "@k8slens/cluster-settings", + "version": "6.5.0-alpha.1", + "description": "Injection token exporter for cluster settings configuration", + "license": "MIT", + "private": false, + "mode": "production", + "publishConfig": { + "access": "public", + "registry": "https://registry.npmjs.org/" + }, + "main": "./dist/index.js", + "types": "./dist/index.d.ts", + "files": [ + "dist" + ], + "scripts": { + "clean": "rimraf dist/", + "generate-types": "tsc --d --declarationDir ./dist --declarationMap --emitDeclarationOnly", + "build": "npm run generate-types && swc ./src/index.ts -d ./dist", + "prepare:test": "npm run build" + }, + "devDependencies": { + "@ogre-tools/injectable": "^15.1.2", + "@swc/cli": "^0.1.61", + "@swc/core": "^1.3.37", + "@types/node": "^16.18.11", + "@types/semver": "^7.3.13", + "rimraf": "^4.1.2" + } +} diff --git a/packages/cluster-settings/src/index.ts b/packages/cluster-settings/src/index.ts new file mode 100644 index 0000000000..181c69d46a --- /dev/null +++ b/packages/cluster-settings/src/index.ts @@ -0,0 +1,30 @@ +import { getInjectionToken } from "@ogre-tools/injectable"; + +type ClusterPreferences = { + clusterName?: string; + icon?: string | null; +} + +export interface ClusterIconMenuItem { + id: string; + title: string; + disabled?: (preferences: ClusterPreferences) => boolean; + onClick: (preferences: ClusterPreferences) => void; +} + +export interface ClusterIconSettingComponentProps { + preferences: ClusterPreferences; +} + +export interface ClusterIconSettingsComponent { + id: string; + Component: React.ComponentType; +} + +export const clusterIconSettingsMenuInjectionToken = getInjectionToken({ + id: "cluster-icon-settings-menu-injection-token", +}); + +export const clusterIconSettingsComponentInjectionToken = getInjectionToken({ + id: "cluster-icon-settings-component-injection-token", +}); \ No newline at end of file diff --git a/packages/cluster-settings/tsconfig.json b/packages/cluster-settings/tsconfig.json new file mode 100644 index 0000000000..534a5fd447 --- /dev/null +++ b/packages/cluster-settings/tsconfig.json @@ -0,0 +1,18 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "outDir": "dist/", + "paths": { + "*": [ + "node_modules/*", + "types/*" + ] + }, + }, + "include": [ + "src/**/*", + ], + "exclude": [ + "node_modules", + ] +} diff --git a/packages/core/package.json b/packages/core/package.json index 42c39d6181..ad6e7e45ae 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -120,6 +120,7 @@ "@astronautlabs/jsonpath": "^1.1.0", "@hapi/call": "^9.0.1", "@hapi/subtext": "^7.1.0", + "@k8slens/cluster-settings": "^6.5.0-alpha.1", "@k8slens/node-fetch": "^6.5.0-alpha.1", "@kubernetes/client-node": "^0.18.1", "@material-ui/styles": "^4.11.5", diff --git a/packages/core/src/renderer/components/cluster-settings/__tests__/__snapshots__/icon-settings.test.tsx.snap b/packages/core/src/renderer/components/cluster-settings/__tests__/__snapshots__/icon-settings.test.tsx.snap index 97eac8fca2..6c22436089 100644 --- a/packages/core/src/renderer/components/cluster-settings/__tests__/__snapshots__/icon-settings.test.tsx.snap +++ b/packages/core/src/renderer/components/cluster-settings/__tests__/__snapshots__/icon-settings.test.tsx.snap @@ -51,3 +51,55 @@ exports[`Icon settings given no external registrations for cluster settings menu
`; + +exports[`Icon settings given no registrations for cluster settings component injection token renders 1`] = ` + +
+
+
+
+
+ + +
+
+ + + more_horiz + + +
+
+
+ +`; diff --git a/packages/core/src/renderer/components/cluster-settings/__tests__/icon-settings.test.tsx b/packages/core/src/renderer/components/cluster-settings/__tests__/icon-settings.test.tsx index 74fd2a6654..31bf671854 100644 --- a/packages/core/src/renderer/components/cluster-settings/__tests__/icon-settings.test.tsx +++ b/packages/core/src/renderer/components/cluster-settings/__tests__/icon-settings.test.tsx @@ -2,8 +2,7 @@ * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ -import type { DiContainer } from "@ogre-tools/injectable"; -import { getInjectable } from "@ogre-tools/injectable"; + import type { RenderResult } from "@testing-library/react"; import React from "react"; import { KubernetesCluster } from "../../../../common/catalog-entities"; @@ -13,13 +12,18 @@ import { renderFor } from "../../test-utils/renderFor"; import { ClusterIconSetting } from "../icon-settings"; import { screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; -import { clusterIconSettingsMenuInjectionToken } from "../cluster-settings-menu-injection-token"; +import type { ClusterIconSettingComponentProps } from "@k8slens/cluster-settings"; +import { clusterIconSettingsComponentInjectionToken, clusterIconSettingsMenuInjectionToken } from "@k8slens/cluster-settings"; import { runInAction } from "mobx"; +import { getInjectable, type DiContainer } from "@ogre-tools/injectable"; const cluster = new Cluster({ contextName: "some-context", id: "some-id", kubeConfigPath: "/some/path/to/kubeconfig", + preferences: { + clusterName: "some-cluster-name", + }, }, { clusterServerUrl: "https://localhost:9999", }); @@ -53,6 +57,29 @@ const newMenuItem = getInjectable({ injectionToken: clusterIconSettingsMenuInjectionToken, }); +function CustomSettingsComponent(props: ClusterIconSettingComponentProps) { + return ( +
+ Test React Component + + Cluster + {props.preferences.clusterName} + +
+ ); +} + +const newSettingsReactComponent = getInjectable({ + id: "cluster-icon-settings-react-component", + + instantiate: () => ({ + id: "test-react-component", + Component: CustomSettingsComponent, + }), + + injectionToken: clusterIconSettingsComponentInjectionToken, +}); + describe("Icon settings", () => { let rendered: RenderResult; let di: DiContainer; @@ -98,4 +125,30 @@ describe("Icon settings", () => { expect(rendered.getByText("Hello World")).toBeInTheDocument(); }); }); + + describe("given no registrations for cluster settings component injection token", () => { + it("renders", () => { + expect(rendered.baseElement).toMatchSnapshot(); + }); + + it("does not have any external components", async () => { + expect(rendered.queryByTestId("test-react-component")).not.toBeInTheDocument(); + }); + }); + + describe("given registration for cluster settings component injection token", () => { + beforeEach(() => { + runInAction(() => { + di.register(newSettingsReactComponent); + }); + }); + + it("renders external component", async () => { + expect(rendered.queryByTestId("my-react-component")).toBeInTheDocument(); + }); + + it("external component has cluster preferences in props", async () => { + expect(rendered.getByText(/some-cluster-name/)).toBeInTheDocument(); + }); + }); }); diff --git a/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-clear-item.injectable.ts b/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-clear-item.injectable.ts index 697c68bb40..87f8c87940 100644 --- a/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-clear-item.injectable.ts +++ b/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-clear-item.injectable.ts @@ -3,7 +3,7 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; -import { clusterIconSettingsMenuInjectionToken } from "./cluster-settings-menu-injection-token"; +import { clusterIconSettingsMenuInjectionToken } from "@k8slens/cluster-settings"; const clusterIconSettingsMenuClearItem = getInjectable({ id: "cluster-icon-settings-menu-clear-item", diff --git a/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-injection-token.ts b/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-injection-token.ts deleted file mode 100644 index 15dbba2754..0000000000 --- a/packages/core/src/renderer/components/cluster-settings/cluster-settings-menu-injection-token.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Copyright (c) OpenLens Authors. All rights reserved. - * Licensed under MIT License. See LICENSE in root directory for more information. - */ -import { getInjectionToken } from "@ogre-tools/injectable"; -import type { ClusterPreferences } from "../../../common/cluster-types"; - -export interface ClusterIconMenuItem { - id: string; - title: string; - disabled?: (preferences: ClusterPreferences) => boolean; - onClick: (preferences: ClusterPreferences) => void; -} - -export const clusterIconSettingsMenuInjectionToken = getInjectionToken({ - id: "cluster-icon-settings-menu-injection-token", -}); diff --git a/packages/core/src/renderer/components/cluster-settings/icon-settings.tsx b/packages/core/src/renderer/components/cluster-settings/icon-settings.tsx index 94706f17a5..a802807c17 100644 --- a/packages/core/src/renderer/components/cluster-settings/icon-settings.tsx +++ b/packages/core/src/renderer/components/cluster-settings/icon-settings.tsx @@ -15,8 +15,8 @@ import { FilePicker, OverSizeLimitStyle } from "../file-picker"; import { MenuActions, MenuItem } from "../menu"; import type { ShowNotification } from "../notifications"; import showErrorNotificationInjectable from "../notifications/show-error-notification.injectable"; -import type { ClusterIconMenuItem } from "./cluster-settings-menu-injection-token"; -import { clusterIconSettingsMenuInjectionToken } from "./cluster-settings-menu-injection-token"; +import { clusterIconSettingsComponentInjectionToken, clusterIconSettingsMenuInjectionToken } from "@k8slens/cluster-settings"; +import type { ClusterIconMenuItem, ClusterIconSettingsComponent } from "@k8slens/cluster-settings"; export interface ClusterIconSettingProps { cluster: Cluster; @@ -25,6 +25,7 @@ export interface ClusterIconSettingProps { interface Dependencies { menuItems: IComputedValue; + settingComponents: IComputedValue; showErrorNotification: ShowNotification; } @@ -95,6 +96,14 @@ const NonInjectedClusterIconSetting = observer((props: ClusterIconSettingProps & )}
+ {props.settingComponents.get().map(item => { + return ( + + ); + })}
); }); @@ -106,6 +115,7 @@ export const ClusterIconSetting = withInjectables Date: Thu, 23 Mar 2023 07:34:02 -0400 Subject: [PATCH 17/17] Fix formatting in release guide (#7398) Signed-off-by: Sebastian Malton --- RELEASE_GUIDE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/RELEASE_GUIDE.md b/RELEASE_GUIDE.md index f89bfa3295..d46911b0ce 100644 --- a/RELEASE_GUIDE.md +++ b/RELEASE_GUIDE.md @@ -15,8 +15,8 @@ All releases will be made by creating a PR which bumps the version field in the 1. If you are making a patch release (or a prerelease for one) make sure you are on the `release/v.` branch. 1. Run `npm run create-release-pr`. 1. Pick the PRs that you want to include in this release using the keys listed. - - If you are making a patch release this might include fixing up some cherry-picking of commits. These actions should be done in a separate terminal. - - If a package version is having a major version bump then `npm` will complain about `peerDependency` conflicts. These will have to be fixed up separately. + - If you are making a patch release this might include fixing up some cherry-picking of commits. These actions should be done in a separate terminal. + - If a package version is having a major version bump then `npm` will complain about `peerDependency` conflicts. These will have to be fixed up separately. 1. Once the PR is created, approved, and then merged the `Release Open Lens` workflow will create a tag and release for you. 1. If you are making a major or minor release, create a `release/v.` branch and push it to `origin` so that future patch releases can be made from it. 1. If you released a major or minor version, create a new patch milestone and move all bug issues to that milestone and all enhancement issues to the next minor milestone.