anear-js-api 0.4.40 → 0.5.3
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/EACH_PARTICIPANT_LIFECYCLE.md +144 -0
- package/RENDER_USAGE_EXAMPLES.md +19 -15
- package/lib/api/AnearApi.js +22 -0
- package/lib/api/ApiService.js +12 -0
- package/lib/models/AnearEvent.js +27 -8
- package/lib/models/AnearParticipant.js +6 -6
- package/lib/state_machines/AnearCoreServiceMachine.js +12 -3
- package/lib/state_machines/AnearEventMachine.js +579 -149
- package/lib/state_machines/AnearParticipantMachine.js +55 -1
- package/lib/utils/AppMachineTransition.js +105 -33
- package/lib/utils/Constants.js +2 -1
- package/lib/utils/DisplayEventProcessor.js +155 -39
- package/lib/utils/FontAssetsUploader.js +10 -0
- package/lib/utils/PugHelpers.js +13 -2
- package/lib/utils/RealtimeMessaging.js +10 -1
- package/lib/utils/RenderContextBuilder.js +26 -7
- package/package.json +1 -1
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# The `eachParticipant` Display Lifecycle
|
|
2
|
+
|
|
3
|
+
This document provides a detailed, step-by-by-step breakdown of how a display targeted at `eachParticipant` travels from the application's state machine (AppM) to an individual participant's browser client.
|
|
4
|
+
|
|
5
|
+
### The Goal
|
|
6
|
+
|
|
7
|
+
We want to render a specific view (`QuestionScreen.pug`) for a single user (`participant-123`) and make sure they answer within 10 seconds.
|
|
8
|
+
|
|
9
|
+
### The Big Picture
|
|
10
|
+
|
|
11
|
+
The core idea is to translate a declarative `meta` block in your application's state machine (AppM) into concrete HTML content that gets delivered to a specific participant's device. This process involves a chain of components:
|
|
12
|
+
|
|
13
|
+
`AppMachineTransition` -> `AnearEventMachine` -> `DisplayEventProcessor` -> `AnearParticipantMachine` -> **Ably Message**
|
|
14
|
+
|
|
15
|
+
Let's break down each step.
|
|
16
|
+
|
|
17
|
+
---
|
|
18
|
+
|
|
19
|
+
### Part 1: The Trigger (Your AppM & `AppMachineTransition.js`)
|
|
20
|
+
|
|
21
|
+
It all starts in your application-specific state machine (e.g., `anear-q-and-a/StateMachine.js`). When your machine enters a state that needs to display something to participants, you define a `meta` object.
|
|
22
|
+
|
|
23
|
+
**Context:** The `meta` object is how your AppM communicates rendering intentions to the Anear platform. The `AppMachineTransition` module is a subscriber that listens for *every* state change in your AppM. Its job is to parse that `meta` object and translate it into a standardized command for the rest of the system.
|
|
24
|
+
|
|
25
|
+
#### Code Example (Your AppM)
|
|
26
|
+
Imagine your Q&A machine enters the `askQuestion` state. The state definition would look like this:
|
|
27
|
+
|
|
28
|
+
```javascript
|
|
29
|
+
// anear-q-and-a/StateMachine.js
|
|
30
|
+
// ...
|
|
31
|
+
confirmMove: {
|
|
32
|
+
meta: {
|
|
33
|
+
// 'eachParticipant' is a function for selective rendering.
|
|
34
|
+
// This example shows how to target a single participant based on the
|
|
35
|
+
// event that triggered this state transition.
|
|
36
|
+
eachParticipant: (appContext, event) => {
|
|
37
|
+
// 'event' is the event that led to this state, e.g., { type: 'MOVE', participantId: 'p1', ... }
|
|
38
|
+
const movingParticipantId = event.participantId;
|
|
39
|
+
|
|
40
|
+
if (!movingParticipantId) return []; // Always return an array
|
|
41
|
+
|
|
42
|
+
// We only want to send a display to the participant who just moved.
|
|
43
|
+
return [{
|
|
44
|
+
participantId: movingParticipantId,
|
|
45
|
+
view: 'participant/MoveConfirmation', // A view confirming their move was received
|
|
46
|
+
props: {
|
|
47
|
+
message: 'Your move has been recorded. Waiting for opponent...',
|
|
48
|
+
move: event.moveData
|
|
49
|
+
},
|
|
50
|
+
timeout: 2000 // A short timeout for the confirmation display
|
|
51
|
+
}];
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// ...
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
#### Lifecycle Step 1: Parsing the `meta` block
|
|
59
|
+
|
|
60
|
+
When your AppM transitions to `confirmMove`, the `AppMachineTransition` function is invoked.
|
|
61
|
+
|
|
62
|
+
* **File:** `/Users/machvee/dev/anear-js-api/lib/utils/AppMachineTransition.js`
|
|
63
|
+
* **Description:** It detects the `meta.eachParticipant` property. Since it's a function, it executes it, receiving the array of display instructions we defined above. It then iterates through that array. For each instruction, it creates a standardized "display event" object.
|
|
64
|
+
* **Code Reference (`AppMachineTransition.js` lines 62-95):**
|
|
65
|
+
|
|
66
|
+
```javascript
|
|
67
|
+
// ... inside AppMachineTransition.js
|
|
68
|
+
if (meta.eachParticipant) {
|
|
69
|
+
if (typeof meta.eachParticipant === 'function') {
|
|
70
|
+
// This is our path: the selective rendering function
|
|
71
|
+
const participantRenderFunc = meta.eachParticipant;
|
|
72
|
+
const participantDisplays = participantRenderFunc(appContext, event); // Executes our function from the AppM
|
|
73
|
+
|
|
74
|
+
// ... loops through the returned array ...
|
|
75
|
+
participantDisplays.forEach(participantDisplay => {
|
|
76
|
+
if (participantDisplay && participantDisplay.participantId && participantDisplay.view) {
|
|
77
|
+
const timeout = participantDisplay.timeout || null;
|
|
78
|
+
|
|
79
|
+
// Packages the info into a standard object
|
|
80
|
+
displayEvent = RenderContextBuilder.buildDisplayEvent(
|
|
81
|
+
participantDisplay.view,
|
|
82
|
+
baseAppRenderContext,
|
|
83
|
+
'eachParticipant',
|
|
84
|
+
participantDisplay.participantId,
|
|
85
|
+
timeout
|
|
86
|
+
);
|
|
87
|
+
displayEvents.push(displayEvent);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
} // ...
|
|
91
|
+
}
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
#### Lifecycle Step 2: Sending the Command
|
|
95
|
+
|
|
96
|
+
After processing all `meta` properties, `AppMachineTransition` bundles all the generated `displayEvent` objects into a single event and sends it to the `AnearEventMachine` (AEM).
|
|
97
|
+
|
|
98
|
+
* **File:** `/Users/machvee/dev/anear-js-api/lib/utils/AppMachineTransition.js`
|
|
99
|
+
* **Code Reference (lines 137-140):**
|
|
100
|
+
|
|
101
|
+
```javascript
|
|
102
|
+
if (displayEvents.length > 0) {
|
|
103
|
+
// Sends one event with a list of all rendering jobs
|
|
104
|
+
anearEvent.send('RENDER_DISPLAY', { displayEvents });
|
|
105
|
+
}
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
---
|
|
109
|
+
|
|
110
|
+
### Part 2: The Router (`AnearEventMachine.js`)
|
|
111
|
+
|
|
112
|
+
**Context:** The `AnearEventMachine` (AEM) is the central orchestrator for an event. When it receives the `RENDER_DISPLAY` event, its role isn't to render anything itself, but to delegate the task to a specialized processor.
|
|
113
|
+
|
|
114
|
+
#### Lifecycle Step 3: Delegation
|
|
115
|
+
|
|
116
|
+
The AEM enters a rendering state (e.g., `announceRendering` or `liveRendering`) and invokes its `renderDisplay` service.
|
|
117
|
+
|
|
118
|
+
* **File:** `/Users/machvee/dev/anear-js-api/lib/state_machines/AnearEventMachine.js`
|
|
119
|
+
* **Description:** This service is simple: it creates an instance of `DisplayEventProcessor` and tells it to handle the `displayEvents` array we sent in the previous step.
|
|
120
|
+
* **Code Reference (lines 1144-1148):**
|
|
121
|
+
|
|
122
|
+
```javascript
|
|
123
|
+
// ... inside AnearEventMachine.js
|
|
124
|
+
services: {
|
|
125
|
+
renderDisplay: async (context, event) => {
|
|
126
|
+
// The event here contains our { displayEvents } payload
|
|
127
|
+
const displayEventProcessor = new DisplayEventProcessor(context);
|
|
128
|
+
return await displayEventProcessor.processAndPublish(event.displayEvents);
|
|
129
|
+
},
|
|
130
|
+
// ...
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
### Part 3: The Processor (`DisplayEventProcessor.js`)
|
|
136
|
+
|
|
137
|
+
**Context:** This class is the workhorse. It knows how to handle different display targets (`allParticipants`, `spectators`, `host`, and our target, `eachParticipant`). It's responsible for compiling the Pug templates and figuring out *who* gets the final HTML.
|
|
138
|
+
|
|
139
|
+
#### Lifecycle Step 4: Processing and Routing the Display
|
|
140
|
+
|
|
141
|
+
The `DisplayEventProcessor` loops through each `displayEvent` and, based on the target, decides what to do.
|
|
142
|
+
|
|
143
|
+
* **File:** `/Users/machvee/dev/anear-js-api/lib/utils/DisplayEventProcessor.js`
|
|
144
|
+
* **Description:** For an `eachParticipant`
|
package/RENDER_USAGE_EXAMPLES.md
CHANGED
|
@@ -18,15 +18,19 @@ const Config = {
|
|
|
18
18
|
states: {
|
|
19
19
|
registration: {
|
|
20
20
|
meta: {
|
|
21
|
-
|
|
21
|
+
allParticipants: 'ViewableGameBoard',
|
|
22
22
|
spectators: 'ViewableGameBoard'
|
|
23
23
|
}
|
|
24
24
|
},
|
|
25
25
|
gameInProgress: {
|
|
26
26
|
meta: {
|
|
27
|
-
|
|
28
|
-
view: 'PlayableGameBoard',
|
|
29
|
-
timeout: calcParticipantTimeout
|
|
27
|
+
eachParticipant: {
|
|
28
|
+
view: 'PlayableGameBoard',
|
|
29
|
+
timeout: calcParticipantTimeout,
|
|
30
|
+
props: {
|
|
31
|
+
title: "Your Move!",
|
|
32
|
+
highlightLastMove: true
|
|
33
|
+
}
|
|
30
34
|
},
|
|
31
35
|
spectators: 'ViewableGameBoard'
|
|
32
36
|
}
|
|
@@ -51,26 +55,26 @@ const actions = {
|
|
|
51
55
|
renderGameOver: (context, event) => {
|
|
52
56
|
anearEvent.render(
|
|
53
57
|
'GameOver', // viewPath
|
|
54
|
-
'
|
|
58
|
+
'allParticipants', // displayType
|
|
55
59
|
context, // appContext (AppM's context)
|
|
56
60
|
event, // event that triggered this render
|
|
57
61
|
null, // timeout (null for no timeout)
|
|
58
62
|
{ winner: context.winningPlayerId } // additional props
|
|
59
63
|
)
|
|
60
64
|
},
|
|
61
|
-
|
|
65
|
+
|
|
62
66
|
// Render with timeout for participant displays
|
|
63
67
|
renderWithTimeout: (context, event) => {
|
|
64
68
|
anearEvent.render(
|
|
65
69
|
'WaitingForMove',
|
|
66
|
-
'
|
|
70
|
+
'eachParticipant',
|
|
67
71
|
context,
|
|
68
72
|
event,
|
|
69
73
|
(appContext, participantId) => 30000, // 30 second timeout
|
|
70
74
|
{ currentPlayer: context.currentPlayerToken }
|
|
71
75
|
)
|
|
72
76
|
},
|
|
73
|
-
|
|
77
|
+
|
|
74
78
|
// Render for spectators
|
|
75
79
|
renderForSpectators: (context, event) => {
|
|
76
80
|
anearEvent.render(
|
|
@@ -95,11 +99,11 @@ const actions = {
|
|
|
95
99
|
// Render winner display
|
|
96
100
|
anearEvent.render(
|
|
97
101
|
'WinnerDisplay',
|
|
98
|
-
'
|
|
102
|
+
'allParticipants',
|
|
99
103
|
context,
|
|
100
104
|
event,
|
|
101
105
|
null,
|
|
102
|
-
{
|
|
106
|
+
{
|
|
103
107
|
winner: context.winner,
|
|
104
108
|
finalScore: context.score,
|
|
105
109
|
gameDuration: context.gameDuration
|
|
@@ -109,14 +113,14 @@ const actions = {
|
|
|
109
113
|
// Render tie display
|
|
110
114
|
anearEvent.render(
|
|
111
115
|
'TieDisplay',
|
|
112
|
-
'
|
|
116
|
+
'allParticipants',
|
|
113
117
|
context,
|
|
114
118
|
event,
|
|
115
119
|
null,
|
|
116
120
|
{ finalScore: context.score }
|
|
117
121
|
)
|
|
118
122
|
}
|
|
119
|
-
|
|
123
|
+
|
|
120
124
|
// Now close the event
|
|
121
125
|
anearEvent.closeEvent()
|
|
122
126
|
}
|
|
@@ -128,14 +132,14 @@ const actions = {
|
|
|
128
132
|
### `anearEvent.render(viewPath, displayType, appContext, event, timeout, props)`
|
|
129
133
|
|
|
130
134
|
- **`viewPath`** (string): Template/view path to render (e.g., 'GameBoard', 'GameOver')
|
|
131
|
-
- **`displayType`** (string): One of '
|
|
135
|
+
- **`displayType`** (string): One of 'allParticipants', 'eachParticipant', or 'spectators'
|
|
132
136
|
- **`appContext`** (Object): The AppM's context object (available in scope)
|
|
133
137
|
- **`event`** (Object): The event that triggered this render (available in scope)
|
|
134
|
-
- **`timeout`** (Function|number|null):
|
|
138
|
+
- **`timeout`** (Function|number|null):
|
|
135
139
|
- `null`: No timeout
|
|
136
140
|
- `number`: Fixed timeout in milliseconds
|
|
137
141
|
- `Function`: Dynamic timeout function `(appContext, participantId) => msecs`
|
|
138
|
-
- **`props`** (Object): Additional properties
|
|
142
|
+
- **`props`** (Object): Additional properties made available at the root of the pug template's render context (optional)
|
|
139
143
|
|
|
140
144
|
## When to Use Each Approach
|
|
141
145
|
|
package/lib/api/AnearApi.js
CHANGED
|
@@ -79,6 +79,28 @@ class AnearApi extends ApiService {
|
|
|
79
79
|
logger.debug('getAppFontAssetsUploadUrls response:', attrs)
|
|
80
80
|
return attrs
|
|
81
81
|
}
|
|
82
|
+
|
|
83
|
+
async saveAppEventContext(eventId, appmContext) {
|
|
84
|
+
logger.debug(`API: POST developer events/${eventId}/app_event_context`)
|
|
85
|
+
const path = `events/${eventId}/app_event_context`
|
|
86
|
+
return this.postRaw(path, { appm_context: appmContext })
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async getLatestAppEventContext(eventId) {
|
|
90
|
+
logger.debug(`API: GET developer events/${eventId}/app_event_context`)
|
|
91
|
+
const path = `events/${eventId}/app_event_context`
|
|
92
|
+
const json = await this.get(path)
|
|
93
|
+
const attrs = json.data && json.data.attributes ? json.data.attributes : {}
|
|
94
|
+
const eventIdAttr = attrs['event-id']
|
|
95
|
+
const raw = attrs['appm-context']
|
|
96
|
+
let appmContext = null
|
|
97
|
+
try {
|
|
98
|
+
appmContext = typeof raw === 'string' ? JSON.parse(raw) : raw
|
|
99
|
+
} catch (e) {
|
|
100
|
+
// leave appmContext as null if parsing fails
|
|
101
|
+
}
|
|
102
|
+
return { eventId: eventIdAttr, appmContext }
|
|
103
|
+
}
|
|
82
104
|
}
|
|
83
105
|
|
|
84
106
|
// Instantiate and export the API immediately
|
package/lib/api/ApiService.js
CHANGED
|
@@ -56,6 +56,18 @@ class ApiService {
|
|
|
56
56
|
return this.issueRequest(request)
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
+
postRaw(path, body={}) {
|
|
60
|
+
const urlString = `${this.api_base_url}/${path}`
|
|
61
|
+
const request = new fetch.Request(
|
|
62
|
+
urlString, {
|
|
63
|
+
method: 'POST',
|
|
64
|
+
headers: this.default_headers,
|
|
65
|
+
body: JSON.stringify(body)
|
|
66
|
+
}
|
|
67
|
+
)
|
|
68
|
+
return this.issueRequest(request)
|
|
69
|
+
}
|
|
70
|
+
|
|
59
71
|
put(resource, id, attributes, relationships={}) {
|
|
60
72
|
const payload = this.formatPayload(resource, attributes, relationships)
|
|
61
73
|
const urlString = `${this.api_base_url}/${resource}/${id}`
|
package/lib/models/AnearEvent.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
"use strict"
|
|
2
2
|
const logger = require('../utils/Logger')
|
|
3
|
+
const anearApi = require('../api/AnearApi')
|
|
3
4
|
|
|
4
5
|
const JsonApiResource = require('./JsonApiResource')
|
|
5
6
|
|
|
@@ -46,6 +47,20 @@ class AnearEvent extends JsonApiResource {
|
|
|
46
47
|
this.send("CLOSE")
|
|
47
48
|
}
|
|
48
49
|
|
|
50
|
+
pauseEvent(context, resumeEvent = { type: 'RESUME' }) {
|
|
51
|
+
// Persist via AEM and acknowledge with PAUSED
|
|
52
|
+
this.send('PAUSE', { appmContext: { context, resumeEvent } })
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
saveEvent(context, resumeEvent = { type: 'RESUME' }) {
|
|
56
|
+
// Delegate save to the AEM; AEM will persist via ANAPI and acknowledge with SAVED
|
|
57
|
+
this.send('SAVE', { appmContext: { context, resumeEvent } })
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
bootParticipant(participantId, reason) {
|
|
61
|
+
this.send("BOOT_PARTICIPANT", { participantId, reason })
|
|
62
|
+
}
|
|
63
|
+
|
|
49
64
|
render(viewPath, displayType, appContext, event, timeout = null, props = {}) {
|
|
50
65
|
// Explicit render method for guaranteed rendering control
|
|
51
66
|
// This complements the meta: {} approach for when you need explicit control
|
|
@@ -80,14 +95,6 @@ class AnearEvent extends JsonApiResource {
|
|
|
80
95
|
})
|
|
81
96
|
}
|
|
82
97
|
|
|
83
|
-
pauseEvent() {
|
|
84
|
-
this.send("PAUSE")
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
resumeEvent() {
|
|
88
|
-
this.send("RESUME")
|
|
89
|
-
}
|
|
90
|
-
|
|
91
98
|
getClonedFromEvent() {
|
|
92
99
|
// if the current event was a clone of previous event, fetch if from
|
|
93
100
|
// Peristence and return
|
|
@@ -111,6 +118,18 @@ class AnearEvent extends JsonApiResource {
|
|
|
111
118
|
return this.attributes.hosted
|
|
112
119
|
}
|
|
113
120
|
|
|
121
|
+
get name() {
|
|
122
|
+
return this.attributes.name
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
get description() {
|
|
126
|
+
return this.attributes.description
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
get createdAt() {
|
|
130
|
+
return this.attributes['created-at']
|
|
131
|
+
}
|
|
132
|
+
|
|
114
133
|
get participantTimeout() {
|
|
115
134
|
// TODO: This probably should be set for each publishEventPrivateMessage
|
|
116
135
|
// and then referenceable as an anear-data attribute in the html. That way
|
|
@@ -18,7 +18,8 @@ class AnearParticipant extends JsonApiResource {
|
|
|
18
18
|
id: this.data.id,
|
|
19
19
|
name: this.name,
|
|
20
20
|
avatarUrl: this.avatarUrl,
|
|
21
|
-
geoLocation: this.geoLocation
|
|
21
|
+
geoLocation: this.geoLocation,
|
|
22
|
+
isHost: this.isHost
|
|
22
23
|
}
|
|
23
24
|
}
|
|
24
25
|
|
|
@@ -62,6 +63,10 @@ class AnearParticipant extends JsonApiResource {
|
|
|
62
63
|
return this.attributes['private-channel-name']
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
get isHost() {
|
|
67
|
+
return this.userType === HostUserType
|
|
68
|
+
}
|
|
69
|
+
|
|
65
70
|
setMachine(service) {
|
|
66
71
|
if (service) {
|
|
67
72
|
this.send = service.send.bind(service)
|
|
@@ -69,11 +74,6 @@ class AnearParticipant extends JsonApiResource {
|
|
|
69
74
|
this.send = () => {}
|
|
70
75
|
}
|
|
71
76
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
isHost() {
|
|
75
|
-
return this.userType === HostUserType
|
|
76
|
-
}
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
module.exports = AnearParticipant
|
|
@@ -134,7 +134,7 @@ const AnearCoreServiceMachineConfig = appId => ({
|
|
|
134
134
|
}
|
|
135
135
|
},
|
|
136
136
|
waitAnearEventLifecycleCommand: {
|
|
137
|
-
// The Anear API backend will send CREATE_EVENT messages with the event JSON data
|
|
137
|
+
// The Anear API backend will send CREATE_EVENT or LOAD_EVENT messages with the event JSON data
|
|
138
138
|
// to this createEventMessages Channel when it needs to create a new instance of an
|
|
139
139
|
// Event
|
|
140
140
|
entry: (context) => logger.debug(`Waiting on ${context.appData.data.attributes['short-name']} lifecycle command`),
|
|
@@ -142,6 +142,9 @@ const AnearCoreServiceMachineConfig = appId => ({
|
|
|
142
142
|
CREATE_EVENT: {
|
|
143
143
|
actions: ['startNewEventMachine']
|
|
144
144
|
},
|
|
145
|
+
LOAD_EVENT: {
|
|
146
|
+
actions: ['startNewEventMachine']
|
|
147
|
+
},
|
|
145
148
|
EVENT_MACHINE_EXIT: {
|
|
146
149
|
actions: [
|
|
147
150
|
'cleanupEventMachine'
|
|
@@ -234,6 +237,11 @@ const AnearCoreServiceMachineFunctions = {
|
|
|
234
237
|
context.coreServiceMachine,
|
|
235
238
|
'CREATE_EVENT'
|
|
236
239
|
)
|
|
240
|
+
RealtimeMessaging.subscribe(
|
|
241
|
+
context.newEventCreationChannel,
|
|
242
|
+
context.coreServiceMachine,
|
|
243
|
+
'LOAD_EVENT'
|
|
244
|
+
)
|
|
237
245
|
},
|
|
238
246
|
startNewEventMachine: assign(
|
|
239
247
|
{
|
|
@@ -242,11 +250,12 @@ const AnearCoreServiceMachineFunctions = {
|
|
|
242
250
|
const anearEvent = new AnearEvent(eventJSON)
|
|
243
251
|
|
|
244
252
|
if (context.anearEventMachines[anearEvent.id]) {
|
|
245
|
-
logger.info(`[ACSM] Event machine for ${anearEvent.id} already exists. Ignoring
|
|
253
|
+
logger.info(`[ACSM] Event machine for ${anearEvent.id} already exists. Ignoring ${event.type}.`)
|
|
246
254
|
return context.anearEventMachines
|
|
247
255
|
}
|
|
248
256
|
|
|
249
|
-
const
|
|
257
|
+
const isLoadEvent = event.type === 'LOAD_EVENT'
|
|
258
|
+
const service = AnearEventMachine(anearEvent, { ...context, rehydrate: isLoadEvent })
|
|
250
259
|
|
|
251
260
|
return {
|
|
252
261
|
...context.anearEventMachines,
|