@magek/core 0.0.6 → 0.0.7
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/dist/authorizer.js +1 -1
- package/dist/command-dispatcher.js +47 -41
- package/dist/core-concepts/data-migration/entities/data-migration-entity.js +5 -2
- package/dist/core-concepts/data-migration/events/data-migration-finished.js +3 -1
- package/dist/core-concepts/data-migration/events/data-migration-started.js +3 -1
- package/dist/core-concepts/data-migration/events/entity-migrated.js +4 -0
- package/dist/core-concepts/touch-entity/events/entity-touched.js +2 -0
- package/dist/data-migrations.js +59 -54
- package/dist/decorators/command.d.ts +4 -11
- package/dist/decorators/command.js +10 -18
- package/dist/decorators/data-migration.d.ts +4 -1
- package/dist/decorators/data-migration.js +3 -1
- package/dist/decorators/decorator-types.d.ts +50 -0
- package/dist/decorators/decorator-types.js +11 -0
- package/dist/decorators/decorator-utils.d.ts +1 -0
- package/dist/decorators/decorator-utils.js +2 -0
- package/dist/decorators/entity.d.ts +7 -15
- package/dist/decorators/entity.js +27 -37
- package/dist/decorators/event-handler.d.ts +11 -1
- package/dist/decorators/event-handler.js +13 -1
- package/dist/decorators/event.d.ts +4 -1
- package/dist/decorators/event.js +3 -2
- package/dist/decorators/field-metadata-reader.d.ts +8 -3
- package/dist/decorators/field-metadata-reader.js +50 -62
- package/dist/decorators/field.d.ts +23 -0
- package/dist/decorators/field.js +41 -0
- package/dist/decorators/global-error-handler.d.ts +10 -1
- package/dist/decorators/global-error-handler.js +9 -1
- package/dist/decorators/global-event-handler.d.ts +10 -1
- package/dist/decorators/global-event-handler.js +9 -1
- package/dist/decorators/health-sensor.d.ts +4 -1
- package/dist/decorators/health-sensor.js +3 -2
- package/dist/decorators/index.d.ts +3 -0
- package/dist/decorators/index.js +2 -0
- package/dist/decorators/metadata.d.ts +17 -1
- package/dist/decorators/metadata.js +22 -22
- package/dist/decorators/non-exposed.d.ts +13 -2
- package/dist/decorators/non-exposed.js +22 -20
- package/dist/decorators/notification.d.ts +6 -18
- package/dist/decorators/notification.js +10 -50
- package/dist/decorators/projects.d.ts +5 -18
- package/dist/decorators/projects.js +23 -54
- package/dist/decorators/query.d.ts +11 -1
- package/dist/decorators/query.js +18 -4
- package/dist/decorators/read-model.d.ts +13 -27
- package/dist/decorators/read-model.js +45 -77
- package/dist/decorators/role.d.ts +9 -3
- package/dist/decorators/role.js +8 -3
- package/dist/decorators/scheduled-command.d.ts +4 -1
- package/dist/decorators/scheduled-command.js +3 -1
- package/dist/decorators/schema-migration.d.ts +11 -27
- package/dist/decorators/schema-migration.js +32 -77
- package/dist/decorators/sequenced-by.d.ts +7 -25
- package/dist/decorators/sequenced-by.js +11 -71
- package/dist/event-dispatcher.js +29 -24
- package/dist/event-processor.js +106 -103
- package/dist/event-stream-consumer.js +25 -20
- package/dist/event-stream-producer.js +22 -17
- package/dist/events-reader.js +1 -0
- package/dist/global-error-dispatcher.js +3 -2
- package/dist/graphql-dispatcher.js +161 -156
- package/dist/index.js +4 -0
- package/dist/instrumentation/decorator/trace.d.ts +11 -3
- package/dist/instrumentation/decorator/trace.js +17 -71
- package/dist/magek.js +2 -2
- package/dist/query-dispatcher.js +2 -0
- package/dist/read-model-schema-migrator.js +71 -68
- package/dist/read-models-reader.js +178 -180
- package/dist/register-handler.js +3 -3
- package/dist/scheduled-command-dispatcher.js +48 -42
- package/dist/schema-migrator.js +63 -59
- package/dist/sensor/health/health-service.js +2 -1
- package/dist/services/event-store.js +221 -224
- package/dist/services/graphql/graphql-generator.js +11 -8
- package/dist/services/graphql/graphql-mutation-generator.js +4 -0
- package/dist/services/graphql/graphql-query-generator.js +14 -0
- package/dist/services/graphql/graphql-subcriptions-generator.js +7 -0
- package/dist/services/graphql/graphql-type-informer.js +4 -3
- package/dist/services/graphql/query-generators/graphql-query-by-keys-generator.js +4 -0
- package/dist/services/graphql/query-generators/graphql-query-events-generator.js +3 -0
- package/dist/services/graphql/query-generators/graphql-query-filters-generator.js +6 -0
- package/dist/services/graphql/query-generators/graphql-query-generator.js +4 -0
- package/dist/services/graphql/query-generators/graphql-query-listed-generator.js +7 -0
- package/dist/services/graphql/query-helpers/graphql-handled-fields-generator.js +5 -2
- package/dist/services/graphql/query-helpers/graphql-query-filter-arguments-builder.js +3 -0
- package/dist/services/graphql/query-helpers/graphql-query-filter-fields-builder.js +4 -0
- package/dist/services/graphql/query-helpers/graphql-query-sort-builder.js +4 -2
- package/dist/services/graphql/websocket-protocol/graphql-websocket-protocol.js +5 -3
- package/dist/services/pub-sub/read-model-pub-sub.js +1 -0
- package/dist/services/raw-events-parser.js +1 -1
- package/dist/services/read-model-store.js +16 -17
- package/dist/services/token-verifiers/jwks-uri-token-verifier.js +8 -4
- package/dist/services/token-verifiers/public-key-token-verifier.js +4 -2
- package/dist/services/token-verifiers/role-based-token-verifier.js +2 -1
- package/dist/services/token-verifiers/utilities.js +1 -1
- package/dist/subscribers-notifier.js +98 -92
- package/dist/token-verifier.js +2 -1
- package/package.json +4 -4
- package/dist/decorators/stage3-utils.d.ts +0 -6
- package/dist/decorators/stage3-utils.js +0 -25
|
@@ -1,36 +1,20 @@
|
|
|
1
|
-
import { Class, AnyClass
|
|
2
|
-
|
|
3
|
-
* Stage 3 method decorator context
|
|
4
|
-
*/
|
|
5
|
-
interface Stage3MethodContext {
|
|
6
|
-
kind: 'method';
|
|
7
|
-
name: string | symbol;
|
|
8
|
-
static: boolean;
|
|
9
|
-
private: boolean;
|
|
10
|
-
metadata: Record<string | symbol, unknown>;
|
|
11
|
-
addInitializer?: (initializer: () => void) => void;
|
|
12
|
-
}
|
|
13
|
-
/**
|
|
14
|
-
* Stage 3 class decorator context
|
|
15
|
-
*/
|
|
16
|
-
interface Stage3ClassContext {
|
|
17
|
-
kind: 'class';
|
|
18
|
-
name: string | undefined;
|
|
19
|
-
metadata: Record<string | symbol, unknown>;
|
|
20
|
-
addInitializer?: (initializer: () => void) => void;
|
|
21
|
-
}
|
|
1
|
+
import { Class, AnyClass } from '@magek/common';
|
|
2
|
+
import { MethodDecoratorContext, ClassDecoratorContext } from './decorator-types';
|
|
22
3
|
/**
|
|
23
4
|
* **NOTE:** Using this decorator for read model migrations is deprecated. Prefer using `@DataMigration` instead.
|
|
5
|
+
*
|
|
6
|
+
* Uses TC39 Stage 3 decorators.
|
|
24
7
|
*/
|
|
25
|
-
export declare function SchemaMigration(conceptClass: AnyClass): (schemaMigrationClass: AnyClass, context
|
|
8
|
+
export declare function SchemaMigration(conceptClass: AnyClass): (schemaMigrationClass: AnyClass, context: ClassDecoratorContext) => void;
|
|
26
9
|
/**
|
|
27
|
-
* Decorator to tell Magek the version you are migrating to
|
|
10
|
+
* Decorator to tell Magek the version you are migrating to.
|
|
11
|
+
*
|
|
12
|
+
* Uses TC39 Stage 3 decorators.
|
|
13
|
+
*
|
|
28
14
|
* @param toVersion
|
|
29
15
|
* @param props
|
|
30
16
|
*/
|
|
31
|
-
export declare function
|
|
17
|
+
export declare function toVersion<TOldSchema, TNewSchema>(toVersion: number, props: {
|
|
32
18
|
fromSchema: Class<TOldSchema>;
|
|
33
19
|
toSchema: Class<TNewSchema>;
|
|
34
|
-
}): (
|
|
35
|
-
type MigrationMethod<TOldSchema, TNewSchema> = TypedPropertyDescriptor<(old: TOldSchema) => Promise<TNewSchema>>;
|
|
36
|
-
export {};
|
|
20
|
+
}): (method: Function, context: MethodDecoratorContext) => void;
|
|
@@ -1,43 +1,24 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.SchemaMigration = SchemaMigration;
|
|
4
|
-
exports.
|
|
4
|
+
exports.toVersion = toVersion;
|
|
5
5
|
const magek_1 = require("../magek");
|
|
6
6
|
const common_1 = require("@magek/common");
|
|
7
7
|
const migrationMethodsMetadataKey = 'magek:migrationsMethods';
|
|
8
|
-
|
|
9
|
-
* Type guard to detect Stage 3 method decorator context
|
|
10
|
-
*/
|
|
11
|
-
function isStage3MethodContext(arg) {
|
|
12
|
-
return (arg !== null &&
|
|
13
|
-
typeof arg === 'object' &&
|
|
14
|
-
'kind' in arg &&
|
|
15
|
-
arg.kind === 'method' &&
|
|
16
|
-
'name' in arg);
|
|
17
|
-
}
|
|
18
|
-
/**
|
|
19
|
-
* Type guard to detect Stage 3 class decorator context
|
|
20
|
-
*/
|
|
21
|
-
function isStage3ClassContext(arg) {
|
|
22
|
-
return (arg !== null &&
|
|
23
|
-
typeof arg === 'object' &&
|
|
24
|
-
'kind' in arg &&
|
|
25
|
-
arg.kind === 'class' &&
|
|
26
|
-
'metadata' in arg);
|
|
27
|
-
}
|
|
28
|
-
// Symbol for storing migration metadata in Stage 3 decorator context.metadata
|
|
8
|
+
// Symbol for storing migration metadata in decorator context.metadata
|
|
29
9
|
const MIGRATIONS_METADATA_KEY = Symbol.for('magek:migrationsMethods');
|
|
30
10
|
/**
|
|
31
11
|
* **NOTE:** Using this decorator for read model migrations is deprecated. Prefer using `@DataMigration` instead.
|
|
12
|
+
*
|
|
13
|
+
* Uses TC39 Stage 3 decorators.
|
|
32
14
|
*/
|
|
33
15
|
function SchemaMigration(conceptClass) {
|
|
34
16
|
return (schemaMigrationClass, context) => {
|
|
35
17
|
magek_1.Magek.configureCurrentEnv((config) => {
|
|
36
18
|
const conceptMigrations = getConceptMigrations(config, conceptClass);
|
|
37
|
-
// Get migration methods
|
|
19
|
+
// Get migration methods from context.metadata
|
|
38
20
|
let migrationMethodsMetadata;
|
|
39
|
-
if (
|
|
40
|
-
// Stage 3: read from context.metadata
|
|
21
|
+
if (context.metadata) {
|
|
41
22
|
migrationMethodsMetadata =
|
|
42
23
|
context.metadata[MIGRATIONS_METADATA_KEY] || [];
|
|
43
24
|
// Update each metadata entry with the actual class reference
|
|
@@ -47,11 +28,10 @@ function SchemaMigration(conceptClass) {
|
|
|
47
28
|
}));
|
|
48
29
|
}
|
|
49
30
|
else {
|
|
50
|
-
|
|
51
|
-
migrationMethodsMetadata = getMigrationMethods(schemaMigrationClass);
|
|
31
|
+
migrationMethodsMetadata = [];
|
|
52
32
|
}
|
|
53
33
|
if (!migrationMethodsMetadata || migrationMethodsMetadata.length === 0) {
|
|
54
|
-
throw new Error('No migration methods found in this class. Define at least one migration and annotate it with @
|
|
34
|
+
throw new Error('No migration methods found in this class. Define at least one migration and annotate it with @toVersion()');
|
|
55
35
|
}
|
|
56
36
|
for (const schemaMigrationMetadata of migrationMethodsMetadata) {
|
|
57
37
|
if (conceptMigrations.has(schemaMigrationMetadata.toVersion)) {
|
|
@@ -69,27 +49,21 @@ function getConceptMigrations(config, conceptClass) {
|
|
|
69
49
|
}
|
|
70
50
|
return config.schemaMigrations[conceptClass.name];
|
|
71
51
|
}
|
|
72
|
-
function getMigrationMethods(migrationClass) {
|
|
73
|
-
const migrationMethods = (0, common_1.getMetadata)(migrationMethodsMetadataKey, migrationClass);
|
|
74
|
-
if (!migrationMethods || migrationMethods.length == 0) {
|
|
75
|
-
throw new Error('No migration methods found in this class. Define at least one migration and annotate it with @ToVersion()');
|
|
76
|
-
}
|
|
77
|
-
return migrationMethods;
|
|
78
|
-
}
|
|
79
52
|
/**
|
|
80
|
-
* Decorator to tell Magek the version you are migrating to
|
|
53
|
+
* Decorator to tell Magek the version you are migrating to.
|
|
54
|
+
*
|
|
55
|
+
* Uses TC39 Stage 3 decorators.
|
|
56
|
+
*
|
|
81
57
|
* @param toVersion
|
|
82
58
|
* @param props
|
|
83
59
|
*/
|
|
84
|
-
function
|
|
60
|
+
function toVersion(toVersion, props) {
|
|
85
61
|
if (toVersion <= 1) {
|
|
86
62
|
throw new Error('Migration versions must always be greater than 1');
|
|
87
63
|
}
|
|
88
|
-
return (
|
|
89
|
-
//
|
|
90
|
-
if (
|
|
91
|
-
// Stage 3 decorator - store in context.metadata so @SchemaMigration can read it
|
|
92
|
-
const context = propertyNameOrContext;
|
|
64
|
+
return (_method, context) => {
|
|
65
|
+
// Stage 3 decorator - store in context.metadata so @SchemaMigration can read it
|
|
66
|
+
if (context.metadata) {
|
|
93
67
|
// Get or initialize the migrations array in context.metadata
|
|
94
68
|
let migrationMethods = context.metadata[MIGRATIONS_METADATA_KEY];
|
|
95
69
|
if (!migrationMethods) {
|
|
@@ -104,43 +78,24 @@ function ToVersion(toVersion, props) {
|
|
|
104
78
|
fromSchema: props.fromSchema,
|
|
105
79
|
toSchema: props.toSchema,
|
|
106
80
|
});
|
|
107
|
-
// Also store in Reflect metadata for the standalone test case
|
|
108
|
-
if (context.addInitializer) {
|
|
109
|
-
context.addInitializer(function () {
|
|
110
|
-
const migrationClass = context.static ? this : this.constructor;
|
|
111
|
-
let reflectMethods = (0, common_1.getMetadata)(migrationMethodsMetadataKey, migrationClass);
|
|
112
|
-
if (!reflectMethods) {
|
|
113
|
-
reflectMethods = [];
|
|
114
|
-
}
|
|
115
|
-
reflectMethods.push({
|
|
116
|
-
migrationClass,
|
|
117
|
-
methodName: context.name.toString(),
|
|
118
|
-
toVersion,
|
|
119
|
-
fromSchema: props.fromSchema,
|
|
120
|
-
toSchema: props.toSchema,
|
|
121
|
-
});
|
|
122
|
-
(0, common_1.defineMetadata)(migrationMethodsMetadataKey, reflectMethods, migrationClass);
|
|
123
|
-
});
|
|
124
|
-
}
|
|
125
81
|
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
82
|
+
// Also store in Reflect metadata for standalone usage
|
|
83
|
+
if (context.addInitializer) {
|
|
84
|
+
context.addInitializer(function () {
|
|
85
|
+
const migrationClass = context.static ? this : this.constructor;
|
|
86
|
+
let reflectMethods = (0, common_1.getMetadata)(migrationMethodsMetadataKey, migrationClass);
|
|
87
|
+
if (!reflectMethods) {
|
|
88
|
+
reflectMethods = [];
|
|
89
|
+
}
|
|
90
|
+
reflectMethods.push({
|
|
91
|
+
migrationClass,
|
|
92
|
+
methodName: context.name.toString(),
|
|
93
|
+
toVersion,
|
|
94
|
+
fromSchema: props.fromSchema,
|
|
95
|
+
toSchema: props.toSchema,
|
|
96
|
+
});
|
|
97
|
+
(0, common_1.defineMetadata)(migrationMethodsMetadataKey, reflectMethods, migrationClass);
|
|
141
98
|
});
|
|
142
|
-
// Here we just store the information (version and method). All the checks will be done in the @Migrates decorator
|
|
143
|
-
(0, common_1.defineMetadata)(migrationMethodsMetadataKey, migrationMethods, migrationClass);
|
|
144
99
|
}
|
|
145
100
|
};
|
|
146
101
|
}
|
|
@@ -1,28 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
/**
|
|
3
|
-
|
|
4
|
-
*/
|
|
5
|
-
interface Stage3FieldContext {
|
|
6
|
-
kind: 'field';
|
|
7
|
-
name: string | symbol;
|
|
8
|
-
static: boolean;
|
|
9
|
-
private: boolean;
|
|
10
|
-
metadata: Record<string | symbol, unknown>;
|
|
11
|
-
access?: {
|
|
12
|
-
get: () => unknown;
|
|
13
|
-
set: (value: unknown) => void;
|
|
14
|
-
};
|
|
15
|
-
addInitializer?: (initializer: () => void) => void;
|
|
16
|
-
}
|
|
1
|
+
import { FieldDecoratorContext } from './decorator-types';
|
|
2
|
+
/** Symbol for storing sequence key in decorator context.metadata */
|
|
3
|
+
export declare const SEQUENCE_KEY_SYMBOL: unique symbol;
|
|
17
4
|
/**
|
|
18
5
|
* Decorator to specify the sequencing key for a ReadModel.
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
|
|
22
|
-
export declare function sequencedBy(target: Class<ReadModelInterface> | Object | undefined, propertyKeyOrContext?: string | symbol | Stage3FieldContext, parameterIndex?: number): void;
|
|
23
|
-
/**
|
|
24
|
-
* Transfer sequence key metadata from Stage 3 context to class.
|
|
25
|
-
* Called by the ReadModel class decorator.
|
|
6
|
+
*
|
|
7
|
+
* Uses TC39 Stage 3 decorators.
|
|
8
|
+
* The sequence key is stored in context.metadata and read by @ReadModel.
|
|
26
9
|
*/
|
|
27
|
-
export declare function
|
|
28
|
-
export {};
|
|
10
|
+
export declare function sequencedBy(_value: undefined, context: FieldDecoratorContext): void;
|
|
@@ -1,79 +1,19 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SEQUENCE_KEY_SYMBOL = void 0;
|
|
3
4
|
exports.sequencedBy = sequencedBy;
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
const metadata_1 = require("./metadata");
|
|
7
|
-
// Symbol for storing sequence key in Stage 3 decorator context.metadata
|
|
8
|
-
const SEQUENCE_KEY_SYMBOL = Symbol.for('magek:sequenceKey');
|
|
9
|
-
/**
|
|
10
|
-
* Type guard to detect Stage 3 field context
|
|
11
|
-
*/
|
|
12
|
-
function isStage3FieldContext(arg) {
|
|
13
|
-
return (arg !== null &&
|
|
14
|
-
typeof arg === 'object' &&
|
|
15
|
-
'kind' in arg &&
|
|
16
|
-
arg.kind === 'field' &&
|
|
17
|
-
'name' in arg &&
|
|
18
|
-
'metadata' in arg);
|
|
19
|
-
}
|
|
20
|
-
/**
|
|
21
|
-
* Register sequence key for a class
|
|
22
|
-
*/
|
|
23
|
-
function registerSequenceKey(klass, propertyName) {
|
|
24
|
-
magek_1.Magek.configureCurrentEnv((config) => {
|
|
25
|
-
if (config.readModelSequenceKeys[klass.name] && config.readModelSequenceKeys[klass.name] !== propertyName) {
|
|
26
|
-
throw new Error(`Error trying to register a sort key named \`${propertyName}\` for class \`${klass.name}\`. It already had the sort key \`${config.readModelSequenceKeys[klass.name]}\` defined and only one sort key is allowed for each read model.`);
|
|
27
|
-
}
|
|
28
|
-
else {
|
|
29
|
-
config.readModelSequenceKeys[klass.name] = propertyName;
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
}
|
|
5
|
+
/** Symbol for storing sequence key in decorator context.metadata */
|
|
6
|
+
exports.SEQUENCE_KEY_SYMBOL = Symbol.for('magek:sequenceKey');
|
|
33
7
|
/**
|
|
34
8
|
* Decorator to specify the sequencing key for a ReadModel.
|
|
35
|
-
*
|
|
36
|
-
*
|
|
37
|
-
|
|
38
|
-
function sequencedBy(target, propertyKeyOrContext, parameterIndex) {
|
|
39
|
-
// Detect Stage 3 field decorator
|
|
40
|
-
if (isStage3FieldContext(propertyKeyOrContext)) {
|
|
41
|
-
const context = propertyKeyOrContext;
|
|
42
|
-
const propertyName = String(context.name);
|
|
43
|
-
// Store the sequence key in context.metadata for ReadModel decorator to pick up
|
|
44
|
-
context.metadata[SEQUENCE_KEY_SYMBOL] = propertyName;
|
|
45
|
-
// Also use addInitializer to register immediately when class is defined
|
|
46
|
-
if (context.addInitializer) {
|
|
47
|
-
context.addInitializer(function () {
|
|
48
|
-
const klass = this.constructor;
|
|
49
|
-
registerSequenceKey(klass, propertyName);
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
// Legacy decorator handling
|
|
55
|
-
const propertyKey = propertyKeyOrContext;
|
|
56
|
-
// Property decorator usage: @sequencedBy on a class property
|
|
57
|
-
if (propertyKey !== undefined && parameterIndex === undefined) {
|
|
58
|
-
const klass = target.constructor;
|
|
59
|
-
const propertyName = String(propertyKey);
|
|
60
|
-
registerSequenceKey(klass, propertyName);
|
|
61
|
-
}
|
|
62
|
-
// Parameter decorator usage: @sequencedBy on constructor parameter
|
|
63
|
-
else if (parameterIndex !== undefined) {
|
|
64
|
-
const klass = target;
|
|
65
|
-
const args = (0, metadata_1.getFunctionArguments)(klass);
|
|
66
|
-
const propertyName = args[parameterIndex];
|
|
67
|
-
registerSequenceKey(klass, propertyName);
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
/**
|
|
71
|
-
* Transfer sequence key metadata from Stage 3 context to class.
|
|
72
|
-
* Called by the ReadModel class decorator.
|
|
9
|
+
*
|
|
10
|
+
* Uses TC39 Stage 3 decorators.
|
|
11
|
+
* The sequence key is stored in context.metadata and read by @ReadModel.
|
|
73
12
|
*/
|
|
74
|
-
function
|
|
75
|
-
const
|
|
76
|
-
|
|
77
|
-
|
|
13
|
+
function sequencedBy(_value, context) {
|
|
14
|
+
const propertyName = String(context.name);
|
|
15
|
+
// Store the sequence key in context.metadata for ReadModel decorator to pick up
|
|
16
|
+
if (context.metadata) {
|
|
17
|
+
context.metadata[exports.SEQUENCE_KEY_SYMBOL] = propertyName;
|
|
78
18
|
}
|
|
79
19
|
}
|
package/dist/event-dispatcher.js
CHANGED
|
@@ -8,30 +8,35 @@ const raw_events_parser_1 = require("./services/raw-events-parser");
|
|
|
8
8
|
const read_model_store_1 = require("./services/read-model-store");
|
|
9
9
|
const instrumentation_1 = require("./instrumentation");
|
|
10
10
|
const event_processor_1 = require("./event-processor");
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
logger.debug('Event workflow started for raw events:', require('util').inspect(rawEvents, false, null, false));
|
|
22
|
-
try {
|
|
23
|
-
const eventEnvelopes = config.eventStore.rawToEnvelopes(rawEvents);
|
|
24
|
-
await raw_events_parser_1.RawEventsParser.streamPerEntityEvents(config, eventEnvelopes, event_processor_1.MagekEventProcessor.eventProcessor(eventStore, readModelStore));
|
|
11
|
+
let MagekEventDispatcher = (() => {
|
|
12
|
+
let _staticExtraInitializers = [];
|
|
13
|
+
let _static_dispatch_decorators;
|
|
14
|
+
return class MagekEventDispatcher {
|
|
15
|
+
static {
|
|
16
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
17
|
+
_static_dispatch_decorators = [(0, instrumentation_1.trace)(common_1.TraceActionTypes.DISPATCH_EVENTS)];
|
|
18
|
+
tslib_1.__esDecorate(this, null, _static_dispatch_decorators, { kind: "method", name: "dispatch", static: true, private: false, access: { has: obj => "dispatch" in obj, get: obj => obj.dispatch }, metadata: _metadata }, null, _staticExtraInitializers);
|
|
19
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
20
|
+
tslib_1.__runInitializers(this, _staticExtraInitializers);
|
|
25
21
|
}
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
/**
|
|
23
|
+
* Entry point to dispatch events.
|
|
24
|
+
* @param rawEvents List of raw events
|
|
25
|
+
* @param config
|
|
26
|
+
*/
|
|
27
|
+
static async dispatch(rawEvents, config) {
|
|
28
|
+
const logger = (0, common_1.getLogger)(config, 'MagekEventDispatcher#dispatch');
|
|
29
|
+
const eventStore = new event_store_1.EventStore(config);
|
|
30
|
+
const readModelStore = new read_model_store_1.ReadModelStore(config);
|
|
31
|
+
logger.debug('Event workflow started for raw events:', require('util').inspect(rawEvents, false, null, false));
|
|
32
|
+
try {
|
|
33
|
+
const eventEnvelopes = config.eventStore.rawToEnvelopes(rawEvents);
|
|
34
|
+
await raw_events_parser_1.RawEventsParser.streamPerEntityEvents(config, eventEnvelopes, event_processor_1.MagekEventProcessor.eventProcessor(eventStore, readModelStore));
|
|
35
|
+
}
|
|
36
|
+
catch (e) {
|
|
37
|
+
logger.error('Unhandled error while dispatching event: ', e);
|
|
38
|
+
}
|
|
28
39
|
}
|
|
29
|
-
}
|
|
30
|
-
}
|
|
40
|
+
};
|
|
41
|
+
})();
|
|
31
42
|
exports.MagekEventDispatcher = MagekEventDispatcher;
|
|
32
|
-
tslib_1.__decorate([
|
|
33
|
-
(0, instrumentation_1.Trace)(common_1.TraceActionTypes.DISPATCH_EVENTS),
|
|
34
|
-
tslib_1.__metadata("design:type", Function),
|
|
35
|
-
tslib_1.__metadata("design:paramtypes", [Object, common_1.MagekConfig]),
|
|
36
|
-
tslib_1.__metadata("design:returntype", Promise)
|
|
37
|
-
], MagekEventDispatcher, "dispatch", null);
|
package/dist/event-processor.js
CHANGED
|
@@ -7,119 +7,122 @@ const register_handler_1 = require("./register-handler");
|
|
|
7
7
|
const global_error_dispatcher_1 = require("./global-error-dispatcher");
|
|
8
8
|
const instrumentation_1 = require("./instrumentation");
|
|
9
9
|
const decorators_1 = require("./decorators");
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
MagekEventProcessor.dispatchEntityEventsToEventHandlers(eventsNotDispatched, config),
|
|
21
|
-
];
|
|
22
|
-
// Read models are not updated for notification events (events that are not related to an entity but a topic)
|
|
23
|
-
if (!(entityName in config.topicToEvent)) {
|
|
24
|
-
eventEnvelopesProcessors.push(MagekEventProcessor.snapshotAndUpdateReadModels(config, entityName, entityID, eventStore, readModelStore));
|
|
25
|
-
}
|
|
26
|
-
await common_1.Promises.allSettledAndFulfilled(eventEnvelopesProcessors);
|
|
27
|
-
};
|
|
28
|
-
}
|
|
29
|
-
static async filterDispatched(config, eventEnvelopes, eventStore) {
|
|
30
|
-
const logger = (0, common_1.getLogger)(config, 'MagekEventDispatcher#filterDispatched');
|
|
31
|
-
const filteredResults = await Promise.all(eventEnvelopes.map(async (eventEnvelope) => {
|
|
32
|
-
const result = await eventStore.storeDispatchedEvent(eventEnvelope);
|
|
33
|
-
if (!result) {
|
|
34
|
-
logger.warn('Event has already been dispatched. Skipping.', eventEnvelope);
|
|
35
|
-
}
|
|
36
|
-
return result;
|
|
37
|
-
}));
|
|
38
|
-
return eventEnvelopes.filter((_, index) => filteredResults[index]);
|
|
39
|
-
}
|
|
40
|
-
static async snapshotAndUpdateReadModels(config, entityName, entityID, eventStore, readModelStore) {
|
|
41
|
-
const logger = (0, common_1.getLogger)(config, 'MagekEventDispatcher#snapshotAndUpdateReadModels');
|
|
42
|
-
let entitySnapshot = undefined;
|
|
43
|
-
try {
|
|
44
|
-
entitySnapshot = await eventStore.fetchEntitySnapshot(entityName, entityID);
|
|
45
|
-
}
|
|
46
|
-
catch (e) {
|
|
47
|
-
logger.error('Error while fetching or reducing entity snapshot:', e);
|
|
10
|
+
let MagekEventProcessor = (() => {
|
|
11
|
+
let _staticExtraInitializers = [];
|
|
12
|
+
let _static_dispatchEntityEventsToEventHandlers_decorators;
|
|
13
|
+
return class MagekEventProcessor {
|
|
14
|
+
static {
|
|
15
|
+
const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(null) : void 0;
|
|
16
|
+
_static_dispatchEntityEventsToEventHandlers_decorators = [(0, instrumentation_1.trace)(common_1.TraceActionTypes.EVENT_HANDLERS_PROCESS)];
|
|
17
|
+
tslib_1.__esDecorate(this, null, _static_dispatchEntityEventsToEventHandlers_decorators, { kind: "method", name: "dispatchEntityEventsToEventHandlers", static: true, private: false, access: { has: obj => "dispatchEntityEventsToEventHandlers" in obj, get: obj => obj.dispatchEntityEventsToEventHandlers }, metadata: _metadata }, null, _staticExtraInitializers);
|
|
18
|
+
if (_metadata) Object.defineProperty(this, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
|
|
19
|
+
tslib_1.__runInitializers(this, _staticExtraInitializers);
|
|
48
20
|
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
eventHandlers = eventHandlers.concat(globalEventHandler);
|
|
21
|
+
/**
|
|
22
|
+
* Function that will be called once for each entity from the `RawEventsParser.streamPerEntityEvents` method
|
|
23
|
+
* after the page of events is grouped by entity.
|
|
24
|
+
*/
|
|
25
|
+
static eventProcessor(eventStore, readModelStore) {
|
|
26
|
+
return async (entityName, entityID, eventEnvelopes, config) => {
|
|
27
|
+
// Filter events that have already been dispatched
|
|
28
|
+
const eventsNotDispatched = await MagekEventProcessor.filterDispatched(config, eventEnvelopes, eventStore);
|
|
29
|
+
const eventEnvelopesProcessors = [
|
|
30
|
+
MagekEventProcessor.dispatchEntityEventsToEventHandlers(eventsNotDispatched, config),
|
|
31
|
+
];
|
|
32
|
+
// Read models are not updated for notification events (events that are not related to an entity but a topic)
|
|
33
|
+
if (!(entityName in config.topicToEvent)) {
|
|
34
|
+
eventEnvelopesProcessors.push(MagekEventProcessor.snapshotAndUpdateReadModels(config, entityName, entityID, eventStore, readModelStore));
|
|
64
35
|
}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
36
|
+
await common_1.Promises.allSettledAndFulfilled(eventEnvelopesProcessors);
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
static async filterDispatched(config, eventEnvelopes, eventStore) {
|
|
40
|
+
const logger = (0, common_1.getLogger)(config, 'MagekEventDispatcher#filterDispatched');
|
|
41
|
+
const filteredResults = await Promise.all(eventEnvelopes.map(async (eventEnvelope) => {
|
|
42
|
+
const result = await eventStore.storeDispatchedEvent(eventEnvelope);
|
|
43
|
+
if (!result) {
|
|
44
|
+
logger.warn('Event has already been dispatched. Skipping.', eventEnvelope);
|
|
68
45
|
}
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
46
|
+
return result;
|
|
47
|
+
}));
|
|
48
|
+
return eventEnvelopes.filter((_, index) => filteredResults[index]);
|
|
49
|
+
}
|
|
50
|
+
static async snapshotAndUpdateReadModels(config, entityName, entityID, eventStore, readModelStore) {
|
|
51
|
+
const logger = (0, common_1.getLogger)(config, 'MagekEventDispatcher#snapshotAndUpdateReadModels');
|
|
52
|
+
let entitySnapshot = undefined;
|
|
53
|
+
try {
|
|
54
|
+
entitySnapshot = await eventStore.fetchEntitySnapshot(entityName, entityID);
|
|
55
|
+
}
|
|
56
|
+
catch (e) {
|
|
57
|
+
logger.error('Error while fetching or reducing entity snapshot:', e);
|
|
58
|
+
}
|
|
59
|
+
if (!entitySnapshot) {
|
|
60
|
+
logger.debug('No new snapshot generated, skipping read models projection');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
logger.debug('Snapshot loaded and started read models projection:', entitySnapshot);
|
|
64
|
+
await readModelStore.project(entitySnapshot);
|
|
65
|
+
}
|
|
66
|
+
static async dispatchEntityEventsToEventHandlers(entityEventEnvelopes, config) {
|
|
67
|
+
const logger = (0, common_1.getLogger)(config, 'MagekEventDispatcher.dispatchEntityEventsToEventHandlers');
|
|
68
|
+
try {
|
|
69
|
+
await common_1.Promises.allSettledAndFulfilled(entityEventEnvelopes.map(async (eventEnvelope) => {
|
|
70
|
+
let eventHandlers = config.eventHandlers[eventEnvelope.typeName] || [];
|
|
71
|
+
const globalEventHandler = config.eventHandlers[decorators_1.GLOBAL_EVENT_HANDLERS];
|
|
72
|
+
if (globalEventHandler && globalEventHandler.length > 0) {
|
|
73
|
+
eventHandlers = eventHandlers.concat(globalEventHandler);
|
|
74
|
+
}
|
|
75
|
+
if (!eventHandlers || eventHandlers.length == 0) {
|
|
76
|
+
logger.debug(`No event-handlers found for event ${eventEnvelope.typeName}. Skipping...`);
|
|
77
|
+
return;
|
|
76
78
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
79
|
+
const eventInstance = this.getEventInstance(config, eventEnvelope);
|
|
80
|
+
if (eventHandlers && eventHandlers.length > 0) {
|
|
81
|
+
try {
|
|
82
|
+
await common_1.Promises.allSettledAndFulfilled(eventHandlers.map(async (eventHandler) => {
|
|
83
|
+
logger.debug('Calling "handle" method on event handler: ', eventHandler);
|
|
84
|
+
await this.callEventHandler(eventHandler, eventInstance, eventEnvelope, config);
|
|
85
|
+
}));
|
|
80
86
|
}
|
|
81
|
-
|
|
82
|
-
|
|
87
|
+
catch (error) {
|
|
88
|
+
if (error instanceof common_1.PromisesError) {
|
|
89
|
+
logger.error(`Failed to process handlers for event ${eventEnvelope.typeName}:`, error.failedReasons);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
logger.error(`Unexpected error processing handlers for event ${eventEnvelope.typeName}:`, error);
|
|
93
|
+
}
|
|
83
94
|
}
|
|
84
95
|
}
|
|
85
|
-
}
|
|
86
|
-
}));
|
|
87
|
-
}
|
|
88
|
-
catch (error) {
|
|
89
|
-
if (error instanceof common_1.PromisesError) {
|
|
90
|
-
logger.error('Failed to process events:', error.failedReasons);
|
|
96
|
+
}));
|
|
91
97
|
}
|
|
92
|
-
|
|
93
|
-
|
|
98
|
+
catch (error) {
|
|
99
|
+
if (error instanceof common_1.PromisesError) {
|
|
100
|
+
logger.error('Failed to process events:', error.failedReasons);
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
logger.error('Unexpected error processing events:', error);
|
|
104
|
+
}
|
|
94
105
|
}
|
|
95
106
|
}
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
const eventClass = (_a = config.events[eventEnvelope.typeName]) !== null && _a !== void 0 ? _a : config.notifications[eventEnvelope.typeName];
|
|
100
|
-
return (0, common_1.createInstance)(eventClass.class, eventEnvelope.value);
|
|
101
|
-
}
|
|
102
|
-
static async callEventHandler(eventHandler, eventInstance, eventEnvelope, config) {
|
|
103
|
-
const register = new common_1.Register(eventEnvelope.requestID, {}, register_handler_1.RegisterHandler.flush, eventEnvelope.currentUser);
|
|
104
|
-
try {
|
|
105
|
-
const logger = (0, common_1.getLogger)(config, 'MagekEventProcessor#handleEvent');
|
|
106
|
-
logger.debug('Calling "handle" method on event handler: ', eventHandler);
|
|
107
|
-
await eventHandler.handle(eventInstance, register);
|
|
107
|
+
static getEventInstance(config, eventEnvelope) {
|
|
108
|
+
const eventClass = config.events[eventEnvelope.typeName] ?? config.notifications[eventEnvelope.typeName];
|
|
109
|
+
return (0, common_1.createInstance)(eventClass.class, eventEnvelope.value);
|
|
108
110
|
}
|
|
109
|
-
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
111
|
+
static async callEventHandler(eventHandler, eventInstance, eventEnvelope, config) {
|
|
112
|
+
const register = new common_1.Register(eventEnvelope.requestID, {}, register_handler_1.RegisterHandler.flush, eventEnvelope.currentUser);
|
|
113
|
+
try {
|
|
114
|
+
const logger = (0, common_1.getLogger)(config, 'MagekEventProcessor#handleEvent');
|
|
115
|
+
logger.debug('Calling "handle" method on event handler: ', eventHandler);
|
|
116
|
+
await eventHandler.handle(eventInstance, register);
|
|
117
|
+
}
|
|
118
|
+
catch (e) {
|
|
119
|
+
const globalErrorDispatcher = new global_error_dispatcher_1.MagekGlobalErrorDispatcher(config);
|
|
120
|
+
const error = await globalErrorDispatcher.dispatch(new common_1.EventHandlerGlobalError(eventEnvelope, eventInstance, e.eventHandlerMetadata, e));
|
|
121
|
+
if (error)
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
await register_handler_1.RegisterHandler.handle(config, register);
|
|
114
125
|
}
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
126
|
+
};
|
|
127
|
+
})();
|
|
118
128
|
exports.MagekEventProcessor = MagekEventProcessor;
|
|
119
|
-
tslib_1.__decorate([
|
|
120
|
-
(0, instrumentation_1.Trace)(common_1.TraceActionTypes.EVENT_HANDLERS_PROCESS),
|
|
121
|
-
tslib_1.__metadata("design:type", Function),
|
|
122
|
-
tslib_1.__metadata("design:paramtypes", [Array,
|
|
123
|
-
common_1.MagekConfig]),
|
|
124
|
-
tslib_1.__metadata("design:returntype", Promise)
|
|
125
|
-
], MagekEventProcessor, "dispatchEntityEventsToEventHandlers", null);
|