@martel/calyx 1.12.0 → 1.13.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/CHANGELOG.md +15 -0
- package/README.md +5 -3
- package/benchmarks/graphql-benchmark.ts +4 -1
- package/benchmarks/serialization-benchmark.ts +46 -6
- package/benchmarks/techniques-benchmark.ts +12 -0
- package/benchmarks/validation-benchmark.ts +8 -1
- package/docs/controllers.md +3 -3
- package/docs/dependency-injection.md +3 -3
- package/docs/lifecycle.md +3 -3
- package/package.json +1 -1
- package/src/cli/index.ts +7 -1
- package/src/config/config.module.ts +16 -2
- package/src/config/config.service.ts +20 -6
- package/src/cookies/cookies.ts +45 -8
- package/src/core/container.ts +340 -154
- package/src/core/testing-module.ts +4 -0
- package/src/cqrs/cqrs.ts +93 -4
- package/src/database/sequelize.module.ts +239 -0
- package/src/event-emitter/decorators.ts +2 -2
- package/src/event-emitter/event-emitter.ts +3 -0
- package/src/graphql/graphql.module.ts +2 -4
- package/src/http/application.ts +140 -10
- package/src/http/decorators.ts +21 -1
- package/src/http/exceptions.ts +97 -0
- package/src/http/factory.ts +3 -0
- package/src/http/router.ts +27 -4
- package/src/index.ts +1 -0
- package/src/microservices/exceptions.ts +10 -0
- package/src/microservices/index.ts +1 -0
- package/src/queue/queue.module.ts +73 -5
- package/src/terminus/terminus.ts +75 -2
- package/src/validation/compiler.ts +137 -17
- package/src/validation/decorators.ts +164 -2
- package/src/websockets/exceptions.ts +10 -0
- package/src/websockets/index.ts +1 -0
- package/tests/circular-di.test.ts +151 -0
- package/tests/di.test.ts +10 -2
- package/tests/nestjs-parity.test.ts +255 -0
|
@@ -15,6 +15,10 @@ export class TestingModule extends ModuleRef {
|
|
|
15
15
|
return app;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
+
createNestApplication(options?: any): CalyxApplication {
|
|
19
|
+
return this.createCalyxApplication();
|
|
20
|
+
}
|
|
21
|
+
|
|
18
22
|
get<T>(token: InjectionToken, options?: { strict: boolean }): T {
|
|
19
23
|
const strict = options?.strict ?? false;
|
|
20
24
|
if (strict) {
|
package/src/cqrs/cqrs.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Module, Injectable } from '../core/decorators.ts';
|
|
2
2
|
import { Type } from '../core/metadata.ts';
|
|
3
3
|
import { ModuleRef } from '../core/module-ref.ts';
|
|
4
|
+
import { Subject, Observable } from 'rxjs';
|
|
4
5
|
|
|
5
6
|
export interface ICommand {}
|
|
6
7
|
export interface ICommandHandler<TCommand extends ICommand = any, TResult = any> {
|
|
@@ -22,6 +23,7 @@ import { METADATA_KEYS } from '../core/metadata.ts';
|
|
|
22
23
|
export const COMMAND_HANDLER_METADATA = 'cqrs:command_handler';
|
|
23
24
|
export const QUERY_HANDLER_METADATA = 'cqrs:query_handler';
|
|
24
25
|
export const EVENT_HANDLER_METADATA = 'cqrs:event_handler';
|
|
26
|
+
export const SAGA_METADATA = 'cqrs:saga';
|
|
25
27
|
|
|
26
28
|
export const CommandHandler = (command: Type<ICommand>): ClassDecorator => {
|
|
27
29
|
return (target) => {
|
|
@@ -44,10 +46,24 @@ export const EventsHandler = (...events: Type<IEvent>[]): ClassDecorator => {
|
|
|
44
46
|
};
|
|
45
47
|
};
|
|
46
48
|
|
|
49
|
+
export function Saga(): PropertyDecorator {
|
|
50
|
+
return (target: any, propertyKey: string | symbol) => {
|
|
51
|
+
const constructor = target.constructor;
|
|
52
|
+
const existing = Reflect.getOwnMetadata(SAGA_METADATA, constructor) || [];
|
|
53
|
+
existing.push(propertyKey);
|
|
54
|
+
Reflect.defineMetadata(SAGA_METADATA, existing, constructor);
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@Injectable()
|
|
59
|
+
export class UnhandledExceptionBus extends Subject<any> {}
|
|
60
|
+
|
|
47
61
|
@Injectable()
|
|
48
62
|
export class CommandBus {
|
|
49
63
|
private handlers = new Map<any, ICommandHandler>();
|
|
50
64
|
|
|
65
|
+
constructor(private readonly exceptionBus: UnhandledExceptionBus) {}
|
|
66
|
+
|
|
51
67
|
register(command: any, handler: ICommandHandler) {
|
|
52
68
|
this.handlers.set(command, handler);
|
|
53
69
|
}
|
|
@@ -58,7 +74,12 @@ export class CommandBus {
|
|
|
58
74
|
if (!handler) {
|
|
59
75
|
throw new Error(`CommandHandler not found for command: ${commandClass.name}`);
|
|
60
76
|
}
|
|
61
|
-
|
|
77
|
+
try {
|
|
78
|
+
return (await handler.execute(command)) as R;
|
|
79
|
+
} catch (err) {
|
|
80
|
+
this.exceptionBus.next({ error: err, command });
|
|
81
|
+
throw err;
|
|
82
|
+
}
|
|
62
83
|
}
|
|
63
84
|
}
|
|
64
85
|
|
|
@@ -66,6 +87,8 @@ export class CommandBus {
|
|
|
66
87
|
export class QueryBus {
|
|
67
88
|
private handlers = new Map<any, IQueryHandler>();
|
|
68
89
|
|
|
90
|
+
constructor(private readonly exceptionBus: UnhandledExceptionBus) {}
|
|
91
|
+
|
|
69
92
|
register(query: any, handler: IQueryHandler) {
|
|
70
93
|
this.handlers.set(query, handler);
|
|
71
94
|
}
|
|
@@ -76,12 +99,18 @@ export class QueryBus {
|
|
|
76
99
|
if (!handler) {
|
|
77
100
|
throw new Error(`QueryHandler not found for query: ${queryClass.name}`);
|
|
78
101
|
}
|
|
79
|
-
|
|
102
|
+
try {
|
|
103
|
+
return (await handler.execute(query)) as R;
|
|
104
|
+
} catch (err) {
|
|
105
|
+
this.exceptionBus.next({ error: err, query });
|
|
106
|
+
throw err;
|
|
107
|
+
}
|
|
80
108
|
}
|
|
81
109
|
}
|
|
82
110
|
|
|
83
111
|
@Injectable()
|
|
84
112
|
export class EventBus {
|
|
113
|
+
public readonly subject$ = new Subject<any>();
|
|
85
114
|
private handlers = new Map<any, IEventHandler[]>();
|
|
86
115
|
|
|
87
116
|
register(event: any, handler: IEventHandler) {
|
|
@@ -100,6 +129,7 @@ export class EventBus {
|
|
|
100
129
|
console.error(`Error in event handler:`, err);
|
|
101
130
|
}
|
|
102
131
|
}
|
|
132
|
+
this.subject$.next(event);
|
|
103
133
|
}
|
|
104
134
|
}
|
|
105
135
|
|
|
@@ -134,9 +164,47 @@ export class EventPublisher {
|
|
|
134
164
|
}
|
|
135
165
|
}
|
|
136
166
|
|
|
167
|
+
export class AggregateRoot<EventBase extends IEvent = IEvent> {
|
|
168
|
+
private readonly _events: EventBase[] = [];
|
|
169
|
+
autoCommit = false;
|
|
170
|
+
|
|
171
|
+
publish(event: EventBase) {}
|
|
172
|
+
publishAll(events: EventBase[]) {}
|
|
173
|
+
|
|
174
|
+
commit() {
|
|
175
|
+
this.publishAll(this._events);
|
|
176
|
+
this._events.length = 0;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
uncommit() {
|
|
180
|
+
this._events.length = 0;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
getUncommittedEvents(): EventBase[] {
|
|
184
|
+
return this._events;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
loadFromHistory(history: EventBase[]) {
|
|
188
|
+
history.forEach((event) => this.apply(event, true));
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
apply(event: EventBase, isFromHistory = false) {
|
|
192
|
+
if (!isFromHistory) {
|
|
193
|
+
this._events.push(event);
|
|
194
|
+
}
|
|
195
|
+
const handlerName = `on${event.constructor.name}`;
|
|
196
|
+
if ((this as any)[handlerName]) {
|
|
197
|
+
(this as any)[handlerName](event);
|
|
198
|
+
}
|
|
199
|
+
if (this.autoCommit) {
|
|
200
|
+
this.commit();
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
|
|
137
205
|
@Module({
|
|
138
|
-
providers: [CommandBus, QueryBus, EventBus, EventPublisher],
|
|
139
|
-
exports: [CommandBus, QueryBus, EventBus, EventPublisher],
|
|
206
|
+
providers: [CommandBus, QueryBus, EventBus, EventPublisher, UnhandledExceptionBus],
|
|
207
|
+
exports: [CommandBus, QueryBus, EventBus, EventPublisher, UnhandledExceptionBus],
|
|
140
208
|
})
|
|
141
209
|
export class CqrsModule {
|
|
142
210
|
constructor(
|
|
@@ -170,6 +238,27 @@ export class CqrsModule {
|
|
|
170
238
|
this.eventBus.register(event, inst);
|
|
171
239
|
}
|
|
172
240
|
}
|
|
241
|
+
|
|
242
|
+
// Check Sagas
|
|
243
|
+
const sagas: (string | symbol)[] = Reflect.getMetadata(SAGA_METADATA, inst.constructor) || [];
|
|
244
|
+
for (const sagaKey of sagas) {
|
|
245
|
+
const sagaFn = inst[sagaKey];
|
|
246
|
+
if (typeof sagaFn === 'function') {
|
|
247
|
+
const commands$ = sagaFn(this.eventBus.subject$);
|
|
248
|
+
if (commands$ && typeof commands$.subscribe === 'function') {
|
|
249
|
+
commands$.subscribe({
|
|
250
|
+
next: (cmd: any) => {
|
|
251
|
+
this.commandBus.execute(cmd).catch((err) => {
|
|
252
|
+
console.error(`Saga error executing command:`, err);
|
|
253
|
+
});
|
|
254
|
+
},
|
|
255
|
+
error: (err: any) => {
|
|
256
|
+
console.error(`Saga stream error:`, err);
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
173
262
|
}
|
|
174
263
|
}
|
|
175
264
|
}
|
|
@@ -0,0 +1,239 @@
|
|
|
1
|
+
import { Database } from 'bun:sqlite';
|
|
2
|
+
import { Module, DynamicModule, Inject } from '../core/decorators.ts';
|
|
3
|
+
import { ConnectionManager } from './typeorm.module.ts';
|
|
4
|
+
|
|
5
|
+
let isSequelizeAvailable = false;
|
|
6
|
+
try {
|
|
7
|
+
require.resolve('sequelize');
|
|
8
|
+
isSequelizeAvailable = true;
|
|
9
|
+
} catch {
|
|
10
|
+
// ignore
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class Model<T extends Record<string, any> = any> {
|
|
14
|
+
static tableName: string;
|
|
15
|
+
static db: Database;
|
|
16
|
+
static isNative = true;
|
|
17
|
+
static realModel: any = null;
|
|
18
|
+
|
|
19
|
+
constructor(values?: Partial<T>) {
|
|
20
|
+
if (values) {
|
|
21
|
+
Object.assign(this, values);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
static async findAll(options?: any): Promise<any[]> {
|
|
26
|
+
if (!this.isNative && this.realModel) {
|
|
27
|
+
const results = await this.realModel.findAll(options);
|
|
28
|
+
return results.map((r: any) => {
|
|
29
|
+
const inst = new this();
|
|
30
|
+
Object.assign(inst, r.toJSON ? r.toJSON() : r);
|
|
31
|
+
return inst;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const tableName = this.tableName || this.name.toLowerCase();
|
|
35
|
+
const db = this.db || ConnectionManager.getOrCreate();
|
|
36
|
+
const rows = db.query(`SELECT id, data FROM ${tableName}`).all() as any[];
|
|
37
|
+
return rows.map((row) => {
|
|
38
|
+
const dataObj = JSON.parse(row.data);
|
|
39
|
+
dataObj.id = row.id;
|
|
40
|
+
const inst = new this();
|
|
41
|
+
Object.assign(inst, dataObj);
|
|
42
|
+
return inst;
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
static async findOne(options?: any): Promise<any | null> {
|
|
47
|
+
const list = await this.findAll(options);
|
|
48
|
+
return list.length > 0 ? list[0] : null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
static async findByPk(id: number | string): Promise<any | null> {
|
|
52
|
+
if (!this.isNative && this.realModel) {
|
|
53
|
+
const r = await this.realModel.findByPk(id);
|
|
54
|
+
if (!r) return null;
|
|
55
|
+
const inst = new this();
|
|
56
|
+
Object.assign(inst, r.toJSON ? r.toJSON() : r);
|
|
57
|
+
return inst;
|
|
58
|
+
}
|
|
59
|
+
const tableName = this.tableName || this.name.toLowerCase();
|
|
60
|
+
const db = this.db || ConnectionManager.getOrCreate();
|
|
61
|
+
const row = db.query(`SELECT id, data FROM ${tableName} WHERE id = $id`).get({ $id: Number(id) }) as any;
|
|
62
|
+
if (!row) return null;
|
|
63
|
+
const dataObj = JSON.parse(row.data);
|
|
64
|
+
dataObj.id = row.id;
|
|
65
|
+
const inst = new this();
|
|
66
|
+
Object.assign(inst, dataObj);
|
|
67
|
+
return inst;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
static async create(values: any): Promise<any> {
|
|
71
|
+
if (!this.isNative && this.realModel) {
|
|
72
|
+
const r = await this.realModel.create(values);
|
|
73
|
+
const inst = new this();
|
|
74
|
+
Object.assign(inst, r.toJSON ? r.toJSON() : r);
|
|
75
|
+
return inst;
|
|
76
|
+
}
|
|
77
|
+
const tableName = this.tableName || this.name.toLowerCase();
|
|
78
|
+
const db = this.db || ConnectionManager.getOrCreate();
|
|
79
|
+
db.run(`
|
|
80
|
+
CREATE TABLE IF NOT EXISTS ${tableName} (
|
|
81
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
82
|
+
data TEXT
|
|
83
|
+
)
|
|
84
|
+
`);
|
|
85
|
+
const dataCopy = { ...values };
|
|
86
|
+
delete dataCopy.id;
|
|
87
|
+
const result = db.query(`INSERT INTO ${tableName} (data) VALUES ($data) RETURNING id`).get({
|
|
88
|
+
$data: JSON.stringify(dataCopy)
|
|
89
|
+
}) as any;
|
|
90
|
+
const inst = new this();
|
|
91
|
+
Object.assign(inst, values, { id: result.id });
|
|
92
|
+
return inst;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
async save(): Promise<this> {
|
|
96
|
+
const modelClass = this.constructor as any;
|
|
97
|
+
if (!modelClass.isNative && modelClass.realModel) {
|
|
98
|
+
const realInst = await modelClass.realModel.build(this);
|
|
99
|
+
await realInst.save();
|
|
100
|
+
Object.assign(this, realInst.toJSON());
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
const tableName = modelClass.tableName || modelClass.name.toLowerCase();
|
|
104
|
+
const db = modelClass.db || ConnectionManager.getOrCreate();
|
|
105
|
+
const self = this as any;
|
|
106
|
+
const dataCopy = { ...this };
|
|
107
|
+
const id = self.id;
|
|
108
|
+
delete (dataCopy as any).id;
|
|
109
|
+
|
|
110
|
+
if (id !== undefined && id !== null) {
|
|
111
|
+
db.query(`UPDATE ${tableName} SET data = $data WHERE id = $id`).run({
|
|
112
|
+
$data: JSON.stringify(dataCopy),
|
|
113
|
+
$id: id
|
|
114
|
+
});
|
|
115
|
+
} else {
|
|
116
|
+
const result = db.query(`INSERT INTO ${tableName} (data) VALUES ($data) RETURNING id`).get({
|
|
117
|
+
$data: JSON.stringify(dataCopy)
|
|
118
|
+
}) as any;
|
|
119
|
+
self.id = result.id;
|
|
120
|
+
}
|
|
121
|
+
return this;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
async update(values: any): Promise<this> {
|
|
125
|
+
Object.assign(this, values);
|
|
126
|
+
return await this.save();
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
async destroy(): Promise<void> {
|
|
130
|
+
const modelClass = this.constructor as any;
|
|
131
|
+
if (!modelClass.isNative && modelClass.realModel) {
|
|
132
|
+
const realInst = await modelClass.realModel.findByPk((this as any).id);
|
|
133
|
+
if (realInst) await realInst.destroy();
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
const tableName = modelClass.tableName || modelClass.name.toLowerCase();
|
|
137
|
+
const db = modelClass.db || ConnectionManager.getOrCreate();
|
|
138
|
+
const id = (this as any).id;
|
|
139
|
+
if (id !== undefined && id !== null) {
|
|
140
|
+
db.query(`DELETE FROM ${tableName} WHERE id = $id`).run({ $id: id });
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function InjectModel(model: any): ParameterDecorator & PropertyDecorator {
|
|
146
|
+
return Inject(`Sequelize_Model_${model.name}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export interface SequelizeModuleOptions {
|
|
150
|
+
dialect?: string;
|
|
151
|
+
storage?: string;
|
|
152
|
+
host?: string;
|
|
153
|
+
port?: number;
|
|
154
|
+
username?: string;
|
|
155
|
+
password?: string;
|
|
156
|
+
database?: string;
|
|
157
|
+
models?: any[];
|
|
158
|
+
autoLoadModels?: boolean;
|
|
159
|
+
synchronize?: boolean;
|
|
160
|
+
[key: string]: any;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
@Module({})
|
|
164
|
+
export class SequelizeModule {
|
|
165
|
+
static forRoot(options: SequelizeModuleOptions = {}): DynamicModule {
|
|
166
|
+
const isUsingSequelize = isSequelizeAvailable && options.dialect !== 'sqlite-native';
|
|
167
|
+
|
|
168
|
+
let seqPromise: Promise<any>;
|
|
169
|
+
if (isUsingSequelize) {
|
|
170
|
+
seqPromise = (async () => {
|
|
171
|
+
const { Sequelize } = await import('sequelize');
|
|
172
|
+
const sequelize = new Sequelize(options as any);
|
|
173
|
+
if (options.models) {
|
|
174
|
+
sequelize.addModels(options.models);
|
|
175
|
+
}
|
|
176
|
+
await sequelize.authenticate();
|
|
177
|
+
if (options.synchronize !== false) {
|
|
178
|
+
await sequelize.sync();
|
|
179
|
+
}
|
|
180
|
+
return sequelize;
|
|
181
|
+
})();
|
|
182
|
+
} else {
|
|
183
|
+
seqPromise = Promise.resolve(ConnectionManager.getOrCreate(options.storage));
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
return {
|
|
187
|
+
module: SequelizeModule,
|
|
188
|
+
providers: [
|
|
189
|
+
{
|
|
190
|
+
provide: 'Calyx_Sequelize_Instance',
|
|
191
|
+
useValue: seqPromise,
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
provide: 'Calyx_Sequelize_IsNative',
|
|
195
|
+
useValue: !isUsingSequelize,
|
|
196
|
+
},
|
|
197
|
+
],
|
|
198
|
+
exports: ['Calyx_Sequelize_Instance', 'Calyx_Sequelize_IsNative'],
|
|
199
|
+
global: true,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
static forFeature(models: any[] = []): DynamicModule {
|
|
204
|
+
const providers = models.map((model) => {
|
|
205
|
+
return {
|
|
206
|
+
provide: `Sequelize_Model_${model.name}`,
|
|
207
|
+
useFactory: (seqInstancePromise: Promise<any>, isNative: boolean) => {
|
|
208
|
+
if (isNative) {
|
|
209
|
+
const db = ConnectionManager.getOrCreate();
|
|
210
|
+
model.db = db;
|
|
211
|
+
model.tableName = model.name.toLowerCase();
|
|
212
|
+
model.isNative = true;
|
|
213
|
+
db.run(`
|
|
214
|
+
CREATE TABLE IF NOT EXISTS ${model.tableName} (
|
|
215
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
216
|
+
data TEXT
|
|
217
|
+
)
|
|
218
|
+
`);
|
|
219
|
+
return model;
|
|
220
|
+
} else {
|
|
221
|
+
return seqInstancePromise.then((seq) => {
|
|
222
|
+
const realModel = seq.models[model.name];
|
|
223
|
+
model.realModel = realModel;
|
|
224
|
+
model.isNative = false;
|
|
225
|
+
return model;
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
},
|
|
229
|
+
inject: ['Calyx_Sequelize_Instance', 'Calyx_Sequelize_IsNative'],
|
|
230
|
+
};
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
return {
|
|
234
|
+
module: SequelizeModule,
|
|
235
|
+
providers,
|
|
236
|
+
exports: models.map((model) => `Sequelize_Model_${model.name}`),
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import 'reflect-metadata';
|
|
2
2
|
|
|
3
|
-
export function OnEvent(event: string): MethodDecorator {
|
|
3
|
+
export function OnEvent(event: string, options?: any): MethodDecorator {
|
|
4
4
|
return (target, propertyKey) => {
|
|
5
5
|
const constructor = target.constructor;
|
|
6
6
|
const existing = Reflect.getOwnMetadata('calyx:on_event', constructor) || [];
|
|
7
|
-
existing.push({ event, propertyKey });
|
|
7
|
+
existing.push({ event, propertyKey, options });
|
|
8
8
|
Reflect.defineMetadata('calyx:on_event', existing, constructor);
|
|
9
9
|
};
|
|
10
10
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { CalyxContainer, DynamicModule } from '../core/container.ts';
|
|
2
2
|
import { Module } from '../core/decorators.ts';
|
|
3
|
+
import { CalyxExecutionContext } from '../lifecycle/context.ts';
|
|
4
|
+
import { HttpException } from '../http/exceptions.ts';
|
|
3
5
|
import {
|
|
4
6
|
GraphQLSchema,
|
|
5
7
|
GraphQLObjectType,
|
|
@@ -262,7 +264,6 @@ export class GraphQLModule {
|
|
|
262
264
|
|
|
263
265
|
const resolveFn = async (parent: any, args: any, context: any, info: any) => {
|
|
264
266
|
const req = context?.req;
|
|
265
|
-
const { CalyxExecutionContext } = await import('../lifecycle/context.ts');
|
|
266
267
|
const execContext = new CalyxExecutionContext(req, null, resolverClass, resolverInstance[fieldMeta.propertyKey]);
|
|
267
268
|
(execContext as any).type = 'graphql';
|
|
268
269
|
(execContext as any).data = args;
|
|
@@ -277,7 +278,6 @@ export class GraphQLModule {
|
|
|
277
278
|
const canActivate = guard.instance.canActivate(execContext);
|
|
278
279
|
const resolved = canActivate instanceof Promise ? await canActivate : canActivate;
|
|
279
280
|
if (!resolved) {
|
|
280
|
-
const { HttpException } = await import('../http/exceptions.ts');
|
|
281
281
|
throw new HttpException('Forbidden resource', 403);
|
|
282
282
|
}
|
|
283
283
|
}
|
|
@@ -429,7 +429,6 @@ export class GraphQLModule {
|
|
|
429
429
|
|
|
430
430
|
targetFields[fieldName].resolve = async (parent: any, args: any, context: any, info: any) => {
|
|
431
431
|
const req = context?.req;
|
|
432
|
-
const { CalyxExecutionContext } = await import('../lifecycle/context.ts');
|
|
433
432
|
const execContext = new CalyxExecutionContext(req, null, resolverClass, resolverInstance[fieldRes.propertyKey]);
|
|
434
433
|
(execContext as any).type = 'graphql';
|
|
435
434
|
(execContext as any).data = args;
|
|
@@ -443,7 +442,6 @@ export class GraphQLModule {
|
|
|
443
442
|
const canActivate = guard.instance.canActivate(execContext);
|
|
444
443
|
const resolved = canActivate instanceof Promise ? await canActivate : canActivate;
|
|
445
444
|
if (!resolved) {
|
|
446
|
-
const { HttpException } = await import('../http/exceptions.ts');
|
|
447
445
|
throw new HttpException('Forbidden resource', 403);
|
|
448
446
|
}
|
|
449
447
|
}
|