electron-injector 1.0.2
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/README.md +285 -0
- package/dist/index.cjs +446 -0
- package/dist/index.d.cts +64 -0
- package/dist/index.d.ts +64 -0
- package/dist/index.js +401 -0
- package/package.json +64 -0
package/README.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# Librería Electron Injector
|
|
2
|
+
|
|
3
|
+
*electron-injector* es una librería diseñada para simplificar y robustecer el desarrollo de aplicaciones con Electron y TypeScript. Ofrece un sistema de Inyección de Dependencias (DI) e Inversión de Control (IoC) que promueve un código más mantenible, testeable y claro, mejorando tanto la experiencia del desarrollador como la calidad final del software.
|
|
4
|
+
|
|
5
|
+
Nace de la necesidad de crear aplicaciones de escritorio multiplataforma donde no solo importa la experiencia de usuario (UX), sino también una experiencia de desarrollo (DX) ágil y bien estructurada.
|
|
6
|
+
|
|
7
|
+
## ✨ Características
|
|
8
|
+
✅ Sistema de Inyección de Dependencias completo con contenedor IoC
|
|
9
|
+
|
|
10
|
+
✅ Decoradores para IPC (@OnSend, @OnInvoke) inspirados en NestJS
|
|
11
|
+
|
|
12
|
+
✅ Gestión automática de handlers de Electron IPC
|
|
13
|
+
|
|
14
|
+
✅ Soporte para Guards (autorización y validación)
|
|
15
|
+
|
|
16
|
+
✅ Metadata reflection para parametrización avanzada
|
|
17
|
+
|
|
18
|
+
✅ Soporte para RxJS (Observables) en guards y handlers
|
|
19
|
+
|
|
20
|
+
✅ Control de ciclo de vida (singleton/transient)
|
|
21
|
+
|
|
22
|
+
✅ Sistema de logging diferenciado (desarrollo/producción)
|
|
23
|
+
|
|
24
|
+
✅ Detección de dependencias circulares
|
|
25
|
+
|
|
26
|
+
✅ Tipado TypeScript completo
|
|
27
|
+
|
|
28
|
+
## 📦 Instalación
|
|
29
|
+
```bash
|
|
30
|
+
npm install electron-injector rxjs
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
> **Nota:**
|
|
34
|
+
> Si estás usando Vite, también debes instalar `@swc/core` y configurar el plugin correspondiente en tu archivo de configuración de Vite:
|
|
35
|
+
>
|
|
36
|
+
> ```bash
|
|
37
|
+
> npm install @swc/core --save-dev
|
|
38
|
+
> ```
|
|
39
|
+
>
|
|
40
|
+
> Luego, agrega el plugin de SWC en tu `vite.config.js` o `vite.config.ts` según la documentación de Vite y el plugin que utilices.
|
|
41
|
+
|
|
42
|
+
## 1. Configuración Principal
|
|
43
|
+
```ts
|
|
44
|
+
// main.ts
|
|
45
|
+
import 'reflect-metadata';
|
|
46
|
+
import { app, BrowserWindow } from 'electron';
|
|
47
|
+
import { Application } from 'electron-injector';
|
|
48
|
+
import { UserController } from './controllers/user.controller';
|
|
49
|
+
import { AuthGuard } from './guards/auth.guard';
|
|
50
|
+
import { UserService } from './services/user.service';
|
|
51
|
+
|
|
52
|
+
async function bootstrap() {
|
|
53
|
+
const electronApp = new Application({
|
|
54
|
+
providers: [
|
|
55
|
+
UserService,
|
|
56
|
+
AuthGuard,
|
|
57
|
+
],
|
|
58
|
+
controllers: [
|
|
59
|
+
UserController,
|
|
60
|
+
],
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
await app.whenReady();
|
|
64
|
+
|
|
65
|
+
const mainWindow = new BrowserWindow({
|
|
66
|
+
width: 800,
|
|
67
|
+
height: 600,
|
|
68
|
+
webPreferences: {
|
|
69
|
+
nodeIntegration: false,
|
|
70
|
+
contextIsolation: true,
|
|
71
|
+
preload: path.join(__dirname, 'preload.js'),
|
|
72
|
+
},
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
mainWindow.loadFile('index.html');
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
bootstrap().catch(console.error);
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
## 2. Creando un servicio
|
|
82
|
+
```ts
|
|
83
|
+
// services/user.service.ts
|
|
84
|
+
import { Injectable } from 'electron-injector';
|
|
85
|
+
|
|
86
|
+
export interface User {
|
|
87
|
+
id: string;
|
|
88
|
+
name: string;
|
|
89
|
+
email: string;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
@Injectable() // Por defecto es singleton
|
|
93
|
+
export class UserService {
|
|
94
|
+
private users: User[] = [];
|
|
95
|
+
|
|
96
|
+
async createUser(user: Omit<User, 'id'>): Promise<User> {
|
|
97
|
+
const newUser = {
|
|
98
|
+
...user,
|
|
99
|
+
id: Date.now().toString(),
|
|
100
|
+
};
|
|
101
|
+
this.users.push(newUser);
|
|
102
|
+
return newUser;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
async findAll(): Promise<User[]> {
|
|
106
|
+
return [...this.users];
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
async findById(id: string): Promise<User | undefined> {
|
|
110
|
+
return this.users.find(user => user.id === id);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
```
|
|
114
|
+
## 3. Creando un controlador IPC
|
|
115
|
+
```ts
|
|
116
|
+
// controllers/user.controller.ts
|
|
117
|
+
import { Controller, OnInvoke, OnSend, Payload, Event } from 'electron-injector';
|
|
118
|
+
import { UserService } from '../services/user.service';
|
|
119
|
+
import { IpcMainEvent } from 'electron';
|
|
120
|
+
|
|
121
|
+
@Controller('user') // Prefijo para todos los handlers
|
|
122
|
+
export class UserController {
|
|
123
|
+
constructor(private userService: UserService) {}
|
|
124
|
+
|
|
125
|
+
// Handler para ipcMain.handle
|
|
126
|
+
@OnInvoke('create')
|
|
127
|
+
async createUser(@Payload() userData: any) {
|
|
128
|
+
return await this.userService.createUser(userData);
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Handler para ipcMain.on
|
|
132
|
+
@OnSend('updated')
|
|
133
|
+
onUserUpdated(@Payload() data: any, @Event() event: IpcMainEvent) {
|
|
134
|
+
console.log('User updated:', data);
|
|
135
|
+
// Puedes enviar respuestas o realizar otras acciones
|
|
136
|
+
return { success: true, timestamp: Date.now() };
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Handler con nombre del método como path
|
|
140
|
+
@OnInvoke()
|
|
141
|
+
async findAll() {
|
|
142
|
+
return await this.userService.findAll();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## 4. Creando un Guard
|
|
148
|
+
```ts
|
|
149
|
+
// guards/auth.guard.ts
|
|
150
|
+
import { Injectable, CanActivate, ExecutionContext } from 'electron-injector';
|
|
151
|
+
import { Observable, of } from 'rxjs';
|
|
152
|
+
import { delay } from 'rxjs/operators';
|
|
153
|
+
|
|
154
|
+
@Injectable()
|
|
155
|
+
export class AuthGuard implements CanActivate {
|
|
156
|
+
async canActivate(context: ExecutionContext): Promise<boolean> {
|
|
157
|
+
const payload = context.payload;
|
|
158
|
+
const event = context.event;
|
|
159
|
+
|
|
160
|
+
// Lógica de autorización aquí
|
|
161
|
+
const token = payload?.token || event.sender.session.cookies.get({ name: 'auth_token' });
|
|
162
|
+
|
|
163
|
+
return !!token; // Ejemplo simple
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Guard con RxJS
|
|
168
|
+
@Injectable()
|
|
169
|
+
export class AsyncGuard implements CanActivate {
|
|
170
|
+
canActivate(context: ExecutionContext): Observable<boolean> {
|
|
171
|
+
return of(true).pipe(delay(100)); // Ejemplo asíncrono
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
# 📖 Decoradores disponibles
|
|
177
|
+
## Decoradores de clase
|
|
178
|
+
|
|
179
|
+
` @Controller(path?: string) `
|
|
180
|
+
|
|
181
|
+
Marca una clase como controlador de IPC. Todos los handlers dentro de esta clase usarán el prefijo especificado.
|
|
182
|
+
```ts
|
|
183
|
+
@Controller('auth') // Todos los handlers empezarán con 'auth:'
|
|
184
|
+
export class AuthController {}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
` @Injectable(type?: 'singleton' | 'transient') `
|
|
188
|
+
|
|
189
|
+
Marca una clase como disponible para inyección de dependencias.
|
|
190
|
+
```ts
|
|
191
|
+
@Injectable() // Por defecto singleton
|
|
192
|
+
export class DatabaseService {}
|
|
193
|
+
|
|
194
|
+
@Injectable('transient') // Nueva instancia cada vez que se inyecta en una clase
|
|
195
|
+
export class RequestScopedService {}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## Decoradores de métodos
|
|
199
|
+
|
|
200
|
+
` @OnInvoke(path?: string) `
|
|
201
|
+
|
|
202
|
+
Crea un handler para `ipcMain.handle`. Responde a invocaciones del renderer.
|
|
203
|
+
```ts
|
|
204
|
+
@OnInvoke('get-data') // Responde a 'controller-prefix:get-data'
|
|
205
|
+
async getData() {
|
|
206
|
+
return { data: 'value' };
|
|
207
|
+
}
|
|
208
|
+
````
|
|
209
|
+
|
|
210
|
+
` @OnSend(path?: string) `
|
|
211
|
+
|
|
212
|
+
Crea un handler para `ipcMain.on`. Escucha eventos del renderer.
|
|
213
|
+
```ts
|
|
214
|
+
@OnSend('message') // Escucha 'controller-prefix:message'
|
|
215
|
+
onMessage(@Payload() data: any) {
|
|
216
|
+
console.log('Received:', data);
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Decoradores de parámetros
|
|
221
|
+
|
|
222
|
+
` @Payload() `
|
|
223
|
+
|
|
224
|
+
Inyecta el payload recibido desde el renderer.
|
|
225
|
+
```ts
|
|
226
|
+
@OnInvoke('update')
|
|
227
|
+
async update(@Payload() data: any) {
|
|
228
|
+
// 'data' contiene el payload enviado desde el renderer
|
|
229
|
+
}
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
` @Event() `
|
|
233
|
+
|
|
234
|
+
Inyecta el objeto `IpcMainEvent` o `IpcMainInvokeEvent`.
|
|
235
|
+
```ts
|
|
236
|
+
@OnSend('action')
|
|
237
|
+
onAction(@Payload() data: any, @Event() event: IpcMainEvent) {
|
|
238
|
+
event.sender.send('response', { received: true });
|
|
239
|
+
}
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
` @Ctx() `
|
|
243
|
+
|
|
244
|
+
Inyecta el `ExecutionContext` completo.
|
|
245
|
+
```ts
|
|
246
|
+
@OnInvoke('process')
|
|
247
|
+
async process(@Ctx() context: ExecutionContext) {
|
|
248
|
+
const { payload, event, getHandler, getClass } = context;
|
|
249
|
+
// Acceso completo al contexto
|
|
250
|
+
}
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Decoradores de Metadata y Guards
|
|
254
|
+
|
|
255
|
+
` @UseGuards(...guards) `
|
|
256
|
+
|
|
257
|
+
Aplica guards a un controlador o método específico.
|
|
258
|
+
```ts
|
|
259
|
+
@Controller('admin')
|
|
260
|
+
@UseGuards(AuthGuard, AdminGuard) // Aplica a todos los métodos
|
|
261
|
+
export class AdminController {
|
|
262
|
+
|
|
263
|
+
@OnInvoke('sensitive')
|
|
264
|
+
@UseGuards(ExtraSecurityGuard) // Guard adicional para este método
|
|
265
|
+
async sensitiveOperation() {
|
|
266
|
+
// Solo accesible si todos los guards retornan true
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
` @SetMetadata(key, value) `
|
|
272
|
+
|
|
273
|
+
Establece metadata personalizada en controladores o métodos.
|
|
274
|
+
```ts
|
|
275
|
+
@Controller('user')
|
|
276
|
+
@SetMetadata('roles', ['admin', 'user'])
|
|
277
|
+
export class UserController {
|
|
278
|
+
|
|
279
|
+
@OnInvoke('delete')
|
|
280
|
+
@SetMetadata('requiresAdmin', true)
|
|
281
|
+
async deleteUser() {
|
|
282
|
+
// Método con metadata personalizada
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
```
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,446 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
9
|
+
var __export = (target, all) => {
|
|
10
|
+
for (var name in all)
|
|
11
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
12
|
+
};
|
|
13
|
+
var __copyProps = (to, from, except, desc) => {
|
|
14
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
15
|
+
for (let key of __getOwnPropNames(from))
|
|
16
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
17
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
18
|
+
}
|
|
19
|
+
return to;
|
|
20
|
+
};
|
|
21
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
22
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
23
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
24
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
25
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
26
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
27
|
+
mod
|
|
28
|
+
));
|
|
29
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
30
|
+
|
|
31
|
+
// src/index.ts
|
|
32
|
+
var index_exports = {};
|
|
33
|
+
__export(index_exports, {
|
|
34
|
+
Application: () => Application,
|
|
35
|
+
Controller: () => Controller,
|
|
36
|
+
Ctx: () => Ctx,
|
|
37
|
+
Event: () => Event,
|
|
38
|
+
ExecutionContext: () => ExecutionContext,
|
|
39
|
+
Injectable: () => Injectable,
|
|
40
|
+
OnInvoke: () => OnInvoke,
|
|
41
|
+
OnSend: () => OnSend,
|
|
42
|
+
Payload: () => Payload,
|
|
43
|
+
Reflector: () => Reflector,
|
|
44
|
+
SetMetadata: () => SetMetadata,
|
|
45
|
+
UseGuards: () => UseGuards,
|
|
46
|
+
applyDecorators: () => applyDecorators
|
|
47
|
+
});
|
|
48
|
+
module.exports = __toCommonJS(index_exports);
|
|
49
|
+
var import_reflect_metadata = require("reflect-metadata");
|
|
50
|
+
|
|
51
|
+
// src/application.ts
|
|
52
|
+
var import_rxjs = require("rxjs");
|
|
53
|
+
|
|
54
|
+
// src/errors.ts
|
|
55
|
+
var ElectronDiError = class extends Error {
|
|
56
|
+
static {
|
|
57
|
+
__name(this, "ElectronDiError");
|
|
58
|
+
}
|
|
59
|
+
constructor(message) {
|
|
60
|
+
super(message);
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var ProviderNotFound = class extends ElectronDiError {
|
|
64
|
+
static {
|
|
65
|
+
__name(this, "ProviderNotFound");
|
|
66
|
+
}
|
|
67
|
+
constructor(providerName) {
|
|
68
|
+
super(`Provider '${providerName}' not found`);
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var CircularDependency = class extends ElectronDiError {
|
|
72
|
+
static {
|
|
73
|
+
__name(this, "CircularDependency");
|
|
74
|
+
}
|
|
75
|
+
constructor(providerName) {
|
|
76
|
+
super(`Circular dependency detected for provider '${providerName}'`);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var ProviderIsNotInjectable = class extends ElectronDiError {
|
|
80
|
+
static {
|
|
81
|
+
__name(this, "ProviderIsNotInjectable");
|
|
82
|
+
}
|
|
83
|
+
constructor(providerName) {
|
|
84
|
+
super(`Provider '${providerName}' is not injectable. Please ensure it is decorated with @Injectable()`);
|
|
85
|
+
}
|
|
86
|
+
};
|
|
87
|
+
var ControllerIsNotValid = class extends ElectronDiError {
|
|
88
|
+
static {
|
|
89
|
+
__name(this, "ControllerIsNotValid");
|
|
90
|
+
}
|
|
91
|
+
constructor(controllerName) {
|
|
92
|
+
super(`Controller '${controllerName}' is not valid. Please ensure it is decorated with @Controller()`);
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// src/keys.ts
|
|
97
|
+
var CONTROLLER = Symbol("electron-di:controller");
|
|
98
|
+
var INJECTABLE = Symbol("electron-di:injectable");
|
|
99
|
+
var HANDLER = Symbol("electron-di:handler");
|
|
100
|
+
var PARAM = Symbol("electron-di:param");
|
|
101
|
+
var GUARD = Symbol("electron-di:guard");
|
|
102
|
+
|
|
103
|
+
// src/utilities.ts
|
|
104
|
+
var Reflector = class {
|
|
105
|
+
static {
|
|
106
|
+
__name(this, "Reflector");
|
|
107
|
+
}
|
|
108
|
+
get(key, target) {
|
|
109
|
+
return Reflect.getMetadata(key, target);
|
|
110
|
+
}
|
|
111
|
+
getAll(key, ...targets) {
|
|
112
|
+
return targets.map((t) => this.get(key, t));
|
|
113
|
+
}
|
|
114
|
+
getAllAndOverride(key, ...targets) {
|
|
115
|
+
return this.getAll(key, ...targets).reverse().find((value) => value !== void 0);
|
|
116
|
+
}
|
|
117
|
+
getAllAndMerge(key, ...targets) {
|
|
118
|
+
return this.getAll(key, ...targets).reduce((a, b) => {
|
|
119
|
+
if (Array.isArray(a)) return a.concat(b);
|
|
120
|
+
if (typeof a === "object" && typeof b === "object") return {
|
|
121
|
+
...a,
|
|
122
|
+
...b
|
|
123
|
+
};
|
|
124
|
+
return b;
|
|
125
|
+
}, []);
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
var ExecutionContext = class {
|
|
129
|
+
static {
|
|
130
|
+
__name(this, "ExecutionContext");
|
|
131
|
+
}
|
|
132
|
+
_classRef;
|
|
133
|
+
_handler;
|
|
134
|
+
_payload;
|
|
135
|
+
_event;
|
|
136
|
+
constructor(_classRef, _handler, _payload, _event) {
|
|
137
|
+
this._classRef = _classRef;
|
|
138
|
+
this._handler = _handler;
|
|
139
|
+
this._payload = _payload;
|
|
140
|
+
this._event = _event;
|
|
141
|
+
}
|
|
142
|
+
getHandler() {
|
|
143
|
+
return this._handler;
|
|
144
|
+
}
|
|
145
|
+
getClass() {
|
|
146
|
+
return this._classRef;
|
|
147
|
+
}
|
|
148
|
+
get payload() {
|
|
149
|
+
return this._payload;
|
|
150
|
+
}
|
|
151
|
+
get event() {
|
|
152
|
+
return this._event;
|
|
153
|
+
}
|
|
154
|
+
set payload(payload) {
|
|
155
|
+
this._payload = payload;
|
|
156
|
+
}
|
|
157
|
+
};
|
|
158
|
+
function applyDecorators(...decorators) {
|
|
159
|
+
return function(target, _propertyKey, descriptor) {
|
|
160
|
+
const targetKey = descriptor ? descriptor.value : target;
|
|
161
|
+
decorators.forEach((decorator) => decorator(targetKey));
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
__name(applyDecorators, "applyDecorators");
|
|
165
|
+
|
|
166
|
+
// src/container.ts
|
|
167
|
+
var Container = class {
|
|
168
|
+
static {
|
|
169
|
+
__name(this, "Container");
|
|
170
|
+
}
|
|
171
|
+
utilities = [
|
|
172
|
+
Reflector
|
|
173
|
+
];
|
|
174
|
+
providers = /* @__PURE__ */ new Map();
|
|
175
|
+
instances = /* @__PURE__ */ new Map();
|
|
176
|
+
addProvider(provider) {
|
|
177
|
+
const token = this.getProviderToken(provider);
|
|
178
|
+
this.providers.set(token, provider);
|
|
179
|
+
}
|
|
180
|
+
getDependencies(providerClass) {
|
|
181
|
+
return Reflect.getMetadata("design:paramtypes", providerClass) ?? [];
|
|
182
|
+
}
|
|
183
|
+
resolve(token, visited = []) {
|
|
184
|
+
const utilitie = this.utilities.find((u) => u === token);
|
|
185
|
+
if (utilitie) return new utilitie();
|
|
186
|
+
const singletonInstance = this.instances.get(token);
|
|
187
|
+
if (singletonInstance) return singletonInstance;
|
|
188
|
+
const provider = this.providers.get(token);
|
|
189
|
+
if (!provider) throw new ProviderNotFound(token.name);
|
|
190
|
+
if (visited.includes(token)) throw new CircularDependency(token.name);
|
|
191
|
+
const providerClass = this.getProviderClass(provider);
|
|
192
|
+
const providerDependencies = this.getDependencies(providerClass);
|
|
193
|
+
const providerMetadata = this.getProviderMetadata(providerClass);
|
|
194
|
+
const instanceDependencies = providerDependencies.map((dep) => this.resolve(dep, [
|
|
195
|
+
...visited,
|
|
196
|
+
token
|
|
197
|
+
]));
|
|
198
|
+
if (!providerMetadata) throw new ProviderIsNotInjectable(token.name);
|
|
199
|
+
const providerInstance = new providerClass(...instanceDependencies);
|
|
200
|
+
if (providerMetadata === "singleton") this.instances.set(token, providerInstance);
|
|
201
|
+
return providerInstance;
|
|
202
|
+
}
|
|
203
|
+
getProviderToken(provider) {
|
|
204
|
+
return typeof provider === "object" ? provider.provided : provider;
|
|
205
|
+
}
|
|
206
|
+
getProviderClass(provider) {
|
|
207
|
+
return typeof provider === "object" ? provider.useClass : provider;
|
|
208
|
+
}
|
|
209
|
+
getProviderMetadata(provider) {
|
|
210
|
+
return Reflect.getMetadata(INJECTABLE, provider);
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
// src/debugger.ts
|
|
215
|
+
var import_debug = __toESM(require("debug"), 1);
|
|
216
|
+
var prodLogger = (0, import_debug.default)("app:prod");
|
|
217
|
+
var devLogger = (0, import_debug.default)("app:dev");
|
|
218
|
+
if (!process.env.APP_LOGGER || process.env.APP_LOGGER === "false") {
|
|
219
|
+
import_debug.default.enable("app:prod");
|
|
220
|
+
} else {
|
|
221
|
+
import_debug.default.enable("app:*");
|
|
222
|
+
}
|
|
223
|
+
var PROD_LOGGER = prodLogger;
|
|
224
|
+
var DEV_LOGGER = devLogger;
|
|
225
|
+
|
|
226
|
+
// src/application.ts
|
|
227
|
+
var import_electron = require("electron");
|
|
228
|
+
var Application = class {
|
|
229
|
+
static {
|
|
230
|
+
__name(this, "Application");
|
|
231
|
+
}
|
|
232
|
+
configOptions;
|
|
233
|
+
container = new Container();
|
|
234
|
+
constructor(configOptions) {
|
|
235
|
+
this.configOptions = configOptions;
|
|
236
|
+
this.loadProviders();
|
|
237
|
+
this.loadControllers();
|
|
238
|
+
}
|
|
239
|
+
loadProviders() {
|
|
240
|
+
for (const provider of this.configOptions.providers || []) {
|
|
241
|
+
this.container.addProvider(provider);
|
|
242
|
+
DEV_LOGGER(`Provider ${typeof provider == "object" ? provider.provided.name : provider.name} loaded`);
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
loadControllers() {
|
|
246
|
+
for (const controller of this.configOptions.controllers || []) {
|
|
247
|
+
const controllerPrefix = this.getControllerPrefix(controller);
|
|
248
|
+
const controllerDependencies = this.getControllerDependencies(controller);
|
|
249
|
+
const controllerGuards = this.getGuards(controller);
|
|
250
|
+
const controllerInstance = new controller(...controllerDependencies.map((dep) => this.container.resolve(dep)));
|
|
251
|
+
const controllerMethods = Object.getOwnPropertyNames(controllerInstance.constructor.prototype).filter((method) => method !== "constructor");
|
|
252
|
+
for (const controllerMethod of controllerMethods) {
|
|
253
|
+
const handlerMetadata = this.getHandlerMetadata(controllerInstance[controllerMethod]);
|
|
254
|
+
if (typeof handlerMetadata !== "object") continue;
|
|
255
|
+
const handlerGuards = this.getGuards(controllerInstance[controllerMethod]);
|
|
256
|
+
const guards = controllerGuards.filter((guard) => !handlerGuards.includes(guard)).concat(handlerGuards).map((guard) => this.container.resolve(guard));
|
|
257
|
+
const path = this.buildPath(controllerPrefix, controllerMethod);
|
|
258
|
+
const handlerCallback = /* @__PURE__ */ __name(async (event, data) => {
|
|
259
|
+
const executionContext = new ExecutionContext(controller, controllerInstance[controllerMethod], data, event);
|
|
260
|
+
for (const guard of guards) {
|
|
261
|
+
const response = await this.guardExecute(guard, executionContext);
|
|
262
|
+
if (!response) return false;
|
|
263
|
+
}
|
|
264
|
+
const params = this.getParams(controllerInstance, controllerMethod, executionContext);
|
|
265
|
+
const controllerResult = await this.controllerExecute(controllerInstance, controllerInstance[controllerMethod], params);
|
|
266
|
+
return controllerResult;
|
|
267
|
+
}, "handlerCallback");
|
|
268
|
+
if (handlerMetadata.type === "invoke") {
|
|
269
|
+
import_electron.ipcMain.handle(path, handlerCallback);
|
|
270
|
+
} else {
|
|
271
|
+
import_electron.ipcMain.on(path, handlerCallback);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
getParams(target, propertyKey, executionContext) {
|
|
277
|
+
const params = Reflect.getMetadata(PARAM, target, propertyKey);
|
|
278
|
+
if (!params) return [];
|
|
279
|
+
return params.map((param) => {
|
|
280
|
+
if (param === "ctx") return executionContext;
|
|
281
|
+
if (param === "event") return executionContext.event;
|
|
282
|
+
if (param === "payload") return executionContext.payload;
|
|
283
|
+
return void 0;
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
buildPath(controllerPrefix, methodPath) {
|
|
287
|
+
const prefix = controllerPrefix.trim();
|
|
288
|
+
const path = methodPath.trim();
|
|
289
|
+
if (prefix && path) return `${prefix}:${path}`;
|
|
290
|
+
if (prefix) return prefix;
|
|
291
|
+
if (path) return path;
|
|
292
|
+
return "";
|
|
293
|
+
}
|
|
294
|
+
async guardExecute(guard, executionContext) {
|
|
295
|
+
try {
|
|
296
|
+
const guardResult = guard.canActivate(executionContext);
|
|
297
|
+
if (guardResult instanceof import_rxjs.Observable) {
|
|
298
|
+
const result = await (0, import_rxjs.lastValueFrom)(guardResult.pipe((0, import_rxjs.first)()));
|
|
299
|
+
if (!result) return false;
|
|
300
|
+
} else if (guardResult instanceof Promise) {
|
|
301
|
+
const result = await guardResult;
|
|
302
|
+
if (!result) return false;
|
|
303
|
+
} else {
|
|
304
|
+
if (!guardResult) return false;
|
|
305
|
+
}
|
|
306
|
+
return true;
|
|
307
|
+
} catch (error) {
|
|
308
|
+
PROD_LOGGER(error);
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
async controllerExecute(context, target, params) {
|
|
313
|
+
try {
|
|
314
|
+
const boundedTarget = target.bind(context);
|
|
315
|
+
let controllerResult = boundedTarget(...params);
|
|
316
|
+
while (controllerResult instanceof import_rxjs.Observable || controllerResult instanceof Promise) {
|
|
317
|
+
if (controllerResult instanceof import_rxjs.Observable) {
|
|
318
|
+
controllerResult = await (0, import_rxjs.lastValueFrom)(controllerResult);
|
|
319
|
+
} else if (controllerResult instanceof Promise) {
|
|
320
|
+
controllerResult = await controllerResult;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
return controllerResult;
|
|
324
|
+
} catch (error) {
|
|
325
|
+
PROD_LOGGER(error.message ?? error);
|
|
326
|
+
return void 0;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
getHandlerMetadata(target) {
|
|
330
|
+
const handlerMetadata = Reflect.getMetadata(HANDLER, target);
|
|
331
|
+
return handlerMetadata ?? {};
|
|
332
|
+
}
|
|
333
|
+
getGuards(target) {
|
|
334
|
+
const guards = Reflect.getMetadata(GUARD, target);
|
|
335
|
+
return guards ?? [];
|
|
336
|
+
}
|
|
337
|
+
getControllerPrefix(target) {
|
|
338
|
+
const prefix = Reflect.getMetadata(CONTROLLER, target);
|
|
339
|
+
if (typeof prefix !== "string") throw new ControllerIsNotValid(target.name);
|
|
340
|
+
return prefix;
|
|
341
|
+
}
|
|
342
|
+
getControllerDependencies(target) {
|
|
343
|
+
const deps = Reflect.getMetadata("design:paramtypes", target);
|
|
344
|
+
return deps ?? [];
|
|
345
|
+
}
|
|
346
|
+
};
|
|
347
|
+
|
|
348
|
+
// src/decorators.ts
|
|
349
|
+
function Controller(path = "") {
|
|
350
|
+
return function(target) {
|
|
351
|
+
Reflect.defineMetadata(CONTROLLER, path, target);
|
|
352
|
+
};
|
|
353
|
+
}
|
|
354
|
+
__name(Controller, "Controller");
|
|
355
|
+
function Injectable(type = "singleton") {
|
|
356
|
+
return function(target) {
|
|
357
|
+
Reflect.defineMetadata(INJECTABLE, type, target);
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
__name(Injectable, "Injectable");
|
|
361
|
+
function OnSend(path = "") {
|
|
362
|
+
return function(_target, _property, descriptor) {
|
|
363
|
+
Reflect.defineMetadata(HANDLER, {
|
|
364
|
+
path,
|
|
365
|
+
type: "send"
|
|
366
|
+
}, descriptor.value);
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
__name(OnSend, "OnSend");
|
|
370
|
+
function OnInvoke(path = "") {
|
|
371
|
+
return function(_target, _property, descriptor) {
|
|
372
|
+
Reflect.defineMetadata(HANDLER, {
|
|
373
|
+
path,
|
|
374
|
+
type: "invoke"
|
|
375
|
+
}, descriptor.value);
|
|
376
|
+
};
|
|
377
|
+
}
|
|
378
|
+
__name(OnInvoke, "OnInvoke");
|
|
379
|
+
function _getParams(target, property) {
|
|
380
|
+
const prevParams = Reflect.getMetadata(PARAM, target, property);
|
|
381
|
+
return prevParams ?? [];
|
|
382
|
+
}
|
|
383
|
+
__name(_getParams, "_getParams");
|
|
384
|
+
function _getGuards(target) {
|
|
385
|
+
const prevGuards = Reflect.getMetadata(GUARD, target);
|
|
386
|
+
return prevGuards ?? [];
|
|
387
|
+
}
|
|
388
|
+
__name(_getGuards, "_getGuards");
|
|
389
|
+
function Payload() {
|
|
390
|
+
return function(target, property, paramIndex) {
|
|
391
|
+
const params = _getParams(target, property);
|
|
392
|
+
params[paramIndex] = "payload";
|
|
393
|
+
Reflect.defineMetadata(PARAM, params, target, property);
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
__name(Payload, "Payload");
|
|
397
|
+
function Event() {
|
|
398
|
+
return function(target, property, paramIndex) {
|
|
399
|
+
const params = _getParams(target, property);
|
|
400
|
+
params[paramIndex] = "event";
|
|
401
|
+
Reflect.defineMetadata(PARAM, params, target, property);
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
__name(Event, "Event");
|
|
405
|
+
function Ctx() {
|
|
406
|
+
return function(target, property, paramIndex) {
|
|
407
|
+
const params = _getParams(target, property);
|
|
408
|
+
params[paramIndex] = "ctx";
|
|
409
|
+
Reflect.defineMetadata(PARAM, params, target, property);
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
__name(Ctx, "Ctx");
|
|
413
|
+
function UseGuards(...guards) {
|
|
414
|
+
return function(_target, _property, descriptor) {
|
|
415
|
+
const target = descriptor ? descriptor.value : _target;
|
|
416
|
+
const prevGuards = _getGuards(target).filter((prevGuard) => !guards.includes(prevGuard));
|
|
417
|
+
Reflect.defineMetadata(GUARD, [
|
|
418
|
+
...guards,
|
|
419
|
+
...prevGuards
|
|
420
|
+
], target);
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
__name(UseGuards, "UseGuards");
|
|
424
|
+
function SetMetadata(key, value) {
|
|
425
|
+
return function(target, propertyKey, descriptor) {
|
|
426
|
+
const targetKey = descriptor ? descriptor.value : target;
|
|
427
|
+
Reflect.defineMetadata(key, value, targetKey);
|
|
428
|
+
};
|
|
429
|
+
}
|
|
430
|
+
__name(SetMetadata, "SetMetadata");
|
|
431
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
432
|
+
0 && (module.exports = {
|
|
433
|
+
Application,
|
|
434
|
+
Controller,
|
|
435
|
+
Ctx,
|
|
436
|
+
Event,
|
|
437
|
+
ExecutionContext,
|
|
438
|
+
Injectable,
|
|
439
|
+
OnInvoke,
|
|
440
|
+
OnSend,
|
|
441
|
+
Payload,
|
|
442
|
+
Reflector,
|
|
443
|
+
SetMetadata,
|
|
444
|
+
UseGuards,
|
|
445
|
+
applyDecorators
|
|
446
|
+
});
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { IpcMainEvent, IpcMainInvokeEvent } from 'electron';
|
|
3
|
+
|
|
4
|
+
declare class Reflector {
|
|
5
|
+
get<T = any>(key: any, target: any): T;
|
|
6
|
+
getAll<T = any>(key: any, ...targets: any[]): T[];
|
|
7
|
+
getAllAndOverride<T = any>(key: any, ...targets: any[]): (T & ({} | null)) | undefined;
|
|
8
|
+
getAllAndMerge<T = any>(key: any, ...targets: any[]): T;
|
|
9
|
+
}
|
|
10
|
+
declare class ExecutionContext {
|
|
11
|
+
private readonly _classRef;
|
|
12
|
+
private readonly _handler;
|
|
13
|
+
private _payload;
|
|
14
|
+
private _event;
|
|
15
|
+
constructor(_classRef: any, _handler: CallableFunction, _payload: any, _event: IpcMainEvent | IpcMainInvokeEvent);
|
|
16
|
+
getHandler(): CallableFunction;
|
|
17
|
+
getClass<T = any>(): T;
|
|
18
|
+
get payload(): any;
|
|
19
|
+
get event(): Electron.IpcMainEvent | Electron.IpcMainInvokeEvent;
|
|
20
|
+
set payload(payload: any);
|
|
21
|
+
}
|
|
22
|
+
declare function applyDecorators(...decorators: CallableFunction[]): (target: Object, _propertyKey?: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
23
|
+
|
|
24
|
+
type Class<T = any> = new (...args: any[]) => T;
|
|
25
|
+
type InjectableType = 'singleton' | 'transient';
|
|
26
|
+
type Provider = Class | {
|
|
27
|
+
provided: Class;
|
|
28
|
+
useClass: Class;
|
|
29
|
+
};
|
|
30
|
+
interface CanActivate {
|
|
31
|
+
canActivate: (context: ExecutionContext) => boolean | Promise<boolean> | Observable<boolean>;
|
|
32
|
+
}
|
|
33
|
+
interface ConfigOptions {
|
|
34
|
+
providers?: Provider[];
|
|
35
|
+
controllers?: Class[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
declare class Application {
|
|
39
|
+
private configOptions;
|
|
40
|
+
private container;
|
|
41
|
+
constructor(configOptions: ConfigOptions);
|
|
42
|
+
private loadProviders;
|
|
43
|
+
private loadControllers;
|
|
44
|
+
private getParams;
|
|
45
|
+
private buildPath;
|
|
46
|
+
private guardExecute;
|
|
47
|
+
private controllerExecute;
|
|
48
|
+
private getHandlerMetadata;
|
|
49
|
+
private getGuards;
|
|
50
|
+
private getControllerPrefix;
|
|
51
|
+
private getControllerDependencies;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
declare function Controller(path?: string): ClassDecorator;
|
|
55
|
+
declare function Injectable(type?: InjectableType): ClassDecorator;
|
|
56
|
+
declare function OnSend(path?: string): MethodDecorator;
|
|
57
|
+
declare function OnInvoke(path?: string): MethodDecorator;
|
|
58
|
+
declare function Payload(): ParameterDecorator;
|
|
59
|
+
declare function Event(): ParameterDecorator;
|
|
60
|
+
declare function Ctx(): ParameterDecorator;
|
|
61
|
+
declare function UseGuards(...guards: Class<CanActivate>[]): (_target: Object, _property?: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
62
|
+
declare function SetMetadata(key: any, value: any): (target: Object, propertyKey?: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
63
|
+
|
|
64
|
+
export { Application, type CanActivate, type ConfigOptions, Controller, Ctx, Event, ExecutionContext, Injectable, type InjectableType, OnInvoke, OnSend, Payload, Reflector, SetMetadata, UseGuards, applyDecorators };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import { Observable } from 'rxjs';
|
|
2
|
+
import { IpcMainEvent, IpcMainInvokeEvent } from 'electron';
|
|
3
|
+
|
|
4
|
+
declare class Reflector {
|
|
5
|
+
get<T = any>(key: any, target: any): T;
|
|
6
|
+
getAll<T = any>(key: any, ...targets: any[]): T[];
|
|
7
|
+
getAllAndOverride<T = any>(key: any, ...targets: any[]): (T & ({} | null)) | undefined;
|
|
8
|
+
getAllAndMerge<T = any>(key: any, ...targets: any[]): T;
|
|
9
|
+
}
|
|
10
|
+
declare class ExecutionContext {
|
|
11
|
+
private readonly _classRef;
|
|
12
|
+
private readonly _handler;
|
|
13
|
+
private _payload;
|
|
14
|
+
private _event;
|
|
15
|
+
constructor(_classRef: any, _handler: CallableFunction, _payload: any, _event: IpcMainEvent | IpcMainInvokeEvent);
|
|
16
|
+
getHandler(): CallableFunction;
|
|
17
|
+
getClass<T = any>(): T;
|
|
18
|
+
get payload(): any;
|
|
19
|
+
get event(): Electron.IpcMainEvent | Electron.IpcMainInvokeEvent;
|
|
20
|
+
set payload(payload: any);
|
|
21
|
+
}
|
|
22
|
+
declare function applyDecorators(...decorators: CallableFunction[]): (target: Object, _propertyKey?: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
23
|
+
|
|
24
|
+
type Class<T = any> = new (...args: any[]) => T;
|
|
25
|
+
type InjectableType = 'singleton' | 'transient';
|
|
26
|
+
type Provider = Class | {
|
|
27
|
+
provided: Class;
|
|
28
|
+
useClass: Class;
|
|
29
|
+
};
|
|
30
|
+
interface CanActivate {
|
|
31
|
+
canActivate: (context: ExecutionContext) => boolean | Promise<boolean> | Observable<boolean>;
|
|
32
|
+
}
|
|
33
|
+
interface ConfigOptions {
|
|
34
|
+
providers?: Provider[];
|
|
35
|
+
controllers?: Class[];
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
declare class Application {
|
|
39
|
+
private configOptions;
|
|
40
|
+
private container;
|
|
41
|
+
constructor(configOptions: ConfigOptions);
|
|
42
|
+
private loadProviders;
|
|
43
|
+
private loadControllers;
|
|
44
|
+
private getParams;
|
|
45
|
+
private buildPath;
|
|
46
|
+
private guardExecute;
|
|
47
|
+
private controllerExecute;
|
|
48
|
+
private getHandlerMetadata;
|
|
49
|
+
private getGuards;
|
|
50
|
+
private getControllerPrefix;
|
|
51
|
+
private getControllerDependencies;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
declare function Controller(path?: string): ClassDecorator;
|
|
55
|
+
declare function Injectable(type?: InjectableType): ClassDecorator;
|
|
56
|
+
declare function OnSend(path?: string): MethodDecorator;
|
|
57
|
+
declare function OnInvoke(path?: string): MethodDecorator;
|
|
58
|
+
declare function Payload(): ParameterDecorator;
|
|
59
|
+
declare function Event(): ParameterDecorator;
|
|
60
|
+
declare function Ctx(): ParameterDecorator;
|
|
61
|
+
declare function UseGuards(...guards: Class<CanActivate>[]): (_target: Object, _property?: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
62
|
+
declare function SetMetadata(key: any, value: any): (target: Object, propertyKey?: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
63
|
+
|
|
64
|
+
export { Application, type CanActivate, type ConfigOptions, Controller, Ctx, Event, ExecutionContext, Injectable, type InjectableType, OnInvoke, OnSend, Payload, Reflector, SetMetadata, UseGuards, applyDecorators };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
3
|
+
|
|
4
|
+
// src/index.ts
|
|
5
|
+
import "reflect-metadata";
|
|
6
|
+
|
|
7
|
+
// src/application.ts
|
|
8
|
+
import { first, lastValueFrom, Observable } from "rxjs";
|
|
9
|
+
|
|
10
|
+
// src/errors.ts
|
|
11
|
+
var ElectronDiError = class extends Error {
|
|
12
|
+
static {
|
|
13
|
+
__name(this, "ElectronDiError");
|
|
14
|
+
}
|
|
15
|
+
constructor(message) {
|
|
16
|
+
super(message);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
var ProviderNotFound = class extends ElectronDiError {
|
|
20
|
+
static {
|
|
21
|
+
__name(this, "ProviderNotFound");
|
|
22
|
+
}
|
|
23
|
+
constructor(providerName) {
|
|
24
|
+
super(`Provider '${providerName}' not found`);
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
var CircularDependency = class extends ElectronDiError {
|
|
28
|
+
static {
|
|
29
|
+
__name(this, "CircularDependency");
|
|
30
|
+
}
|
|
31
|
+
constructor(providerName) {
|
|
32
|
+
super(`Circular dependency detected for provider '${providerName}'`);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
var ProviderIsNotInjectable = class extends ElectronDiError {
|
|
36
|
+
static {
|
|
37
|
+
__name(this, "ProviderIsNotInjectable");
|
|
38
|
+
}
|
|
39
|
+
constructor(providerName) {
|
|
40
|
+
super(`Provider '${providerName}' is not injectable. Please ensure it is decorated with @Injectable()`);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
var ControllerIsNotValid = class extends ElectronDiError {
|
|
44
|
+
static {
|
|
45
|
+
__name(this, "ControllerIsNotValid");
|
|
46
|
+
}
|
|
47
|
+
constructor(controllerName) {
|
|
48
|
+
super(`Controller '${controllerName}' is not valid. Please ensure it is decorated with @Controller()`);
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// src/keys.ts
|
|
53
|
+
var CONTROLLER = Symbol("electron-di:controller");
|
|
54
|
+
var INJECTABLE = Symbol("electron-di:injectable");
|
|
55
|
+
var HANDLER = Symbol("electron-di:handler");
|
|
56
|
+
var PARAM = Symbol("electron-di:param");
|
|
57
|
+
var GUARD = Symbol("electron-di:guard");
|
|
58
|
+
|
|
59
|
+
// src/utilities.ts
|
|
60
|
+
var Reflector = class {
|
|
61
|
+
static {
|
|
62
|
+
__name(this, "Reflector");
|
|
63
|
+
}
|
|
64
|
+
get(key, target) {
|
|
65
|
+
return Reflect.getMetadata(key, target);
|
|
66
|
+
}
|
|
67
|
+
getAll(key, ...targets) {
|
|
68
|
+
return targets.map((t) => this.get(key, t));
|
|
69
|
+
}
|
|
70
|
+
getAllAndOverride(key, ...targets) {
|
|
71
|
+
return this.getAll(key, ...targets).reverse().find((value) => value !== void 0);
|
|
72
|
+
}
|
|
73
|
+
getAllAndMerge(key, ...targets) {
|
|
74
|
+
return this.getAll(key, ...targets).reduce((a, b) => {
|
|
75
|
+
if (Array.isArray(a)) return a.concat(b);
|
|
76
|
+
if (typeof a === "object" && typeof b === "object") return {
|
|
77
|
+
...a,
|
|
78
|
+
...b
|
|
79
|
+
};
|
|
80
|
+
return b;
|
|
81
|
+
}, []);
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
var ExecutionContext = class {
|
|
85
|
+
static {
|
|
86
|
+
__name(this, "ExecutionContext");
|
|
87
|
+
}
|
|
88
|
+
_classRef;
|
|
89
|
+
_handler;
|
|
90
|
+
_payload;
|
|
91
|
+
_event;
|
|
92
|
+
constructor(_classRef, _handler, _payload, _event) {
|
|
93
|
+
this._classRef = _classRef;
|
|
94
|
+
this._handler = _handler;
|
|
95
|
+
this._payload = _payload;
|
|
96
|
+
this._event = _event;
|
|
97
|
+
}
|
|
98
|
+
getHandler() {
|
|
99
|
+
return this._handler;
|
|
100
|
+
}
|
|
101
|
+
getClass() {
|
|
102
|
+
return this._classRef;
|
|
103
|
+
}
|
|
104
|
+
get payload() {
|
|
105
|
+
return this._payload;
|
|
106
|
+
}
|
|
107
|
+
get event() {
|
|
108
|
+
return this._event;
|
|
109
|
+
}
|
|
110
|
+
set payload(payload) {
|
|
111
|
+
this._payload = payload;
|
|
112
|
+
}
|
|
113
|
+
};
|
|
114
|
+
function applyDecorators(...decorators) {
|
|
115
|
+
return function(target, _propertyKey, descriptor) {
|
|
116
|
+
const targetKey = descriptor ? descriptor.value : target;
|
|
117
|
+
decorators.forEach((decorator) => decorator(targetKey));
|
|
118
|
+
};
|
|
119
|
+
}
|
|
120
|
+
__name(applyDecorators, "applyDecorators");
|
|
121
|
+
|
|
122
|
+
// src/container.ts
|
|
123
|
+
var Container = class {
|
|
124
|
+
static {
|
|
125
|
+
__name(this, "Container");
|
|
126
|
+
}
|
|
127
|
+
utilities = [
|
|
128
|
+
Reflector
|
|
129
|
+
];
|
|
130
|
+
providers = /* @__PURE__ */ new Map();
|
|
131
|
+
instances = /* @__PURE__ */ new Map();
|
|
132
|
+
addProvider(provider) {
|
|
133
|
+
const token = this.getProviderToken(provider);
|
|
134
|
+
this.providers.set(token, provider);
|
|
135
|
+
}
|
|
136
|
+
getDependencies(providerClass) {
|
|
137
|
+
return Reflect.getMetadata("design:paramtypes", providerClass) ?? [];
|
|
138
|
+
}
|
|
139
|
+
resolve(token, visited = []) {
|
|
140
|
+
const utilitie = this.utilities.find((u) => u === token);
|
|
141
|
+
if (utilitie) return new utilitie();
|
|
142
|
+
const singletonInstance = this.instances.get(token);
|
|
143
|
+
if (singletonInstance) return singletonInstance;
|
|
144
|
+
const provider = this.providers.get(token);
|
|
145
|
+
if (!provider) throw new ProviderNotFound(token.name);
|
|
146
|
+
if (visited.includes(token)) throw new CircularDependency(token.name);
|
|
147
|
+
const providerClass = this.getProviderClass(provider);
|
|
148
|
+
const providerDependencies = this.getDependencies(providerClass);
|
|
149
|
+
const providerMetadata = this.getProviderMetadata(providerClass);
|
|
150
|
+
const instanceDependencies = providerDependencies.map((dep) => this.resolve(dep, [
|
|
151
|
+
...visited,
|
|
152
|
+
token
|
|
153
|
+
]));
|
|
154
|
+
if (!providerMetadata) throw new ProviderIsNotInjectable(token.name);
|
|
155
|
+
const providerInstance = new providerClass(...instanceDependencies);
|
|
156
|
+
if (providerMetadata === "singleton") this.instances.set(token, providerInstance);
|
|
157
|
+
return providerInstance;
|
|
158
|
+
}
|
|
159
|
+
getProviderToken(provider) {
|
|
160
|
+
return typeof provider === "object" ? provider.provided : provider;
|
|
161
|
+
}
|
|
162
|
+
getProviderClass(provider) {
|
|
163
|
+
return typeof provider === "object" ? provider.useClass : provider;
|
|
164
|
+
}
|
|
165
|
+
getProviderMetadata(provider) {
|
|
166
|
+
return Reflect.getMetadata(INJECTABLE, provider);
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
|
|
170
|
+
// src/debugger.ts
|
|
171
|
+
import debug from "debug";
|
|
172
|
+
var prodLogger = debug("app:prod");
|
|
173
|
+
var devLogger = debug("app:dev");
|
|
174
|
+
if (!process.env.APP_LOGGER || process.env.APP_LOGGER === "false") {
|
|
175
|
+
debug.enable("app:prod");
|
|
176
|
+
} else {
|
|
177
|
+
debug.enable("app:*");
|
|
178
|
+
}
|
|
179
|
+
var PROD_LOGGER = prodLogger;
|
|
180
|
+
var DEV_LOGGER = devLogger;
|
|
181
|
+
|
|
182
|
+
// src/application.ts
|
|
183
|
+
import { ipcMain } from "electron";
|
|
184
|
+
var Application = class {
|
|
185
|
+
static {
|
|
186
|
+
__name(this, "Application");
|
|
187
|
+
}
|
|
188
|
+
configOptions;
|
|
189
|
+
container = new Container();
|
|
190
|
+
constructor(configOptions) {
|
|
191
|
+
this.configOptions = configOptions;
|
|
192
|
+
this.loadProviders();
|
|
193
|
+
this.loadControllers();
|
|
194
|
+
}
|
|
195
|
+
loadProviders() {
|
|
196
|
+
for (const provider of this.configOptions.providers || []) {
|
|
197
|
+
this.container.addProvider(provider);
|
|
198
|
+
DEV_LOGGER(`Provider ${typeof provider == "object" ? provider.provided.name : provider.name} loaded`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
loadControllers() {
|
|
202
|
+
for (const controller of this.configOptions.controllers || []) {
|
|
203
|
+
const controllerPrefix = this.getControllerPrefix(controller);
|
|
204
|
+
const controllerDependencies = this.getControllerDependencies(controller);
|
|
205
|
+
const controllerGuards = this.getGuards(controller);
|
|
206
|
+
const controllerInstance = new controller(...controllerDependencies.map((dep) => this.container.resolve(dep)));
|
|
207
|
+
const controllerMethods = Object.getOwnPropertyNames(controllerInstance.constructor.prototype).filter((method) => method !== "constructor");
|
|
208
|
+
for (const controllerMethod of controllerMethods) {
|
|
209
|
+
const handlerMetadata = this.getHandlerMetadata(controllerInstance[controllerMethod]);
|
|
210
|
+
if (typeof handlerMetadata !== "object") continue;
|
|
211
|
+
const handlerGuards = this.getGuards(controllerInstance[controllerMethod]);
|
|
212
|
+
const guards = controllerGuards.filter((guard) => !handlerGuards.includes(guard)).concat(handlerGuards).map((guard) => this.container.resolve(guard));
|
|
213
|
+
const path = this.buildPath(controllerPrefix, controllerMethod);
|
|
214
|
+
const handlerCallback = /* @__PURE__ */ __name(async (event, data) => {
|
|
215
|
+
const executionContext = new ExecutionContext(controller, controllerInstance[controllerMethod], data, event);
|
|
216
|
+
for (const guard of guards) {
|
|
217
|
+
const response = await this.guardExecute(guard, executionContext);
|
|
218
|
+
if (!response) return false;
|
|
219
|
+
}
|
|
220
|
+
const params = this.getParams(controllerInstance, controllerMethod, executionContext);
|
|
221
|
+
const controllerResult = await this.controllerExecute(controllerInstance, controllerInstance[controllerMethod], params);
|
|
222
|
+
return controllerResult;
|
|
223
|
+
}, "handlerCallback");
|
|
224
|
+
if (handlerMetadata.type === "invoke") {
|
|
225
|
+
ipcMain.handle(path, handlerCallback);
|
|
226
|
+
} else {
|
|
227
|
+
ipcMain.on(path, handlerCallback);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
getParams(target, propertyKey, executionContext) {
|
|
233
|
+
const params = Reflect.getMetadata(PARAM, target, propertyKey);
|
|
234
|
+
if (!params) return [];
|
|
235
|
+
return params.map((param) => {
|
|
236
|
+
if (param === "ctx") return executionContext;
|
|
237
|
+
if (param === "event") return executionContext.event;
|
|
238
|
+
if (param === "payload") return executionContext.payload;
|
|
239
|
+
return void 0;
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
buildPath(controllerPrefix, methodPath) {
|
|
243
|
+
const prefix = controllerPrefix.trim();
|
|
244
|
+
const path = methodPath.trim();
|
|
245
|
+
if (prefix && path) return `${prefix}:${path}`;
|
|
246
|
+
if (prefix) return prefix;
|
|
247
|
+
if (path) return path;
|
|
248
|
+
return "";
|
|
249
|
+
}
|
|
250
|
+
async guardExecute(guard, executionContext) {
|
|
251
|
+
try {
|
|
252
|
+
const guardResult = guard.canActivate(executionContext);
|
|
253
|
+
if (guardResult instanceof Observable) {
|
|
254
|
+
const result = await lastValueFrom(guardResult.pipe(first()));
|
|
255
|
+
if (!result) return false;
|
|
256
|
+
} else if (guardResult instanceof Promise) {
|
|
257
|
+
const result = await guardResult;
|
|
258
|
+
if (!result) return false;
|
|
259
|
+
} else {
|
|
260
|
+
if (!guardResult) return false;
|
|
261
|
+
}
|
|
262
|
+
return true;
|
|
263
|
+
} catch (error) {
|
|
264
|
+
PROD_LOGGER(error);
|
|
265
|
+
return false;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
async controllerExecute(context, target, params) {
|
|
269
|
+
try {
|
|
270
|
+
const boundedTarget = target.bind(context);
|
|
271
|
+
let controllerResult = boundedTarget(...params);
|
|
272
|
+
while (controllerResult instanceof Observable || controllerResult instanceof Promise) {
|
|
273
|
+
if (controllerResult instanceof Observable) {
|
|
274
|
+
controllerResult = await lastValueFrom(controllerResult);
|
|
275
|
+
} else if (controllerResult instanceof Promise) {
|
|
276
|
+
controllerResult = await controllerResult;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
return controllerResult;
|
|
280
|
+
} catch (error) {
|
|
281
|
+
PROD_LOGGER(error.message ?? error);
|
|
282
|
+
return void 0;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
getHandlerMetadata(target) {
|
|
286
|
+
const handlerMetadata = Reflect.getMetadata(HANDLER, target);
|
|
287
|
+
return handlerMetadata ?? {};
|
|
288
|
+
}
|
|
289
|
+
getGuards(target) {
|
|
290
|
+
const guards = Reflect.getMetadata(GUARD, target);
|
|
291
|
+
return guards ?? [];
|
|
292
|
+
}
|
|
293
|
+
getControllerPrefix(target) {
|
|
294
|
+
const prefix = Reflect.getMetadata(CONTROLLER, target);
|
|
295
|
+
if (typeof prefix !== "string") throw new ControllerIsNotValid(target.name);
|
|
296
|
+
return prefix;
|
|
297
|
+
}
|
|
298
|
+
getControllerDependencies(target) {
|
|
299
|
+
const deps = Reflect.getMetadata("design:paramtypes", target);
|
|
300
|
+
return deps ?? [];
|
|
301
|
+
}
|
|
302
|
+
};
|
|
303
|
+
|
|
304
|
+
// src/decorators.ts
|
|
305
|
+
function Controller(path = "") {
|
|
306
|
+
return function(target) {
|
|
307
|
+
Reflect.defineMetadata(CONTROLLER, path, target);
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
__name(Controller, "Controller");
|
|
311
|
+
function Injectable(type = "singleton") {
|
|
312
|
+
return function(target) {
|
|
313
|
+
Reflect.defineMetadata(INJECTABLE, type, target);
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
__name(Injectable, "Injectable");
|
|
317
|
+
function OnSend(path = "") {
|
|
318
|
+
return function(_target, _property, descriptor) {
|
|
319
|
+
Reflect.defineMetadata(HANDLER, {
|
|
320
|
+
path,
|
|
321
|
+
type: "send"
|
|
322
|
+
}, descriptor.value);
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
__name(OnSend, "OnSend");
|
|
326
|
+
function OnInvoke(path = "") {
|
|
327
|
+
return function(_target, _property, descriptor) {
|
|
328
|
+
Reflect.defineMetadata(HANDLER, {
|
|
329
|
+
path,
|
|
330
|
+
type: "invoke"
|
|
331
|
+
}, descriptor.value);
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
__name(OnInvoke, "OnInvoke");
|
|
335
|
+
function _getParams(target, property) {
|
|
336
|
+
const prevParams = Reflect.getMetadata(PARAM, target, property);
|
|
337
|
+
return prevParams ?? [];
|
|
338
|
+
}
|
|
339
|
+
__name(_getParams, "_getParams");
|
|
340
|
+
function _getGuards(target) {
|
|
341
|
+
const prevGuards = Reflect.getMetadata(GUARD, target);
|
|
342
|
+
return prevGuards ?? [];
|
|
343
|
+
}
|
|
344
|
+
__name(_getGuards, "_getGuards");
|
|
345
|
+
function Payload() {
|
|
346
|
+
return function(target, property, paramIndex) {
|
|
347
|
+
const params = _getParams(target, property);
|
|
348
|
+
params[paramIndex] = "payload";
|
|
349
|
+
Reflect.defineMetadata(PARAM, params, target, property);
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
__name(Payload, "Payload");
|
|
353
|
+
function Event() {
|
|
354
|
+
return function(target, property, paramIndex) {
|
|
355
|
+
const params = _getParams(target, property);
|
|
356
|
+
params[paramIndex] = "event";
|
|
357
|
+
Reflect.defineMetadata(PARAM, params, target, property);
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
__name(Event, "Event");
|
|
361
|
+
function Ctx() {
|
|
362
|
+
return function(target, property, paramIndex) {
|
|
363
|
+
const params = _getParams(target, property);
|
|
364
|
+
params[paramIndex] = "ctx";
|
|
365
|
+
Reflect.defineMetadata(PARAM, params, target, property);
|
|
366
|
+
};
|
|
367
|
+
}
|
|
368
|
+
__name(Ctx, "Ctx");
|
|
369
|
+
function UseGuards(...guards) {
|
|
370
|
+
return function(_target, _property, descriptor) {
|
|
371
|
+
const target = descriptor ? descriptor.value : _target;
|
|
372
|
+
const prevGuards = _getGuards(target).filter((prevGuard) => !guards.includes(prevGuard));
|
|
373
|
+
Reflect.defineMetadata(GUARD, [
|
|
374
|
+
...guards,
|
|
375
|
+
...prevGuards
|
|
376
|
+
], target);
|
|
377
|
+
};
|
|
378
|
+
}
|
|
379
|
+
__name(UseGuards, "UseGuards");
|
|
380
|
+
function SetMetadata(key, value) {
|
|
381
|
+
return function(target, propertyKey, descriptor) {
|
|
382
|
+
const targetKey = descriptor ? descriptor.value : target;
|
|
383
|
+
Reflect.defineMetadata(key, value, targetKey);
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
__name(SetMetadata, "SetMetadata");
|
|
387
|
+
export {
|
|
388
|
+
Application,
|
|
389
|
+
Controller,
|
|
390
|
+
Ctx,
|
|
391
|
+
Event,
|
|
392
|
+
ExecutionContext,
|
|
393
|
+
Injectable,
|
|
394
|
+
OnInvoke,
|
|
395
|
+
OnSend,
|
|
396
|
+
Payload,
|
|
397
|
+
Reflector,
|
|
398
|
+
SetMetadata,
|
|
399
|
+
UseGuards,
|
|
400
|
+
applyDecorators
|
|
401
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "electron-injector",
|
|
3
|
+
"version": "1.0.2",
|
|
4
|
+
"description": "Biblioteca para el desarrollo de aplicaciones con electron que proporciona una arquitectura robusta con inyección e inversion de dependencias.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "tsup"
|
|
9
|
+
},
|
|
10
|
+
"author": {
|
|
11
|
+
"name": "Alejandro Jorgen",
|
|
12
|
+
"email": "ajorgenmarten35@gmail.com",
|
|
13
|
+
"url": "https://github.com/ajorgenmarten"
|
|
14
|
+
},
|
|
15
|
+
"keywords": [
|
|
16
|
+
"electron",
|
|
17
|
+
"dependency injection",
|
|
18
|
+
"dependency inversion",
|
|
19
|
+
"injection",
|
|
20
|
+
"inversion"
|
|
21
|
+
],
|
|
22
|
+
"repository": {
|
|
23
|
+
"type": "git",
|
|
24
|
+
"url": "git+https://github.com/ajorgenmarten/electron-injector"
|
|
25
|
+
},
|
|
26
|
+
"license": "MIT",
|
|
27
|
+
"homepage": "https://github.com/ajorgenmarten/electron-injector#readme",
|
|
28
|
+
"bugs": {
|
|
29
|
+
"email": "ajorgenmarten35@gmail.com",
|
|
30
|
+
"url": "https://github.com/ajorgenmarten/electron-injector/issues"
|
|
31
|
+
},
|
|
32
|
+
"packageManager": "pnpm@10.24.0",
|
|
33
|
+
"type": "module",
|
|
34
|
+
"devDependencies": {
|
|
35
|
+
"@eslint/eslintrc": "^3.3.3",
|
|
36
|
+
"@eslint/js": "^9.39.1",
|
|
37
|
+
"@swc/core": "^1.15.3",
|
|
38
|
+
"@types/debug": "^4.1.12",
|
|
39
|
+
"@types/node": "^24.10.1",
|
|
40
|
+
"electron": "^39.2.4",
|
|
41
|
+
"eslint": "^9.39.1",
|
|
42
|
+
"eslint-config-prettier": "^10.1.8",
|
|
43
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
44
|
+
"globals": "^16.5.0",
|
|
45
|
+
"prettier": "^3.7.2",
|
|
46
|
+
"rxjs": "^7.8.2",
|
|
47
|
+
"tsup": "^8.5.1",
|
|
48
|
+
"typescript": "^5.9.3",
|
|
49
|
+
"typescript-eslint": "^8.48.0"
|
|
50
|
+
},
|
|
51
|
+
"peerDependencies": {
|
|
52
|
+
"electron": "^39.2.4",
|
|
53
|
+
"rxjs": "^7.8.2"
|
|
54
|
+
},
|
|
55
|
+
"files": [
|
|
56
|
+
"dist/",
|
|
57
|
+
"LICENSE",
|
|
58
|
+
"README.md"
|
|
59
|
+
],
|
|
60
|
+
"dependencies": {
|
|
61
|
+
"debug": "^4.4.3",
|
|
62
|
+
"reflect-metadata": "0.2.2"
|
|
63
|
+
}
|
|
64
|
+
}
|