@_traeop_/electron-modular 1.0.7 → 1.0.8

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.
@@ -1,3 +1,3 @@
1
1
  import type { BrowserWindow } from "electron";
2
2
  import type { TWindowManagerWithHandlers } from "../../types/window-manager.js";
3
- export declare const attachWindowEventListeners: (browserWindow: BrowserWindow, windowInstance: TWindowManagerWithHandlers) => void;
3
+ export declare const attachWindowEventListeners: (win: BrowserWindow, inst: TWindowManagerWithHandlers) => void;
@@ -1,90 +1,61 @@
1
1
  const windowListeners = new WeakMap();
2
- const EVENT_PREFIX = "on";
3
- const WINDOW_PREFIX = "onWindow";
4
- const WEB_CONTENTS_PREFIX = "onWebContents";
5
2
  const getPrototypeMethodNames = (instance) => {
6
3
  const names = new Set();
7
4
  let proto = Object.getPrototypeOf(instance);
8
5
  while (proto && proto !== Object.prototype) {
9
- Object.getOwnPropertyNames(proto).forEach((name) => {
10
- if (name !== "constructor") {
11
- names.add(name);
12
- }
13
- });
6
+ Object.getOwnPropertyNames(proto).forEach((n) => n !== "constructor" && names.add(n));
14
7
  proto = Object.getPrototypeOf(proto);
15
8
  }
16
9
  return Array.from(names);
17
10
  };
18
- const toEventName = (handlerName) => {
19
- const cleaned = handlerName
20
- .replace(WINDOW_PREFIX, "")
21
- .replace(WEB_CONTENTS_PREFIX, "")
22
- .replace(EVENT_PREFIX, "");
23
- return cleaned
11
+ const toEventName = (h) => {
12
+ const c = h.replace(/^(onWindow|onWebContents|on)/, "");
13
+ return c
24
14
  .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
25
15
  .replace(/([A-Z])([A-Z][a-z])/g, "$1-$2")
26
16
  .toLowerCase();
27
17
  };
28
- const isHandlerName = (name) => {
29
- return name.startsWith(EVENT_PREFIX);
30
- };
31
- const isWebContentsHandler = (name) => {
32
- return name.startsWith(WEB_CONTENTS_PREFIX);
33
- };
34
- const addListener = (emitter, eventName, listener) => {
35
- emitter.on(eventName, listener);
36
- return () => {
37
- if (emitter.off) {
38
- emitter.off(eventName, listener);
39
- }
40
- else if (emitter.removeListener) {
41
- emitter.removeListener(eventName, listener);
42
- }
43
- };
44
- };
45
- const attachHandlersToEmitter = (emitter, browserWindow, windowInstance, handlerNames, filter) => {
18
+ const attachHandlersToEmitter = (emitter, win, inst, names, filter) => {
46
19
  const cleanups = [];
47
- for (const handlerName of handlerNames) {
48
- if (!filter(handlerName)) {
20
+ for (const name of names) {
21
+ if (!filter(name))
49
22
  continue;
50
- }
51
- const handler = windowInstance[handlerName];
52
- if (typeof handler !== "function") {
23
+ const h = inst[name];
24
+ if (typeof h !== "function")
53
25
  continue;
54
- }
55
- const eventName = toEventName(handlerName);
26
+ const evt = toEventName(name);
56
27
  const listener = (...args) => {
57
- if (handler.length <= 1) {
58
- handler.apply(windowInstance, [browserWindow]);
59
- }
60
- else {
61
- handler.apply(windowInstance, [...args, browserWindow]);
62
- }
28
+ h.length <= 1 ? h.apply(inst, [win]) : h.apply(inst, [...args, win]);
63
29
  };
64
- cleanups.push(addListener(emitter, eventName, listener));
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
+ });
65
37
  }
66
38
  return cleanups;
67
39
  };
68
- export const attachWindowEventListeners = (browserWindow, windowInstance) => {
69
- const entry = windowListeners.get(browserWindow);
70
- if (entry?.instance === windowInstance) {
40
+ export const attachWindowEventListeners = (win, inst) => {
41
+ const entry = windowListeners.get(win);
42
+ if (entry?.instance === inst)
71
43
  return;
72
- }
73
- if (entry) {
74
- entry.cleanup.forEach((cleanup) => cleanup());
75
- }
76
- const handlerNames = getPrototypeMethodNames(windowInstance).filter(isHandlerName);
77
- const windowCleanups = attachHandlersToEmitter(browserWindow, browserWindow, windowInstance, handlerNames, (name) => !isWebContentsHandler(name));
78
- const webContentsCleanups = attachHandlersToEmitter(browserWindow.webContents, browserWindow, windowInstance, handlerNames, isWebContentsHandler);
79
- windowListeners.set(browserWindow, {
80
- instance: windowInstance,
81
- cleanup: [...windowCleanups, ...webContentsCleanups],
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],
82
53
  });
83
- browserWindow.once("closed", () => {
84
- const existing = windowListeners.get(browserWindow);
85
- if (existing) {
86
- existing.cleanup.forEach((cleanup) => cleanup());
87
- windowListeners.delete(browserWindow);
54
+ win.once("closed", () => {
55
+ const e = windowListeners.get(win);
56
+ if (e) {
57
+ e.cleanup.forEach((c) => c());
58
+ windowListeners.delete(win);
88
59
  }
89
60
  });
90
61
  };
@@ -22,10 +22,5 @@ export declare class Container {
22
22
  private instantiateClassProvider;
23
23
  private instantiateClassConstructor;
24
24
  private resolveDependencies;
25
- private isProviderObject;
26
- private isFactoryProvider;
27
- private isClassProvider;
28
- private isValueProvider;
29
- private isExistingProvider;
30
25
  }
31
26
  export declare const container: Container;
@@ -96,17 +96,25 @@ export class Container {
96
96
  return undefined;
97
97
  }
98
98
  async instantiateProvider(moduleClass, token, provider) {
99
- if (this.isFactoryProvider(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") {
100
105
  return this.instantiateFactoryProvider(moduleClass, token, provider);
101
106
  }
102
- if (this.isClassProvider(provider)) {
107
+ if (isObj &&
108
+ "useClass" in provider &&
109
+ typeof provider.useClass === "function") {
103
110
  return this.instantiateClassProvider(moduleClass, token, provider);
104
111
  }
105
- if (this.isValueProvider(provider)) {
106
- this.instances.set(token, provider.useValue);
107
- return provider.useValue;
112
+ if (isObj && "useValue" in provider) {
113
+ const val = provider.useValue;
114
+ this.instances.set(token, val);
115
+ return val;
108
116
  }
109
- if (this.isExistingProvider(provider)) {
117
+ if (isObj && "useExisting" in provider) {
110
118
  const instance = await this.resolve(moduleClass, provider.useExisting);
111
119
  if (instance !== undefined) {
112
120
  this.instances.set(token, instance);
@@ -142,24 +150,5 @@ export class Container {
142
150
  async resolveDependencies(moduleClass, dependencies) {
143
151
  return Promise.all(dependencies.map((dep) => this.resolve(moduleClass, dep)));
144
152
  }
145
- isProviderObject(provider) {
146
- return (typeof provider === "object" && provider !== null && "provide" in provider);
147
- }
148
- isFactoryProvider(provider) {
149
- return (this.isProviderObject(provider) &&
150
- "useFactory" in provider &&
151
- typeof provider.useFactory === "function");
152
- }
153
- isClassProvider(provider) {
154
- return (this.isProviderObject(provider) &&
155
- "useClass" in provider &&
156
- typeof provider.useClass === "function");
157
- }
158
- isValueProvider(provider) {
159
- return this.isProviderObject(provider) && "useValue" in provider;
160
- }
161
- isExistingProvider(provider) {
162
- return this.isProviderObject(provider) && "useExisting" in provider;
163
- }
164
153
  }
165
154
  export const container = new Container();
@@ -3,79 +3,61 @@ import path from "node:path";
3
3
  import { cacheWindows } from "./cache.js";
4
4
  import { getWindow } from "./receive.js";
5
5
  import { getSettings } from "../bootstrap/settings.js";
6
- const createContentSecurityPolicy = (baseRestApi, isDev) => {
7
- const csp = `
8
- default-src 'self';
9
- connect-src 'self' ${baseRestApi};
10
- img-src * data:;
11
- style-src 'self' 'unsafe-inline';
12
- script-src 'self' ${isDev ? "'unsafe-inline'" : ""};
13
- `
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'" : ""};`
14
8
  .replace(/\s{2,}/g, " ")
15
9
  .trim();
16
- return csp;
17
- };
18
- const setupContentSecurityPolicy = (baseRestApi, isDev) => {
19
- const csp = createContentSecurityPolicy(baseRestApi, isDev);
20
- session.defaultSession.webRequest.onHeadersReceived((details, callback) => {
21
- callback({
10
+ session.defaultSession.webRequest.onHeadersReceived((d, cb) => {
11
+ cb({
22
12
  responseHeaders: {
23
- ...details.responseHeaders,
13
+ ...d.responseHeaders,
24
14
  "Content-Security-Policy": [csp],
25
15
  },
26
16
  });
27
17
  });
28
18
  };
29
- const getAppPaths = (settings, isDev) => {
30
- return {
31
- ui: path.join(app.getAppPath(), `/${settings.folders.distRenderer}/index.html`),
32
- preload: path.join(app.getAppPath(), isDev ? "." : "..", `/${settings.folders.distMain}/preload.cjs`),
33
- };
34
- };
35
19
  export const createWindow = ({ hash, options, isCache, loadURL, }) => {
36
20
  const settings = getSettings();
37
21
  const isDev = process.env.NODE_ENV === "development";
38
- const { ui: uiPath, preload: preloadPath } = getAppPaths(settings, isDev);
39
- if (!settings.baseRestApi) {
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)
40
25
  console.warn('Warning: You have to add an environment variable called "process.env.BASE_REST_API"!');
41
- }
42
- if (!settings.localhostPort) {
26
+ if (!settings.localhostPort)
43
27
  console.warn('Warning: You have to add an environment variable called "process.env.LOCALHOST_ELECTRON_SERVER_PORT"!');
44
- }
45
28
  if (hash && isCache) {
46
- const existingWindow = getWindow(hash);
47
- if (existingWindow) {
48
- existingWindow.show();
49
- return existingWindow;
29
+ const existing = getWindow(hash);
30
+ if (existing) {
31
+ existing.show();
32
+ return existing;
50
33
  }
51
34
  }
52
- const newWindow = new BrowserWindow({
35
+ const win = new BrowserWindow({
53
36
  ...options,
54
37
  webPreferences: {
55
- preload: preloadPath,
38
+ preload,
56
39
  contextIsolation: true,
57
40
  nodeIntegration: false,
58
41
  ...options?.webPreferences,
59
42
  },
60
43
  });
61
- if (isCache && !loadURL) {
62
- setupContentSecurityPolicy(settings.baseRestApi, isDev);
63
- }
44
+ if (isCache && !loadURL)
45
+ setupCSP(settings.baseRestApi, isDev);
64
46
  if (loadURL) {
65
- newWindow.loadURL(loadURL);
47
+ win.loadURL(loadURL);
66
48
  }
67
49
  else if (isDev) {
68
- newWindow.loadURL(`http://localhost:${settings.localhostPort}${hash ? `#${hash}` : ""}`);
50
+ win.loadURL(`http://localhost:${settings.localhostPort}${hash ? `#${hash}` : ""}`);
69
51
  }
70
52
  else if (hash) {
71
- newWindow.loadFile(uiPath, { hash });
53
+ win.loadFile(ui, { hash });
72
54
  }
73
55
  if (hash && isCache) {
74
- cacheWindows.set(hash, newWindow);
75
- newWindow.on("close", (event) => {
76
- event.preventDefault();
77
- newWindow.hide();
56
+ cacheWindows.set(hash, win);
57
+ win.on("close", (e) => {
58
+ e.preventDefault();
59
+ win.hide();
78
60
  });
79
61
  }
80
- return newWindow;
62
+ return win;
81
63
  };
@@ -1,15 +1,19 @@
1
- export declare class ModuleNotRegisteredError extends Error {
2
- constructor(moduleName: string);
1
+ declare class BaseError extends Error {
2
+ constructor(msg: string, name: string);
3
3
  }
4
- export declare class ProviderNotFoundError extends Error {
5
- constructor(token: string, moduleName: string);
4
+ export declare class ModuleNotRegisteredError extends BaseError {
5
+ constructor(m: string);
6
6
  }
7
- export declare class ModuleDecoratorMissingError extends Error {
8
- constructor(moduleName: string);
7
+ export declare class ProviderNotFoundError extends BaseError {
8
+ constructor(t: string, m: string);
9
9
  }
10
- export declare class InvalidProviderError extends Error {
11
- constructor(moduleName: string);
10
+ export declare class ModuleDecoratorMissingError extends BaseError {
11
+ constructor(m: string);
12
12
  }
13
- export declare class SettingsNotInitializedError extends Error {
13
+ export declare class InvalidProviderError extends BaseError {
14
+ constructor(m: string);
15
+ }
16
+ export declare class SettingsNotInitializedError extends BaseError {
14
17
  constructor();
15
18
  }
19
+ export {};
@@ -1,30 +1,31 @@
1
- export class ModuleNotRegisteredError extends Error {
2
- constructor(moduleName) {
3
- super(`Module "${moduleName}" is not registered in the container.`);
4
- this.name = "ModuleNotRegisteredError";
1
+ class BaseError extends Error {
2
+ constructor(msg, name) {
3
+ super(msg);
4
+ this.name = name;
5
5
  }
6
6
  }
7
- export class ProviderNotFoundError extends Error {
8
- constructor(token, moduleName) {
9
- super(`Provider not found for token "${token}" in module "${moduleName}" or its imports.`);
10
- this.name = "ProviderNotFoundError";
7
+ export class ModuleNotRegisteredError extends BaseError {
8
+ constructor(m) {
9
+ super(`Module "${m}" is not registered in the container.`, "ModuleNotRegisteredError");
11
10
  }
12
11
  }
13
- export class ModuleDecoratorMissingError extends Error {
14
- constructor(moduleName) {
15
- super(`Module ${moduleName} does not have the @RgModule decorator`);
16
- this.name = "ModuleDecoratorMissingError";
12
+ export class ProviderNotFoundError extends BaseError {
13
+ constructor(t, m) {
14
+ super(`Provider not found for token "${t}" in module "${m}" or its imports.`, "ProviderNotFoundError");
17
15
  }
18
16
  }
19
- export class InvalidProviderError extends Error {
20
- constructor(moduleName) {
21
- super(`Invalid provider definition registered in module ${moduleName}`);
22
- this.name = "InvalidProviderError";
17
+ export class ModuleDecoratorMissingError extends BaseError {
18
+ constructor(m) {
19
+ super(`Module ${m} does not have the @RgModule decorator`, "ModuleDecoratorMissingError");
23
20
  }
24
21
  }
25
- export class SettingsNotInitializedError extends Error {
22
+ export class InvalidProviderError extends BaseError {
23
+ constructor(m) {
24
+ super(`Invalid provider definition registered in module ${m}`, "InvalidProviderError");
25
+ }
26
+ }
27
+ export class SettingsNotInitializedError extends BaseError {
26
28
  constructor() {
27
- super("App settings cache has not been initialized.");
28
- this.name = "SettingsNotInitializedError";
29
+ super("App settings cache has not been initialized.", "SettingsNotInitializedError");
29
30
  }
30
31
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@_traeop_/electron-modular",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "Core module system, DI container, IPC handlers, and window utilities for Electron main process.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",