electron-injector 1.0.3 → 1.1.1
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 +30 -25
- package/dist/index.cjs +149 -41
- package/dist/index.d.cts +42 -4
- package/dist/index.d.ts +42 -4
- package/dist/index.js +140 -41
- package/package.json +5 -1
package/README.md
CHANGED
|
@@ -27,7 +27,7 @@ Nace de la necesidad de crear aplicaciones de escritorio multiplataforma donde n
|
|
|
27
27
|
|
|
28
28
|
## 📦 Instalación
|
|
29
29
|
```bash
|
|
30
|
-
npm install electron-injector rxjs
|
|
30
|
+
npm install electron-injector rxjs class-validator class-transformer
|
|
31
31
|
```
|
|
32
32
|
|
|
33
33
|
> **Nota:**
|
|
@@ -48,34 +48,39 @@ import { Application } from 'electron-injector';
|
|
|
48
48
|
import { UserController } from './controllers/user.controller';
|
|
49
49
|
import { AuthGuard } from './guards/auth.guard';
|
|
50
50
|
import { UserService } from './services/user.service';
|
|
51
|
+
import { DtoFilter } from './filters/dto.filter';
|
|
51
52
|
|
|
52
|
-
|
|
53
|
-
const electronApp = new Application({
|
|
54
|
-
providers: [
|
|
55
|
-
UserService,
|
|
56
|
-
AuthGuard,
|
|
57
|
-
],
|
|
58
|
-
controllers: [
|
|
59
|
-
UserController,
|
|
60
|
-
],
|
|
61
|
-
});
|
|
62
|
-
|
|
63
|
-
await app.whenReady();
|
|
64
|
-
|
|
53
|
+
function createWindow() {
|
|
65
54
|
const mainWindow = new BrowserWindow({
|
|
66
|
-
width:
|
|
67
|
-
height:
|
|
55
|
+
width: 900,
|
|
56
|
+
height: 670,
|
|
57
|
+
autoHideMenuBar: true,
|
|
58
|
+
...(process.platform === 'linux' ? { icon } : {}),
|
|
68
59
|
webPreferences: {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
60
|
+
preload: join(__dirname, '../preload/index.js'),
|
|
61
|
+
sandbox: false
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
if (is.dev && process.env['ELECTRON_RENDERER_URL']) {
|
|
66
|
+
mainWindow.loadURL(process.env['ELECTRON_RENDERER_URL'])
|
|
67
|
+
} else {
|
|
68
|
+
mainWindow.loadFile(join(__dirname, '../renderer/index.html'))
|
|
69
|
+
}
|
|
76
70
|
}
|
|
77
71
|
|
|
78
|
-
|
|
72
|
+
app.whenReady().then(() {
|
|
73
|
+
const application = Application.create({
|
|
74
|
+
providers: [UserService, AuthGuard],
|
|
75
|
+
controllers: [UserController]
|
|
76
|
+
})
|
|
77
|
+
|
|
78
|
+
application.useGlobalFilters(DtoFilter)
|
|
79
|
+
|
|
80
|
+
application.bootstrap()
|
|
81
|
+
|
|
82
|
+
createWindow()
|
|
83
|
+
})
|
|
79
84
|
```
|
|
80
85
|
|
|
81
86
|
## 2. Creando un servicio
|
|
@@ -221,7 +226,7 @@ onMessage(@Payload() data: any) {
|
|
|
221
226
|
|
|
222
227
|
` @Payload() `
|
|
223
228
|
|
|
224
|
-
Inyecta el payload recibido desde el renderer.
|
|
229
|
+
Inyecta el payload recibido desde el renderer. Si defines como tipo una clase decorada con class-validator, esto realiza la validación automática.
|
|
225
230
|
```ts
|
|
226
231
|
@OnInvoke('update')
|
|
227
232
|
async update(@Payload() data: any) {
|
package/dist/index.cjs
CHANGED
|
@@ -32,14 +32,23 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
32
32
|
var index_exports = {};
|
|
33
33
|
__export(index_exports, {
|
|
34
34
|
Application: () => Application,
|
|
35
|
+
Catch: () => Catch,
|
|
36
|
+
CircularDependency: () => CircularDependency,
|
|
35
37
|
Controller: () => Controller,
|
|
38
|
+
ControllerIsNotValid: () => ControllerIsNotValid,
|
|
36
39
|
Ctx: () => Ctx,
|
|
40
|
+
DataValidationError: () => DataValidationError,
|
|
41
|
+
ElectronInjectorError: () => ElectronInjectorError,
|
|
37
42
|
Event: () => Event,
|
|
38
43
|
ExecutionContext: () => ExecutionContext,
|
|
44
|
+
ForbiddenAccessError: () => ForbiddenAccessError,
|
|
39
45
|
Injectable: () => Injectable,
|
|
46
|
+
IsNotExceptionFilter: () => IsNotExceptionFilter,
|
|
40
47
|
OnInvoke: () => OnInvoke,
|
|
41
48
|
OnSend: () => OnSend,
|
|
42
49
|
Payload: () => Payload,
|
|
50
|
+
ProviderIsNotInjectable: () => ProviderIsNotInjectable,
|
|
51
|
+
ProviderNotFound: () => ProviderNotFound,
|
|
43
52
|
Reflector: () => Reflector,
|
|
44
53
|
SetMetadata: () => SetMetadata,
|
|
45
54
|
UseGuards: () => UseGuards,
|
|
@@ -68,6 +77,14 @@ var ProviderNotFound = class extends ElectronInjectorError {
|
|
|
68
77
|
super(`Provider '${providerName}' not found`);
|
|
69
78
|
}
|
|
70
79
|
};
|
|
80
|
+
var IsNotExceptionFilter = class extends ElectronInjectorError {
|
|
81
|
+
static {
|
|
82
|
+
__name(this, "IsNotExceptionFilter");
|
|
83
|
+
}
|
|
84
|
+
constructor(filterName) {
|
|
85
|
+
super(`Class ${filterName} is not a filter. Please ensure it is decorated with @Catch(...filters)`);
|
|
86
|
+
}
|
|
87
|
+
};
|
|
71
88
|
var CircularDependency = class extends ElectronInjectorError {
|
|
72
89
|
static {
|
|
73
90
|
__name(this, "CircularDependency");
|
|
@@ -92,6 +109,26 @@ var ControllerIsNotValid = class extends ElectronInjectorError {
|
|
|
92
109
|
super(`Controller '${controllerName}' is not valid. Please ensure it is decorated with @Controller()`);
|
|
93
110
|
}
|
|
94
111
|
};
|
|
112
|
+
var DataValidationError = class {
|
|
113
|
+
static {
|
|
114
|
+
__name(this, "DataValidationError");
|
|
115
|
+
}
|
|
116
|
+
messages;
|
|
117
|
+
constructor(validationError) {
|
|
118
|
+
this.messages = validationError.constraints;
|
|
119
|
+
}
|
|
120
|
+
get Messages() {
|
|
121
|
+
return this.messages;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
var ForbiddenAccessError = class extends ElectronInjectorError {
|
|
125
|
+
static {
|
|
126
|
+
__name(this, "ForbiddenAccessError");
|
|
127
|
+
}
|
|
128
|
+
constructor(path, guardName) {
|
|
129
|
+
super(`Can not access to "${path}" path, by the gaurd "${guardName}"`);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
95
132
|
|
|
96
133
|
// src/keys.ts
|
|
97
134
|
var CONTROLLER = Symbol("electron-di:controller");
|
|
@@ -99,6 +136,7 @@ var INJECTABLE = Symbol("electron-di:injectable");
|
|
|
99
136
|
var HANDLER = Symbol("electron-di:handler");
|
|
100
137
|
var PARAM = Symbol("electron-di:param");
|
|
101
138
|
var GUARD = Symbol("electron-di:guard");
|
|
139
|
+
var FILTER = Symbol("electron-di:filter");
|
|
102
140
|
|
|
103
141
|
// src/utilities.ts
|
|
104
142
|
var Reflector = class {
|
|
@@ -225,19 +263,33 @@ var DEV_LOGGER = devLogger;
|
|
|
225
263
|
|
|
226
264
|
// src/application.ts
|
|
227
265
|
var import_electron = require("electron");
|
|
266
|
+
var import_class_validator = require("class-validator");
|
|
267
|
+
var import_class_transformer = require("class-transformer");
|
|
228
268
|
var Application = class _Application {
|
|
229
269
|
static {
|
|
230
270
|
__name(this, "Application");
|
|
231
271
|
}
|
|
232
272
|
configOptions;
|
|
273
|
+
validationOptions;
|
|
233
274
|
container = new Container();
|
|
234
|
-
|
|
235
|
-
|
|
275
|
+
filters = /* @__PURE__ */ new Map();
|
|
276
|
+
static create(configOptions, validationOptions = {}) {
|
|
277
|
+
return new _Application(configOptions, validationOptions);
|
|
278
|
+
}
|
|
279
|
+
useGlobalFilters(...filters) {
|
|
280
|
+
for (const filter of filters) {
|
|
281
|
+
const exceptionsClasses = Reflect.getMetadata(FILTER, filter);
|
|
282
|
+
if (!exceptionsClasses) throw new IsNotExceptionFilter(filter.name);
|
|
283
|
+
exceptionsClasses.forEach((excls) => {
|
|
284
|
+
this.filters.set(excls, filter);
|
|
285
|
+
this.container.addProvider(filter);
|
|
286
|
+
});
|
|
287
|
+
}
|
|
236
288
|
}
|
|
237
|
-
constructor(configOptions) {
|
|
289
|
+
constructor(configOptions, validationOptions) {
|
|
238
290
|
this.configOptions = configOptions;
|
|
291
|
+
this.validationOptions = validationOptions;
|
|
239
292
|
this.loadProviders();
|
|
240
|
-
this.loadControllers();
|
|
241
293
|
}
|
|
242
294
|
loadProviders() {
|
|
243
295
|
for (const provider of this.configOptions.providers || []) {
|
|
@@ -245,7 +297,7 @@ var Application = class _Application {
|
|
|
245
297
|
DEV_LOGGER(`Provider ${typeof provider == "object" ? provider.provided.name : provider.name} loaded`);
|
|
246
298
|
}
|
|
247
299
|
}
|
|
248
|
-
|
|
300
|
+
bootstrap() {
|
|
249
301
|
for (const controller of this.configOptions.controllers || []) {
|
|
250
302
|
const controllerPrefix = this.getControllerPrefix(controller);
|
|
251
303
|
const controllerDependencies = this.getControllerDependencies(controller);
|
|
@@ -261,11 +313,28 @@ var Application = class _Application {
|
|
|
261
313
|
const handlerCallback = /* @__PURE__ */ __name(async (event, data) => {
|
|
262
314
|
const executionContext = new ExecutionContext(controller, controllerInstance[controllerMethod], data, event);
|
|
263
315
|
for (const guard of guards) {
|
|
264
|
-
|
|
265
|
-
|
|
316
|
+
try {
|
|
317
|
+
const response = await this.guardExecute(guard, executionContext);
|
|
318
|
+
if (!response) return {
|
|
319
|
+
success: false,
|
|
320
|
+
error: new ForbiddenAccessError(path, guard.constructor.prototype.name)
|
|
321
|
+
};
|
|
322
|
+
} catch (e) {
|
|
323
|
+
return await this.useFilter(e, executionContext);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
let params = [];
|
|
327
|
+
try {
|
|
328
|
+
params = await this.getParams(controllerInstance, controllerMethod, executionContext);
|
|
329
|
+
} catch (e) {
|
|
330
|
+
return await this.useFilter(e, executionContext);
|
|
331
|
+
}
|
|
332
|
+
let controllerResult = void 0;
|
|
333
|
+
try {
|
|
334
|
+
controllerResult = await this.controllerExecute(controllerInstance, controllerInstance[controllerMethod], params);
|
|
335
|
+
} catch (e) {
|
|
336
|
+
return await this.useFilter(e, executionContext);
|
|
266
337
|
}
|
|
267
|
-
const params = this.getParams(controllerInstance, controllerMethod, executionContext);
|
|
268
|
-
const controllerResult = await this.controllerExecute(controllerInstance, controllerInstance[controllerMethod], params);
|
|
269
338
|
return controllerResult;
|
|
270
339
|
}, "handlerCallback");
|
|
271
340
|
if (handlerMetadata.type === "invoke") {
|
|
@@ -273,18 +342,28 @@ var Application = class _Application {
|
|
|
273
342
|
} else {
|
|
274
343
|
import_electron.ipcMain.on(path, handlerCallback);
|
|
275
344
|
}
|
|
345
|
+
DEV_LOGGER(`[Electron Injector] Route ${path} has initialized (${handlerMetadata.type === "invoke" ? "invoke" : "send"})`);
|
|
276
346
|
}
|
|
277
347
|
}
|
|
278
348
|
}
|
|
279
|
-
getParams(target, propertyKey, executionContext) {
|
|
349
|
+
async getParams(target, propertyKey, executionContext) {
|
|
280
350
|
const params = Reflect.getMetadata(PARAM, target, propertyKey);
|
|
281
351
|
if (!params) return [];
|
|
282
|
-
return params.map((param) => {
|
|
352
|
+
return await Promise.all(params.map(async (param, index) => {
|
|
283
353
|
if (param === "ctx") return executionContext;
|
|
284
354
|
if (param === "event") return executionContext.event;
|
|
285
|
-
if (param === "payload")
|
|
355
|
+
if (param === "payload") {
|
|
356
|
+
const validationClass = Reflect.getMetadata("design:paramtypes", target, propertyKey)[index];
|
|
357
|
+
const metadata = (0, import_class_validator.getMetadataStorage)().getTargetValidationMetadatas(validationClass, null, false, false);
|
|
358
|
+
if (typeof validationClass == "function" && metadata.length) {
|
|
359
|
+
const validatorObjectInstance = (0, import_class_transformer.plainToInstance)(validationClass, executionContext.payload);
|
|
360
|
+
const errors = await (0, import_class_validator.validate)(validatorObjectInstance, this.validationOptions);
|
|
361
|
+
if (errors.length) throw new DataValidationError(errors[0]);
|
|
362
|
+
}
|
|
363
|
+
return executionContext.payload;
|
|
364
|
+
}
|
|
286
365
|
return void 0;
|
|
287
|
-
});
|
|
366
|
+
}));
|
|
288
367
|
}
|
|
289
368
|
buildPath(controllerPrefix, methodPath) {
|
|
290
369
|
const prefix = controllerPrefix.trim();
|
|
@@ -295,39 +374,48 @@ var Application = class _Application {
|
|
|
295
374
|
return "";
|
|
296
375
|
}
|
|
297
376
|
async guardExecute(guard, executionContext) {
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
if (!guardResult) return false;
|
|
308
|
-
}
|
|
309
|
-
return true;
|
|
310
|
-
} catch (error) {
|
|
311
|
-
PROD_LOGGER(error);
|
|
312
|
-
return false;
|
|
377
|
+
const guardResult = guard.canActivate(executionContext);
|
|
378
|
+
if (guardResult instanceof import_rxjs.Observable) {
|
|
379
|
+
const result = await (0, import_rxjs.lastValueFrom)(guardResult.pipe((0, import_rxjs.first)()));
|
|
380
|
+
if (!result) return false;
|
|
381
|
+
} else if (guardResult instanceof Promise) {
|
|
382
|
+
const result = await guardResult;
|
|
383
|
+
if (!result) return false;
|
|
384
|
+
} else {
|
|
385
|
+
if (!guardResult) return false;
|
|
313
386
|
}
|
|
387
|
+
return true;
|
|
314
388
|
}
|
|
315
389
|
async controllerExecute(context, target, params) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
controllerResult = await controllerResult;
|
|
324
|
-
}
|
|
390
|
+
const boundedTarget = target.bind(context);
|
|
391
|
+
let controllerResult = boundedTarget(...params);
|
|
392
|
+
while (controllerResult instanceof import_rxjs.Observable || controllerResult instanceof Promise) {
|
|
393
|
+
if (controllerResult instanceof import_rxjs.Observable) {
|
|
394
|
+
controllerResult = await (0, import_rxjs.lastValueFrom)(controllerResult);
|
|
395
|
+
} else if (controllerResult instanceof Promise) {
|
|
396
|
+
controllerResult = await controllerResult;
|
|
325
397
|
}
|
|
326
|
-
return controllerResult;
|
|
327
|
-
} catch (error) {
|
|
328
|
-
PROD_LOGGER(error.message ?? error);
|
|
329
|
-
return void 0;
|
|
330
398
|
}
|
|
399
|
+
return controllerResult;
|
|
400
|
+
}
|
|
401
|
+
async useFilter(error, executionContext) {
|
|
402
|
+
PROD_LOGGER(error);
|
|
403
|
+
for (const [cls, fltr] of this.filters) {
|
|
404
|
+
if (!(error instanceof cls)) continue;
|
|
405
|
+
const filterInstance = this.container.resolve(fltr);
|
|
406
|
+
const response = filterInstance.catch(error, executionContext);
|
|
407
|
+
if (response instanceof Promise) {
|
|
408
|
+
return await response;
|
|
409
|
+
}
|
|
410
|
+
if (response instanceof import_rxjs.Observable) {
|
|
411
|
+
return await (0, import_rxjs.lastValueFrom)(response);
|
|
412
|
+
}
|
|
413
|
+
return response;
|
|
414
|
+
}
|
|
415
|
+
return {
|
|
416
|
+
success: false,
|
|
417
|
+
error
|
|
418
|
+
};
|
|
331
419
|
}
|
|
332
420
|
getHandlerMetadata(target) {
|
|
333
421
|
const handlerMetadata = Reflect.getMetadata(HANDLER, target);
|
|
@@ -431,17 +519,37 @@ function SetMetadata(key, value) {
|
|
|
431
519
|
};
|
|
432
520
|
}
|
|
433
521
|
__name(SetMetadata, "SetMetadata");
|
|
522
|
+
function Catch(...filters) {
|
|
523
|
+
return function(target) {
|
|
524
|
+
const prevFilters = Reflect.getMetadata(FILTER, target) || [];
|
|
525
|
+
Reflect.defineMetadata(INJECTABLE, "singleton", target);
|
|
526
|
+
Reflect.defineMetadata(FILTER, [
|
|
527
|
+
...prevFilters,
|
|
528
|
+
...filters
|
|
529
|
+
], target);
|
|
530
|
+
};
|
|
531
|
+
}
|
|
532
|
+
__name(Catch, "Catch");
|
|
434
533
|
// Annotate the CommonJS export names for ESM import in node:
|
|
435
534
|
0 && (module.exports = {
|
|
436
535
|
Application,
|
|
536
|
+
Catch,
|
|
537
|
+
CircularDependency,
|
|
437
538
|
Controller,
|
|
539
|
+
ControllerIsNotValid,
|
|
438
540
|
Ctx,
|
|
541
|
+
DataValidationError,
|
|
542
|
+
ElectronInjectorError,
|
|
439
543
|
Event,
|
|
440
544
|
ExecutionContext,
|
|
545
|
+
ForbiddenAccessError,
|
|
441
546
|
Injectable,
|
|
547
|
+
IsNotExceptionFilter,
|
|
442
548
|
OnInvoke,
|
|
443
549
|
OnSend,
|
|
444
550
|
Payload,
|
|
551
|
+
ProviderIsNotInjectable,
|
|
552
|
+
ProviderNotFound,
|
|
445
553
|
Reflector,
|
|
446
554
|
SetMetadata,
|
|
447
555
|
UseGuards,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { IpcMainEvent, IpcMainInvokeEvent } from 'electron';
|
|
3
|
+
import { ValidatorOptions, ValidationError } from 'class-validator';
|
|
3
4
|
|
|
4
5
|
declare class Reflector {
|
|
5
6
|
get<T = any>(key: any, target: any): T;
|
|
@@ -30,6 +31,9 @@ type Provider = Class | {
|
|
|
30
31
|
interface CanActivate {
|
|
31
32
|
canActivate: (context: ExecutionContext) => boolean | Promise<boolean> | Observable<boolean>;
|
|
32
33
|
}
|
|
34
|
+
interface ExceptionFilter {
|
|
35
|
+
catch: (e: any, context: ExecutionContext) => any;
|
|
36
|
+
}
|
|
33
37
|
interface ConfigOptions {
|
|
34
38
|
providers?: Provider[];
|
|
35
39
|
controllers?: Class[];
|
|
@@ -37,15 +41,19 @@ interface ConfigOptions {
|
|
|
37
41
|
|
|
38
42
|
declare class Application {
|
|
39
43
|
private configOptions;
|
|
44
|
+
private validationOptions;
|
|
40
45
|
private container;
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
private filters;
|
|
47
|
+
static create(configOptions: ConfigOptions, validationOptions?: ValidatorOptions): Application;
|
|
48
|
+
useGlobalFilters(...filters: Class<ExceptionFilter>[]): void;
|
|
49
|
+
constructor(configOptions: ConfigOptions, validationOptions: ValidatorOptions);
|
|
43
50
|
private loadProviders;
|
|
44
|
-
|
|
51
|
+
bootstrap(): void;
|
|
45
52
|
private getParams;
|
|
46
53
|
private buildPath;
|
|
47
54
|
private guardExecute;
|
|
48
55
|
private controllerExecute;
|
|
56
|
+
private useFilter;
|
|
49
57
|
private getHandlerMetadata;
|
|
50
58
|
private getGuards;
|
|
51
59
|
private getControllerPrefix;
|
|
@@ -61,5 +69,35 @@ declare function Event(): ParameterDecorator;
|
|
|
61
69
|
declare function Ctx(): ParameterDecorator;
|
|
62
70
|
declare function UseGuards(...guards: Class<CanActivate>[]): (_target: Object, _property?: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
63
71
|
declare function SetMetadata(key: any, value: any): (target: Object, propertyKey?: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
72
|
+
declare function Catch(...filters: Class[]): (target: Object) => void;
|
|
73
|
+
|
|
74
|
+
declare class ElectronInjectorError extends Error {
|
|
75
|
+
constructor(message: string);
|
|
76
|
+
}
|
|
77
|
+
declare class ProviderNotFound extends ElectronInjectorError {
|
|
78
|
+
constructor(providerName: string);
|
|
79
|
+
}
|
|
80
|
+
declare class IsNotExceptionFilter extends ElectronInjectorError {
|
|
81
|
+
constructor(filterName: string);
|
|
82
|
+
}
|
|
83
|
+
declare class CircularDependency extends ElectronInjectorError {
|
|
84
|
+
constructor(providerName: string);
|
|
85
|
+
}
|
|
86
|
+
declare class ProviderIsNotInjectable extends ElectronInjectorError {
|
|
87
|
+
constructor(providerName: string);
|
|
88
|
+
}
|
|
89
|
+
declare class ControllerIsNotValid extends ElectronInjectorError {
|
|
90
|
+
constructor(controllerName: string);
|
|
91
|
+
}
|
|
92
|
+
declare class DataValidationError {
|
|
93
|
+
private messages;
|
|
94
|
+
constructor(validationError: ValidationError);
|
|
95
|
+
get Messages(): {
|
|
96
|
+
[type: string]: string;
|
|
97
|
+
} | undefined;
|
|
98
|
+
}
|
|
99
|
+
declare class ForbiddenAccessError extends ElectronInjectorError {
|
|
100
|
+
constructor(path: string, guardName: string);
|
|
101
|
+
}
|
|
64
102
|
|
|
65
|
-
export { Application, type CanActivate, type ConfigOptions, Controller, Ctx, Event, ExecutionContext, Injectable, type InjectableType, OnInvoke, OnSend, Payload, Reflector, SetMetadata, UseGuards, applyDecorators };
|
|
103
|
+
export { Application, type CanActivate, Catch, CircularDependency, type ConfigOptions, Controller, ControllerIsNotValid, Ctx, DataValidationError, ElectronInjectorError, Event, type ExceptionFilter, ExecutionContext, ForbiddenAccessError, Injectable, type InjectableType, IsNotExceptionFilter, OnInvoke, OnSend, Payload, ProviderIsNotInjectable, ProviderNotFound, Reflector, SetMetadata, UseGuards, applyDecorators };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Observable } from 'rxjs';
|
|
2
2
|
import { IpcMainEvent, IpcMainInvokeEvent } from 'electron';
|
|
3
|
+
import { ValidatorOptions, ValidationError } from 'class-validator';
|
|
3
4
|
|
|
4
5
|
declare class Reflector {
|
|
5
6
|
get<T = any>(key: any, target: any): T;
|
|
@@ -30,6 +31,9 @@ type Provider = Class | {
|
|
|
30
31
|
interface CanActivate {
|
|
31
32
|
canActivate: (context: ExecutionContext) => boolean | Promise<boolean> | Observable<boolean>;
|
|
32
33
|
}
|
|
34
|
+
interface ExceptionFilter {
|
|
35
|
+
catch: (e: any, context: ExecutionContext) => any;
|
|
36
|
+
}
|
|
33
37
|
interface ConfigOptions {
|
|
34
38
|
providers?: Provider[];
|
|
35
39
|
controllers?: Class[];
|
|
@@ -37,15 +41,19 @@ interface ConfigOptions {
|
|
|
37
41
|
|
|
38
42
|
declare class Application {
|
|
39
43
|
private configOptions;
|
|
44
|
+
private validationOptions;
|
|
40
45
|
private container;
|
|
41
|
-
|
|
42
|
-
|
|
46
|
+
private filters;
|
|
47
|
+
static create(configOptions: ConfigOptions, validationOptions?: ValidatorOptions): Application;
|
|
48
|
+
useGlobalFilters(...filters: Class<ExceptionFilter>[]): void;
|
|
49
|
+
constructor(configOptions: ConfigOptions, validationOptions: ValidatorOptions);
|
|
43
50
|
private loadProviders;
|
|
44
|
-
|
|
51
|
+
bootstrap(): void;
|
|
45
52
|
private getParams;
|
|
46
53
|
private buildPath;
|
|
47
54
|
private guardExecute;
|
|
48
55
|
private controllerExecute;
|
|
56
|
+
private useFilter;
|
|
49
57
|
private getHandlerMetadata;
|
|
50
58
|
private getGuards;
|
|
51
59
|
private getControllerPrefix;
|
|
@@ -61,5 +69,35 @@ declare function Event(): ParameterDecorator;
|
|
|
61
69
|
declare function Ctx(): ParameterDecorator;
|
|
62
70
|
declare function UseGuards(...guards: Class<CanActivate>[]): (_target: Object, _property?: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
63
71
|
declare function SetMetadata(key: any, value: any): (target: Object, propertyKey?: string | symbol, descriptor?: PropertyDescriptor) => void;
|
|
72
|
+
declare function Catch(...filters: Class[]): (target: Object) => void;
|
|
73
|
+
|
|
74
|
+
declare class ElectronInjectorError extends Error {
|
|
75
|
+
constructor(message: string);
|
|
76
|
+
}
|
|
77
|
+
declare class ProviderNotFound extends ElectronInjectorError {
|
|
78
|
+
constructor(providerName: string);
|
|
79
|
+
}
|
|
80
|
+
declare class IsNotExceptionFilter extends ElectronInjectorError {
|
|
81
|
+
constructor(filterName: string);
|
|
82
|
+
}
|
|
83
|
+
declare class CircularDependency extends ElectronInjectorError {
|
|
84
|
+
constructor(providerName: string);
|
|
85
|
+
}
|
|
86
|
+
declare class ProviderIsNotInjectable extends ElectronInjectorError {
|
|
87
|
+
constructor(providerName: string);
|
|
88
|
+
}
|
|
89
|
+
declare class ControllerIsNotValid extends ElectronInjectorError {
|
|
90
|
+
constructor(controllerName: string);
|
|
91
|
+
}
|
|
92
|
+
declare class DataValidationError {
|
|
93
|
+
private messages;
|
|
94
|
+
constructor(validationError: ValidationError);
|
|
95
|
+
get Messages(): {
|
|
96
|
+
[type: string]: string;
|
|
97
|
+
} | undefined;
|
|
98
|
+
}
|
|
99
|
+
declare class ForbiddenAccessError extends ElectronInjectorError {
|
|
100
|
+
constructor(path: string, guardName: string);
|
|
101
|
+
}
|
|
64
102
|
|
|
65
|
-
export { Application, type CanActivate, type ConfigOptions, Controller, Ctx, Event, ExecutionContext, Injectable, type InjectableType, OnInvoke, OnSend, Payload, Reflector, SetMetadata, UseGuards, applyDecorators };
|
|
103
|
+
export { Application, type CanActivate, Catch, CircularDependency, type ConfigOptions, Controller, ControllerIsNotValid, Ctx, DataValidationError, ElectronInjectorError, Event, type ExceptionFilter, ExecutionContext, ForbiddenAccessError, Injectable, type InjectableType, IsNotExceptionFilter, OnInvoke, OnSend, Payload, ProviderIsNotInjectable, ProviderNotFound, Reflector, SetMetadata, UseGuards, applyDecorators };
|
package/dist/index.js
CHANGED
|
@@ -24,6 +24,14 @@ var ProviderNotFound = class extends ElectronInjectorError {
|
|
|
24
24
|
super(`Provider '${providerName}' not found`);
|
|
25
25
|
}
|
|
26
26
|
};
|
|
27
|
+
var IsNotExceptionFilter = class extends ElectronInjectorError {
|
|
28
|
+
static {
|
|
29
|
+
__name(this, "IsNotExceptionFilter");
|
|
30
|
+
}
|
|
31
|
+
constructor(filterName) {
|
|
32
|
+
super(`Class ${filterName} is not a filter. Please ensure it is decorated with @Catch(...filters)`);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
27
35
|
var CircularDependency = class extends ElectronInjectorError {
|
|
28
36
|
static {
|
|
29
37
|
__name(this, "CircularDependency");
|
|
@@ -48,6 +56,26 @@ var ControllerIsNotValid = class extends ElectronInjectorError {
|
|
|
48
56
|
super(`Controller '${controllerName}' is not valid. Please ensure it is decorated with @Controller()`);
|
|
49
57
|
}
|
|
50
58
|
};
|
|
59
|
+
var DataValidationError = class {
|
|
60
|
+
static {
|
|
61
|
+
__name(this, "DataValidationError");
|
|
62
|
+
}
|
|
63
|
+
messages;
|
|
64
|
+
constructor(validationError) {
|
|
65
|
+
this.messages = validationError.constraints;
|
|
66
|
+
}
|
|
67
|
+
get Messages() {
|
|
68
|
+
return this.messages;
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
var ForbiddenAccessError = class extends ElectronInjectorError {
|
|
72
|
+
static {
|
|
73
|
+
__name(this, "ForbiddenAccessError");
|
|
74
|
+
}
|
|
75
|
+
constructor(path, guardName) {
|
|
76
|
+
super(`Can not access to "${path}" path, by the gaurd "${guardName}"`);
|
|
77
|
+
}
|
|
78
|
+
};
|
|
51
79
|
|
|
52
80
|
// src/keys.ts
|
|
53
81
|
var CONTROLLER = Symbol("electron-di:controller");
|
|
@@ -55,6 +83,7 @@ var INJECTABLE = Symbol("electron-di:injectable");
|
|
|
55
83
|
var HANDLER = Symbol("electron-di:handler");
|
|
56
84
|
var PARAM = Symbol("electron-di:param");
|
|
57
85
|
var GUARD = Symbol("electron-di:guard");
|
|
86
|
+
var FILTER = Symbol("electron-di:filter");
|
|
58
87
|
|
|
59
88
|
// src/utilities.ts
|
|
60
89
|
var Reflector = class {
|
|
@@ -181,19 +210,33 @@ var DEV_LOGGER = devLogger;
|
|
|
181
210
|
|
|
182
211
|
// src/application.ts
|
|
183
212
|
import { ipcMain } from "electron";
|
|
213
|
+
import { getMetadataStorage, validate } from "class-validator";
|
|
214
|
+
import { plainToInstance } from "class-transformer";
|
|
184
215
|
var Application = class _Application {
|
|
185
216
|
static {
|
|
186
217
|
__name(this, "Application");
|
|
187
218
|
}
|
|
188
219
|
configOptions;
|
|
220
|
+
validationOptions;
|
|
189
221
|
container = new Container();
|
|
190
|
-
|
|
191
|
-
|
|
222
|
+
filters = /* @__PURE__ */ new Map();
|
|
223
|
+
static create(configOptions, validationOptions = {}) {
|
|
224
|
+
return new _Application(configOptions, validationOptions);
|
|
225
|
+
}
|
|
226
|
+
useGlobalFilters(...filters) {
|
|
227
|
+
for (const filter of filters) {
|
|
228
|
+
const exceptionsClasses = Reflect.getMetadata(FILTER, filter);
|
|
229
|
+
if (!exceptionsClasses) throw new IsNotExceptionFilter(filter.name);
|
|
230
|
+
exceptionsClasses.forEach((excls) => {
|
|
231
|
+
this.filters.set(excls, filter);
|
|
232
|
+
this.container.addProvider(filter);
|
|
233
|
+
});
|
|
234
|
+
}
|
|
192
235
|
}
|
|
193
|
-
constructor(configOptions) {
|
|
236
|
+
constructor(configOptions, validationOptions) {
|
|
194
237
|
this.configOptions = configOptions;
|
|
238
|
+
this.validationOptions = validationOptions;
|
|
195
239
|
this.loadProviders();
|
|
196
|
-
this.loadControllers();
|
|
197
240
|
}
|
|
198
241
|
loadProviders() {
|
|
199
242
|
for (const provider of this.configOptions.providers || []) {
|
|
@@ -201,7 +244,7 @@ var Application = class _Application {
|
|
|
201
244
|
DEV_LOGGER(`Provider ${typeof provider == "object" ? provider.provided.name : provider.name} loaded`);
|
|
202
245
|
}
|
|
203
246
|
}
|
|
204
|
-
|
|
247
|
+
bootstrap() {
|
|
205
248
|
for (const controller of this.configOptions.controllers || []) {
|
|
206
249
|
const controllerPrefix = this.getControllerPrefix(controller);
|
|
207
250
|
const controllerDependencies = this.getControllerDependencies(controller);
|
|
@@ -217,11 +260,28 @@ var Application = class _Application {
|
|
|
217
260
|
const handlerCallback = /* @__PURE__ */ __name(async (event, data) => {
|
|
218
261
|
const executionContext = new ExecutionContext(controller, controllerInstance[controllerMethod], data, event);
|
|
219
262
|
for (const guard of guards) {
|
|
220
|
-
|
|
221
|
-
|
|
263
|
+
try {
|
|
264
|
+
const response = await this.guardExecute(guard, executionContext);
|
|
265
|
+
if (!response) return {
|
|
266
|
+
success: false,
|
|
267
|
+
error: new ForbiddenAccessError(path, guard.constructor.prototype.name)
|
|
268
|
+
};
|
|
269
|
+
} catch (e) {
|
|
270
|
+
return await this.useFilter(e, executionContext);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
let params = [];
|
|
274
|
+
try {
|
|
275
|
+
params = await this.getParams(controllerInstance, controllerMethod, executionContext);
|
|
276
|
+
} catch (e) {
|
|
277
|
+
return await this.useFilter(e, executionContext);
|
|
278
|
+
}
|
|
279
|
+
let controllerResult = void 0;
|
|
280
|
+
try {
|
|
281
|
+
controllerResult = await this.controllerExecute(controllerInstance, controllerInstance[controllerMethod], params);
|
|
282
|
+
} catch (e) {
|
|
283
|
+
return await this.useFilter(e, executionContext);
|
|
222
284
|
}
|
|
223
|
-
const params = this.getParams(controllerInstance, controllerMethod, executionContext);
|
|
224
|
-
const controllerResult = await this.controllerExecute(controllerInstance, controllerInstance[controllerMethod], params);
|
|
225
285
|
return controllerResult;
|
|
226
286
|
}, "handlerCallback");
|
|
227
287
|
if (handlerMetadata.type === "invoke") {
|
|
@@ -229,18 +289,28 @@ var Application = class _Application {
|
|
|
229
289
|
} else {
|
|
230
290
|
ipcMain.on(path, handlerCallback);
|
|
231
291
|
}
|
|
292
|
+
DEV_LOGGER(`[Electron Injector] Route ${path} has initialized (${handlerMetadata.type === "invoke" ? "invoke" : "send"})`);
|
|
232
293
|
}
|
|
233
294
|
}
|
|
234
295
|
}
|
|
235
|
-
getParams(target, propertyKey, executionContext) {
|
|
296
|
+
async getParams(target, propertyKey, executionContext) {
|
|
236
297
|
const params = Reflect.getMetadata(PARAM, target, propertyKey);
|
|
237
298
|
if (!params) return [];
|
|
238
|
-
return params.map((param) => {
|
|
299
|
+
return await Promise.all(params.map(async (param, index) => {
|
|
239
300
|
if (param === "ctx") return executionContext;
|
|
240
301
|
if (param === "event") return executionContext.event;
|
|
241
|
-
if (param === "payload")
|
|
302
|
+
if (param === "payload") {
|
|
303
|
+
const validationClass = Reflect.getMetadata("design:paramtypes", target, propertyKey)[index];
|
|
304
|
+
const metadata = getMetadataStorage().getTargetValidationMetadatas(validationClass, null, false, false);
|
|
305
|
+
if (typeof validationClass == "function" && metadata.length) {
|
|
306
|
+
const validatorObjectInstance = plainToInstance(validationClass, executionContext.payload);
|
|
307
|
+
const errors = await validate(validatorObjectInstance, this.validationOptions);
|
|
308
|
+
if (errors.length) throw new DataValidationError(errors[0]);
|
|
309
|
+
}
|
|
310
|
+
return executionContext.payload;
|
|
311
|
+
}
|
|
242
312
|
return void 0;
|
|
243
|
-
});
|
|
313
|
+
}));
|
|
244
314
|
}
|
|
245
315
|
buildPath(controllerPrefix, methodPath) {
|
|
246
316
|
const prefix = controllerPrefix.trim();
|
|
@@ -251,39 +321,48 @@ var Application = class _Application {
|
|
|
251
321
|
return "";
|
|
252
322
|
}
|
|
253
323
|
async guardExecute(guard, executionContext) {
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
if (!guardResult) return false;
|
|
264
|
-
}
|
|
265
|
-
return true;
|
|
266
|
-
} catch (error) {
|
|
267
|
-
PROD_LOGGER(error);
|
|
268
|
-
return false;
|
|
324
|
+
const guardResult = guard.canActivate(executionContext);
|
|
325
|
+
if (guardResult instanceof Observable) {
|
|
326
|
+
const result = await lastValueFrom(guardResult.pipe(first()));
|
|
327
|
+
if (!result) return false;
|
|
328
|
+
} else if (guardResult instanceof Promise) {
|
|
329
|
+
const result = await guardResult;
|
|
330
|
+
if (!result) return false;
|
|
331
|
+
} else {
|
|
332
|
+
if (!guardResult) return false;
|
|
269
333
|
}
|
|
334
|
+
return true;
|
|
270
335
|
}
|
|
271
336
|
async controllerExecute(context, target, params) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
controllerResult = await controllerResult;
|
|
280
|
-
}
|
|
337
|
+
const boundedTarget = target.bind(context);
|
|
338
|
+
let controllerResult = boundedTarget(...params);
|
|
339
|
+
while (controllerResult instanceof Observable || controllerResult instanceof Promise) {
|
|
340
|
+
if (controllerResult instanceof Observable) {
|
|
341
|
+
controllerResult = await lastValueFrom(controllerResult);
|
|
342
|
+
} else if (controllerResult instanceof Promise) {
|
|
343
|
+
controllerResult = await controllerResult;
|
|
281
344
|
}
|
|
282
|
-
return controllerResult;
|
|
283
|
-
} catch (error) {
|
|
284
|
-
PROD_LOGGER(error.message ?? error);
|
|
285
|
-
return void 0;
|
|
286
345
|
}
|
|
346
|
+
return controllerResult;
|
|
347
|
+
}
|
|
348
|
+
async useFilter(error, executionContext) {
|
|
349
|
+
PROD_LOGGER(error);
|
|
350
|
+
for (const [cls, fltr] of this.filters) {
|
|
351
|
+
if (!(error instanceof cls)) continue;
|
|
352
|
+
const filterInstance = this.container.resolve(fltr);
|
|
353
|
+
const response = filterInstance.catch(error, executionContext);
|
|
354
|
+
if (response instanceof Promise) {
|
|
355
|
+
return await response;
|
|
356
|
+
}
|
|
357
|
+
if (response instanceof Observable) {
|
|
358
|
+
return await lastValueFrom(response);
|
|
359
|
+
}
|
|
360
|
+
return response;
|
|
361
|
+
}
|
|
362
|
+
return {
|
|
363
|
+
success: false,
|
|
364
|
+
error
|
|
365
|
+
};
|
|
287
366
|
}
|
|
288
367
|
getHandlerMetadata(target) {
|
|
289
368
|
const handlerMetadata = Reflect.getMetadata(HANDLER, target);
|
|
@@ -387,16 +466,36 @@ function SetMetadata(key, value) {
|
|
|
387
466
|
};
|
|
388
467
|
}
|
|
389
468
|
__name(SetMetadata, "SetMetadata");
|
|
469
|
+
function Catch(...filters) {
|
|
470
|
+
return function(target) {
|
|
471
|
+
const prevFilters = Reflect.getMetadata(FILTER, target) || [];
|
|
472
|
+
Reflect.defineMetadata(INJECTABLE, "singleton", target);
|
|
473
|
+
Reflect.defineMetadata(FILTER, [
|
|
474
|
+
...prevFilters,
|
|
475
|
+
...filters
|
|
476
|
+
], target);
|
|
477
|
+
};
|
|
478
|
+
}
|
|
479
|
+
__name(Catch, "Catch");
|
|
390
480
|
export {
|
|
391
481
|
Application,
|
|
482
|
+
Catch,
|
|
483
|
+
CircularDependency,
|
|
392
484
|
Controller,
|
|
485
|
+
ControllerIsNotValid,
|
|
393
486
|
Ctx,
|
|
487
|
+
DataValidationError,
|
|
488
|
+
ElectronInjectorError,
|
|
394
489
|
Event,
|
|
395
490
|
ExecutionContext,
|
|
491
|
+
ForbiddenAccessError,
|
|
396
492
|
Injectable,
|
|
493
|
+
IsNotExceptionFilter,
|
|
397
494
|
OnInvoke,
|
|
398
495
|
OnSend,
|
|
399
496
|
Payload,
|
|
497
|
+
ProviderIsNotInjectable,
|
|
498
|
+
ProviderNotFound,
|
|
400
499
|
Reflector,
|
|
401
500
|
SetMetadata,
|
|
402
501
|
UseGuards,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electron-injector",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Biblioteca para el desarrollo de aplicaciones con electron que proporciona una arquitectura robusta con inyección e inversion de dependencias.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -37,6 +37,8 @@
|
|
|
37
37
|
"@swc/core": "^1.15.3",
|
|
38
38
|
"@types/debug": "^4.1.12",
|
|
39
39
|
"@types/node": "^24.10.1",
|
|
40
|
+
"class-transformer": "^0.5.1",
|
|
41
|
+
"class-validator": "^0.14.3",
|
|
40
42
|
"electron": "^39.2.4",
|
|
41
43
|
"eslint": "^9.39.1",
|
|
42
44
|
"eslint-config-prettier": "^10.1.8",
|
|
@@ -49,6 +51,8 @@
|
|
|
49
51
|
"typescript-eslint": "^8.48.0"
|
|
50
52
|
},
|
|
51
53
|
"peerDependencies": {
|
|
54
|
+
"class-transformer": "^0.5.1",
|
|
55
|
+
"class-validator": "^0.14.3",
|
|
52
56
|
"electron": "^39.2.4",
|
|
53
57
|
"rxjs": "^7.8.2"
|
|
54
58
|
},
|