@devisfuture/electron-modular 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +731 -0
- package/dist/@core/bootstrap/bootstrap.d.ts +2 -0
- package/dist/@core/bootstrap/bootstrap.js +20 -0
- package/dist/@core/bootstrap/initialize-ipc/handlers.d.ts +3 -0
- package/dist/@core/bootstrap/initialize-ipc/handlers.js +47 -0
- package/dist/@core/bootstrap/initialize-ipc/window-creator.d.ts +3 -0
- package/dist/@core/bootstrap/initialize-ipc/window-creator.js +28 -0
- package/dist/@core/bootstrap/initialize-ipc/window-event-listeners.d.ts +3 -0
- package/dist/@core/bootstrap/initialize-ipc/window-event-listeners.js +61 -0
- package/dist/@core/bootstrap/initialize-ipc/window-instance-creator.d.ts +3 -0
- package/dist/@core/bootstrap/initialize-ipc/window-instance-creator.js +10 -0
- package/dist/@core/bootstrap/initialize-module.d.ts +3 -0
- package/dist/@core/bootstrap/initialize-module.js +18 -0
- package/dist/@core/bootstrap/instantiate-module.d.ts +2 -0
- package/dist/@core/bootstrap/instantiate-module.js +9 -0
- package/dist/@core/bootstrap/register-imports.d.ts +2 -0
- package/dist/@core/bootstrap/register-imports.js +12 -0
- package/dist/@core/bootstrap/register-ipc-handlers.d.ts +3 -0
- package/dist/@core/bootstrap/register-ipc-handlers.js +9 -0
- package/dist/@core/bootstrap/register-providers.d.ts +3 -0
- package/dist/@core/bootstrap/register-providers.js +21 -0
- package/dist/@core/bootstrap/register-windows.d.ts +3 -0
- package/dist/@core/bootstrap/register-windows.js +15 -0
- package/dist/@core/bootstrap/settings.d.ts +11 -0
- package/dist/@core/bootstrap/settings.js +13 -0
- package/dist/@core/container.d.ts +26 -0
- package/dist/@core/container.js +154 -0
- package/dist/@core/control-window/cache.d.ts +1 -0
- package/dist/@core/control-window/cache.js +1 -0
- package/dist/@core/control-window/create.d.ts +3 -0
- package/dist/@core/control-window/create.js +63 -0
- package/dist/@core/control-window/destroy.d.ts +1 -0
- package/dist/@core/control-window/destroy.js +9 -0
- package/dist/@core/control-window/receive.d.ts +2 -0
- package/dist/@core/control-window/receive.js +8 -0
- package/dist/@core/control-window/types.d.ts +14 -0
- package/dist/@core/control-window/types.js +1 -0
- package/dist/@core/decorators/inject.d.ts +6 -0
- package/dist/@core/decorators/inject.js +15 -0
- package/dist/@core/decorators/injectable.d.ts +2 -0
- package/dist/@core/decorators/injectable.js +6 -0
- package/dist/@core/decorators/ipc-handler.d.ts +2 -0
- package/dist/@core/decorators/ipc-handler.js +6 -0
- package/dist/@core/decorators/rg-module.d.ts +3 -0
- package/dist/@core/decorators/rg-module.js +6 -0
- package/dist/@core/decorators/window-manager.d.ts +3 -0
- package/dist/@core/decorators/window-manager.js +6 -0
- package/dist/@core/errors/index.d.ts +19 -0
- package/dist/@core/errors/index.js +31 -0
- package/dist/@core/types/constructor.d.ts +1 -0
- package/dist/@core/types/constructor.js +1 -0
- package/dist/@core/types/index.d.ts +7 -0
- package/dist/@core/types/index.js +1 -0
- package/dist/@core/types/ipc-handler.d.ts +7 -0
- package/dist/@core/types/ipc-handler.js +1 -0
- package/dist/@core/types/module-metadata.d.ts +10 -0
- package/dist/@core/types/module-metadata.js +1 -0
- package/dist/@core/types/provider.d.ts +21 -0
- package/dist/@core/types/provider.js +1 -0
- package/dist/@core/types/window-factory.d.ts +6 -0
- package/dist/@core/types/window-factory.js +1 -0
- package/dist/@core/types/window-manager.d.ts +10 -0
- package/dist/@core/types/window-manager.js +1 -0
- package/dist/@core/types/window-metadata.d.ts +6 -0
- package/dist/@core/types/window-metadata.js +1 -0
- package/dist/@core/utils/dependency-tokens.d.ts +4 -0
- package/dist/@core/utils/dependency-tokens.js +23 -0
- package/dist/config.d.ts +4 -0
- package/dist/config.js +4 -0
- package/dist/index.d.ts +26 -0
- package/dist/index.js +34 -0
- package/package.json +53 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ModuleDecoratorMissingError } from "../errors/index.js";
|
|
2
|
+
import { instantiateModule } from "./instantiate-module.js";
|
|
3
|
+
import { initializeModule } from "./initialize-module.js";
|
|
4
|
+
import { container } from "../container.js";
|
|
5
|
+
import { initializeIpcHandlers } from "./initialize-ipc/handlers.js";
|
|
6
|
+
export const bootstrapModules = async (modulesClass) => {
|
|
7
|
+
for (const moduleClass of modulesClass) {
|
|
8
|
+
const metadata = Reflect.getMetadata("RgModule", moduleClass);
|
|
9
|
+
if (!metadata) {
|
|
10
|
+
throw new ModuleDecoratorMissingError(moduleClass.name);
|
|
11
|
+
}
|
|
12
|
+
await initializeModule(moduleClass, metadata);
|
|
13
|
+
await instantiateModule(moduleClass);
|
|
14
|
+
await container.resolve(moduleClass, moduleClass);
|
|
15
|
+
if (metadata.windows?.length && !metadata.ipc?.length) {
|
|
16
|
+
console.warn(`Warning: Window(s) declared in module "${moduleClass.name}" but no IPC handlers found to manage them.`);
|
|
17
|
+
}
|
|
18
|
+
await initializeIpcHandlers(moduleClass, metadata);
|
|
19
|
+
}
|
|
20
|
+
};
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { container } from "../../container.js";
|
|
2
|
+
import { createWindowWithParams } from "./window-creator.js";
|
|
3
|
+
import { createWindowInstance } from "./window-instance-creator.js";
|
|
4
|
+
import { attachWindowEventListeners } from "./window-event-listeners.js";
|
|
5
|
+
const createWindowFactory = (moduleClass, windowMetadata) => {
|
|
6
|
+
if (!windowMetadata?.metadata?.options ||
|
|
7
|
+
!windowMetadata.metadata.hash ||
|
|
8
|
+
!windowMetadata.windowClass) {
|
|
9
|
+
return {
|
|
10
|
+
create: async () => undefined,
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
create: async (params) => {
|
|
15
|
+
const browserWindow = createWindowWithParams(windowMetadata.metadata, params);
|
|
16
|
+
const windowInstance = await createWindowInstance(moduleClass, windowMetadata.windowClass);
|
|
17
|
+
if (browserWindow && windowInstance) {
|
|
18
|
+
attachWindowEventListeners(browserWindow, windowInstance);
|
|
19
|
+
return browserWindow;
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
},
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
const createGetWindowFunction = (moduleClass) => {
|
|
26
|
+
return (name) => {
|
|
27
|
+
if (!name) {
|
|
28
|
+
return {
|
|
29
|
+
create: async () => undefined,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
const windowMetadata = container.getProvider(moduleClass, name);
|
|
33
|
+
return createWindowFactory(moduleClass, windowMetadata);
|
|
34
|
+
};
|
|
35
|
+
};
|
|
36
|
+
export const initializeIpcHandlers = async (moduleClass, metadata) => {
|
|
37
|
+
if (!metadata.ipc) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const getWindow = createGetWindowFunction(moduleClass);
|
|
41
|
+
for (const ipcClass of metadata.ipc) {
|
|
42
|
+
const ipcInstance = await container.resolve(moduleClass, ipcClass);
|
|
43
|
+
if (ipcInstance?.onInit) {
|
|
44
|
+
ipcInstance.onInit({ getWindow });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { createWindow } from "../../control-window/create.js";
|
|
2
|
+
const isPlainObject = (value) => {
|
|
3
|
+
return (typeof value === "object" &&
|
|
4
|
+
value !== null &&
|
|
5
|
+
!Array.isArray(value) &&
|
|
6
|
+
Object.prototype.toString.call(value) === "[object Object]");
|
|
7
|
+
};
|
|
8
|
+
const mergeDeep = (target, source) => {
|
|
9
|
+
const output = { ...target };
|
|
10
|
+
for (const [key, value] of Object.entries(source)) {
|
|
11
|
+
if (isPlainObject(value)) {
|
|
12
|
+
const current = output[key];
|
|
13
|
+
output[key] = isPlainObject(current)
|
|
14
|
+
? mergeDeep(current, value)
|
|
15
|
+
: mergeDeep({}, value);
|
|
16
|
+
}
|
|
17
|
+
else {
|
|
18
|
+
output[key] = value;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
return output;
|
|
22
|
+
};
|
|
23
|
+
export const createWindowWithParams = (baseMetadata, params) => {
|
|
24
|
+
const mergedSettings = params !== undefined
|
|
25
|
+
? mergeDeep(baseMetadata, params)
|
|
26
|
+
: baseMetadata;
|
|
27
|
+
return createWindow(mergedSettings);
|
|
28
|
+
};
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
const windowListeners = new WeakMap();
|
|
2
|
+
const getPrototypeMethodNames = (instance) => {
|
|
3
|
+
const names = new Set();
|
|
4
|
+
let proto = Object.getPrototypeOf(instance);
|
|
5
|
+
while (proto && proto !== Object.prototype) {
|
|
6
|
+
Object.getOwnPropertyNames(proto).forEach((n) => n !== "constructor" && names.add(n));
|
|
7
|
+
proto = Object.getPrototypeOf(proto);
|
|
8
|
+
}
|
|
9
|
+
return Array.from(names);
|
|
10
|
+
};
|
|
11
|
+
const toEventName = (h) => {
|
|
12
|
+
const c = h.replace(/^(onWindow|onWebContents|on)/, "");
|
|
13
|
+
return c
|
|
14
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1-$2")
|
|
15
|
+
.replace(/([A-Z])([A-Z][a-z])/g, "$1-$2")
|
|
16
|
+
.toLowerCase();
|
|
17
|
+
};
|
|
18
|
+
const attachHandlersToEmitter = (emitter, win, inst, names, filter) => {
|
|
19
|
+
const cleanups = [];
|
|
20
|
+
for (const name of names) {
|
|
21
|
+
if (!filter(name))
|
|
22
|
+
continue;
|
|
23
|
+
const h = inst[name];
|
|
24
|
+
if (typeof h !== "function")
|
|
25
|
+
continue;
|
|
26
|
+
const evt = toEventName(name);
|
|
27
|
+
const listener = (...args) => {
|
|
28
|
+
h.length <= 1 ? h.apply(inst, [win]) : h.apply(inst, [...args, win]);
|
|
29
|
+
};
|
|
30
|
+
emitter.on(evt, listener);
|
|
31
|
+
cleanups.push(() => {
|
|
32
|
+
emitter.off
|
|
33
|
+
? emitter.off(evt, listener)
|
|
34
|
+
: emitter.removeListener &&
|
|
35
|
+
emitter.removeListener(evt, listener);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
return cleanups;
|
|
39
|
+
};
|
|
40
|
+
export const attachWindowEventListeners = (win, inst) => {
|
|
41
|
+
const entry = windowListeners.get(win);
|
|
42
|
+
if (entry?.instance === inst)
|
|
43
|
+
return;
|
|
44
|
+
if (entry)
|
|
45
|
+
entry.cleanup.forEach((c) => c());
|
|
46
|
+
const names = getPrototypeMethodNames(inst).filter((n) => n.startsWith("on"));
|
|
47
|
+
const isWebContents = (n) => n.startsWith("onWebContents");
|
|
48
|
+
const winCleanups = attachHandlersToEmitter(win, win, inst, names, (n) => !isWebContents(n));
|
|
49
|
+
const webCleanups = attachHandlersToEmitter(win.webContents, win, inst, names, isWebContents);
|
|
50
|
+
windowListeners.set(win, {
|
|
51
|
+
instance: inst,
|
|
52
|
+
cleanup: [...winCleanups, ...webCleanups],
|
|
53
|
+
});
|
|
54
|
+
win.once("closed", () => {
|
|
55
|
+
const e = windowListeners.get(win);
|
|
56
|
+
if (e) {
|
|
57
|
+
e.cleanup.forEach((c) => c());
|
|
58
|
+
windowListeners.delete(win);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import type { Constructor } from "../../types/constructor.js";
|
|
2
|
+
import type { TWindowManagerWithHandlers } from "../../types/window-manager.js";
|
|
3
|
+
export declare const createWindowInstance: <T extends TWindowManagerWithHandlers>(moduleClass: Constructor, windowClass: Constructor<T>) => Promise<T | undefined>;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { container } from "../../container.js";
|
|
2
|
+
import { getDependencyTokens } from "../../utils/dependency-tokens.js";
|
|
3
|
+
export const createWindowInstance = async (moduleClass, windowClass) => {
|
|
4
|
+
if (!windowClass) {
|
|
5
|
+
return undefined;
|
|
6
|
+
}
|
|
7
|
+
const dependenciesTypes = getDependencyTokens(windowClass);
|
|
8
|
+
const resolvedDependencies = await Promise.all(dependenciesTypes.map((depType) => container.resolve(moduleClass, depType)));
|
|
9
|
+
return new windowClass(...resolvedDependencies);
|
|
10
|
+
};
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { container } from "../container.js";
|
|
2
|
+
import { registerProviders } from "./register-providers.js";
|
|
3
|
+
import { registerImports } from "./register-imports.js";
|
|
4
|
+
import { registerWindows } from "./register-windows.js";
|
|
5
|
+
import { registerIpcHandlers } from "./register-ipc-handlers.js";
|
|
6
|
+
export const initializeModule = async (moduleClass, metadata) => {
|
|
7
|
+
const isNewModule = container.addModule(moduleClass, metadata);
|
|
8
|
+
container.setModuleMetadata(moduleClass, metadata);
|
|
9
|
+
if (!isNewModule) {
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
await Promise.all([
|
|
13
|
+
registerProviders(moduleClass, metadata),
|
|
14
|
+
registerImports(metadata),
|
|
15
|
+
registerWindows(moduleClass, metadata),
|
|
16
|
+
registerIpcHandlers(moduleClass, metadata),
|
|
17
|
+
]);
|
|
18
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { container } from "../container.js";
|
|
2
|
+
import { getDependencyTokens } from "../utils/dependency-tokens.js";
|
|
3
|
+
export const instantiateModule = async (moduleClass) => {
|
|
4
|
+
const dependencies = getDependencyTokens(moduleClass);
|
|
5
|
+
const resolvedDependencies = await Promise.all(dependencies.map((dependency) => container.resolve(moduleClass, dependency)));
|
|
6
|
+
const instance = new moduleClass(...resolvedDependencies);
|
|
7
|
+
container.registerInstance(moduleClass, instance);
|
|
8
|
+
return instance;
|
|
9
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { initializeModule } from "./initialize-module.js";
|
|
2
|
+
export const registerImports = async (metadata) => {
|
|
3
|
+
if (!metadata.imports) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
for (const importedModuleClass of metadata.imports) {
|
|
7
|
+
const importedModuleMetadata = Reflect.getMetadata("RgModule", importedModuleClass);
|
|
8
|
+
if (importedModuleMetadata) {
|
|
9
|
+
await initializeModule(importedModuleClass, importedModuleMetadata);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { InvalidProviderError } from "../errors/index.js";
|
|
2
|
+
import { container } from "../container.js";
|
|
3
|
+
const isProviderObject = (provider) => {
|
|
4
|
+
return (typeof provider === "object" && provider !== null && "provide" in provider);
|
|
5
|
+
};
|
|
6
|
+
export const registerProviders = async (moduleClass, metadata) => {
|
|
7
|
+
if (!metadata.providers) {
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
for (const provider of metadata.providers) {
|
|
11
|
+
if (typeof provider === "function") {
|
|
12
|
+
container.addProvider(moduleClass, provider);
|
|
13
|
+
continue;
|
|
14
|
+
}
|
|
15
|
+
if (isProviderObject(provider)) {
|
|
16
|
+
container.addProvider(moduleClass, provider.provide, provider);
|
|
17
|
+
continue;
|
|
18
|
+
}
|
|
19
|
+
throw new InvalidProviderError(moduleClass.name);
|
|
20
|
+
}
|
|
21
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { container } from "../container.js";
|
|
2
|
+
export const registerWindows = async (moduleClass, metadata) => {
|
|
3
|
+
if (!metadata.windows) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
for (const windowClass of metadata.windows) {
|
|
7
|
+
const windowMetadataValue = Reflect.getMetadata("WindowManager", windowClass);
|
|
8
|
+
if (windowMetadataValue?.hash) {
|
|
9
|
+
container.addProvider(moduleClass, windowMetadataValue.hash, {
|
|
10
|
+
metadata: windowMetadataValue,
|
|
11
|
+
windowClass,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export type TFolderSettings = {
|
|
2
|
+
distRenderer: string;
|
|
3
|
+
distMain: string;
|
|
4
|
+
};
|
|
5
|
+
export type TSettings = {
|
|
6
|
+
baseRestApi: string;
|
|
7
|
+
localhostPort: string;
|
|
8
|
+
folders: TFolderSettings;
|
|
9
|
+
};
|
|
10
|
+
export declare const initSettings: (options: TSettings) => void;
|
|
11
|
+
export declare const getSettings: () => TSettings;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { SettingsNotInitializedError } from "../errors/index.js";
|
|
2
|
+
const KEY = "settings";
|
|
3
|
+
const settings = new Map();
|
|
4
|
+
export const initSettings = (options) => {
|
|
5
|
+
settings.set(KEY, options);
|
|
6
|
+
};
|
|
7
|
+
export const getSettings = () => {
|
|
8
|
+
const cachedSettings = settings.get(KEY);
|
|
9
|
+
if (!cachedSettings) {
|
|
10
|
+
throw new SettingsNotInitializedError();
|
|
11
|
+
}
|
|
12
|
+
return cachedSettings;
|
|
13
|
+
};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Constructor } from "./types/constructor.js";
|
|
2
|
+
import type { RgModuleMetadata } from "./types/module-metadata.js";
|
|
3
|
+
import type { TProviderToken } from "./types/provider.js";
|
|
4
|
+
export declare class Container {
|
|
5
|
+
private readonly modules;
|
|
6
|
+
private readonly moduleMetadata;
|
|
7
|
+
private readonly instances;
|
|
8
|
+
private readonly resolutionCache;
|
|
9
|
+
addModule(moduleClass: Constructor, metadata: Pick<RgModuleMetadata, "exports" | "providers">): boolean;
|
|
10
|
+
setModuleMetadata(moduleClass: Constructor, metadata: RgModuleMetadata): void;
|
|
11
|
+
hasModule(moduleClass: Constructor): boolean;
|
|
12
|
+
private getCacheKey;
|
|
13
|
+
addProvider(moduleClass: Constructor, provider: TProviderToken, instance?: unknown): void;
|
|
14
|
+
getProvider<T = unknown>(moduleClass: Constructor, token: TProviderToken): T | undefined;
|
|
15
|
+
getModuleExports(moduleClass: Constructor): Set<TProviderToken>;
|
|
16
|
+
getModuleMetadata(moduleClass: Constructor): RgModuleMetadata | undefined;
|
|
17
|
+
registerInstance(token: TProviderToken, instance: unknown): void;
|
|
18
|
+
resolve<T>(moduleClass: Constructor, token: TProviderToken): Promise<T | undefined>;
|
|
19
|
+
private resolveFromImports;
|
|
20
|
+
private instantiateProvider;
|
|
21
|
+
private instantiateFactoryProvider;
|
|
22
|
+
private instantiateClassProvider;
|
|
23
|
+
private instantiateClassConstructor;
|
|
24
|
+
private resolveDependencies;
|
|
25
|
+
}
|
|
26
|
+
export declare const container: Container;
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import { getDependencyTokens } from "./utils/dependency-tokens.js";
|
|
2
|
+
import { ModuleNotRegisteredError, ProviderNotFoundError, } from "./errors/index.js";
|
|
3
|
+
export class Container {
|
|
4
|
+
modules = new Map();
|
|
5
|
+
moduleMetadata = new Map();
|
|
6
|
+
instances = new Map();
|
|
7
|
+
resolutionCache = new Map();
|
|
8
|
+
addModule(moduleClass, metadata) {
|
|
9
|
+
if (this.modules.has(moduleClass)) {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
this.modules.set(moduleClass, {
|
|
13
|
+
providers: new Map(),
|
|
14
|
+
exports: new Set(metadata.exports ?? []),
|
|
15
|
+
});
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
setModuleMetadata(moduleClass, metadata) {
|
|
19
|
+
this.moduleMetadata.set(moduleClass, metadata);
|
|
20
|
+
}
|
|
21
|
+
hasModule(moduleClass) {
|
|
22
|
+
return this.modules.has(moduleClass);
|
|
23
|
+
}
|
|
24
|
+
getCacheKey(moduleClass, token) {
|
|
25
|
+
const tokenKey = typeof token === "string" || typeof token === "symbol"
|
|
26
|
+
? String(token)
|
|
27
|
+
: token.name;
|
|
28
|
+
return `${moduleClass.name}:${tokenKey}`;
|
|
29
|
+
}
|
|
30
|
+
addProvider(moduleClass, provider, instance) {
|
|
31
|
+
const moduleData = this.modules.get(moduleClass);
|
|
32
|
+
if (!moduleData) {
|
|
33
|
+
throw new ModuleNotRegisteredError(moduleClass.name);
|
|
34
|
+
}
|
|
35
|
+
moduleData.providers.set(provider, instance ?? provider);
|
|
36
|
+
}
|
|
37
|
+
getProvider(moduleClass, token) {
|
|
38
|
+
const moduleData = this.modules.get(moduleClass);
|
|
39
|
+
if (!moduleData) {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
42
|
+
return moduleData.providers.get(token);
|
|
43
|
+
}
|
|
44
|
+
getModuleExports(moduleClass) {
|
|
45
|
+
const moduleData = this.modules.get(moduleClass);
|
|
46
|
+
return moduleData?.exports ?? new Set();
|
|
47
|
+
}
|
|
48
|
+
getModuleMetadata(moduleClass) {
|
|
49
|
+
return this.moduleMetadata.get(moduleClass);
|
|
50
|
+
}
|
|
51
|
+
registerInstance(token, instance) {
|
|
52
|
+
this.instances.set(token, instance);
|
|
53
|
+
}
|
|
54
|
+
async resolve(moduleClass, token) {
|
|
55
|
+
const cacheKey = this.getCacheKey(moduleClass, token);
|
|
56
|
+
if (this.resolutionCache.has(cacheKey)) {
|
|
57
|
+
return this.resolutionCache.get(cacheKey);
|
|
58
|
+
}
|
|
59
|
+
if (this.instances.has(token)) {
|
|
60
|
+
const instance = this.instances.get(token);
|
|
61
|
+
this.resolutionCache.set(cacheKey, instance);
|
|
62
|
+
return instance;
|
|
63
|
+
}
|
|
64
|
+
const provider = this.getProvider(moduleClass, token);
|
|
65
|
+
if (!provider) {
|
|
66
|
+
const resolvedFromImports = await this.resolveFromImports(moduleClass, token);
|
|
67
|
+
if (resolvedFromImports !== undefined) {
|
|
68
|
+
this.resolutionCache.set(cacheKey, resolvedFromImports);
|
|
69
|
+
return resolvedFromImports;
|
|
70
|
+
}
|
|
71
|
+
if (token !== moduleClass) {
|
|
72
|
+
throw new ProviderNotFoundError(String(token), moduleClass.name);
|
|
73
|
+
}
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
const instance = await this.instantiateProvider(moduleClass, token, provider);
|
|
77
|
+
if (instance !== undefined) {
|
|
78
|
+
this.resolutionCache.set(cacheKey, instance);
|
|
79
|
+
}
|
|
80
|
+
return instance;
|
|
81
|
+
}
|
|
82
|
+
async resolveFromImports(moduleClass, token) {
|
|
83
|
+
const moduleMetadata = this.getModuleMetadata(moduleClass);
|
|
84
|
+
if (!moduleMetadata?.imports) {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
for (const importedModuleClass of moduleMetadata.imports) {
|
|
88
|
+
const exportedProviders = this.getModuleExports(importedModuleClass);
|
|
89
|
+
if (exportedProviders.has(token)) {
|
|
90
|
+
const exportedProvider = this.getProvider(importedModuleClass, token);
|
|
91
|
+
if (exportedProvider !== undefined) {
|
|
92
|
+
return this.resolve(importedModuleClass, token);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return undefined;
|
|
97
|
+
}
|
|
98
|
+
async instantiateProvider(moduleClass, token, provider) {
|
|
99
|
+
const isObj = typeof provider === "object" &&
|
|
100
|
+
provider !== null &&
|
|
101
|
+
"provide" in provider;
|
|
102
|
+
if (isObj &&
|
|
103
|
+
"useFactory" in provider &&
|
|
104
|
+
typeof provider.useFactory === "function") {
|
|
105
|
+
return this.instantiateFactoryProvider(moduleClass, token, provider);
|
|
106
|
+
}
|
|
107
|
+
if (isObj &&
|
|
108
|
+
"useClass" in provider &&
|
|
109
|
+
typeof provider.useClass === "function") {
|
|
110
|
+
return this.instantiateClassProvider(moduleClass, token, provider);
|
|
111
|
+
}
|
|
112
|
+
if (isObj && "useValue" in provider) {
|
|
113
|
+
const val = provider.useValue;
|
|
114
|
+
this.instances.set(token, val);
|
|
115
|
+
return val;
|
|
116
|
+
}
|
|
117
|
+
if (isObj && "useExisting" in provider) {
|
|
118
|
+
const instance = await this.resolve(moduleClass, provider.useExisting);
|
|
119
|
+
if (instance !== undefined) {
|
|
120
|
+
this.instances.set(token, instance);
|
|
121
|
+
}
|
|
122
|
+
return instance;
|
|
123
|
+
}
|
|
124
|
+
if (typeof provider === "function") {
|
|
125
|
+
return this.instantiateClassConstructor(moduleClass, token, provider);
|
|
126
|
+
}
|
|
127
|
+
return provider;
|
|
128
|
+
}
|
|
129
|
+
async instantiateFactoryProvider(moduleClass, token, provider) {
|
|
130
|
+
const dependencies = provider.inject ?? [];
|
|
131
|
+
const resolvedDependencies = await this.resolveDependencies(moduleClass, dependencies);
|
|
132
|
+
const instance = provider.useFactory(...resolvedDependencies);
|
|
133
|
+
this.instances.set(token, instance);
|
|
134
|
+
return instance;
|
|
135
|
+
}
|
|
136
|
+
async instantiateClassProvider(moduleClass, token, provider) {
|
|
137
|
+
const dependencies = provider.inject ?? getDependencyTokens(provider.useClass);
|
|
138
|
+
const resolvedDependencies = await this.resolveDependencies(moduleClass, dependencies);
|
|
139
|
+
const instance = new provider.useClass(...resolvedDependencies);
|
|
140
|
+
this.instances.set(token, instance);
|
|
141
|
+
return instance;
|
|
142
|
+
}
|
|
143
|
+
async instantiateClassConstructor(moduleClass, token, providerClass) {
|
|
144
|
+
const dependencies = getDependencyTokens(providerClass);
|
|
145
|
+
const resolvedDependencies = await this.resolveDependencies(moduleClass, dependencies);
|
|
146
|
+
const instance = new providerClass(...resolvedDependencies);
|
|
147
|
+
this.instances.set(token, instance);
|
|
148
|
+
return instance;
|
|
149
|
+
}
|
|
150
|
+
async resolveDependencies(moduleClass, dependencies) {
|
|
151
|
+
return Promise.all(dependencies.map((dep) => this.resolve(moduleClass, dep)));
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export const container = new Container();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const cacheWindows: Map<string, Electron.CrossProcessExports.BrowserWindow>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const cacheWindows = new Map();
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { BrowserWindow, session, app } from "electron";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { cacheWindows } from "./cache.js";
|
|
4
|
+
import { getWindow } from "./receive.js";
|
|
5
|
+
import { getSettings } from "../bootstrap/settings.js";
|
|
6
|
+
const setupCSP = (base, dev) => {
|
|
7
|
+
const csp = `default-src 'self'; connect-src 'self' ${base}; img-src * data:; style-src 'self' 'unsafe-inline'; script-src 'self' ${dev ? "'unsafe-inline'" : ""};`
|
|
8
|
+
.replace(/\s{2,}/g, " ")
|
|
9
|
+
.trim();
|
|
10
|
+
session.defaultSession.webRequest.onHeadersReceived((d, cb) => {
|
|
11
|
+
cb({
|
|
12
|
+
responseHeaders: {
|
|
13
|
+
...d.responseHeaders,
|
|
14
|
+
"Content-Security-Policy": [csp],
|
|
15
|
+
},
|
|
16
|
+
});
|
|
17
|
+
});
|
|
18
|
+
};
|
|
19
|
+
export const createWindow = ({ hash, options, isCache, loadURL, }) => {
|
|
20
|
+
const settings = getSettings();
|
|
21
|
+
const isDev = process.env.NODE_ENV === "development";
|
|
22
|
+
const ui = path.join(app.getAppPath(), `/${settings.folders.distRenderer}/index.html`);
|
|
23
|
+
const preload = path.join(app.getAppPath(), isDev ? "." : "..", `/${settings.folders.distMain}/preload.cjs`);
|
|
24
|
+
if (!settings.baseRestApi)
|
|
25
|
+
console.warn('Warning: You have to add an environment variable called "process.env.BASE_REST_API"!');
|
|
26
|
+
if (!settings.localhostPort)
|
|
27
|
+
console.warn('Warning: You have to add an environment variable called "process.env.LOCALHOST_ELECTRON_SERVER_PORT"!');
|
|
28
|
+
if (hash && isCache) {
|
|
29
|
+
const existing = getWindow(hash);
|
|
30
|
+
if (existing) {
|
|
31
|
+
existing.show();
|
|
32
|
+
return existing;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const win = new BrowserWindow({
|
|
36
|
+
...options,
|
|
37
|
+
webPreferences: {
|
|
38
|
+
preload,
|
|
39
|
+
contextIsolation: true,
|
|
40
|
+
nodeIntegration: false,
|
|
41
|
+
...options?.webPreferences,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
if (isCache && !loadURL)
|
|
45
|
+
setupCSP(settings.baseRestApi, isDev);
|
|
46
|
+
if (loadURL) {
|
|
47
|
+
win.loadURL(loadURL);
|
|
48
|
+
}
|
|
49
|
+
else if (isDev) {
|
|
50
|
+
win.loadURL(`http://localhost:${settings.localhostPort}${hash ? `#${hash}` : ""}`);
|
|
51
|
+
}
|
|
52
|
+
else if (hash) {
|
|
53
|
+
win.loadFile(ui, { hash });
|
|
54
|
+
}
|
|
55
|
+
if (hash && isCache) {
|
|
56
|
+
cacheWindows.set(hash, win);
|
|
57
|
+
win.on("close", (e) => {
|
|
58
|
+
e.preventDefault();
|
|
59
|
+
win.hide();
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return win;
|
|
63
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const destroyWindows: () => void;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { BrowserWindow, type BrowserWindowConstructorOptions } from "electron";
|
|
2
|
+
export type TParamsRoute = {
|
|
3
|
+
[key: string]: string;
|
|
4
|
+
};
|
|
5
|
+
export type TParamsCreateWindow<N = string> = {
|
|
6
|
+
hash?: N;
|
|
7
|
+
isCache?: boolean;
|
|
8
|
+
paramsRoute?: TParamsRoute;
|
|
9
|
+
options?: BrowserWindowConstructorOptions;
|
|
10
|
+
loadURL?: string;
|
|
11
|
+
};
|
|
12
|
+
export type TCache = {
|
|
13
|
+
[key in string]: BrowserWindow;
|
|
14
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import { BrowserWindow } from "electron";
|