@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.
- package/README.md +42 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +25 -0
- package/dist/prompts/cqrs-flow.d.ts +15 -0
- package/dist/prompts/cqrs-flow.js +252 -0
- package/dist/prompts/troubleshooting.d.ts +15 -0
- package/dist/prompts/troubleshooting.js +239 -0
- package/dist/resources/cli-reference.d.ts +13 -0
- package/dist/resources/cli-reference.js +193 -0
- package/dist/resources/documentation.d.ts +18 -0
- package/dist/resources/documentation.js +62 -0
- package/dist/server.d.ts +5 -0
- package/dist/server.js +127 -0
- package/dist/utils/docs-loader.d.ts +19 -0
- package/dist/utils/docs-loader.js +111 -0
- package/docs/advanced/custom-templates.md +96 -0
- package/docs/advanced/data-migrations.md +181 -0
- package/docs/advanced/environment-configuration.md +74 -0
- package/docs/advanced/framework-packages.md +17 -0
- package/docs/advanced/health/sensor-health.md +389 -0
- package/docs/advanced/instrumentation.md +135 -0
- package/docs/advanced/register.md +119 -0
- package/docs/advanced/sensor.md +10 -0
- package/docs/advanced/testing.md +96 -0
- package/docs/advanced/touch-entities.md +45 -0
- package/docs/architecture/command.md +367 -0
- package/docs/architecture/entity.md +214 -0
- package/docs/architecture/event-driven.md +30 -0
- package/docs/architecture/event-handler.md +108 -0
- package/docs/architecture/event.md +145 -0
- package/docs/architecture/notifications.md +54 -0
- package/docs/architecture/queries.md +207 -0
- package/docs/architecture/read-model.md +507 -0
- package/docs/contributing.md +349 -0
- package/docs/docs-index.json +200 -0
- package/docs/features/error-handling.md +204 -0
- package/docs/features/event-stream.md +35 -0
- package/docs/features/logging.md +81 -0
- package/docs/features/schedule-actions.md +44 -0
- package/docs/getting-started/ai-coding-assistants.md +181 -0
- package/docs/getting-started/coding.md +543 -0
- package/docs/getting-started/installation.md +143 -0
- package/docs/graphql.md +1213 -0
- package/docs/index.md +62 -0
- package/docs/introduction.md +58 -0
- package/docs/magek-arch.png +0 -0
- package/docs/magek-cli.md +67 -0
- package/docs/magek-logo.svg +1 -0
- package/docs/security/authentication.md +189 -0
- package/docs/security/authorization.md +242 -0
- package/docs/security/security.md +16 -0
- 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,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.
|