electron-injector 1.0.3 → 1.1.0
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 +148 -41
- package/dist/index.d.cts +42 -4
- package/dist/index.d.ts +42 -4
- package/dist/index.js +139 -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") {
|
|
@@ -276,15 +345,24 @@ var Application = class _Application {
|
|
|
276
345
|
}
|
|
277
346
|
}
|
|
278
347
|
}
|
|
279
|
-
getParams(target, propertyKey, executionContext) {
|
|
348
|
+
async getParams(target, propertyKey, executionContext) {
|
|
280
349
|
const params = Reflect.getMetadata(PARAM, target, propertyKey);
|
|
281
350
|
if (!params) return [];
|
|
282
|
-
return params.map((param) => {
|
|
351
|
+
return await Promise.all(params.map(async (param, index) => {
|
|
283
352
|
if (param === "ctx") return executionContext;
|
|
284
353
|
if (param === "event") return executionContext.event;
|
|
285
|
-
if (param === "payload")
|
|
354
|
+
if (param === "payload") {
|
|
355
|
+
const validationClass = Reflect.getMetadata("design:paramtypes", target, propertyKey)[index];
|
|
356
|
+
const metadata = (0, import_class_validator.getMetadataStorage)().getTargetValidationMetadatas(validationClass, null, false, false);
|
|
357
|
+
if (typeof validationClass == "function" && metadata.length) {
|
|
358
|
+
const validatorObjectInstance = (0, import_class_transformer.plainToInstance)(validationClass, executionContext.payload);
|
|
359
|
+
const errors = await (0, import_class_validator.validate)(validatorObjectInstance, this.validationOptions);
|
|
360
|
+
if (errors.length) throw new DataValidationError(errors[0]);
|
|
361
|
+
}
|
|
362
|
+
return executionContext.payload;
|
|
363
|
+
}
|
|
286
364
|
return void 0;
|
|
287
|
-
});
|
|
365
|
+
}));
|
|
288
366
|
}
|
|
289
367
|
buildPath(controllerPrefix, methodPath) {
|
|
290
368
|
const prefix = controllerPrefix.trim();
|
|
@@ -295,39 +373,48 @@ var Application = class _Application {
|
|
|
295
373
|
return "";
|
|
296
374
|
}
|
|
297
375
|
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;
|
|
376
|
+
const guardResult = guard.canActivate(executionContext);
|
|
377
|
+
if (guardResult instanceof import_rxjs.Observable) {
|
|
378
|
+
const result = await (0, import_rxjs.lastValueFrom)(guardResult.pipe((0, import_rxjs.first)()));
|
|
379
|
+
if (!result) return false;
|
|
380
|
+
} else if (guardResult instanceof Promise) {
|
|
381
|
+
const result = await guardResult;
|
|
382
|
+
if (!result) return false;
|
|
383
|
+
} else {
|
|
384
|
+
if (!guardResult) return false;
|
|
313
385
|
}
|
|
386
|
+
return true;
|
|
314
387
|
}
|
|
315
388
|
async controllerExecute(context, target, params) {
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
controllerResult = await controllerResult;
|
|
324
|
-
}
|
|
389
|
+
const boundedTarget = target.bind(context);
|
|
390
|
+
let controllerResult = boundedTarget(...params);
|
|
391
|
+
while (controllerResult instanceof import_rxjs.Observable || controllerResult instanceof Promise) {
|
|
392
|
+
if (controllerResult instanceof import_rxjs.Observable) {
|
|
393
|
+
controllerResult = await (0, import_rxjs.lastValueFrom)(controllerResult);
|
|
394
|
+
} else if (controllerResult instanceof Promise) {
|
|
395
|
+
controllerResult = await controllerResult;
|
|
325
396
|
}
|
|
326
|
-
return controllerResult;
|
|
327
|
-
} catch (error) {
|
|
328
|
-
PROD_LOGGER(error.message ?? error);
|
|
329
|
-
return void 0;
|
|
330
397
|
}
|
|
398
|
+
return controllerResult;
|
|
399
|
+
}
|
|
400
|
+
async useFilter(error, executionContext) {
|
|
401
|
+
PROD_LOGGER(error);
|
|
402
|
+
for (const [cls, fltr] of this.filters) {
|
|
403
|
+
if (!(error instanceof cls)) continue;
|
|
404
|
+
const filterInstance = this.container.resolve(fltr);
|
|
405
|
+
const response = filterInstance.catch(error, executionContext);
|
|
406
|
+
if (response instanceof Promise) {
|
|
407
|
+
return await response;
|
|
408
|
+
}
|
|
409
|
+
if (response instanceof import_rxjs.Observable) {
|
|
410
|
+
return await (0, import_rxjs.lastValueFrom)(response);
|
|
411
|
+
}
|
|
412
|
+
return response;
|
|
413
|
+
}
|
|
414
|
+
return {
|
|
415
|
+
success: false,
|
|
416
|
+
error
|
|
417
|
+
};
|
|
331
418
|
}
|
|
332
419
|
getHandlerMetadata(target) {
|
|
333
420
|
const handlerMetadata = Reflect.getMetadata(HANDLER, target);
|
|
@@ -431,17 +518,37 @@ function SetMetadata(key, value) {
|
|
|
431
518
|
};
|
|
432
519
|
}
|
|
433
520
|
__name(SetMetadata, "SetMetadata");
|
|
521
|
+
function Catch(...filters) {
|
|
522
|
+
return function(target) {
|
|
523
|
+
const prevFilters = Reflect.getMetadata(FILTER, target) || [];
|
|
524
|
+
Reflect.defineMetadata(INJECTABLE, "singleton", target);
|
|
525
|
+
Reflect.defineMetadata(FILTER, [
|
|
526
|
+
...prevFilters,
|
|
527
|
+
...filters
|
|
528
|
+
], target);
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
__name(Catch, "Catch");
|
|
434
532
|
// Annotate the CommonJS export names for ESM import in node:
|
|
435
533
|
0 && (module.exports = {
|
|
436
534
|
Application,
|
|
535
|
+
Catch,
|
|
536
|
+
CircularDependency,
|
|
437
537
|
Controller,
|
|
538
|
+
ControllerIsNotValid,
|
|
438
539
|
Ctx,
|
|
540
|
+
DataValidationError,
|
|
541
|
+
ElectronInjectorError,
|
|
439
542
|
Event,
|
|
440
543
|
ExecutionContext,
|
|
544
|
+
ForbiddenAccessError,
|
|
441
545
|
Injectable,
|
|
546
|
+
IsNotExceptionFilter,
|
|
442
547
|
OnInvoke,
|
|
443
548
|
OnSend,
|
|
444
549
|
Payload,
|
|
550
|
+
ProviderIsNotInjectable,
|
|
551
|
+
ProviderNotFound,
|
|
445
552
|
Reflector,
|
|
446
553
|
SetMetadata,
|
|
447
554
|
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") {
|
|
@@ -232,15 +292,24 @@ var Application = class _Application {
|
|
|
232
292
|
}
|
|
233
293
|
}
|
|
234
294
|
}
|
|
235
|
-
getParams(target, propertyKey, executionContext) {
|
|
295
|
+
async getParams(target, propertyKey, executionContext) {
|
|
236
296
|
const params = Reflect.getMetadata(PARAM, target, propertyKey);
|
|
237
297
|
if (!params) return [];
|
|
238
|
-
return params.map((param) => {
|
|
298
|
+
return await Promise.all(params.map(async (param, index) => {
|
|
239
299
|
if (param === "ctx") return executionContext;
|
|
240
300
|
if (param === "event") return executionContext.event;
|
|
241
|
-
if (param === "payload")
|
|
301
|
+
if (param === "payload") {
|
|
302
|
+
const validationClass = Reflect.getMetadata("design:paramtypes", target, propertyKey)[index];
|
|
303
|
+
const metadata = getMetadataStorage().getTargetValidationMetadatas(validationClass, null, false, false);
|
|
304
|
+
if (typeof validationClass == "function" && metadata.length) {
|
|
305
|
+
const validatorObjectInstance = plainToInstance(validationClass, executionContext.payload);
|
|
306
|
+
const errors = await validate(validatorObjectInstance, this.validationOptions);
|
|
307
|
+
if (errors.length) throw new DataValidationError(errors[0]);
|
|
308
|
+
}
|
|
309
|
+
return executionContext.payload;
|
|
310
|
+
}
|
|
242
311
|
return void 0;
|
|
243
|
-
});
|
|
312
|
+
}));
|
|
244
313
|
}
|
|
245
314
|
buildPath(controllerPrefix, methodPath) {
|
|
246
315
|
const prefix = controllerPrefix.trim();
|
|
@@ -251,39 +320,48 @@ var Application = class _Application {
|
|
|
251
320
|
return "";
|
|
252
321
|
}
|
|
253
322
|
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;
|
|
323
|
+
const guardResult = guard.canActivate(executionContext);
|
|
324
|
+
if (guardResult instanceof Observable) {
|
|
325
|
+
const result = await lastValueFrom(guardResult.pipe(first()));
|
|
326
|
+
if (!result) return false;
|
|
327
|
+
} else if (guardResult instanceof Promise) {
|
|
328
|
+
const result = await guardResult;
|
|
329
|
+
if (!result) return false;
|
|
330
|
+
} else {
|
|
331
|
+
if (!guardResult) return false;
|
|
269
332
|
}
|
|
333
|
+
return true;
|
|
270
334
|
}
|
|
271
335
|
async controllerExecute(context, target, params) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
controllerResult = await controllerResult;
|
|
280
|
-
}
|
|
336
|
+
const boundedTarget = target.bind(context);
|
|
337
|
+
let controllerResult = boundedTarget(...params);
|
|
338
|
+
while (controllerResult instanceof Observable || controllerResult instanceof Promise) {
|
|
339
|
+
if (controllerResult instanceof Observable) {
|
|
340
|
+
controllerResult = await lastValueFrom(controllerResult);
|
|
341
|
+
} else if (controllerResult instanceof Promise) {
|
|
342
|
+
controllerResult = await controllerResult;
|
|
281
343
|
}
|
|
282
|
-
return controllerResult;
|
|
283
|
-
} catch (error) {
|
|
284
|
-
PROD_LOGGER(error.message ?? error);
|
|
285
|
-
return void 0;
|
|
286
344
|
}
|
|
345
|
+
return controllerResult;
|
|
346
|
+
}
|
|
347
|
+
async useFilter(error, executionContext) {
|
|
348
|
+
PROD_LOGGER(error);
|
|
349
|
+
for (const [cls, fltr] of this.filters) {
|
|
350
|
+
if (!(error instanceof cls)) continue;
|
|
351
|
+
const filterInstance = this.container.resolve(fltr);
|
|
352
|
+
const response = filterInstance.catch(error, executionContext);
|
|
353
|
+
if (response instanceof Promise) {
|
|
354
|
+
return await response;
|
|
355
|
+
}
|
|
356
|
+
if (response instanceof Observable) {
|
|
357
|
+
return await lastValueFrom(response);
|
|
358
|
+
}
|
|
359
|
+
return response;
|
|
360
|
+
}
|
|
361
|
+
return {
|
|
362
|
+
success: false,
|
|
363
|
+
error
|
|
364
|
+
};
|
|
287
365
|
}
|
|
288
366
|
getHandlerMetadata(target) {
|
|
289
367
|
const handlerMetadata = Reflect.getMetadata(HANDLER, target);
|
|
@@ -387,16 +465,36 @@ function SetMetadata(key, value) {
|
|
|
387
465
|
};
|
|
388
466
|
}
|
|
389
467
|
__name(SetMetadata, "SetMetadata");
|
|
468
|
+
function Catch(...filters) {
|
|
469
|
+
return function(target) {
|
|
470
|
+
const prevFilters = Reflect.getMetadata(FILTER, target) || [];
|
|
471
|
+
Reflect.defineMetadata(INJECTABLE, "singleton", target);
|
|
472
|
+
Reflect.defineMetadata(FILTER, [
|
|
473
|
+
...prevFilters,
|
|
474
|
+
...filters
|
|
475
|
+
], target);
|
|
476
|
+
};
|
|
477
|
+
}
|
|
478
|
+
__name(Catch, "Catch");
|
|
390
479
|
export {
|
|
391
480
|
Application,
|
|
481
|
+
Catch,
|
|
482
|
+
CircularDependency,
|
|
392
483
|
Controller,
|
|
484
|
+
ControllerIsNotValid,
|
|
393
485
|
Ctx,
|
|
486
|
+
DataValidationError,
|
|
487
|
+
ElectronInjectorError,
|
|
394
488
|
Event,
|
|
395
489
|
ExecutionContext,
|
|
490
|
+
ForbiddenAccessError,
|
|
396
491
|
Injectable,
|
|
492
|
+
IsNotExceptionFilter,
|
|
397
493
|
OnInvoke,
|
|
398
494
|
OnSend,
|
|
399
495
|
Payload,
|
|
496
|
+
ProviderIsNotInjectable,
|
|
497
|
+
ProviderNotFound,
|
|
400
498
|
Reflector,
|
|
401
499
|
SetMetadata,
|
|
402
500
|
UseGuards,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "electron-injector",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
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
|
},
|