@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.
Files changed (100) hide show
  1. package/dist/authorizer.js +1 -1
  2. package/dist/command-dispatcher.js +47 -41
  3. package/dist/core-concepts/data-migration/entities/data-migration-entity.js +5 -2
  4. package/dist/core-concepts/data-migration/events/data-migration-finished.js +3 -1
  5. package/dist/core-concepts/data-migration/events/data-migration-started.js +3 -1
  6. package/dist/core-concepts/data-migration/events/entity-migrated.js +4 -0
  7. package/dist/core-concepts/touch-entity/events/entity-touched.js +2 -0
  8. package/dist/data-migrations.js +59 -54
  9. package/dist/decorators/command.d.ts +4 -11
  10. package/dist/decorators/command.js +10 -18
  11. package/dist/decorators/data-migration.d.ts +4 -1
  12. package/dist/decorators/data-migration.js +3 -1
  13. package/dist/decorators/decorator-types.d.ts +50 -0
  14. package/dist/decorators/decorator-types.js +11 -0
  15. package/dist/decorators/decorator-utils.d.ts +1 -0
  16. package/dist/decorators/decorator-utils.js +2 -0
  17. package/dist/decorators/entity.d.ts +7 -15
  18. package/dist/decorators/entity.js +27 -37
  19. package/dist/decorators/event-handler.d.ts +11 -1
  20. package/dist/decorators/event-handler.js +13 -1
  21. package/dist/decorators/event.d.ts +4 -1
  22. package/dist/decorators/event.js +3 -2
  23. package/dist/decorators/field-metadata-reader.d.ts +8 -3
  24. package/dist/decorators/field-metadata-reader.js +50 -62
  25. package/dist/decorators/field.d.ts +23 -0
  26. package/dist/decorators/field.js +41 -0
  27. package/dist/decorators/global-error-handler.d.ts +10 -1
  28. package/dist/decorators/global-error-handler.js +9 -1
  29. package/dist/decorators/global-event-handler.d.ts +10 -1
  30. package/dist/decorators/global-event-handler.js +9 -1
  31. package/dist/decorators/health-sensor.d.ts +4 -1
  32. package/dist/decorators/health-sensor.js +3 -2
  33. package/dist/decorators/index.d.ts +3 -0
  34. package/dist/decorators/index.js +2 -0
  35. package/dist/decorators/metadata.d.ts +17 -1
  36. package/dist/decorators/metadata.js +22 -22
  37. package/dist/decorators/non-exposed.d.ts +13 -2
  38. package/dist/decorators/non-exposed.js +22 -20
  39. package/dist/decorators/notification.d.ts +6 -18
  40. package/dist/decorators/notification.js +10 -50
  41. package/dist/decorators/projects.d.ts +5 -18
  42. package/dist/decorators/projects.js +23 -54
  43. package/dist/decorators/query.d.ts +11 -1
  44. package/dist/decorators/query.js +18 -4
  45. package/dist/decorators/read-model.d.ts +13 -27
  46. package/dist/decorators/read-model.js +45 -77
  47. package/dist/decorators/role.d.ts +9 -3
  48. package/dist/decorators/role.js +8 -3
  49. package/dist/decorators/scheduled-command.d.ts +4 -1
  50. package/dist/decorators/scheduled-command.js +3 -1
  51. package/dist/decorators/schema-migration.d.ts +11 -27
  52. package/dist/decorators/schema-migration.js +32 -77
  53. package/dist/decorators/sequenced-by.d.ts +7 -25
  54. package/dist/decorators/sequenced-by.js +11 -71
  55. package/dist/event-dispatcher.js +29 -24
  56. package/dist/event-processor.js +106 -103
  57. package/dist/event-stream-consumer.js +25 -20
  58. package/dist/event-stream-producer.js +22 -17
  59. package/dist/events-reader.js +1 -0
  60. package/dist/global-error-dispatcher.js +3 -2
  61. package/dist/graphql-dispatcher.js +161 -156
  62. package/dist/index.js +4 -0
  63. package/dist/instrumentation/decorator/trace.d.ts +11 -3
  64. package/dist/instrumentation/decorator/trace.js +17 -71
  65. package/dist/magek.js +2 -2
  66. package/dist/query-dispatcher.js +2 -0
  67. package/dist/read-model-schema-migrator.js +71 -68
  68. package/dist/read-models-reader.js +178 -180
  69. package/dist/register-handler.js +3 -3
  70. package/dist/scheduled-command-dispatcher.js +48 -42
  71. package/dist/schema-migrator.js +63 -59
  72. package/dist/sensor/health/health-service.js +2 -1
  73. package/dist/services/event-store.js +221 -224
  74. package/dist/services/graphql/graphql-generator.js +11 -8
  75. package/dist/services/graphql/graphql-mutation-generator.js +4 -0
  76. package/dist/services/graphql/graphql-query-generator.js +14 -0
  77. package/dist/services/graphql/graphql-subcriptions-generator.js +7 -0
  78. package/dist/services/graphql/graphql-type-informer.js +4 -3
  79. package/dist/services/graphql/query-generators/graphql-query-by-keys-generator.js +4 -0
  80. package/dist/services/graphql/query-generators/graphql-query-events-generator.js +3 -0
  81. package/dist/services/graphql/query-generators/graphql-query-filters-generator.js +6 -0
  82. package/dist/services/graphql/query-generators/graphql-query-generator.js +4 -0
  83. package/dist/services/graphql/query-generators/graphql-query-listed-generator.js +7 -0
  84. package/dist/services/graphql/query-helpers/graphql-handled-fields-generator.js +5 -2
  85. package/dist/services/graphql/query-helpers/graphql-query-filter-arguments-builder.js +3 -0
  86. package/dist/services/graphql/query-helpers/graphql-query-filter-fields-builder.js +4 -0
  87. package/dist/services/graphql/query-helpers/graphql-query-sort-builder.js +4 -2
  88. package/dist/services/graphql/websocket-protocol/graphql-websocket-protocol.js +5 -3
  89. package/dist/services/pub-sub/read-model-pub-sub.js +1 -0
  90. package/dist/services/raw-events-parser.js +1 -1
  91. package/dist/services/read-model-store.js +16 -17
  92. package/dist/services/token-verifiers/jwks-uri-token-verifier.js +8 -4
  93. package/dist/services/token-verifiers/public-key-token-verifier.js +4 -2
  94. package/dist/services/token-verifiers/role-based-token-verifier.js +2 -1
  95. package/dist/services/token-verifiers/utilities.js +1 -1
  96. package/dist/subscribers-notifier.js +98 -92
  97. package/dist/token-verifier.js +2 -1
  98. package/package.json +4 -4
  99. package/dist/decorators/stage3-utils.d.ts +0 -6
  100. package/dist/decorators/stage3-utils.js +0 -25
@@ -1,35 +1,23 @@
1
1
  import { Class, NotificationInterface } from '@magek/common';
2
+ import { FieldDecoratorContext, ClassDecoratorContext } from './decorator-types';
2
3
  export type NotificationOptions = {
3
4
  topic?: string;
4
5
  };
5
- /**
6
- * Stage 3 field decorator context
7
- */
8
- interface Stage3FieldContext {
9
- kind: 'field';
10
- name: string | symbol;
11
- static: boolean;
12
- private: boolean;
13
- metadata: Record<string | symbol, unknown>;
14
- addInitializer?: (initializer: () => void) => void;
15
- }
16
6
  /**
17
7
  * Decorator to mark a class as a Magek Notification.
18
8
  * Notifications are events that can be published to external systems.
19
9
  *
10
+ * Uses TC39 Stage 3 decorators.
11
+ *
20
12
  * @param options - Optional configuration for the notification (e.g., topic name)
21
13
  * @returns A class decorator function
22
14
  */
23
- export declare const Notification: <TEvent extends NotificationInterface>(options?: NotificationOptions) => (eventClass: Class<TEvent>, context?: {
24
- kind: "class";
25
- metadata: Record<string | symbol, unknown>;
26
- }) => void;
15
+ export declare const Notification: <TEvent extends NotificationInterface>(options?: NotificationOptions) => (eventClass: Class<TEvent>, context: ClassDecoratorContext) => void;
27
16
  /**
28
17
  * Optional decorator that marks a field in a notification class as the partition key.
29
18
  * This is useful if you want to guarantee that all the event handlers for notifications
30
19
  * of the same type will be executed in the same order.
31
20
  *
32
- * Can be used as both a parameter decorator and property decorator.
21
+ * Uses TC39 Stage 3 decorators.
33
22
  */
34
- export declare function partitionKey(target: Class<NotificationInterface> | Object | undefined, propertyKeyOrContext?: string | symbol | Stage3FieldContext, parameterIndex?: number): void;
35
- export {};
23
+ export declare function partitionKey(_value: undefined, context: FieldDecoratorContext): void;
@@ -3,41 +3,31 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Notification = void 0;
4
4
  exports.partitionKey = partitionKey;
5
5
  const magek_1 = require("../magek");
6
- const metadata_1 = require("./metadata");
7
- /**
8
- * Type guard to detect Stage 3 field decorator context
9
- */
10
- function isStage3FieldContext(arg) {
11
- return (arg !== null &&
12
- typeof arg === 'object' &&
13
- 'kind' in arg &&
14
- arg.kind === 'field' &&
15
- 'name' in arg);
16
- }
17
- // Symbol for storing partition key in Stage 3 metadata
6
+ // Symbol for storing partition key in decorator metadata
18
7
  const PARTITION_KEY_SYMBOL = Symbol.for('magek:partitionKey');
19
8
  /**
20
9
  * Decorator to mark a class as a Magek Notification.
21
10
  * Notifications are events that can be published to external systems.
22
11
  *
12
+ * Uses TC39 Stage 3 decorators.
13
+ *
23
14
  * @param options - Optional configuration for the notification (e.g., topic name)
24
15
  * @returns A class decorator function
25
16
  */
26
17
  const Notification = (options) => (eventClass, context) => {
27
18
  // Handle Stage 3: transfer partition key from context.metadata to config
28
- if (context && context.kind === 'class' && context.metadata[PARTITION_KEY_SYMBOL]) {
19
+ if (context.metadata && context.metadata[PARTITION_KEY_SYMBOL]) {
29
20
  const propertyName = context.metadata[PARTITION_KEY_SYMBOL];
30
21
  magek_1.Magek.configureCurrentEnv((config) => {
31
22
  config.partitionKeys[eventClass.name] = propertyName;
32
23
  });
33
24
  }
34
25
  magek_1.Magek.configureCurrentEnv((config) => {
35
- var _a;
36
26
  if (config.notifications[eventClass.name] || config.events[eventClass.name]) {
37
27
  throw new Error(`A notification called ${eventClass.name} is already registered.
38
28
  If you think that this is an error, try performing a clean build.`);
39
29
  }
40
- const topic = (_a = options === null || options === void 0 ? void 0 : options.topic) !== null && _a !== void 0 ? _a : 'defaultTopic';
30
+ const topic = options?.topic ?? 'defaultTopic';
41
31
  if (topic) {
42
32
  config.eventToTopic[eventClass.name] = topic;
43
33
  config.topicToEvent[topic] = eventClass.name;
@@ -53,42 +43,12 @@ exports.Notification = Notification;
53
43
  * This is useful if you want to guarantee that all the event handlers for notifications
54
44
  * of the same type will be executed in the same order.
55
45
  *
56
- * Can be used as both a parameter decorator and property decorator.
46
+ * Uses TC39 Stage 3 decorators.
57
47
  */
58
- function partitionKey(target, propertyKeyOrContext, parameterIndex) {
59
- // Stage 3 field decorator usage
60
- if (isStage3FieldContext(propertyKeyOrContext)) {
61
- const context = propertyKeyOrContext;
62
- const propertyName = String(context.name);
63
- // Store in context.metadata so @Notification can read it
48
+ function partitionKey(_value, context) {
49
+ const propertyName = String(context.name);
50
+ // Store in context.metadata so @Notification can read it
51
+ if (context.metadata) {
64
52
  context.metadata[PARTITION_KEY_SYMBOL] = propertyName;
65
- return;
66
- }
67
- // Property decorator usage: @partitionKey on a class property (legacy)
68
- if (propertyKeyOrContext !== undefined && parameterIndex === undefined && target) {
69
- const notificationClass = target.constructor;
70
- const propertyName = String(propertyKeyOrContext);
71
- magek_1.Magek.configureCurrentEnv((config) => {
72
- if (config.partitionKeys[notificationClass.name] && config.partitionKeys[notificationClass.name] !== propertyName) {
73
- throw new Error(`Error trying to register a partition key named \`${propertyName}\` for class \`${notificationClass.name}\`. It already had the partition key \`${config.partitionKeys[notificationClass.name]}\` defined and only one partition key is allowed for each notification event.`);
74
- }
75
- else {
76
- config.partitionKeys[notificationClass.name] = propertyName;
77
- }
78
- });
79
- }
80
- // Parameter decorator usage: @partitionKey on constructor parameter
81
- else if (parameterIndex !== undefined && target) {
82
- const notificationClass = target;
83
- const args = (0, metadata_1.getFunctionArguments)(notificationClass);
84
- const propertyName = args[parameterIndex];
85
- magek_1.Magek.configureCurrentEnv((config) => {
86
- if (config.partitionKeys[notificationClass.name] && config.partitionKeys[notificationClass.name] !== propertyName) {
87
- throw new Error(`Error trying to register a partition key named \`${propertyName}\` for class \`${notificationClass.name}\`. It already had the partition key \`${config.partitionKeys[notificationClass.name]}\` defined and only one partition key is allowed for each notification event.`);
88
- }
89
- else {
90
- config.partitionKeys[notificationClass.name] = propertyName;
91
- }
92
- });
93
53
  }
94
54
  }
@@ -1,32 +1,19 @@
1
1
  import { Class, EntityInterface, ProjectionInfo, ProjectionResult, ReadModelInterface, ReadModelJoinKeyFunction, UUID } from '@magek/common';
2
+ import { MethodDecoratorContext } from './decorator-types';
2
3
  type PropertyType<TObj, TProp extends keyof TObj> = TObj[TProp];
3
4
  type JoinKeyType<TEntity extends EntityInterface, TReadModel extends ReadModelInterface> = keyof TEntity | ReadModelJoinKeyFunction<TEntity, TReadModel>;
4
- type UUIDLike = string | UUID;
5
- /**
6
- * Stage 3 method decorator context
7
- */
8
- interface Stage3MethodContext {
9
- kind: 'method';
10
- name: string | symbol;
11
- static: boolean;
12
- private: boolean;
13
- metadata: Record<string | symbol, unknown>;
14
- addInitializer?: (initializer: () => void) => void;
15
- }
16
5
  /**
17
6
  * Decorator to register a read model method as a projection
18
- * for a specific entity
7
+ * for a specific entity.
8
+ *
9
+ * Uses TC39 Stage 3 decorators.
19
10
  *
20
11
  * @param originEntity The entity that this method will react to
21
12
  * @param joinKey
22
13
  * @param unProject
23
14
  */
24
- export declare function Projects<TEntity extends EntityInterface, TJoinKey extends keyof TEntity, TReadModel extends ReadModelInterface>(originEntity: Class<TEntity>, joinKey: JoinKeyType<TEntity, TReadModel>, unProject?: UnprojectionMethod<TEntity, TReadModel, PropertyType<TEntity, TJoinKey>>): <TReceivedReadModel extends ReadModelInterface>(readModelClassOrMethod: Class<TReceivedReadModel> | Function, methodNameOrContext: string | Stage3MethodContext, methodDescriptor?: ProjectionMethod<TEntity, TReceivedReadModel, JoinKeyType<TEntity, TReceivedReadModel>>) => void;
15
+ export declare function projects<TEntity extends EntityInterface, TJoinKey extends keyof TEntity, TReadModel extends ReadModelInterface>(originEntity: Class<TEntity>, joinKey: JoinKeyType<TEntity, TReadModel>, unProject?: UnprojectionMethod<TEntity, TReadModel, PropertyType<TEntity, TJoinKey>>): <TReceivedReadModel extends ReadModelInterface>(method: Function, context: MethodDecoratorContext) => void;
25
16
  type ProjectionMethodDefinitionForArray<TEntity, TReadModel> = (_: TEntity, readModelID: UUID, readModel?: TReadModel, projectionInfo?: ProjectionInfo) => ProjectionResult<TReadModel>;
26
17
  type ProjectionMethodDefinition<TEntity, TReadModel> = (_: TEntity, readModel?: TReadModel, projectionInfo?: ProjectionInfo) => ProjectionResult<TReadModel>;
27
- type ProjectionMethod<TEntity extends EntityInterface, TReadModel extends ReadModelInterface, TJoinKeyType extends JoinKeyType<TEntity, TReadModel>> = TJoinKeyType extends ReadModelJoinKeyFunction<TEntity, TReadModel> ? ProjectionMethodWithEntityConditionalReadModelIdAndReadModel<TEntity, TReadModel> : TJoinKeyType extends keyof TEntity ? NonNullable<PropertyType<TEntity, TJoinKeyType>> extends Array<UUIDLike> ? ProjectionMethodWithEntityReadModelIdAndReadModel<TEntity, TReadModel> : ProjectionMethodWithEntityAndReadModel<TEntity, TReadModel> : never;
28
- type ProjectionMethodWithEntityAndReadModel<TEntity extends EntityInterface, TReadModel extends ReadModelInterface> = TypedPropertyDescriptor<(_: TEntity, readModel?: TReadModel) => ProjectionResult<TReadModel>>;
29
- type ProjectionMethodWithEntityConditionalReadModelIdAndReadModel<TEntity extends EntityInterface, TReadModel extends ReadModelInterface> = TypedPropertyDescriptor<(_: TEntity, readModelID: UUID | undefined, readModel?: TReadModel) => ProjectionResult<TReadModel>>;
30
- type ProjectionMethodWithEntityReadModelIdAndReadModel<TEntity extends EntityInterface, TReadModel extends ReadModelInterface> = TypedPropertyDescriptor<(_: TEntity, readModelID: UUID, readModel?: TReadModel) => ProjectionResult<TReadModel>>;
31
18
  type UnprojectionMethod<TEntity, TReadModel, TPropType> = TPropType extends Array<UUID> ? ProjectionMethodDefinitionForArray<TEntity, TReadModel> : ProjectionMethodDefinition<TEntity, TReadModel>;
32
19
  export {};
@@ -1,69 +1,38 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.Projects = Projects;
3
+ exports.projects = projects;
4
4
  const magek_1 = require("../magek");
5
- /**
6
- * Type guard for Stage 3 method context
7
- */
8
- function isStage3MethodContext(arg) {
9
- return (arg !== null &&
10
- typeof arg === 'object' &&
11
- 'kind' in arg &&
12
- arg.kind === 'method' &&
13
- 'name' in arg);
14
- }
15
5
  /**
16
6
  * Decorator to register a read model method as a projection
17
- * for a specific entity
7
+ * for a specific entity.
8
+ *
9
+ * Uses TC39 Stage 3 decorators.
18
10
  *
19
11
  * @param originEntity The entity that this method will react to
20
12
  * @param joinKey
21
13
  * @param unProject
22
14
  */
23
- function Projects(originEntity, joinKey, unProject) {
24
- return (readModelClassOrMethod, methodNameOrContext) => {
25
- // Detect Stage 3 vs Legacy decorator
26
- if (isStage3MethodContext(methodNameOrContext)) {
27
- // Stage 3 decorator - use addInitializer to get the class
28
- const context = methodNameOrContext;
29
- if (context.addInitializer) {
30
- context.addInitializer(function () {
31
- const readModelClass = context.static ? this : this.constructor;
32
- const projectionMetadata = {
33
- joinKey: joinKey,
34
- class: readModelClass,
35
- methodName: context.name.toString(),
36
- };
37
- registerProjection(originEntity.name, projectionMetadata);
38
- if (unProject) {
39
- const unProjectionMetadata = {
40
- joinKey,
41
- class: readModelClass,
42
- methodName: unProject.name,
43
- };
44
- registerUnProjection(originEntity.name, unProjectionMetadata);
45
- }
46
- });
47
- }
48
- }
49
- else {
50
- // Legacy decorator
51
- const readModelClass = readModelClassOrMethod;
52
- const methodName = methodNameOrContext;
53
- const projectionMetadata = {
54
- joinKey: joinKey,
55
- class: readModelClass,
56
- methodName: methodName,
57
- };
58
- registerProjection(originEntity.name, projectionMetadata);
59
- if (unProject) {
60
- const unProjectionMetadata = {
61
- joinKey,
15
+ function projects(originEntity, joinKey, unProject) {
16
+ return (_method, context) => {
17
+ // Stage 3 decorator - use addInitializer to get the class
18
+ if (context.addInitializer) {
19
+ context.addInitializer(function () {
20
+ const readModelClass = context.static ? this : this.constructor;
21
+ const projectionMetadata = {
22
+ joinKey: joinKey,
62
23
  class: readModelClass,
63
- methodName: unProject.name,
24
+ methodName: context.name.toString(),
64
25
  };
65
- registerUnProjection(originEntity.name, unProjectionMetadata);
66
- }
26
+ registerProjection(originEntity.name, projectionMetadata);
27
+ if (unProject) {
28
+ const unProjectionMetadata = {
29
+ joinKey,
30
+ class: readModelClass,
31
+ methodName: unProject.name,
32
+ };
33
+ registerUnProjection(originEntity.name, unProjectionMetadata);
34
+ }
35
+ });
67
36
  }
68
37
  };
69
38
  }
@@ -1,2 +1,12 @@
1
1
  import { CommandFilterHooks, QueryInterface, QueryRoleAccess } from '@magek/common';
2
- export declare function Query(attributes: QueryRoleAccess & CommandFilterHooks): <TCommand>(queryClass: QueryInterface<TCommand>) => void;
2
+ import { ClassDecoratorContext } from './decorator-utils';
3
+ /**
4
+ * Decorator to mark a class as a Magek Query.
5
+ * Queries represent read operations that don't modify state.
6
+ *
7
+ * Uses TC39 Stage 3 decorators.
8
+ *
9
+ * @param attributes - Role access control and filter hooks configuration
10
+ * @returns A class decorator function
11
+ */
12
+ export declare function Query(attributes: QueryRoleAccess & CommandFilterHooks): <TCommand>(queryClass: QueryInterface<TCommand>, context: ClassDecoratorContext) => void;
@@ -4,22 +4,36 @@ exports.Query = Query;
4
4
  const magek_1 = require("../magek");
5
5
  const metadata_1 = require("./metadata");
6
6
  const authorizer_1 = require("../authorizer");
7
+ /**
8
+ * Decorator to mark a class as a Magek Query.
9
+ * Queries represent read operations that don't modify state.
10
+ *
11
+ * Uses TC39 Stage 3 decorators.
12
+ *
13
+ * @param attributes - Role access control and filter hooks configuration
14
+ * @returns A class decorator function
15
+ */
7
16
  function Query(attributes) {
8
- return (queryClass) => {
17
+ return (queryClass, context) => {
9
18
  magek_1.Magek.configureCurrentEnv((config) => {
10
- var _a;
11
19
  if (config.queryHandlers[queryClass.name]) {
12
20
  throw new Error(`A query called ${queryClass.name} is already registered.
13
21
  If you think that this is an error, try performing a clean build.`);
14
22
  }
15
- const metadata = (0, metadata_1.getClassMetadata)(queryClass);
23
+ // Pass context.metadata because Symbol.metadata isn't attached to class yet during decorator execution
24
+ const metadata = (0, metadata_1.getClassMetadata)(queryClass, context.metadata);
16
25
  config.queryHandlers[queryClass.name] = {
17
26
  class: queryClass,
18
27
  authorizer: authorizer_1.MagekAuthorizer.build(attributes),
19
28
  properties: metadata.fields,
20
29
  methods: metadata.methods,
21
- before: (_a = attributes.before) !== null && _a !== void 0 ? _a : [],
30
+ before: attributes.before ?? [],
22
31
  };
32
+ // Register non-exposed fields from context.metadata
33
+ const nonExposedFields = (0, metadata_1.getNonExposedFields)(context.metadata);
34
+ if (nonExposedFields.length > 0) {
35
+ config.nonExposedGraphQLMetadataKey[queryClass.name] = nonExposedFields;
36
+ }
23
37
  });
24
38
  };
25
39
  }
@@ -1,39 +1,25 @@
1
1
  import { Class, ReadModelFilterHooks, ReadModelInterface, ReadModelRoleAccess } from '@magek/common';
2
+ import { ClassDecoratorContext, GetterDecoratorContext } from './decorator-utils';
2
3
  /**
3
- * Stage 3 class decorator context
4
- */
5
- interface Stage3ClassContext {
6
- kind: 'class';
7
- name: string | undefined;
8
- metadata: Record<string | symbol, unknown>;
9
- addInitializer?: (initializer: () => void) => void;
10
- }
11
- /**
12
- * Decorator to register a class as a ReadModel
4
+ * Decorator to register a class as a ReadModel.
5
+ *
6
+ * Uses TC39 Stage 3 decorators.
7
+ *
13
8
  * @param attributes
14
9
  */
15
- export declare function ReadModel(attributes: ReadModelRoleAccess & ReadModelFilterHooks): (readModelClass: Class<ReadModelInterface>, context?: Stage3ClassContext) => void;
10
+ export declare function ReadModel(attributes: ReadModelRoleAccess & ReadModelFilterHooks): (readModelClass: Class<ReadModelInterface>, context: ClassDecoratorContext) => void;
16
11
  interface CalculatedFieldOptions {
17
12
  dependsOn: string[];
18
13
  }
19
- /**
20
- * Stage 3 getter decorator context
21
- */
22
- interface Stage3GetterContext {
23
- kind: 'getter';
24
- name: string | symbol;
25
- static: boolean;
26
- private: boolean;
27
- metadata: Record<string | symbol, unknown>;
28
- access?: {
29
- get: () => unknown;
30
- };
31
- addInitializer?: (initializer: () => void) => void;
32
- }
14
+ /** Symbol for storing calculated field dependencies in decorator context.metadata */
15
+ export declare const CALCULATED_FIELDS_SYMBOL: unique symbol;
33
16
  /**
34
17
  * Decorator to mark a property as a calculated field with dependencies.
35
- * Supports both legacy and Stage 3 decorators.
18
+ *
19
+ * Uses TC39 Stage 3 decorators.
20
+ * Dependencies are stored in context.metadata and read by field-metadata-reader.
21
+ *
36
22
  * @param options - A `CalculatedFieldOptions` object indicating the dependencies.
37
23
  */
38
- export declare function CalculatedField(options: CalculatedFieldOptions): (target: object | Function, propertyKeyOrContext: string | symbol | Stage3GetterContext) => void;
24
+ export declare function calculatedField(options: CalculatedFieldOptions): (target: Function, context: GetterDecoratorContext) => void;
39
25
  export {};
@@ -1,56 +1,59 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.CALCULATED_FIELDS_SYMBOL = void 0;
3
4
  exports.ReadModel = ReadModel;
4
- exports.CalculatedField = CalculatedField;
5
- const common_1 = require("@magek/common");
5
+ exports.calculatedField = calculatedField;
6
6
  const magek_1 = require("../magek");
7
7
  const authorizer_1 = require("../authorizer");
8
8
  const metadata_1 = require("./metadata");
9
- const stage3_utils_1 = require("./stage3-utils");
10
9
  const sequenced_by_1 = require("./sequenced-by");
11
10
  /**
12
- * Type guard to detect Stage 3 class decorator context
11
+ * Register sequence key for a class
13
12
  */
14
- function isStage3ClassContext(arg) {
15
- return (arg !== null &&
16
- typeof arg === 'object' &&
17
- 'kind' in arg &&
18
- arg.kind === 'class' &&
19
- 'metadata' in arg);
13
+ function registerSequenceKey(klass, propertyName) {
14
+ magek_1.Magek.configureCurrentEnv((config) => {
15
+ if (config.readModelSequenceKeys[klass.name] && config.readModelSequenceKeys[klass.name] !== propertyName) {
16
+ 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.`);
17
+ }
18
+ else {
19
+ config.readModelSequenceKeys[klass.name] = propertyName;
20
+ }
21
+ });
20
22
  }
21
23
  /**
22
- * Decorator to register a class as a ReadModel
24
+ * Decorator to register a class as a ReadModel.
25
+ *
26
+ * Uses TC39 Stage 3 decorators.
27
+ *
23
28
  * @param attributes
24
29
  */
25
30
  function ReadModel(attributes) {
26
31
  return (readModelClass, context) => {
27
- // Transfer Stage 3 field metadata if applicable
28
- if (isStage3ClassContext(context)) {
29
- (0, stage3_utils_1.transferStage3FieldMetadata)(readModelClass, context.metadata);
30
- (0, sequenced_by_1.transferSequenceKeyMetadata)(readModelClass, context.metadata);
31
- transferCalculatedFieldDependencies(readModelClass, context.metadata);
32
+ // Read sequence key from Symbol.metadata and register to config
33
+ const sequenceKey = context.metadata?.[sequenced_by_1.SEQUENCE_KEY_SYMBOL];
34
+ if (sequenceKey) {
35
+ registerSequenceKey(readModelClass, sequenceKey);
32
36
  }
33
37
  magek_1.Magek.configureCurrentEnv((config) => {
34
- var _a;
35
38
  if (config.readModels[readModelClass.name]) {
36
39
  throw new Error(`A read model called ${readModelClass.name} is already registered.
37
40
  If you think that this is an error, try performing a clean build.`);
38
41
  }
39
42
  const authorizer = authorizer_1.MagekAuthorizer.build(attributes);
40
- const classMetadata = (0, metadata_1.getClassMetadata)(readModelClass);
41
- const dynamicDependencies = (0, common_1.getMetadata)('dynamic:dependencies', readModelClass) || {};
42
- // Combine fields with dynamic dependencies
43
+ // Pass context.metadata because Symbol.metadata isn't attached to class yet during decorator execution
44
+ const classMetadata = (0, metadata_1.getClassMetadata)(readModelClass, context.metadata);
45
+ // Combine fields with empty dependencies (fields don't have dependencies)
43
46
  const fieldProperties = classMetadata.fields.map((field) => {
44
47
  return {
45
48
  ...field,
46
- dependencies: dynamicDependencies[field.name] || [],
49
+ dependencies: [],
47
50
  };
48
51
  });
49
52
  // Include calculated fields (getters) from methods with their dependencies
53
+ // Dependencies are already included in method from getAllGetters (reads from Symbol.metadata)
50
54
  const methodProperties = classMetadata.methods.map((method) => {
51
55
  return {
52
56
  ...method,
53
- // Dependencies already included in method from getAllGetters
54
57
  };
55
58
  });
56
59
  // Merge fields and methods into properties
@@ -59,71 +62,36 @@ function ReadModel(attributes) {
59
62
  class: readModelClass,
60
63
  properties,
61
64
  authorizer,
62
- before: (_a = attributes.before) !== null && _a !== void 0 ? _a : [],
65
+ before: attributes.before ?? [],
63
66
  };
67
+ // Register non-exposed fields from context.metadata
68
+ const nonExposedFields = (0, metadata_1.getNonExposedFields)(context.metadata);
69
+ if (nonExposedFields.length > 0) {
70
+ config.nonExposedGraphQLMetadataKey[readModelClass.name] = nonExposedFields;
71
+ }
64
72
  });
65
73
  };
66
74
  }
67
- /**
68
- * Type guard for Stage 3 getter context
69
- */
70
- function isStage3GetterContext(arg) {
71
- return (arg !== null &&
72
- typeof arg === 'object' &&
73
- 'kind' in arg &&
74
- arg.kind === 'getter' &&
75
- 'name' in arg &&
76
- 'metadata' in arg);
77
- }
78
- // Symbol for storing calculated field dependencies in Stage 3 decorator context.metadata
79
- const CALCULATED_FIELDS_SYMBOL = Symbol.for('magek:calculatedFields');
80
- /**
81
- * Transfer calculated field dependencies from Stage 3 context.metadata to class metadata.
82
- * Called by the ReadModel class decorator.
83
- */
84
- function transferCalculatedFieldDependencies(classType, contextMetadata) {
85
- const calculatedFields = contextMetadata[CALCULATED_FIELDS_SYMBOL];
86
- if (calculatedFields) {
87
- const existingDependencies = (0, common_1.getMetadata)('dynamic:dependencies', classType) || {};
88
- for (const [propertyName, dependencies] of Object.entries(calculatedFields)) {
89
- existingDependencies[propertyName] = dependencies;
90
- }
91
- (0, common_1.defineMetadata)('dynamic:dependencies', existingDependencies, classType);
92
- }
93
- }
75
+ /** Symbol for storing calculated field dependencies in decorator context.metadata */
76
+ exports.CALCULATED_FIELDS_SYMBOL = Symbol.for('magek:calculatedFields');
94
77
  /**
95
78
  * Decorator to mark a property as a calculated field with dependencies.
96
- * Supports both legacy and Stage 3 decorators.
79
+ *
80
+ * Uses TC39 Stage 3 decorators.
81
+ * Dependencies are stored in context.metadata and read by field-metadata-reader.
82
+ *
97
83
  * @param options - A `CalculatedFieldOptions` object indicating the dependencies.
98
84
  */
99
- function CalculatedField(options) {
100
- return (target, propertyKeyOrContext) => {
101
- // Detect Stage 3 getter decorator
102
- if (isStage3GetterContext(propertyKeyOrContext)) {
103
- const context = propertyKeyOrContext;
104
- const propertyName = String(context.name);
105
- // Store in context.metadata for ReadModel decorator to pick up
106
- if (!context.metadata[CALCULATED_FIELDS_SYMBOL]) {
107
- context.metadata[CALCULATED_FIELDS_SYMBOL] = {};
85
+ function calculatedField(options) {
86
+ return (_target, context) => {
87
+ const propertyName = String(context.name);
88
+ // Store in context.metadata (becomes class[Symbol.metadata])
89
+ if (context.metadata) {
90
+ if (!context.metadata[exports.CALCULATED_FIELDS_SYMBOL]) {
91
+ context.metadata[exports.CALCULATED_FIELDS_SYMBOL] = {};
108
92
  }
109
- const calculatedFields = context.metadata[CALCULATED_FIELDS_SYMBOL];
93
+ const calculatedFields = context.metadata[exports.CALCULATED_FIELDS_SYMBOL];
110
94
  calculatedFields[propertyName] = options.dependsOn;
111
- // Also use addInitializer to set Reflect metadata
112
- if (context.addInitializer) {
113
- context.addInitializer(function () {
114
- const klass = this.constructor;
115
- const existingDependencies = (0, common_1.getMetadata)('dynamic:dependencies', klass) || {};
116
- existingDependencies[propertyName] = options.dependsOn;
117
- (0, common_1.defineMetadata)('dynamic:dependencies', existingDependencies, klass);
118
- });
119
- }
120
- return;
121
95
  }
122
- // Legacy decorator
123
- const propertyKey = propertyKeyOrContext;
124
- const existingDependencies = (0, common_1.getMetadata)('dynamic:dependencies', target.constructor) ||
125
- {};
126
- existingDependencies[propertyKey] = options.dependsOn;
127
- (0, common_1.defineMetadata)('dynamic:dependencies', existingDependencies, target.constructor);
128
96
  };
129
97
  }
@@ -1,6 +1,12 @@
1
1
  import { Class, RoleMetadata, RoleInterface } from '@magek/common';
2
+ import { ClassDecoratorContext } from './decorator-types';
2
3
  /**
3
- * Annotation to tell Magek which classes represent your roles
4
- * @param roleMetadata
4
+ * Decorator to mark a class as a Magek Role.
5
+ * Roles define authorization and authentication configurations.
6
+ *
7
+ * Uses TC39 Stage 3 decorators.
8
+ *
9
+ * @param roleMetadata - Role configuration including auth settings
10
+ * @returns A class decorator function
5
11
  */
6
- export declare function Role(roleMetadata?: RoleMetadata): (role: Class<RoleInterface>) => void;
12
+ export declare function Role(roleMetadata?: RoleMetadata): (role: Class<RoleInterface>, context: ClassDecoratorContext) => void;
@@ -3,11 +3,16 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Role = Role;
4
4
  const magek_1 = require("../magek");
5
5
  /**
6
- * Annotation to tell Magek which classes represent your roles
7
- * @param roleMetadata
6
+ * Decorator to mark a class as a Magek Role.
7
+ * Roles define authorization and authentication configurations.
8
+ *
9
+ * Uses TC39 Stage 3 decorators.
10
+ *
11
+ * @param roleMetadata - Role configuration including auth settings
12
+ * @returns A class decorator function
8
13
  */
9
14
  function Role(roleMetadata = { auth: {} }) {
10
- return (role) => {
15
+ return (role, _context) => {
11
16
  magek_1.Magek.configureCurrentEnv((config) => {
12
17
  config.roles[role.name] = roleMetadata;
13
18
  });
@@ -1,9 +1,12 @@
1
1
  import { ScheduledCommandInterface, ScheduleInterface } from '@magek/common';
2
+ import { ClassDecoratorContext } from './decorator-types';
2
3
  /**
3
4
  * Decorator to mark a class as a Magek Scheduled Command.
4
5
  * Scheduled commands are executed automatically based on a schedule.
5
6
  *
7
+ * Uses TC39 Stage 3 decorators.
8
+ *
6
9
  * @param attributes - Schedule configuration (e.g., cron expression)
7
10
  * @returns A class decorator function
8
11
  */
9
- export declare function ScheduledCommand(attributes: ScheduleInterface): (scheduledCommandClass: ScheduledCommandInterface) => void;
12
+ export declare function ScheduledCommand(attributes: ScheduleInterface): (scheduledCommandClass: ScheduledCommandInterface, context: ClassDecoratorContext) => void;
@@ -6,11 +6,13 @@ const magek_1 = require("../magek");
6
6
  * Decorator to mark a class as a Magek Scheduled Command.
7
7
  * Scheduled commands are executed automatically based on a schedule.
8
8
  *
9
+ * Uses TC39 Stage 3 decorators.
10
+ *
9
11
  * @param attributes - Schedule configuration (e.g., cron expression)
10
12
  * @returns A class decorator function
11
13
  */
12
14
  function ScheduledCommand(attributes) {
13
- return (commandClass) => {
15
+ return (commandClass, _context) => {
14
16
  magek_1.Magek.configureCurrentEnv((config) => {
15
17
  if (config.scheduledCommandHandlers[commandClass.name]) {
16
18
  throw new Error(`A command called ${commandClass.name} is already registered.