@_traeop_/electron-modular 1.0.5

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.
Files changed (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +675 -0
  3. package/dist/@core/bootstrap/bootstrap.d.ts +3 -0
  4. package/dist/@core/bootstrap/bootstrap.d.ts.map +1 -0
  5. package/dist/@core/bootstrap/bootstrap.js +21 -0
  6. package/dist/@core/bootstrap/bootstrap.js.map +1 -0
  7. package/dist/@core/bootstrap/initialize-ipc/handlers.d.ts +4 -0
  8. package/dist/@core/bootstrap/initialize-ipc/handlers.d.ts.map +1 -0
  9. package/dist/@core/bootstrap/initialize-ipc/handlers.js +48 -0
  10. package/dist/@core/bootstrap/initialize-ipc/handlers.js.map +1 -0
  11. package/dist/@core/bootstrap/initialize-ipc/window-creator.d.ts +4 -0
  12. package/dist/@core/bootstrap/initialize-ipc/window-creator.d.ts.map +1 -0
  13. package/dist/@core/bootstrap/initialize-ipc/window-creator.js +29 -0
  14. package/dist/@core/bootstrap/initialize-ipc/window-creator.js.map +1 -0
  15. package/dist/@core/bootstrap/initialize-ipc/window-event-listeners.d.ts +4 -0
  16. package/dist/@core/bootstrap/initialize-ipc/window-event-listeners.d.ts.map +1 -0
  17. package/dist/@core/bootstrap/initialize-ipc/window-event-listeners.js +91 -0
  18. package/dist/@core/bootstrap/initialize-ipc/window-event-listeners.js.map +1 -0
  19. package/dist/@core/bootstrap/initialize-ipc/window-instance-creator.d.ts +4 -0
  20. package/dist/@core/bootstrap/initialize-ipc/window-instance-creator.d.ts.map +1 -0
  21. package/dist/@core/bootstrap/initialize-ipc/window-instance-creator.js +11 -0
  22. package/dist/@core/bootstrap/initialize-ipc/window-instance-creator.js.map +1 -0
  23. package/dist/@core/bootstrap/initialize-module.d.ts +4 -0
  24. package/dist/@core/bootstrap/initialize-module.d.ts.map +1 -0
  25. package/dist/@core/bootstrap/initialize-module.js +19 -0
  26. package/dist/@core/bootstrap/initialize-module.js.map +1 -0
  27. package/dist/@core/bootstrap/instantiate-module.d.ts +3 -0
  28. package/dist/@core/bootstrap/instantiate-module.d.ts.map +1 -0
  29. package/dist/@core/bootstrap/instantiate-module.js +10 -0
  30. package/dist/@core/bootstrap/instantiate-module.js.map +1 -0
  31. package/dist/@core/bootstrap/register-imports.d.ts +3 -0
  32. package/dist/@core/bootstrap/register-imports.d.ts.map +1 -0
  33. package/dist/@core/bootstrap/register-imports.js +13 -0
  34. package/dist/@core/bootstrap/register-imports.js.map +1 -0
  35. package/dist/@core/bootstrap/register-ipc-handlers.d.ts +4 -0
  36. package/dist/@core/bootstrap/register-ipc-handlers.d.ts.map +1 -0
  37. package/dist/@core/bootstrap/register-ipc-handlers.js +10 -0
  38. package/dist/@core/bootstrap/register-ipc-handlers.js.map +1 -0
  39. package/dist/@core/bootstrap/register-providers.d.ts +4 -0
  40. package/dist/@core/bootstrap/register-providers.d.ts.map +1 -0
  41. package/dist/@core/bootstrap/register-providers.js +22 -0
  42. package/dist/@core/bootstrap/register-providers.js.map +1 -0
  43. package/dist/@core/bootstrap/register-windows.d.ts +4 -0
  44. package/dist/@core/bootstrap/register-windows.d.ts.map +1 -0
  45. package/dist/@core/bootstrap/register-windows.js +16 -0
  46. package/dist/@core/bootstrap/register-windows.js.map +1 -0
  47. package/dist/@core/bootstrap/settings.d.ts +12 -0
  48. package/dist/@core/bootstrap/settings.d.ts.map +1 -0
  49. package/dist/@core/bootstrap/settings.js +14 -0
  50. package/dist/@core/bootstrap/settings.js.map +1 -0
  51. package/dist/@core/container.d.ts +32 -0
  52. package/dist/@core/container.d.ts.map +1 -0
  53. package/dist/@core/container.js +166 -0
  54. package/dist/@core/container.js.map +1 -0
  55. package/dist/@core/control-window/cache.d.ts +2 -0
  56. package/dist/@core/control-window/cache.d.ts.map +1 -0
  57. package/dist/@core/control-window/cache.js +2 -0
  58. package/dist/@core/control-window/cache.js.map +1 -0
  59. package/dist/@core/control-window/create.d.ts +4 -0
  60. package/dist/@core/control-window/create.d.ts.map +1 -0
  61. package/dist/@core/control-window/create.js +82 -0
  62. package/dist/@core/control-window/create.js.map +1 -0
  63. package/dist/@core/control-window/destroy.d.ts +2 -0
  64. package/dist/@core/control-window/destroy.d.ts.map +1 -0
  65. package/dist/@core/control-window/destroy.js +10 -0
  66. package/dist/@core/control-window/destroy.js.map +1 -0
  67. package/dist/@core/control-window/receive.d.ts +3 -0
  68. package/dist/@core/control-window/receive.d.ts.map +1 -0
  69. package/dist/@core/control-window/receive.js +9 -0
  70. package/dist/@core/control-window/receive.js.map +1 -0
  71. package/dist/@core/control-window/types.d.ts +15 -0
  72. package/dist/@core/control-window/types.d.ts.map +1 -0
  73. package/dist/@core/control-window/types.js +2 -0
  74. package/dist/@core/control-window/types.js.map +1 -0
  75. package/dist/@core/decorators/inject.d.ts +7 -0
  76. package/dist/@core/decorators/inject.d.ts.map +1 -0
  77. package/dist/@core/decorators/inject.js +16 -0
  78. package/dist/@core/decorators/inject.js.map +1 -0
  79. package/dist/@core/decorators/injectable.d.ts +3 -0
  80. package/dist/@core/decorators/injectable.d.ts.map +1 -0
  81. package/dist/@core/decorators/injectable.js +7 -0
  82. package/dist/@core/decorators/injectable.js.map +1 -0
  83. package/dist/@core/decorators/ipc-handler.d.ts +3 -0
  84. package/dist/@core/decorators/ipc-handler.d.ts.map +1 -0
  85. package/dist/@core/decorators/ipc-handler.js +7 -0
  86. package/dist/@core/decorators/ipc-handler.js.map +1 -0
  87. package/dist/@core/decorators/rg-module.d.ts +4 -0
  88. package/dist/@core/decorators/rg-module.d.ts.map +1 -0
  89. package/dist/@core/decorators/rg-module.js +7 -0
  90. package/dist/@core/decorators/rg-module.js.map +1 -0
  91. package/dist/@core/decorators/window-manager.d.ts +4 -0
  92. package/dist/@core/decorators/window-manager.d.ts.map +1 -0
  93. package/dist/@core/decorators/window-manager.js +7 -0
  94. package/dist/@core/decorators/window-manager.js.map +1 -0
  95. package/dist/@core/errors/index.d.ts +16 -0
  96. package/dist/@core/errors/index.d.ts.map +1 -0
  97. package/dist/@core/errors/index.js +31 -0
  98. package/dist/@core/errors/index.js.map +1 -0
  99. package/dist/@core/types/constructor.d.ts +2 -0
  100. package/dist/@core/types/constructor.d.ts.map +1 -0
  101. package/dist/@core/types/constructor.js +2 -0
  102. package/dist/@core/types/constructor.js.map +1 -0
  103. package/dist/@core/types/index.d.ts +8 -0
  104. package/dist/@core/types/index.d.ts.map +1 -0
  105. package/dist/@core/types/index.js +2 -0
  106. package/dist/@core/types/index.js.map +1 -0
  107. package/dist/@core/types/ipc-handler.d.ts +8 -0
  108. package/dist/@core/types/ipc-handler.d.ts.map +1 -0
  109. package/dist/@core/types/ipc-handler.js +2 -0
  110. package/dist/@core/types/ipc-handler.js.map +1 -0
  111. package/dist/@core/types/module-metadata.d.ts +11 -0
  112. package/dist/@core/types/module-metadata.d.ts.map +1 -0
  113. package/dist/@core/types/module-metadata.js +2 -0
  114. package/dist/@core/types/module-metadata.js.map +1 -0
  115. package/dist/@core/types/provider.d.ts +22 -0
  116. package/dist/@core/types/provider.d.ts.map +1 -0
  117. package/dist/@core/types/provider.js +2 -0
  118. package/dist/@core/types/provider.js.map +1 -0
  119. package/dist/@core/types/window-factory.d.ts +7 -0
  120. package/dist/@core/types/window-factory.d.ts.map +1 -0
  121. package/dist/@core/types/window-factory.js +2 -0
  122. package/dist/@core/types/window-factory.js.map +1 -0
  123. package/dist/@core/types/window-manager.d.ts +11 -0
  124. package/dist/@core/types/window-manager.d.ts.map +1 -0
  125. package/dist/@core/types/window-manager.js +2 -0
  126. package/dist/@core/types/window-manager.js.map +1 -0
  127. package/dist/@core/types/window-metadata.d.ts +7 -0
  128. package/dist/@core/types/window-metadata.d.ts.map +1 -0
  129. package/dist/@core/types/window-metadata.js +2 -0
  130. package/dist/@core/types/window-metadata.js.map +1 -0
  131. package/dist/@core/utils/dependency-tokens.d.ts +5 -0
  132. package/dist/@core/utils/dependency-tokens.d.ts.map +1 -0
  133. package/dist/@core/utils/dependency-tokens.js +24 -0
  134. package/dist/@core/utils/dependency-tokens.js.map +1 -0
  135. package/dist/config.d.ts +5 -0
  136. package/dist/config.d.ts.map +1 -0
  137. package/dist/config.js +5 -0
  138. package/dist/config.js.map +1 -0
  139. package/dist/index.d.ts +27 -0
  140. package/dist/index.d.ts.map +1 -0
  141. package/dist/index.js +35 -0
  142. package/dist/index.js.map +1 -0
  143. package/package.json +53 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,675 @@
1
+ # Package Documentation
2
+
3
+ ## Overview
4
+
5
+ `@traeop/electron-modular` is a dependency injection framework for Electron main process. It uses TypeScript decorators to manage services, IPC handlers, and windows.
6
+
7
+ ### Key Features
8
+
9
+ - **Dependency Injection** - Automatic service instantiation and injection
10
+ - **Module System** - Organize code into feature modules
11
+ - **TypeScript Decorators** - `@RgModule`, `@Injectable`, `@IpcHandler`, `@WindowManager`
12
+ - **Provider Pattern** - Share only necessary interfaces between modules
13
+ - **Type Safety** - Full TypeScript support
14
+
15
+ ---
16
+
17
+ ## Quick Start
18
+
19
+ ### 1. Bootstrap Application `app.ts`
20
+
21
+ Initialize the framework and bootstrap all modules:
22
+
23
+ ```typescript
24
+ import { app } from "electron";
25
+ import { initSettings, bootstrapModules } from "@traeop/electron-modular";
26
+ import { UserModule } from "./user/module.js";
27
+ import { ResourcesModule } from "./resources/module.js";
28
+
29
+ initSettings({
30
+ baseRestApi: process.env.BASE_REST_API ?? "",
31
+ localhostPort: process.env.LOCALHOST_ELECTRON_SERVER_PORT ?? "",
32
+ folders: {
33
+ distRenderer: "dist-renderer",
34
+ distMain: "dist-main",
35
+ },
36
+ });
37
+
38
+ app.on("ready", async () => {
39
+ await bootstrapModules([
40
+ UserModule,
41
+ ResourcesModule,
42
+ // ... other modules
43
+ ]);
44
+ });
45
+ ```
46
+
47
+ ---
48
+
49
+ ## Module Structure
50
+
51
+ An example of each module's structure, but you can use your own:
52
+
53
+ ```
54
+ user/
55
+ ├── module.ts # Module definition
56
+ ├── service.ts # Business logic or several services in the folder
57
+ ├── ipc.ts # IPC handlers (optional) or several ipc in the folder
58
+ ├── window.ts # Window manager (optional) or several windows in the folder
59
+ ├── tokens.ts # DI tokens (optional)
60
+ └── types.ts # Type definitions (optional)
61
+ ```
62
+
63
+ ---
64
+
65
+ ## Two Approaches to Using Modules
66
+
67
+ ### Approach 1: Direct Service Injection (Simple)
68
+
69
+ Import a module and directly inject its exported service.
70
+
71
+ #### Module Definition `user/module.ts`
72
+
73
+ ```typescript
74
+ import { RgModule } from "@traeop/electron-modular";
75
+ import { RestApiModule } from "../rest-api/module.js";
76
+ import { UserService } from "./service.js";
77
+ import { UserIpc } from "./ipc.js";
78
+
79
+ @RgModule({
80
+ imports: [RestApiModule],
81
+ ipc: [UserIpc],
82
+ providers: [UserService],
83
+ exports: [UserService],
84
+ })
85
+ export class UserModule {}
86
+ ```
87
+
88
+ #### Service Implementation `user/service.ts`
89
+
90
+ ```typescript
91
+ import { Injectable } from "@traeop/electron-modular";
92
+ import { RestApiService } from "../rest-api/service.js";
93
+
94
+ @Injectable()
95
+ export class UserService {
96
+ constructor(private restApiService: RestApiService) {}
97
+
98
+ async byId<R extends TUser>(id: string): Promise<R | undefined> {
99
+ const response = await this.restApiService.get<R>(
100
+ `https://example.com/api/users/${id}`,
101
+ );
102
+
103
+ if (response.error !== undefined) {
104
+ return;
105
+ }
106
+
107
+ return response.data;
108
+ }
109
+ }
110
+ ```
111
+
112
+ **When to use:**
113
+
114
+ - Simple dependencies
115
+ - You need the full service functionality
116
+ - No circular dependency issues
117
+
118
+ ---
119
+
120
+ ### Approach 2: Provider Pattern (Advanced)
121
+
122
+ Use `provide` and `useFactory` to expose only necessary interface.
123
+
124
+ #### tokens.ts
125
+
126
+ ```typescript
127
+ export const USER_REST_API_PROVIDER = Symbol("USER_REST_API_PROVIDER");
128
+ ```
129
+
130
+ #### types.ts
131
+
132
+ ```typescript
133
+ export type TUserRestApiProvider = {
134
+ get: <T>(
135
+ endpoint: string,
136
+ options?: AxiosRequestConfig,
137
+ ) => Promise<TResponse<T>>;
138
+ post: <T>(
139
+ endpoint: string,
140
+ data: unknown,
141
+ options?: AxiosRequestConfig,
142
+ ) => Promise<TResponse<T>>;
143
+ };
144
+ ```
145
+
146
+ #### Module Definition `user/module.ts`
147
+
148
+ ```typescript
149
+ import { RgModule } from "@traeop/electron-modular";
150
+ import { RestApiModule } from "../rest-api/module.js";
151
+ import { RestApiService } from "../rest-api/service.js";
152
+ import { UserService } from "./service.js";
153
+ import { UserIpc } from "./ipc.js";
154
+ import { USER_REST_API_PROVIDER } from "./tokens.js";
155
+ import type { TUserRestApiProvider } from "./types.js";
156
+
157
+ @RgModule({
158
+ imports: [RestApiModule],
159
+ ipc: [UserIpc],
160
+ providers: [
161
+ UserService,
162
+ {
163
+ provide: USER_REST_API_PROVIDER,
164
+ useFactory: (restApiService: RestApiService): TUserRestApiProvider => ({
165
+ get: (endpoint, options) => restApiService.get(endpoint, options),
166
+ post: (endpoint, data, options) =>
167
+ restApiService.post(endpoint, data, options),
168
+ }),
169
+ inject: [RestApiService],
170
+ },
171
+ ],
172
+ exports: [UserService],
173
+ })
174
+ export class UserModule {}
175
+ ```
176
+
177
+ #### Service Implementation `user/service.ts`
178
+
179
+ ```typescript
180
+ @Injectable()
181
+ export class UserService {
182
+ constructor(
183
+ @Inject(USER_REST_API_PROVIDER)
184
+ private restApiProvider: TUserRestApiProvider,
185
+ ) {}
186
+
187
+ async byId<R extends TUser>(id: string): Promise<R | undefined> {
188
+ const response = await this.restApiProvider.get<R>(
189
+ `https://example.com/api/users/${id}`,
190
+ );
191
+
192
+ if (response.error !== undefined) {
193
+ return;
194
+ }
195
+
196
+ return response.data;
197
+ }
198
+ }
199
+ ```
200
+
201
+ **When to use:**
202
+
203
+ - Need to expose limited interface
204
+ - Prevent circular dependencies
205
+ - Multiple implementations possible
206
+ - Better encapsulation
207
+
208
+ ---
209
+
210
+ ## IPC Handlers
211
+
212
+ Handle communication between main and renderer processes.
213
+
214
+ ```typescript
215
+ import {
216
+ IpcHandler,
217
+ TIpcHandlerInterface,
218
+ TParamOnInit,
219
+ } from "@traeop/electron-modular";
220
+ import { UserService } from "./service.js";
221
+
222
+ @IpcHandler()
223
+ export class UserIpc implements TIpcHandlerInterface {
224
+ constructor(private userService: UserService) {}
225
+
226
+ async onInit({ getWindow }: TParamOnInit<TWindows["main"]>) {
227
+ const mainWindow = getWindow("window:main");
228
+
229
+ ipcMainOn("user:fetch", async (event, userId: string) => {
230
+ const user = await this.userService.byId(userId);
231
+ event.reply("user:fetch:response", user);
232
+ });
233
+ }
234
+ }
235
+ ```
236
+
237
+ ---
238
+
239
+ ## Window Managers
240
+
241
+ Manage BrowserWindow lifecycle and configuration.
242
+
243
+ ```typescript
244
+ import { WindowManager } from "@traeop/electron-modular";
245
+ import type { TWindowManager } from "../types.js";
246
+
247
+ @WindowManager<TWindows["userProfile"]>({
248
+ hash: "window:user-profile",
249
+ isCache: true,
250
+ options: {
251
+ width: 600,
252
+ height: 400,
253
+ resizable: false,
254
+ },
255
+ })
256
+ export class UserWindow implements TWindowManager {
257
+ constructor(private userService: UserService) {}
258
+
259
+ onWebContentsDidFinishLoad(window: BrowserWindow): void {
260
+ // Initialize when window content loads
261
+ this.loadUserData(window);
262
+ }
263
+
264
+ private async loadUserData(window: BrowserWindow): Promise<void> {
265
+ const user = await this.userService.getCurrentUser();
266
+ window.webContents.send("user:loaded", user);
267
+ }
268
+ }
269
+ ```
270
+
271
+ ### Lifecycle Hooks (Window & WebContents events) ✅
272
+
273
+ The window manager supports lifecycle hooks by naming methods on your class following a simple convention:
274
+
275
+ - Use `on<ClassicEvent>` for BrowserWindow events (e.g. `onFocus`, `onMaximize`).
276
+ - Use `onWebContents<Thing>` for WebContents events (e.g. `onWebContentsDidFinishLoad`, `onWebContentsWillNavigate`).
277
+
278
+ How method names map to Electron events:
279
+
280
+ - The framework removes the `on` or `onWebContents` prefix, converts the remaining CamelCase to kebab-case and uses that as the event name.
281
+ - `onFocus` → `focus`
282
+ - `onMaximize` → `maximize`
283
+ - `onWebContentsDidFinishLoad` → `did-finish-load`
284
+ - `onWebContentsWillNavigate` → `will-navigate`
285
+
286
+ Handler signatures and parameters 🔧
287
+
288
+ - If your method declares 0 or 1 parameter (i.e. `handler.length <= 1`) it will be called with the `BrowserWindow` instance only:
289
+
290
+ ```ts
291
+ onFocus(window: BrowserWindow): void {
292
+ // Called when window receives focus
293
+ window.webContents.send("window:focused");
294
+ }
295
+ ```
296
+
297
+ - If your method declares more than 1 parameter, the original Electron event arguments are forwarded first and the `BrowserWindow` is appended as the last argument. This is useful for WebContents or events that include event objects and additional data:
298
+
299
+ ```ts
300
+ onWebContentsWillNavigate(ev: Electron.Event, url: string, window: BrowserWindow) {
301
+ // ev and url come from webContents, window is appended by the framework
302
+ console.log("navigating to", url);
303
+ }
304
+ ```
305
+
306
+ Common BrowserWindow events you can handle:
307
+
308
+ - `onFocus`, `onBlur`, `onMaximize`, `onUnmaximize`, `onMinimize`, `onRestore`, `onResize`, `onMove`, `onClose`, `onClosed`
309
+
310
+ Common WebContents events you can handle:
311
+
312
+ - `onWebContentsDidFinishLoad`, `onWebContentsDidFailLoad`, `onWebContentsDomReady`, `onWebContentsWillNavigate`, `onWebContentsDidNavigate`, `onWebContentsNewWindow`, `onWebContentsDestroyed`
313
+
314
+ Important implementation notes ⚠️
315
+
316
+ - Handlers are attached per BrowserWindow instance and cleaned up automatically when the window is closed, so you don't have to manually remove listeners.
317
+ - The same instance and set of handlers are tracked in a WeakMap internally; re-attaching the same `windowInstance` will not duplicate listeners.
318
+
319
+ ---
320
+
321
+ ## TypeScript types — `TWindows["myWindow"]`
322
+
323
+ `TWindows` maps window keys to their unique hash strings. Use `TWindows["<key>"]` for typing windows in `@WindowManager` and `getWindow`.
324
+
325
+ ```typescript
326
+ // types/windows.d.ts
327
+ type TWindows = {
328
+ main: "window:main";
329
+ updateResource: "window/resource/update";
330
+ };
331
+ ```
332
+
333
+ Examples:
334
+
335
+ ```typescript
336
+ // Using as generic for WindowManager
337
+ @WindowManager<TWindows["main"]>({
338
+ hash: "window:main",
339
+ isCache: true,
340
+ options: {},
341
+ })
342
+ export class AppWindow implements TWindowManager {}
343
+
344
+ // Using with getWindow()
345
+ const mainWindow = getWindow<TWindows["main"]>("window:main");
346
+ ```
347
+
348
+ ---
349
+
350
+ ## API Reference
351
+
352
+ ### Core Decorators
353
+
354
+ #### `@RgModule(config)`
355
+
356
+ Defines a module with its dependencies and providers.
357
+
358
+ **Parameters:**
359
+
360
+ - `imports?: Class[]` - Modules to import
361
+ - `providers?: Provider[]` - Services and factories
362
+ - `ipc?: Class[]` - IPC handler classes
363
+ - `windows?: Class[]` - Window manager classes
364
+ - `exports?: Class[]` - Providers to export
365
+
366
+ #### `@Injectable()`
367
+
368
+ Marks a class as injectable into the DI container.
369
+
370
+ ```typescript
371
+ @Injectable()
372
+ export class MyService {
373
+ constructor(private dependency: OtherService) {}
374
+ }
375
+ ```
376
+
377
+ #### `@Inject(token)`
378
+
379
+ Injects a dependency by token (Symbol).
380
+
381
+ ```typescript
382
+ constructor(
383
+ @Inject(MY_PROVIDER) private provider: TMyProvider
384
+ ) {}
385
+ ```
386
+
387
+ #### `@IpcHandler()`
388
+
389
+ Marks a class as an IPC communication handler.
390
+
391
+ ```typescript
392
+ @IpcHandler()
393
+ export class MyIpc implements TIpcHandlerInterface {
394
+ async onInit({ getWindow }: TParamOnInit) {
395
+ // Setup IPC listeners
396
+ }
397
+ }
398
+ ```
399
+
400
+ #### `@WindowManager<T>(config)`
401
+
402
+ Defines a BrowserWindow manager.
403
+
404
+ **Parameters:**
405
+
406
+ - `hash: string` - Unique window identifier
407
+ - `isCache?: boolean` - Cache window instance
408
+ - `options: BrowserWindowConstructorOptions` - Electron window options
409
+
410
+ ```typescript
411
+ @WindowManager<TWindows["myWindow"]>({
412
+ hash: "window:my-window",
413
+ isCache: true,
414
+ options: { width: 800, height: 600 },
415
+ })
416
+ export class MyWindow implements TWindowManager {
417
+ onWebContentsDidFinishLoad(window: BrowserWindow): void {
418
+ // Lifecycle hook
419
+ }
420
+ }
421
+ ```
422
+
423
+ ### Core Functions
424
+
425
+ #### `initSettings(config)`
426
+
427
+ Initializes framework configuration.
428
+
429
+ **Parameters:**
430
+
431
+ - `baseRestApi: string` - Base REST API URL
432
+ - `localhostPort: string` - Development server port
433
+ - `folders: { distRenderer: string; distMain: string }` - Build output folders
434
+
435
+ ```typescript
436
+ initSettings({
437
+ baseRestApi: process.env.BASE_REST_API ?? "",
438
+ localhostPort: process.env.LOCALHOST_ELECTRON_SERVER_PORT ?? "",
439
+ folders: {
440
+ distRenderer: "dist-renderer",
441
+ distMain: "dist-main",
442
+ },
443
+ });
444
+ ```
445
+
446
+ #### `bootstrapModules(modules[])`
447
+
448
+ Bootstraps all modules and initializes the DI container.
449
+
450
+ ```typescript
451
+ await bootstrapModules([AppModule, AuthModule, ResourcesModule]);
452
+ ```
453
+
454
+ #### `getWindow<T>(hash)`
455
+
456
+ Retrieves a window instance by its hash identifier.
457
+
458
+ ```typescript
459
+ const mainWindow = getWindow<TWindows["main"]>("window:main");
460
+ const window = await mainWindow.create();
461
+ ```
462
+
463
+ #### `destroyWindows()`
464
+
465
+ Destroys all cached windows.
466
+
467
+ ```typescript
468
+ app.on("before-quit", () => {
469
+ destroyWindows();
470
+ });
471
+ ```
472
+
473
+ ### Lifecycle Interfaces
474
+
475
+ #### `TIpcHandlerInterface`
476
+
477
+ Interface for IPC handlers.
478
+
479
+ ```typescript
480
+ export interface TIpcHandlerInterface {
481
+ onInit?(params: TParamOnInit): void | Promise<void>;
482
+ }
483
+ ```
484
+
485
+ #### `TWindowManager`
486
+
487
+ Interface for window managers.
488
+
489
+ ```typescript
490
+ export interface TWindowManager {
491
+ onWebContentsDidFinishLoad?(window: BrowserWindow): void;
492
+ }
493
+ ```
494
+
495
+ ---
496
+
497
+ ## Module Structure
498
+
499
+ Recommended file organization for a feature module:
500
+
501
+ ```
502
+ my-feature/
503
+ ├── module.ts # Module definition with @RgModule
504
+ ├── service.ts # Main business logic service
505
+ ├── ipc.ts # IPC communication handlers
506
+ ├── window.ts # BrowserWindow manager
507
+ ├── tokens.ts # Dependency injection tokens
508
+ ├── types.ts # TypeScript type definitions
509
+ └── services/ # Additional services (optional)
510
+ ├── helper.ts
511
+ └── validator.ts
512
+ ```
513
+
514
+ ---
515
+
516
+ ## Best Practices
517
+
518
+ ### 1. Use Providers for Cross-Module Communication
519
+
520
+ ✅ **Good:**
521
+
522
+ ```typescript
523
+ {
524
+ provide: AUTH_PROVIDER,
525
+ useFactory: (authService: AuthService): TAuthProvider => ({
526
+ checkAuthenticated: (window) => authService.checkAuthenticated(window),
527
+ logout: (window) => authService.logout(window),
528
+ }),
529
+ inject: [AuthService],
530
+ }
531
+ ```
532
+
533
+ ❌ **Bad:**
534
+
535
+ ```typescript
536
+ // Don't export entire service
537
+ exports: [AuthService];
538
+ ```
539
+
540
+ ### 2. Keep Services Focused
541
+
542
+ Each service should have a single responsibility.
543
+
544
+ ✅ **Good:**
545
+
546
+ ```typescript
547
+ @Injectable()
548
+ export class ResourcesService {
549
+ // Only handles resource data operations
550
+ }
551
+
552
+ @Injectable()
553
+ export class CacheWindowsService {
554
+ // Only handles window caching
555
+ }
556
+ ```
557
+
558
+ ### 3. Use Tokens for All Cross-Module Dependencies
559
+
560
+ ✅ **Good:**
561
+
562
+ ```typescript
563
+ export const RESOURCES_REST_API_PROVIDER = Symbol("RESOURCES_REST_API_PROVIDER");
564
+
565
+ constructor(
566
+ @Inject(RESOURCES_REST_API_PROVIDER) private restApiProvider
567
+ ) {}
568
+ ```
569
+
570
+ ### 4. Implement Lifecycle Hooks
571
+
572
+ Use lifecycle hooks for initialization logic.
573
+
574
+ ```typescript
575
+ @IpcHandler()
576
+ export class MyIpc implements TIpcHandlerInterface {
577
+ async onInit({ getWindow }: TParamOnInit) {
578
+ // Initialize IPC listeners
579
+ }
580
+ }
581
+
582
+ @WindowManager(config)
583
+ export class MyWindow implements TWindowManager {
584
+ onWebContentsDidFinishLoad(window: BrowserWindow): void {
585
+ // Initialize when content loads
586
+ }
587
+ }
588
+ ```
589
+
590
+ ### 5. Type Everything
591
+
592
+ Use TypeScript for all services, providers, and interfaces.
593
+ Decorators Reference
594
+
595
+ ### `@RgModule(config)`
596
+
597
+ Defines a module.
598
+
599
+ - `imports?: Class[]` - Modules to import
600
+ - `providers?: Provider[]` - Services and factories
601
+ - `ipc?: Class[]` - IPC handler classes
602
+ - `windows?: Class[]` - Window manager classes
603
+ - `exports?: Class[]` - Providers to export
604
+
605
+ ### `@Injectable()`
606
+
607
+ Makes a class injectable.
608
+
609
+ ```typescript
610
+ @Injectable()
611
+ export class MyService {}
612
+ ```
613
+
614
+ ### `@Inject(token)`
615
+
616
+ Injects a dependency by token.
617
+
618
+ ```typescript
619
+ constructor(@Inject(MY_PROVIDER) private provider: TMyProvider) {}
620
+ ```
621
+
622
+ ### `@IpcHandler()`
623
+
624
+ Marks a class as IPC handler.
625
+
626
+ ```typescript
627
+ @IpcHandler()
628
+ export class MyIpc implements TIpcHandlerInterface {}
629
+ ```
630
+
631
+ ### `@WindowManager<T>(config)`
632
+
633
+ Defines a window manager.
634
+
635
+ ```typescript
636
+ @WindowManager<TWindows["myWindow"]>({
637
+ hash: "window:my-window",
638
+ isCache: true,
639
+ options: { width: 800, height: 600 },
640
+ })
641
+ export class MyWindow implements TWindowManager {}
642
+ ```
643
+
644
+ ---
645
+
646
+ ## Key Functions
647
+
648
+ ### `initSettings(config)`
649
+
650
+ ```typescript
651
+ initSettings({
652
+ baseRestApi: process.env.BASE_REST_API ?? "",
653
+ localhostPort: process.env.LOCALHOST_ELECTRON_SERVER_PORT ?? "",
654
+ folders: { distRenderer: "dist-renderer", distMain: "dist-main" },
655
+ });
656
+ ```
657
+
658
+ ### `bootstrapModules(modules[])`
659
+
660
+ ```typescript
661
+ await bootstrapModules([AppModule, UserModule]);
662
+ ```
663
+
664
+ ### `getWindow<T>(hash)`
665
+
666
+ ```typescript
667
+ const mainWindow = getWindow<TWindows["main"]>("window:main");
668
+ const window = await mainWindow.create();
669
+ ```
670
+
671
+ ### `destroyWindows()`
672
+
673
+ ```typescript
674
+ app.on("before-quit", () => destroyWindows());
675
+ ```
@@ -0,0 +1,3 @@
1
+ import type { Constructor } from "../types/constructor.js";
2
+ export declare const bootstrapModules: (modulesClass: Constructor[]) => Promise<void>;
3
+ //# sourceMappingURL=bootstrap.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bootstrap.d.ts","sourceRoot":"","sources":["../../../src/@core/bootstrap/bootstrap.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAO3D,eAAO,MAAM,gBAAgB,GAC3B,cAAc,WAAW,EAAE,KAC1B,OAAO,CAAC,IAAI,CAsBd,CAAC"}
@@ -0,0 +1,21 @@
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
+ };
21
+ //# sourceMappingURL=bootstrap.js.map