quidproquo-xstate 0.1.0
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 +1 -0
- package/lib/commonjs/actionProcessor/getStateMachineCreateActionProcessor.d.ts +2 -0
- package/lib/commonjs/actionProcessor/getStateMachineCreateActionProcessor.js +66 -0
- package/lib/commonjs/actionProcessor/getStateMachineGetActionProcessor.d.ts +2 -0
- package/lib/commonjs/actionProcessor/getStateMachineGetActionProcessor.js +39 -0
- package/lib/commonjs/actionProcessor/getStateMachineGetStateActionProcessor.d.ts +2 -0
- package/lib/commonjs/actionProcessor/getStateMachineGetStateActionProcessor.js +54 -0
- package/lib/commonjs/actionProcessor/getStateMachineSendEventActionProcessor.d.ts +2 -0
- package/lib/commonjs/actionProcessor/getStateMachineSendEventActionProcessor.js +100 -0
- package/lib/commonjs/actionProcessor/index.d.ts +2 -0
- package/lib/commonjs/actionProcessor/index.js +20 -0
- package/lib/commonjs/actions/StateMachineActionType.d.ts +6 -0
- package/lib/commonjs/actions/StateMachineActionType.js +10 -0
- package/lib/commonjs/actions/StateMachineCreateActionRequester.d.ts +2 -0
- package/lib/commonjs/actions/StateMachineCreateActionRequester.js +14 -0
- package/lib/commonjs/actions/StateMachineCreateActionTypes.d.ts +13 -0
- package/lib/commonjs/actions/StateMachineCreateActionTypes.js +2 -0
- package/lib/commonjs/actions/StateMachineGetActionRequester.d.ts +2 -0
- package/lib/commonjs/actions/StateMachineGetActionRequester.js +13 -0
- package/lib/commonjs/actions/StateMachineGetActionTypes.d.ts +12 -0
- package/lib/commonjs/actions/StateMachineGetActionTypes.js +2 -0
- package/lib/commonjs/actions/StateMachineGetStateActionRequester.d.ts +2 -0
- package/lib/commonjs/actions/StateMachineGetStateActionRequester.js +13 -0
- package/lib/commonjs/actions/StateMachineGetStateActionTypes.d.ts +16 -0
- package/lib/commonjs/actions/StateMachineGetStateActionTypes.js +2 -0
- package/lib/commonjs/actions/StateMachineSendEventActionRequester.d.ts +2 -0
- package/lib/commonjs/actions/StateMachineSendEventActionRequester.js +14 -0
- package/lib/commonjs/actions/StateMachineSendEventActionTypes.d.ts +17 -0
- package/lib/commonjs/actions/StateMachineSendEventActionTypes.js +2 -0
- package/lib/commonjs/actions/index.d.ts +9 -0
- package/lib/commonjs/actions/index.js +25 -0
- package/lib/commonjs/config/QPQConfig.d.ts +3 -0
- package/lib/commonjs/config/QPQConfig.js +7 -0
- package/lib/commonjs/config/index.d.ts +3 -0
- package/lib/commonjs/config/index.js +19 -0
- package/lib/commonjs/config/qpqXStateConfigUtils.d.ts +4 -0
- package/lib/commonjs/config/qpqXStateConfigUtils.js +13 -0
- package/lib/commonjs/config/settings/index.d.ts +1 -0
- package/lib/commonjs/config/settings/index.js +17 -0
- package/lib/commonjs/config/settings/stateMachine.d.ts +22 -0
- package/lib/commonjs/config/settings/stateMachine.js +27 -0
- package/lib/commonjs/index.d.ts +3 -0
- package/lib/commonjs/index.js +19 -0
- package/lib/esm/actionProcessor/getStateMachineCreateActionProcessor.d.ts +2 -0
- package/lib/esm/actionProcessor/getStateMachineCreateActionProcessor.js +51 -0
- package/lib/esm/actionProcessor/getStateMachineGetActionProcessor.d.ts +2 -0
- package/lib/esm/actionProcessor/getStateMachineGetActionProcessor.js +24 -0
- package/lib/esm/actionProcessor/getStateMachineGetStateActionProcessor.d.ts +2 -0
- package/lib/esm/actionProcessor/getStateMachineGetStateActionProcessor.js +39 -0
- package/lib/esm/actionProcessor/getStateMachineSendEventActionProcessor.d.ts +2 -0
- package/lib/esm/actionProcessor/getStateMachineSendEventActionProcessor.js +85 -0
- package/lib/esm/actionProcessor/index.d.ts +2 -0
- package/lib/esm/actionProcessor/index.js +10 -0
- package/lib/esm/actions/StateMachineActionType.d.ts +6 -0
- package/lib/esm/actions/StateMachineActionType.js +7 -0
- package/lib/esm/actions/StateMachineCreateActionRequester.d.ts +2 -0
- package/lib/esm/actions/StateMachineCreateActionRequester.js +11 -0
- package/lib/esm/actions/StateMachineCreateActionTypes.d.ts +13 -0
- package/lib/esm/actions/StateMachineCreateActionTypes.js +1 -0
- package/lib/esm/actions/StateMachineGetActionRequester.d.ts +2 -0
- package/lib/esm/actions/StateMachineGetActionRequester.js +10 -0
- package/lib/esm/actions/StateMachineGetActionTypes.d.ts +12 -0
- package/lib/esm/actions/StateMachineGetActionTypes.js +1 -0
- package/lib/esm/actions/StateMachineGetStateActionRequester.d.ts +2 -0
- package/lib/esm/actions/StateMachineGetStateActionRequester.js +10 -0
- package/lib/esm/actions/StateMachineGetStateActionTypes.d.ts +16 -0
- package/lib/esm/actions/StateMachineGetStateActionTypes.js +1 -0
- package/lib/esm/actions/StateMachineSendEventActionRequester.d.ts +2 -0
- package/lib/esm/actions/StateMachineSendEventActionRequester.js +11 -0
- package/lib/esm/actions/StateMachineSendEventActionTypes.d.ts +17 -0
- package/lib/esm/actions/StateMachineSendEventActionTypes.js +1 -0
- package/lib/esm/actions/index.d.ts +9 -0
- package/lib/esm/actions/index.js +9 -0
- package/lib/esm/config/QPQConfig.d.ts +3 -0
- package/lib/esm/config/QPQConfig.js +4 -0
- package/lib/esm/config/index.d.ts +3 -0
- package/lib/esm/config/index.js +3 -0
- package/lib/esm/config/qpqXStateConfigUtils.d.ts +4 -0
- package/lib/esm/config/qpqXStateConfigUtils.js +8 -0
- package/lib/esm/config/settings/index.d.ts +1 -0
- package/lib/esm/config/settings/index.js +1 -0
- package/lib/esm/config/settings/stateMachine.d.ts +22 -0
- package/lib/esm/config/settings/stateMachine.js +21 -0
- package/lib/esm/index.d.ts +3 -0
- package/lib/esm/index.js +3 -0
- package/package.json +42 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CrossModuleOwner, QPQConfigAdvancedSettings, QPQConfigSetting, QpqFunctionRuntime } from 'quidproquo-core';
|
|
2
|
+
import { EventObject, MachineConfig, MachineContext } from 'xstate';
|
|
3
|
+
export interface StateMachineRuntimeMap {
|
|
4
|
+
[name: string]: QpqFunctionRuntime;
|
|
5
|
+
}
|
|
6
|
+
export interface QPQConfigAdvancedStateMachineSettings extends QPQConfigAdvancedSettings {
|
|
7
|
+
config: MachineConfig<MachineContext, EventObject>;
|
|
8
|
+
actions?: StateMachineRuntimeMap;
|
|
9
|
+
guards?: StateMachineRuntimeMap;
|
|
10
|
+
stateField?: string;
|
|
11
|
+
owner?: CrossModuleOwner;
|
|
12
|
+
}
|
|
13
|
+
export interface StateMachineQPQConfigSetting extends QPQConfigSetting {
|
|
14
|
+
stateMachineName: string;
|
|
15
|
+
keyValueStoreName: string;
|
|
16
|
+
config: MachineConfig<MachineContext, EventObject>;
|
|
17
|
+
actions: StateMachineRuntimeMap;
|
|
18
|
+
guards: StateMachineRuntimeMap;
|
|
19
|
+
stateField: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const getStateMachineStoreName: (stateMachineName: string) => string;
|
|
22
|
+
export declare const defineStateMachine: (stateMachineName: string, options: QPQConfigAdvancedStateMachineSettings) => QPQConfigSetting[];
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.defineStateMachine = exports.getStateMachineStoreName = void 0;
|
|
4
|
+
const quidproquo_core_1 = require("quidproquo-core");
|
|
5
|
+
const QPQConfig_1 = require("../QPQConfig");
|
|
6
|
+
const getStateMachineStoreName = (stateMachineName) => `qpq-sm-${stateMachineName}`;
|
|
7
|
+
exports.getStateMachineStoreName = getStateMachineStoreName;
|
|
8
|
+
const defineStateMachine = (stateMachineName, options) => {
|
|
9
|
+
var _a, _b, _c;
|
|
10
|
+
const keyValueStoreName = (0, exports.getStateMachineStoreName)(stateMachineName);
|
|
11
|
+
const stateMachineConfig = {
|
|
12
|
+
configSettingType: QPQConfig_1.QPQXStateConfigSettingType.StateMachine,
|
|
13
|
+
uniqueKey: stateMachineName,
|
|
14
|
+
stateMachineName,
|
|
15
|
+
keyValueStoreName,
|
|
16
|
+
config: options.config,
|
|
17
|
+
actions: (_a = options.actions) !== null && _a !== void 0 ? _a : {},
|
|
18
|
+
guards: (_b = options.guards) !== null && _b !== void 0 ? _b : {},
|
|
19
|
+
stateField: (_c = options.stateField) !== null && _c !== void 0 ? _c : '__machineState',
|
|
20
|
+
owner: options.owner,
|
|
21
|
+
};
|
|
22
|
+
return [
|
|
23
|
+
(0, quidproquo_core_1.defineKeyValueStore)(keyValueStoreName, 'id'),
|
|
24
|
+
stateMachineConfig
|
|
25
|
+
];
|
|
26
|
+
};
|
|
27
|
+
exports.defineStateMachine = defineStateMachine;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
__exportStar(require("./actionProcessor"), exports);
|
|
18
|
+
__exportStar(require("./actions"), exports);
|
|
19
|
+
__exportStar(require("./config"), exports);
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { actionResult, actionResultError, askKeyValueStoreUpsert, createImplementationRuntime, ErrorTypeEnum, } from 'quidproquo-core';
|
|
2
|
+
import { createActor, createMachine } from 'xstate';
|
|
3
|
+
import { StateMachineActionType } from '../actions';
|
|
4
|
+
import { getStateMachineByName } from '../config';
|
|
5
|
+
const getProcessStateMachineCreate = (qpqConfig) => {
|
|
6
|
+
return async (payload, session, actionProcessors, logger, updateSession, dynamicModuleLoader, streamRegistry) => {
|
|
7
|
+
const smConfig = getStateMachineByName(qpqConfig, payload.stateMachineName);
|
|
8
|
+
if (!smConfig) {
|
|
9
|
+
return actionResultError(ErrorTypeEnum.NotFound, `State machine not found: ${payload.stateMachineName}`);
|
|
10
|
+
}
|
|
11
|
+
const resolveStory = createImplementationRuntime(qpqConfig, ['StateMachine Create'], () => new Date().toISOString(), () => `${Date.now()}-${Math.random().toString(36).slice(2)}`, session, actionProcessors, logger, dynamicModuleLoader, streamRegistry);
|
|
12
|
+
// XState: determine initial state and which entry actions fire
|
|
13
|
+
const firedActions = [];
|
|
14
|
+
const actionImpls = {};
|
|
15
|
+
for (const actionName of Object.keys(smConfig.actions)) {
|
|
16
|
+
actionImpls[actionName] = () => {
|
|
17
|
+
firedActions.push(actionName);
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const machine = createMachine(smConfig.config, {
|
|
21
|
+
actions: actionImpls,
|
|
22
|
+
});
|
|
23
|
+
const actor = createActor(machine);
|
|
24
|
+
actor.start();
|
|
25
|
+
const initialSnapshot = actor.getPersistedSnapshot();
|
|
26
|
+
actor.stop();
|
|
27
|
+
// Build entity with id and machine state
|
|
28
|
+
const entity = { ...payload.item, id: payload.id };
|
|
29
|
+
entity[smConfig.stateField] = initialSnapshot;
|
|
30
|
+
// Persist to KVS
|
|
31
|
+
const upsertResult = await resolveStory(function* () { yield* askKeyValueStoreUpsert(smConfig.keyValueStoreName, entity); }, []);
|
|
32
|
+
if (upsertResult.error) {
|
|
33
|
+
return actionResultError(upsertResult.error.errorType, upsertResult.error.errorText);
|
|
34
|
+
}
|
|
35
|
+
// Execute side-effect stories for any initial entry actions
|
|
36
|
+
for (const actionName of firedActions) {
|
|
37
|
+
const runtime = smConfig.actions[actionName];
|
|
38
|
+
if (runtime) {
|
|
39
|
+
const storyModule = await dynamicModuleLoader(runtime);
|
|
40
|
+
const storyResult = await resolveStory(storyModule, [entity]);
|
|
41
|
+
if (storyResult.error) {
|
|
42
|
+
return actionResultError(storyResult.error.errorType, storyResult.error.errorText);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return actionResult(entity);
|
|
47
|
+
};
|
|
48
|
+
};
|
|
49
|
+
export const getStateMachineCreateActionProcessor = async (qpqConfig) => ({
|
|
50
|
+
[StateMachineActionType.Create]: getProcessStateMachineCreate(qpqConfig),
|
|
51
|
+
});
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { actionResult, actionResultError, askKeyValueStoreGet, createImplementationRuntime, ErrorTypeEnum, } from 'quidproquo-core';
|
|
2
|
+
import { StateMachineActionType } from '../actions';
|
|
3
|
+
import { getStateMachineByName } from '../config';
|
|
4
|
+
const getProcessStateMachineGet = (qpqConfig) => {
|
|
5
|
+
return async (payload, session, actionProcessors, logger, updateSession, dynamicModuleLoader, streamRegistry) => {
|
|
6
|
+
const smConfig = getStateMachineByName(qpqConfig, payload.stateMachineName);
|
|
7
|
+
if (!smConfig) {
|
|
8
|
+
return actionResultError(ErrorTypeEnum.NotFound, `State machine not found: ${payload.stateMachineName}`);
|
|
9
|
+
}
|
|
10
|
+
const resolveStory = createImplementationRuntime(qpqConfig, ['StateMachine Get'], () => new Date().toISOString(), () => `${Date.now()}-${Math.random().toString(36).slice(2)}`, session, actionProcessors, logger, dynamicModuleLoader, streamRegistry);
|
|
11
|
+
const getResult = await resolveStory(function* () { return yield* askKeyValueStoreGet(smConfig.keyValueStoreName, payload.id); }, []);
|
|
12
|
+
if (getResult.error) {
|
|
13
|
+
return actionResultError(getResult.error.errorType, getResult.error.errorText);
|
|
14
|
+
}
|
|
15
|
+
const entity = getResult.result;
|
|
16
|
+
if (!entity) {
|
|
17
|
+
return actionResultError(ErrorTypeEnum.NotFound, `Entity not found: ${payload.id}`);
|
|
18
|
+
}
|
|
19
|
+
return actionResult(entity);
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export const getStateMachineGetActionProcessor = async (qpqConfig) => ({
|
|
23
|
+
[StateMachineActionType.Get]: getProcessStateMachineGet(qpqConfig),
|
|
24
|
+
});
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { actionResult, actionResultError, askKeyValueStoreGet, createImplementationRuntime, ErrorTypeEnum, } from 'quidproquo-core';
|
|
2
|
+
import { createActor, createMachine } from 'xstate';
|
|
3
|
+
import { StateMachineActionType } from '../actions';
|
|
4
|
+
import { getStateMachineByName } from '../config';
|
|
5
|
+
const getProcessStateMachineGetState = (qpqConfig) => {
|
|
6
|
+
return async (payload, session, actionProcessors, logger, updateSession, dynamicModuleLoader, streamRegistry) => {
|
|
7
|
+
const smConfig = getStateMachineByName(qpqConfig, payload.stateMachineName);
|
|
8
|
+
if (!smConfig) {
|
|
9
|
+
return actionResultError(ErrorTypeEnum.NotFound, `State machine not found: ${payload.stateMachineName}`);
|
|
10
|
+
}
|
|
11
|
+
const resolveStory = createImplementationRuntime(qpqConfig, ['StateMachine GetState'], () => new Date().toISOString(), () => `${Date.now()}-${Math.random().toString(36).slice(2)}`, session, actionProcessors, logger, dynamicModuleLoader, streamRegistry);
|
|
12
|
+
// Load entity from KVS
|
|
13
|
+
const getResult = await resolveStory(function* () { return yield* askKeyValueStoreGet(smConfig.keyValueStoreName, payload.id); }, []);
|
|
14
|
+
if (getResult.error) {
|
|
15
|
+
return actionResultError(getResult.error.errorType, getResult.error.errorText);
|
|
16
|
+
}
|
|
17
|
+
const entity = getResult.result;
|
|
18
|
+
if (!entity) {
|
|
19
|
+
return actionResultError(ErrorTypeEnum.NotFound, `Entity not found: ${payload.id}`);
|
|
20
|
+
}
|
|
21
|
+
const persistedSnapshot = entity[smConfig.stateField];
|
|
22
|
+
if (!persistedSnapshot) {
|
|
23
|
+
return actionResultError(ErrorTypeEnum.NotFound, `No state machine state found on entity: ${payload.id}`);
|
|
24
|
+
}
|
|
25
|
+
// XState: rehydrate to read current state
|
|
26
|
+
const machine = createMachine(smConfig.config);
|
|
27
|
+
const actor = createActor(machine, { snapshot: persistedSnapshot });
|
|
28
|
+
actor.start();
|
|
29
|
+
const snapshot = actor.getSnapshot();
|
|
30
|
+
actor.stop();
|
|
31
|
+
return actionResult({
|
|
32
|
+
value: typeof snapshot.value === 'string' ? snapshot.value : JSON.stringify(snapshot.value),
|
|
33
|
+
done: snapshot.status === 'done',
|
|
34
|
+
});
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
export const getStateMachineGetStateActionProcessor = async (qpqConfig) => ({
|
|
38
|
+
[StateMachineActionType.GetState]: getProcessStateMachineGetState(qpqConfig),
|
|
39
|
+
});
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { actionResult, actionResultError, askKeyValueStoreGet, askKeyValueStoreUpsert, createImplementationRuntime, ErrorTypeEnum, } from 'quidproquo-core';
|
|
2
|
+
import { createActor, createMachine } from 'xstate';
|
|
3
|
+
import { StateMachineActionType } from '../actions';
|
|
4
|
+
import { getStateMachineByName } from '../config';
|
|
5
|
+
const getProcessStateMachineSendEvent = (qpqConfig) => {
|
|
6
|
+
return async (payload, session, actionProcessors, logger, updateSession, dynamicModuleLoader, streamRegistry) => {
|
|
7
|
+
const smConfig = getStateMachineByName(qpqConfig, payload.stateMachineName);
|
|
8
|
+
if (!smConfig) {
|
|
9
|
+
return actionResultError(ErrorTypeEnum.NotFound, `State machine not found: ${payload.stateMachineName}`);
|
|
10
|
+
}
|
|
11
|
+
const resolveStory = createImplementationRuntime(qpqConfig, ['StateMachine SendEvent'], () => new Date().toISOString(), () => `${Date.now()}-${Math.random().toString(36).slice(2)}`, session, actionProcessors, logger, dynamicModuleLoader, streamRegistry);
|
|
12
|
+
// Load entity from KVS
|
|
13
|
+
let entity;
|
|
14
|
+
const getResult = await resolveStory(function* () { return yield* askKeyValueStoreGet(smConfig.keyValueStoreName, payload.id); }, []);
|
|
15
|
+
if (getResult.error) {
|
|
16
|
+
return actionResultError(getResult.error.errorType, getResult.error.errorText);
|
|
17
|
+
}
|
|
18
|
+
entity = getResult.result;
|
|
19
|
+
if (!entity) {
|
|
20
|
+
return actionResultError(ErrorTypeEnum.NotFound, `Entity not found: ${payload.id}`);
|
|
21
|
+
}
|
|
22
|
+
// Pre-evaluate guards via QPQ stories
|
|
23
|
+
const guardResults = {};
|
|
24
|
+
for (const [guardName, guardRuntime] of Object.entries(smConfig.guards)) {
|
|
25
|
+
const guardModule = await dynamicModuleLoader(guardRuntime);
|
|
26
|
+
const guardResult = await resolveStory(guardModule, [entity, payload.event]);
|
|
27
|
+
if (guardResult.error) {
|
|
28
|
+
return actionResultError(guardResult.error.errorType, guardResult.error.errorText);
|
|
29
|
+
}
|
|
30
|
+
guardResults[guardName] = guardResult.result;
|
|
31
|
+
}
|
|
32
|
+
const guardImpls = {};
|
|
33
|
+
for (const [guardName, result] of Object.entries(guardResults)) {
|
|
34
|
+
guardImpls[guardName] = () => result;
|
|
35
|
+
}
|
|
36
|
+
// Track which actions fire during the transition
|
|
37
|
+
const firedActions = [];
|
|
38
|
+
const actionImpls = {};
|
|
39
|
+
for (const actionName of Object.keys(smConfig.actions)) {
|
|
40
|
+
actionImpls[actionName] = () => {
|
|
41
|
+
firedActions.push(actionName);
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
// XState: build machine, rehydrate, send event
|
|
45
|
+
const machine = createMachine(smConfig.config, {
|
|
46
|
+
actions: actionImpls,
|
|
47
|
+
guards: guardImpls,
|
|
48
|
+
});
|
|
49
|
+
const persistedSnapshot = entity[smConfig.stateField];
|
|
50
|
+
const actor = createActor(machine, {
|
|
51
|
+
snapshot: persistedSnapshot || undefined,
|
|
52
|
+
});
|
|
53
|
+
const previousState = actor.getSnapshot().value;
|
|
54
|
+
actor.start();
|
|
55
|
+
actor.send(payload.event);
|
|
56
|
+
const newSnapshot = actor.getPersistedSnapshot();
|
|
57
|
+
const currentState = actor.getSnapshot().value;
|
|
58
|
+
const isDone = actor.getSnapshot().status === 'done';
|
|
59
|
+
actor.stop();
|
|
60
|
+
if (previousState === currentState && !isDone) {
|
|
61
|
+
return actionResultError(ErrorTypeEnum.BadRequest, `Event '${payload.event.type}' is not valid for current state '${JSON.stringify(previousState)}'`);
|
|
62
|
+
}
|
|
63
|
+
// Persist new snapshot
|
|
64
|
+
entity[smConfig.stateField] = newSnapshot;
|
|
65
|
+
const upsertResult = await resolveStory(function* () { yield* askKeyValueStoreUpsert(smConfig.keyValueStoreName, entity); }, []);
|
|
66
|
+
if (upsertResult.error) {
|
|
67
|
+
return actionResultError(upsertResult.error.errorType, upsertResult.error.errorText);
|
|
68
|
+
}
|
|
69
|
+
// Execute side-effect stories for fired actions
|
|
70
|
+
for (const actionName of firedActions) {
|
|
71
|
+
const runtime = smConfig.actions[actionName];
|
|
72
|
+
if (runtime) {
|
|
73
|
+
const storyModule = await dynamicModuleLoader(runtime);
|
|
74
|
+
const storyResult = await resolveStory(storyModule, [entity, payload.event]);
|
|
75
|
+
if (storyResult.error) {
|
|
76
|
+
return actionResultError(storyResult.error.errorType, storyResult.error.errorText);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return actionResult(entity);
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
export const getStateMachineSendEventActionProcessor = async (qpqConfig) => ({
|
|
84
|
+
[StateMachineActionType.SendEvent]: getProcessStateMachineSendEvent(qpqConfig),
|
|
85
|
+
});
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { getStateMachineCreateActionProcessor } from './getStateMachineCreateActionProcessor';
|
|
2
|
+
import { getStateMachineGetActionProcessor } from './getStateMachineGetActionProcessor';
|
|
3
|
+
import { getStateMachineGetStateActionProcessor } from './getStateMachineGetStateActionProcessor';
|
|
4
|
+
import { getStateMachineSendEventActionProcessor } from './getStateMachineSendEventActionProcessor';
|
|
5
|
+
export const getStateMachineActionProcessor = async (qpqConfig, dynamicModuleLoader) => ({
|
|
6
|
+
...(await getStateMachineCreateActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
7
|
+
...(await getStateMachineGetActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
8
|
+
...(await getStateMachineGetStateActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
9
|
+
...(await getStateMachineSendEventActionProcessor(qpqConfig, dynamicModuleLoader)),
|
|
10
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export var StateMachineActionType;
|
|
2
|
+
(function (StateMachineActionType) {
|
|
3
|
+
StateMachineActionType["Create"] = "@quidproquo-core/StateMachine/Create";
|
|
4
|
+
StateMachineActionType["Get"] = "@quidproquo-core/StateMachine/Get";
|
|
5
|
+
StateMachineActionType["GetState"] = "@quidproquo-core/StateMachine/GetState";
|
|
6
|
+
StateMachineActionType["SendEvent"] = "@quidproquo-core/StateMachine/SendEvent";
|
|
7
|
+
})(StateMachineActionType || (StateMachineActionType = {}));
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Action, ActionProcessor, ActionRequester } from 'quidproquo-core';
|
|
2
|
+
import { StateMachineActionType } from './StateMachineActionType';
|
|
3
|
+
export interface StateMachineCreateActionPayload<T> {
|
|
4
|
+
stateMachineName: string;
|
|
5
|
+
id: string;
|
|
6
|
+
item: T;
|
|
7
|
+
}
|
|
8
|
+
export interface StateMachineCreateAction<T> extends Action<StateMachineCreateActionPayload<T>> {
|
|
9
|
+
type: StateMachineActionType.Create;
|
|
10
|
+
payload: StateMachineCreateActionPayload<T>;
|
|
11
|
+
}
|
|
12
|
+
export type StateMachineCreateActionProcessor<T> = ActionProcessor<StateMachineCreateAction<T>, T>;
|
|
13
|
+
export type StateMachineCreateActionRequester<T> = ActionRequester<StateMachineCreateAction<T>, T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Action, ActionProcessor, ActionRequester } from 'quidproquo-core';
|
|
2
|
+
import { StateMachineActionType } from './StateMachineActionType';
|
|
3
|
+
export interface StateMachineGetActionPayload {
|
|
4
|
+
stateMachineName: string;
|
|
5
|
+
id: string;
|
|
6
|
+
}
|
|
7
|
+
export interface StateMachineGetAction<T> extends Action<StateMachineGetActionPayload> {
|
|
8
|
+
type: StateMachineActionType.Get;
|
|
9
|
+
payload: StateMachineGetActionPayload;
|
|
10
|
+
}
|
|
11
|
+
export type StateMachineGetActionProcessor<T> = ActionProcessor<StateMachineGetAction<T>, T>;
|
|
12
|
+
export type StateMachineGetActionRequester<T> = ActionRequester<StateMachineGetAction<T>, T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Action, ActionProcessor, ActionRequester } from 'quidproquo-core';
|
|
2
|
+
import { StateMachineActionType } from './StateMachineActionType';
|
|
3
|
+
export interface StateMachineGetStateActionPayload {
|
|
4
|
+
stateMachineName: string;
|
|
5
|
+
id: string;
|
|
6
|
+
}
|
|
7
|
+
export interface StateMachineStateInfo {
|
|
8
|
+
value: string;
|
|
9
|
+
done: boolean;
|
|
10
|
+
}
|
|
11
|
+
export interface StateMachineGetStateAction extends Action<StateMachineGetStateActionPayload> {
|
|
12
|
+
type: StateMachineActionType.GetState;
|
|
13
|
+
payload: StateMachineGetStateActionPayload;
|
|
14
|
+
}
|
|
15
|
+
export type StateMachineGetStateActionProcessor = ActionProcessor<StateMachineGetStateAction, StateMachineStateInfo>;
|
|
16
|
+
export type StateMachineGetStateActionRequester = ActionRequester<StateMachineGetStateAction, StateMachineStateInfo>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { StateMachineActionType } from './StateMachineActionType';
|
|
2
|
+
export function* askStateMachineSendEvent(stateMachineName, id, event) {
|
|
3
|
+
return yield {
|
|
4
|
+
type: StateMachineActionType.SendEvent,
|
|
5
|
+
payload: {
|
|
6
|
+
stateMachineName,
|
|
7
|
+
id,
|
|
8
|
+
event,
|
|
9
|
+
},
|
|
10
|
+
};
|
|
11
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Action, ActionProcessor, ActionRequester } from 'quidproquo-core';
|
|
2
|
+
import { StateMachineActionType } from './StateMachineActionType';
|
|
3
|
+
export interface StateMachineEvent {
|
|
4
|
+
type: string;
|
|
5
|
+
[key: string]: any;
|
|
6
|
+
}
|
|
7
|
+
export interface StateMachineSendEventActionPayload {
|
|
8
|
+
stateMachineName: string;
|
|
9
|
+
id: string;
|
|
10
|
+
event: StateMachineEvent;
|
|
11
|
+
}
|
|
12
|
+
export interface StateMachineSendEventAction<T> extends Action<StateMachineSendEventActionPayload> {
|
|
13
|
+
type: StateMachineActionType.SendEvent;
|
|
14
|
+
payload: StateMachineSendEventActionPayload;
|
|
15
|
+
}
|
|
16
|
+
export type StateMachineSendEventActionProcessor<T> = ActionProcessor<StateMachineSendEventAction<T>, T>;
|
|
17
|
+
export type StateMachineSendEventActionRequester<T> = ActionRequester<StateMachineSendEventAction<T>, T>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './StateMachineActionType';
|
|
2
|
+
export * from './StateMachineCreateActionRequester';
|
|
3
|
+
export * from './StateMachineCreateActionTypes';
|
|
4
|
+
export * from './StateMachineGetActionRequester';
|
|
5
|
+
export * from './StateMachineGetActionTypes';
|
|
6
|
+
export * from './StateMachineGetStateActionRequester';
|
|
7
|
+
export * from './StateMachineGetStateActionTypes';
|
|
8
|
+
export * from './StateMachineSendEventActionRequester';
|
|
9
|
+
export * from './StateMachineSendEventActionTypes';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export * from './StateMachineActionType';
|
|
2
|
+
export * from './StateMachineCreateActionRequester';
|
|
3
|
+
export * from './StateMachineCreateActionTypes';
|
|
4
|
+
export * from './StateMachineGetActionRequester';
|
|
5
|
+
export * from './StateMachineGetActionTypes';
|
|
6
|
+
export * from './StateMachineGetStateActionRequester';
|
|
7
|
+
export * from './StateMachineGetStateActionTypes';
|
|
8
|
+
export * from './StateMachineSendEventActionRequester';
|
|
9
|
+
export * from './StateMachineSendEventActionTypes';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { QPQConfig } from 'quidproquo-core';
|
|
2
|
+
import { StateMachineQPQConfigSetting } from './settings/stateMachine';
|
|
3
|
+
export declare const getAllStateMachines: (qpqConfig: QPQConfig) => StateMachineQPQConfigSetting[];
|
|
4
|
+
export declare const getStateMachineByName: (qpqConfig: QPQConfig, stateMachineName: string) => StateMachineQPQConfigSetting | undefined;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { qpqCoreUtils } from 'quidproquo-core';
|
|
2
|
+
import { QPQXStateConfigSettingType } from './QPQConfig';
|
|
3
|
+
export const getAllStateMachines = (qpqConfig) => {
|
|
4
|
+
return qpqCoreUtils.getConfigSettings(qpqConfig, QPQXStateConfigSettingType.StateMachine);
|
|
5
|
+
};
|
|
6
|
+
export const getStateMachineByName = (qpqConfig, stateMachineName) => {
|
|
7
|
+
return getAllStateMachines(qpqConfig).find((sm) => sm.stateMachineName === stateMachineName);
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './stateMachine';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './stateMachine';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CrossModuleOwner, QPQConfigAdvancedSettings, QPQConfigSetting, QpqFunctionRuntime } from 'quidproquo-core';
|
|
2
|
+
import { EventObject, MachineConfig, MachineContext } from 'xstate';
|
|
3
|
+
export interface StateMachineRuntimeMap {
|
|
4
|
+
[name: string]: QpqFunctionRuntime;
|
|
5
|
+
}
|
|
6
|
+
export interface QPQConfigAdvancedStateMachineSettings extends QPQConfigAdvancedSettings {
|
|
7
|
+
config: MachineConfig<MachineContext, EventObject>;
|
|
8
|
+
actions?: StateMachineRuntimeMap;
|
|
9
|
+
guards?: StateMachineRuntimeMap;
|
|
10
|
+
stateField?: string;
|
|
11
|
+
owner?: CrossModuleOwner;
|
|
12
|
+
}
|
|
13
|
+
export interface StateMachineQPQConfigSetting extends QPQConfigSetting {
|
|
14
|
+
stateMachineName: string;
|
|
15
|
+
keyValueStoreName: string;
|
|
16
|
+
config: MachineConfig<MachineContext, EventObject>;
|
|
17
|
+
actions: StateMachineRuntimeMap;
|
|
18
|
+
guards: StateMachineRuntimeMap;
|
|
19
|
+
stateField: string;
|
|
20
|
+
}
|
|
21
|
+
export declare const getStateMachineStoreName: (stateMachineName: string) => string;
|
|
22
|
+
export declare const defineStateMachine: (stateMachineName: string, options: QPQConfigAdvancedStateMachineSettings) => QPQConfigSetting[];
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineKeyValueStore, } from 'quidproquo-core';
|
|
2
|
+
import { QPQXStateConfigSettingType } from '../QPQConfig';
|
|
3
|
+
export const getStateMachineStoreName = (stateMachineName) => `qpq-sm-${stateMachineName}`;
|
|
4
|
+
export const defineStateMachine = (stateMachineName, options) => {
|
|
5
|
+
const keyValueStoreName = getStateMachineStoreName(stateMachineName);
|
|
6
|
+
const stateMachineConfig = {
|
|
7
|
+
configSettingType: QPQXStateConfigSettingType.StateMachine,
|
|
8
|
+
uniqueKey: stateMachineName,
|
|
9
|
+
stateMachineName,
|
|
10
|
+
keyValueStoreName,
|
|
11
|
+
config: options.config,
|
|
12
|
+
actions: options.actions ?? {},
|
|
13
|
+
guards: options.guards ?? {},
|
|
14
|
+
stateField: options.stateField ?? '__machineState',
|
|
15
|
+
owner: options.owner,
|
|
16
|
+
};
|
|
17
|
+
return [
|
|
18
|
+
defineKeyValueStore(keyValueStoreName, 'id'),
|
|
19
|
+
stateMachineConfig
|
|
20
|
+
];
|
|
21
|
+
};
|
package/lib/esm/index.js
ADDED