@magek/mcp-server 0.0.8

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 (52) hide show
  1. package/README.md +42 -0
  2. package/dist/index.d.ts +2 -0
  3. package/dist/index.js +25 -0
  4. package/dist/prompts/cqrs-flow.d.ts +15 -0
  5. package/dist/prompts/cqrs-flow.js +252 -0
  6. package/dist/prompts/troubleshooting.d.ts +15 -0
  7. package/dist/prompts/troubleshooting.js +239 -0
  8. package/dist/resources/cli-reference.d.ts +13 -0
  9. package/dist/resources/cli-reference.js +193 -0
  10. package/dist/resources/documentation.d.ts +18 -0
  11. package/dist/resources/documentation.js +62 -0
  12. package/dist/server.d.ts +5 -0
  13. package/dist/server.js +127 -0
  14. package/dist/utils/docs-loader.d.ts +19 -0
  15. package/dist/utils/docs-loader.js +111 -0
  16. package/docs/advanced/custom-templates.md +96 -0
  17. package/docs/advanced/data-migrations.md +181 -0
  18. package/docs/advanced/environment-configuration.md +74 -0
  19. package/docs/advanced/framework-packages.md +17 -0
  20. package/docs/advanced/health/sensor-health.md +389 -0
  21. package/docs/advanced/instrumentation.md +135 -0
  22. package/docs/advanced/register.md +119 -0
  23. package/docs/advanced/sensor.md +10 -0
  24. package/docs/advanced/testing.md +96 -0
  25. package/docs/advanced/touch-entities.md +45 -0
  26. package/docs/architecture/command.md +367 -0
  27. package/docs/architecture/entity.md +214 -0
  28. package/docs/architecture/event-driven.md +30 -0
  29. package/docs/architecture/event-handler.md +108 -0
  30. package/docs/architecture/event.md +145 -0
  31. package/docs/architecture/notifications.md +54 -0
  32. package/docs/architecture/queries.md +207 -0
  33. package/docs/architecture/read-model.md +507 -0
  34. package/docs/contributing.md +349 -0
  35. package/docs/docs-index.json +200 -0
  36. package/docs/features/error-handling.md +204 -0
  37. package/docs/features/event-stream.md +35 -0
  38. package/docs/features/logging.md +81 -0
  39. package/docs/features/schedule-actions.md +44 -0
  40. package/docs/getting-started/ai-coding-assistants.md +181 -0
  41. package/docs/getting-started/coding.md +543 -0
  42. package/docs/getting-started/installation.md +143 -0
  43. package/docs/graphql.md +1213 -0
  44. package/docs/index.md +62 -0
  45. package/docs/introduction.md +58 -0
  46. package/docs/magek-arch.png +0 -0
  47. package/docs/magek-cli.md +67 -0
  48. package/docs/magek-logo.svg +1 -0
  49. package/docs/security/authentication.md +189 -0
  50. package/docs/security/authorization.md +242 -0
  51. package/docs/security/security.md +16 -0
  52. package/package.json +46 -0
@@ -0,0 +1,135 @@
1
+ ---
2
+ title: "Instrumentation"
3
+ group: "Advanced"
4
+ ---
5
+
6
+ # Magek instrumentation
7
+
8
+ ## Trace Decorator
9
+ The Trace Decorator is a **Magek** functionality that facilitates the reception of notifications whenever significant events occur in Magek's core, such as event dispatching or migration execution.
10
+
11
+ ### Usage
12
+ To configure a custom tracer, you need to define an object with two methods: onStart and onEnd. The onStart method is called before the traced method is invoked, and the onEnd method is called after the method completes. Both methods receive a TraceInfo object, which contains information about the traced method and its arguments.
13
+
14
+ Here's an example of a custom tracer that logs trace events to the console:
15
+
16
+ ```typescript
17
+ import {
18
+ TraceParameters,
19
+ MagekConfig,
20
+ TraceActionTypes,
21
+ } from '@magek/common'
22
+
23
+ class MyTracer {
24
+ static async onStart(config: MagekConfig, actionType: string, traceParameters: TraceParameters): Promise<void> {
25
+ console.log(`Start ${actionType}: ${traceParameters.className}.${traceParameters.methodName}`)
26
+ }
27
+
28
+ static async onEnd(config: MagekConfig, actionType: string, traceParameters: TraceParameters): Promise<void> {
29
+ console.log(`End ${actionType}: ${traceParameters.className}.${traceParameters.methodName}`)
30
+ }
31
+ }
32
+ ```
33
+
34
+ You can then configure the tracer in your Magek application's configuration:
35
+
36
+ ```typescript
37
+
38
+ const config: MagekConfig = {
39
+ // ...other configuration options...
40
+ trace: {
41
+ enableTraceNotification: true,
42
+ onStart: MyTracer.onStart,
43
+ onEnd: MyTracer.onStart,
44
+ }
45
+ }
46
+ ```
47
+
48
+ In the configuration above, we've enabled trace notifications and specified our onStart and onEnd as the methods to use. Verbose disable will reduce the amount of information generated excluding the internal parameter in the trace parameters.
49
+
50
+ Setting `enableTraceNotification: true` would enable the trace for all actions. You can either disable them by setting it to `false` or selectively enable only specific actions using an array of TraceActionTypes.
51
+
52
+ ```typescript
53
+
54
+ const config: MagekConfig = {
55
+ // ...other configuration options...
56
+ trace: {
57
+ enableTraceNotification: [TraceActionTypes.DISPATCH_EVENT, TraceActionTypes.MIGRATION_RUN, 'OTHER'],
58
+ includeInternal: false,
59
+ onStart: MyTracer.onStart,
60
+ onEnd: MyTracer.onStart,
61
+ }
62
+ }
63
+ ```
64
+
65
+ In this example, only DISPATCH_EVENT, MIGRATION_RUN and 'OTHER' actions will trigger trace notifications.
66
+
67
+ ### TraceActionTypes
68
+
69
+ The TraceActionTypes enum defines all the traceable actions in Magek's core:
70
+
71
+ ```typescript
72
+ export enum TraceActionTypes {
73
+ CUSTOM,
74
+ EVENT_HANDLERS_PROCESS,
75
+ HANDLE_EVENT,
76
+ DISPATCH_ENTITY_TO_EVENT_HANDLERS,
77
+ DISPATCH_EVENTS,
78
+ FETCH_ENTITY_SNAPSHOT,
79
+ STORE_SNAPSHOT,
80
+ LOAD_LATEST_SNAPSHOT,
81
+ LOAD_EVENT_STREAM_SINCE,
82
+ ENTITY_REDUCER,
83
+ READ_MODEL_FIND_BY_ID,
84
+ GRAPHQL_READ_MODEL_SEARCH,
85
+ READ_MODEL_SEARCH,
86
+ COMMAND_HANDLER,
87
+ MIGRATION_RUN,
88
+ GRAPHQL_DISPATCH,
89
+ GRAPHQL_RUN_OPERATION,
90
+ SCHEDULED_COMMAND_HANDLER,
91
+ DISPATCH_SUBSCRIBER_NOTIFIER,
92
+ READ_MODEL_SCHEMA_MIGRATOR_RUN,
93
+ SCHEMA_MIGRATOR_MIGRATE,
94
+ }
95
+ ```
96
+
97
+ ### TraceInfo
98
+ The TraceInfo interface defines the data that is passed to the tracer's onBefore and onAfter methods:
99
+
100
+ ```typescript
101
+ export interface TraceInfo {
102
+ className: string
103
+ methodName: string
104
+ args: Array<unknown>
105
+ traceId: UUID
106
+ elapsedInvocationMillis?: number
107
+ internal: {
108
+ target: unknown
109
+ descriptor: PropertyDescriptor
110
+ }
111
+ description?: string
112
+ }
113
+ ```
114
+
115
+ `className` and `methodName` identify the function that is being traced.
116
+
117
+ ### Adding the Trace Decorator to Your own async methods
118
+ In addition to using the Trace Decorator to receive notifications when events occur in Magek's core, you can also use it to trace your own methods. To add the Trace Decorator to your own methods, simply add @Trace() before your method declaration.
119
+
120
+ Here's an example of how to use the Trace Decorator on a custom method:
121
+
122
+ ```typescript
123
+
124
+ export class MyCustomClass {
125
+ @Trace('OTHER')
126
+ public async myCustomMethod(config: MagekConfig, logger: Logger): Promise<void> {
127
+ logger.debug('This is my custom method')
128
+ // Do some custom logic here...
129
+ }
130
+ }
131
+ ```
132
+
133
+ In the example above, we added the @Trace('OTHER') decorator to the myCustomMethod method. This will cause the method to emit trace events when it's invoked, allowing you to trace the flow of your application and detect performance bottlenecks or errors.
134
+
135
+ Note that when you add the Trace Decorator to your own methods, you'll need to configure your Magek instance to use a tracer that implements the necessary methods to handle these events.
@@ -0,0 +1,119 @@
1
+ ---
2
+ title: "Register"
3
+ group: "Advanced"
4
+ ---
5
+
6
+ # Advanced uses of the Register object
7
+
8
+ The Register object is a built-in object that is automatically injected by the framework into all command or event handlers to let users interact with the execution context. It can be used for a variety of purposes, including:
9
+
10
+ * Registering events to be emitted at the end of the command or event handler
11
+ * Manually flush the events to be persisted synchronously to the event store
12
+ * Access the current signed in user, their roles and other claims included in their JWT token
13
+ * In a command: Access the request context or alter the HTTP response headers
14
+
15
+ ## Registering events
16
+
17
+ When handling a command or event, you can use the Register object to register one or more events that will be emitted when the command or event handler is completed. Events are registered using the `register.events()` method, which takes one or more events as arguments. For example:
18
+
19
+ ```typescript
20
+ public async handle(register: Register): Promise<void> {
21
+ // Do some work...
22
+ register.events(new OrderConfirmed(this.orderID))
23
+ // Do more work...
24
+ }
25
+ ```
26
+
27
+ In this example, we're registering an OrderConfirmed event to be persisted to the event store when the handler finishes. You can also register multiple events by passing them as separate arguments to the register.events() method:
28
+
29
+ ```typescript
30
+ public async handle(register: Register): Promise<void> {
31
+ // Do some work...
32
+ register.events(
33
+ new OrderConfirmed(this.orderID),
34
+ new OrderShipped(this.orderID)
35
+ )
36
+ // Do more work...
37
+ }
38
+ ```
39
+
40
+ It's worth noting that events registered with `register.events()` aren't immediately persisted to the event store. Instead, they're stored in memory until the command or event handler finishes executing. To force the events to be persisted immediately, you can call the `register.flush()` method that is described in the next section.
41
+
42
+ ## Manually flush the events
43
+
44
+ As mentioned in the previous section, events registered with `register.events()` aren't immediately persisted to the event store. Instead, they're stored in memory until the command or event handler finishes its execution, but this doesn't work in all situations, sometimes it's useful to store partial updates of a longer process, and some scenarios could accept partial successes. To force the events to be persisted and wait for the database to confirm the write, you can use the `register.flush()` method.
45
+
46
+ The `register.flush()` method takes no arguments and returns a promise that resolves when the events have been successfully persisted to the event store. For example:
47
+
48
+ ```typescript
49
+ public async handle(register: Register): Promise<void> {
50
+ // Do some work...
51
+ register.events(new OrderConfirmed(this.orderID))
52
+ await register.flush()
53
+ const mailID = await sendConfirmationEmail(this.orderID)
54
+ register.events(new MailSent(this.orderID, mailID))
55
+ // Do more work...
56
+ }
57
+ ```
58
+
59
+ In this example, we're calling `register.flush()` after registering an `OrderConfirmed` event to ensure that it's persisted to the event store before continuing with the rest of the handler logic. In this way, even if an error happens while sending the confirmation email, the order will be persisted.
60
+
61
+ ## Access the current signed in user
62
+
63
+ When handling a command or event, you can use the injected `Register` object to access the currently signed-in user as well as any metadata included in their JWT token like their roles or other claims (the specific claims will depend on the specific auth provider used). To do this, you can use the `currentUser` property. This property is an instance of the `UserEnvelope` class, which has the following properties:
64
+
65
+ ```typescript
66
+ export interface UserEnvelope {
67
+ id?: string // An optional identifier of the user
68
+ username: string // The unique username of the current user
69
+ roles: Array<string> // The list of role names assigned to this user
70
+ claims: Record<string, unknown> // An object containing the claims included in the body of the JWT token
71
+ header?: Record<string, unknown> // An object containing the headers of the JWT token for further verification
72
+ }
73
+ ```
74
+
75
+ For example, to access the username of the currently signed-in user, you can use the `currentUser.username` property:
76
+
77
+ ```typescript
78
+ public async handle(register: Register): Promise<void> {
79
+ console.log(`The currently signed-in user is ${register.currentUser?.username}`)
80
+ }
81
+
82
+ // Output: The currently signed-in user is john.doe
83
+ ```
84
+
85
+ ## Command-specific features
86
+
87
+ The command handlers are executed as part of a GraphQL mutation request, so they have access to a few additional features that are specific to commands that can be used to access the request context or alter the HTTP response headers.
88
+
89
+ ### Access the request context
90
+
91
+ The request context is injected in the command handler as part of the register command and you can access it using the `context` property. This property is an instance of the `ContextEnvelope` interface, which has the following properties:
92
+
93
+ ```typescript
94
+ export interface ContextEnvelope {
95
+ /** Decoded request header and body */
96
+ request: {
97
+ headers: unknown
98
+ body: unknown
99
+ }
100
+ /** Runtime-dependent raw request context object */
101
+ rawContext: unknown
102
+ }
103
+ ```
104
+
105
+ The `request` property exposes a normalized version of the request headers and body that can be used regardless the provider. We recommend using this property instead of the `rawContext` property, as it will be more portable across providers.
106
+
107
+ The `rawContext` property exposes the full raw request context as it comes in the original request.
108
+
109
+ ### Alter the HTTP response headers
110
+
111
+ Finally, you can use the `responseHeaders` property to alter the HTTP response headers that will be sent back to the client. This property is a plain Typescript object which is initialized with the default headers. You can add, remove or modify any of the headers by using the standard object methods:
112
+
113
+ ```typescript
114
+ public async handle(register: Register): Promise<void> {
115
+ register.responseHeaders['X-My-Header'] = 'My custom header'
116
+ register.responseHeaders['X-My-Other-Header'] = 'My other custom header'
117
+ delete register.responseHeaders['X-My-Other-Header']
118
+ }
119
+ ```
@@ -0,0 +1,10 @@
1
+ ---
2
+ title: "Sensors"
3
+ group: "Advanced"
4
+ ---
5
+
6
+ # Sensor
7
+
8
+ ## Related Topics
9
+
10
+ - [Sensor Health](health/sensor-health.md) - Health monitoring and indicators
@@ -0,0 +1,96 @@
1
+ ---
2
+ title: "Testing"
3
+ group: "Advanced"
4
+ ---
5
+
6
+ # Testing
7
+
8
+ Magek applications are fully tested by default. This means that you can be sure that your application will work as expected. However, you can also write your own tests to check that your application behaves as you expect. In this section, we will leave some recommendations on how to test your Magek application.
9
+
10
+ ## Testing Magek applications
11
+
12
+ To properly test a Magek application, you should create a `test` folder at the same level as the `src` one. Apart from that, tests' names should have the `<my_test>.test.ts` format.
13
+
14
+ When a Magek application is generated, you will have a script in a `package.json` like this:
15
+
16
+ ```typescript
17
+ "scripts": {
18
+ "test": "nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\""
19
+ }
20
+ ```
21
+
22
+ The only thing that you should add to this line are the `AWS_SDK_LOAD_CONFIG=true` and `MAGEK_ENV=test` environment variables, so the script will look like this:
23
+
24
+ ```typescript
25
+ "scripts": {
26
+ "test": "AWS_SDK_LOAD_CONFIG=true MAGEK_ENV=test nyc --extension .ts mocha --forbid-only \"test/**/*.test.ts\""
27
+ }
28
+ ```
29
+
30
+ ### Testing with `sinon-chai`
31
+
32
+ The `MagekConfig` can be accessed through the `Magek.config` on any part of a Magek application. To properly mock it for your objective, we really recommend to use sinon `replace` method, after configuring your `Magek.config` as desired.
33
+
34
+ In the example below, we add 2 "empty" read-models, since we are iterating `Magek.config.readModels` from a command handler:
35
+
36
+ ```typescript
37
+ // Test
38
+
39
+ const config = new MagekConfig('test')
40
+ config.appName = 'testing-time'
41
+ config.runtime = {} as Runtime
42
+ config.readModels['WoW'] = {} as ReadModelMetadata
43
+ config.readModels['Amazing'] = {} as ReadModelMetadata
44
+ replace(Magek, 'config', config)
45
+
46
+ const spyMyCall = spy(MyCommand, 'myCall')
47
+ const command = new MyCommand('1', true)
48
+ const register = new Register('request-id-1')
49
+ const registerSpy = spy(register, 'events')
50
+ await MyCommand.handle(command, register)
51
+
52
+ expect(spyMyCall).to.have.been.calledOnceWithExactly('WoW')
53
+ expect(spyMyCall).to.have.been.calledOnceWithExactly('Amazing')
54
+ expect(registerSpy).to.have.been.calledOnceWithExactly(new MyEvent('1', 'WoW'))
55
+ expect(registerSpy).to.have.been.calledOnceWithExactly(new MyEvent('1', 'Amazing'))
56
+ ```
57
+
58
+ ```typescript
59
+ // Example code
60
+ public static async handle(command: MyCommand, register: Register): Promise<void> {
61
+ const readModels = Magek.config.readModels
62
+ for (const readModelName in readModels) {
63
+ myCall(readModelName)
64
+ register.events(new MyEvent(command.ID, readModelName))
65
+ }
66
+ }
67
+ ```
68
+
69
+ ### Recommended files
70
+
71
+ These are some files that might help you speed up your testing with Magek.
72
+
73
+ ```typescript
74
+ // <root_dir>/test/expect.ts
75
+
76
+ chai.use(require('sinon-chai'))
77
+ chai.use(require('chai-as-promised'))
78
+
79
+ export const expect = chai.expect
80
+ ```
81
+
82
+ This `expect` method will help you with some more additional methods like `expect(<my_stub>).to.have.been.calledOnceWithExactly(<my_params..>)`
83
+
84
+ ```yaml
85
+ # <root_dir>/.mocharc.yml
86
+ diff: true
87
+ require: 'ts-node/register'
88
+ extension:
89
+ - ts
90
+ package: './package.json'
91
+ recursive: true
92
+ reporter: 'spec'
93
+ timeout: 5000
94
+ full-trace: true
95
+ bail: true
96
+ ```
@@ -0,0 +1,45 @@
1
+ ---
2
+ title: "Touch Entities"
3
+ group: "Advanced"
4
+ ---
5
+
6
+ # TouchEntities
7
+
8
+ Magek provides a way to refresh the value of an entity and update the corresponding ReadModels that depend on it.
9
+ This functionality is useful when a new projection is added to a ReadModel and you want to apply it retroactively to the events that have already occurred.
10
+ It is also helpful when there was an error when calculating a ReadModel or when the snapshot of an entity was not generated.
11
+
12
+ To migrate an existing entity to a new version, you need to call `MagekTouchEntityHandler.touchEntity` to touch entities.
13
+ For example, this command will touch all the entities of the class Cart.:
14
+
15
+ ```typescript
16
+
17
+ @Command({
18
+ authorize: 'all',
19
+ })
20
+ export class TouchCommand {
21
+ public constructor() {}
22
+
23
+ public static async handle(_command: TouchCommand, _register: Register): Promise<void> {
24
+ const entitiesIdsResult = await Magek.entitiesIDs('Cart', 500, undefined)
25
+ const paginatedEntityIdResults = entitiesIdsResult.items
26
+ const carts = await Promise.all(
27
+ paginatedEntityIdResults.map(async (entity) => await Magek.entity(Cart, entity.entityID))
28
+ )
29
+ if (!carts || carts.length === 0) {
30
+ return
31
+ }
32
+ await Promise.all(
33
+ carts.map(async (cart) => {
34
+ const validCart = cart!
35
+ await MagekTouchEntityHandler.touchEntity('Cart', validCart.id)
36
+ console.log('Touched', validCart)
37
+ return validCart.id
38
+ })
39
+ )
40
+ }
41
+ }
42
+ ```
43
+
44
+ Please note that touching entities is an advanced feature that should be used with caution and only when necessary.
45
+ It may affect your application performance and consistency if not used properly.