create-moost 0.4.23 → 0.5.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/dist/index.cjs +30 -52
- package/dist/index.mjs +30 -52
- package/package.json +4 -4
- package/templates/common/.domelintrc.yml +14 -0
- package/templates/common/package.jsonc +38 -0
- package/templates/common/tsconfig.json +19 -13
- package/templates/common/vite.config.ts +13 -0
- package/templates/http/src/controllers/app.controller.ts +98 -5
- package/templates/http/src/main.ts +46 -13
- package/templates/wf/src/static/wf.css +135 -0
- package/templates/wf/src/workflow/wf.controller.ts +230 -0
- package/templates/wf/src/workflow/wf.encrypt.ts +122 -0
- package/templates/wf/src/workflow/wf.types.ts +176 -0
- package/templates/wf/src/workflow/wf2html.interceptor.ts +233 -0
- package/templates/common/.eslintrc.json +0 -52
- package/templates/common/.prettierignore +0 -4
- package/templates/common/.prettierrc +0 -8
- package/templates/common/build.js +0 -28
- package/templates/common/package.json +0 -78
- package/templates/common/rollup.config.js +0 -23
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
body {
|
|
2
|
+
margin: 0;
|
|
3
|
+
min-height: 100vh;
|
|
4
|
+
font-family: sans-serif;
|
|
5
|
+
display: flex;
|
|
6
|
+
flex-direction: column;
|
|
7
|
+
justify-content: center;
|
|
8
|
+
align-items: center;
|
|
9
|
+
gap: 1em;
|
|
10
|
+
position: relative;
|
|
11
|
+
overflow: hidden;
|
|
12
|
+
/* Main gradient background */
|
|
13
|
+
background: linear-gradient(135deg, #151e38 0%, #233e88 100%);
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/* Top-left shape overlay */
|
|
17
|
+
body::before {
|
|
18
|
+
content: "";
|
|
19
|
+
position: absolute;
|
|
20
|
+
top: -10%;
|
|
21
|
+
left: -15%;
|
|
22
|
+
width: 40vw;
|
|
23
|
+
height: 40vw;
|
|
24
|
+
background: radial-gradient(circle, #213b82 20%, transparent 70%);
|
|
25
|
+
filter: blur(60px); /* Add some blur for a more ethereal effect */
|
|
26
|
+
opacity: 0.8;
|
|
27
|
+
transform: rotate(20deg);
|
|
28
|
+
z-index: -1;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
/* Container (section) with glass-like effect */
|
|
33
|
+
section {
|
|
34
|
+
display: flex;
|
|
35
|
+
flex-direction: column;
|
|
36
|
+
gap: 1em;
|
|
37
|
+
max-width: 400px;
|
|
38
|
+
width: 100%;
|
|
39
|
+
padding: 1.6em;
|
|
40
|
+
border-radius: 1.6em;
|
|
41
|
+
position: relative;
|
|
42
|
+
color: #fff;
|
|
43
|
+
background: rgba(40, 69, 150, .8);
|
|
44
|
+
backdrop-filter: blur(8px);
|
|
45
|
+
box-shadow: 0 0 20px rgba(0, 0, 0, 0.2);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
h1 {
|
|
49
|
+
margin: 12px 0;
|
|
50
|
+
display: flex;
|
|
51
|
+
gap: .5em;
|
|
52
|
+
font-size: 28px;
|
|
53
|
+
justify-content: start;
|
|
54
|
+
align-items: center;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
h1 svg {
|
|
58
|
+
width: 48px;
|
|
59
|
+
height: 48px;;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
form {
|
|
63
|
+
display: flex;
|
|
64
|
+
flex-direction: column;
|
|
65
|
+
gap: 1em;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
label {
|
|
69
|
+
display: flex;
|
|
70
|
+
flex-direction: column;
|
|
71
|
+
gap: 0.5em;
|
|
72
|
+
font-weight: 600;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* Inputs with a subtle focus effect */
|
|
76
|
+
input {
|
|
77
|
+
padding: 0.7em;
|
|
78
|
+
border: 1px solid #ccc;
|
|
79
|
+
border-radius: 0.25em;
|
|
80
|
+
transition: border-color 0.2s ease;
|
|
81
|
+
background-color: #ffffffa0;
|
|
82
|
+
}
|
|
83
|
+
input:focus {
|
|
84
|
+
outline: none;
|
|
85
|
+
border-color: #4758ed;
|
|
86
|
+
outline: 2px solid #4758ed;
|
|
87
|
+
background-color: #ffffff;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* Modern button styling */
|
|
91
|
+
button {
|
|
92
|
+
margin-top: .7em;
|
|
93
|
+
padding: 1em;
|
|
94
|
+
border: none;
|
|
95
|
+
border-radius: 0.25em;
|
|
96
|
+
cursor: pointer;
|
|
97
|
+
background-color: #4758ed;
|
|
98
|
+
color: #fff;
|
|
99
|
+
font-weight: 600;
|
|
100
|
+
transition: background-color 0.2s ease, transform 0.2s ease;
|
|
101
|
+
}
|
|
102
|
+
button:hover {
|
|
103
|
+
background-color: #5f6bf2;
|
|
104
|
+
transform: translateY(-1px);
|
|
105
|
+
}
|
|
106
|
+
button:active {
|
|
107
|
+
transform: translateY(0);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
p {
|
|
111
|
+
margin: 0;
|
|
112
|
+
padding: 0;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
a {
|
|
116
|
+
margin: 1em 0 0 0;
|
|
117
|
+
opacity: 0.75;
|
|
118
|
+
color: white;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
a:hover {
|
|
122
|
+
opacity: 1;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
a:visited {
|
|
126
|
+
color: white;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
p.error {
|
|
130
|
+
background-color: #ff000020;
|
|
131
|
+
border: 1px solid #aa000070;
|
|
132
|
+
padding: 1em;
|
|
133
|
+
border-radius: 1em;
|
|
134
|
+
color: #ff4444;
|
|
135
|
+
}
|
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Workflow Controller for Moost Workflow Template
|
|
3
|
+
*
|
|
4
|
+
* This file defines the `WfController` class, which orchestrates the workflow
|
|
5
|
+
* steps using the Moost Workflow (MoostWf) framework. The controller manages
|
|
6
|
+
* the workflow's context, handles user inputs, sends and verifies one-time codes (OTC),
|
|
7
|
+
* updates the database, and produces the final output.
|
|
8
|
+
*
|
|
9
|
+
* **Important:** This example is a simplified demonstration. A production implementation
|
|
10
|
+
* would involve more complex logic, robust error handling, secure key management,
|
|
11
|
+
* and integration with persistent storage systems.
|
|
12
|
+
*
|
|
13
|
+
* For more information on Moost Workflows, visit: https://moost.org/wf/
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import {
|
|
17
|
+
Step,
|
|
18
|
+
Workflow,
|
|
19
|
+
WorkflowParam,
|
|
20
|
+
WorkflowSchema,
|
|
21
|
+
} from "@moostjs/event-wf";
|
|
22
|
+
import { Controller, EventLogger, Injectable, InjectEventLogger } from "moost";
|
|
23
|
+
|
|
24
|
+
import type {
|
|
25
|
+
TWfExampleContext,
|
|
26
|
+
TWfExampleInput,
|
|
27
|
+
TWfExampleInputSchema,
|
|
28
|
+
} from "./wf.types";
|
|
29
|
+
import { wfInputsSchema } from "./wf.types";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* `WfController` manages the workflow steps for the example workflow "wf-example".
|
|
33
|
+
*
|
|
34
|
+
* It handles user inputs, conditional steps based on context, sending and checking
|
|
35
|
+
* one-time codes, updating the database, and generating the final output greeting.
|
|
36
|
+
*/
|
|
37
|
+
@Injectable("FOR_EVENT")
|
|
38
|
+
@Controller()
|
|
39
|
+
export class WfController {
|
|
40
|
+
/**
|
|
41
|
+
* The workflow context that holds all necessary data throughout the workflow lifecycle.
|
|
42
|
+
*
|
|
43
|
+
* @type {TWfExampleContext}
|
|
44
|
+
*/
|
|
45
|
+
@WorkflowParam("context")
|
|
46
|
+
ctx!: TWfExampleContext;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Defines the entry point for the workflow "wf-example" and its schema.
|
|
50
|
+
*
|
|
51
|
+
* The workflow schema outlines the sequence of steps and any conditional logic
|
|
52
|
+
* based on the workflow context.
|
|
53
|
+
*
|
|
54
|
+
* **Workflow Steps:**
|
|
55
|
+
* 1. `inputs` - Collect user inputs.
|
|
56
|
+
* 2. `get_supervisor_email` - Conditionally collect supervisor email if age < 18.
|
|
57
|
+
* 3. `send_otc` - Send a one-time code to the user's email.
|
|
58
|
+
* 4. `check_otc` - Verify the received one-time code.
|
|
59
|
+
* 5. `update_db` - Update the database with the user's information.
|
|
60
|
+
* 6. `output` - Generate a greeting message.
|
|
61
|
+
*
|
|
62
|
+
* **Note:** This workflow schema is a simplified demonstration. A production workflow
|
|
63
|
+
* would require more comprehensive validation, error handling, and possibly additional steps.
|
|
64
|
+
*/
|
|
65
|
+
@Workflow("wf-example")
|
|
66
|
+
@WorkflowSchema<TWfExampleContext>([
|
|
67
|
+
"inputs",
|
|
68
|
+
{ id: "get_supervisor_email", condition: (ctx) => (ctx.age ?? 0) < 18 },
|
|
69
|
+
"send_otc",
|
|
70
|
+
"check_otc",
|
|
71
|
+
"update_db",
|
|
72
|
+
"output",
|
|
73
|
+
])
|
|
74
|
+
entry() {
|
|
75
|
+
// Entry point for the workflow. The actual implementation is managed by MoostWf.
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Handles the "inputs" step of the workflow.
|
|
80
|
+
*
|
|
81
|
+
* This step collects user inputs such as name, email, password, and age. It validates
|
|
82
|
+
* that all required fields are provided. If any fields are missing, it prompts the user
|
|
83
|
+
* to provide the necessary inputs.
|
|
84
|
+
*
|
|
85
|
+
* @param {TWfExampleInput} [input] - The input data provided by the user.
|
|
86
|
+
* @returns {TWfExampleInputSchema | void} - Returns input schema requirements if validation fails.
|
|
87
|
+
*/
|
|
88
|
+
@Step("inputs")
|
|
89
|
+
inputs(@WorkflowParam("input") input?: TWfExampleInput) {
|
|
90
|
+
// Validate required inputs: name, email, password, age
|
|
91
|
+
if (!input?.name || !input.email || !input.password || !input.age) {
|
|
92
|
+
console.log({ input });
|
|
93
|
+
return this.getInputsRequired({
|
|
94
|
+
fields: ["name", "email", "password", "age"],
|
|
95
|
+
values: input,
|
|
96
|
+
errorMessage: input ? "Please fill in all the fields" : "",
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Populate the workflow context with validated inputs
|
|
101
|
+
this.ctx.name = input.name as string;
|
|
102
|
+
this.ctx.email = input.email as string;
|
|
103
|
+
this.ctx.password = input.password as string;
|
|
104
|
+
this.ctx.age = input.age as number;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Handles the "get_supervisor_email" step of the workflow.
|
|
109
|
+
*
|
|
110
|
+
* This step is conditionally executed if the user's age is below 18. It collects
|
|
111
|
+
* the supervisor's email address to ensure that an underage user has appropriate oversight.
|
|
112
|
+
*
|
|
113
|
+
* @param {TWfExampleInput} [input] - The input data provided by the user.
|
|
114
|
+
* @returns {TWfExampleInputSchema | void} - Returns input schema requirements if validation fails.
|
|
115
|
+
*/
|
|
116
|
+
@Step("get_supervisor_email")
|
|
117
|
+
supervisorEmail(@WorkflowParam("input") input?: TWfExampleInput) {
|
|
118
|
+
// Validate supervisorEmail input for underage users
|
|
119
|
+
if (!input?.supervisorEmail) {
|
|
120
|
+
return this.getInputsRequired({
|
|
121
|
+
message: "Underage person must input supervisor email",
|
|
122
|
+
fields: ["supervisorEmail"],
|
|
123
|
+
values: input,
|
|
124
|
+
});
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Handles the "send_otc" step of the workflow.
|
|
130
|
+
*
|
|
131
|
+
* This step generates a one-time code (OTC) and logs its dispatch. In a real-world
|
|
132
|
+
* scenario, the OTC would be sent to the user's email address.
|
|
133
|
+
*
|
|
134
|
+
* @param {EventLogger} logger - The event logger instance for logging purposes.
|
|
135
|
+
*/
|
|
136
|
+
@Step("send_otc")
|
|
137
|
+
sendOtc(@InjectEventLogger() logger: EventLogger) {
|
|
138
|
+
// Generate a simple 4-digit one-time code (OTC)
|
|
139
|
+
this.ctx.otcSent = `0000${String(Math.random() * 9999)}`.slice(-4);
|
|
140
|
+
logger.log(`OTC sent: ${this.ctx.otcSent}`);
|
|
141
|
+
// **Note:** In production, send the OTC via a secure channel (e.g., email or SMS)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Handles the "check_otc" step of the workflow.
|
|
146
|
+
*
|
|
147
|
+
* This step verifies that the OTC received from the user matches the one sent.
|
|
148
|
+
* If the OTC is invalid or missing, it prompts the user to re-enter it.
|
|
149
|
+
*
|
|
150
|
+
* @param {TWfExampleInput} [input] - The input data provided by the user.
|
|
151
|
+
* @returns {TWfExampleInputSchema | void} - Returns input schema requirements if validation fails.
|
|
152
|
+
*/
|
|
153
|
+
@Step("check_otc")
|
|
154
|
+
check(@WorkflowParam("input") input?: TWfExampleInput) {
|
|
155
|
+
// Validate the received OTC against the sent OTC
|
|
156
|
+
if (!input?.otcReceived || input.otcReceived !== this.ctx.otcSent) {
|
|
157
|
+
return this.getInputsRequired({
|
|
158
|
+
message: "One Time Code has been sent (check logs)",
|
|
159
|
+
fields: ["otcReceived"],
|
|
160
|
+
values: input,
|
|
161
|
+
errorMessage: input?.otcReceived ? "OTC is invalid" : "",
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
this.ctx.otcReceived = input.otcReceived;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Handles the "update_db" step of the workflow.
|
|
169
|
+
*
|
|
170
|
+
* This step is responsible for updating the database with the user's information.
|
|
171
|
+
* In this demonstration, the implementation is left as a placeholder.
|
|
172
|
+
*
|
|
173
|
+
* **Note:** In a production environment, implement secure and reliable database operations here.
|
|
174
|
+
*/
|
|
175
|
+
@Step("update_db")
|
|
176
|
+
updateDb() {
|
|
177
|
+
// Placeholder for database update logic
|
|
178
|
+
// **Example:** Save user information to the database
|
|
179
|
+
// this.database.saveUser(this.ctx);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Handles the "output" step of the workflow.
|
|
184
|
+
*
|
|
185
|
+
* This final step generates a greeting message for the user based on the collected data.
|
|
186
|
+
*/
|
|
187
|
+
@Step("output")
|
|
188
|
+
outputs() {
|
|
189
|
+
this.ctx.greeting = `Welcome ${this.ctx.name}!`;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Generates the required input schema based on the specified options.
|
|
194
|
+
*
|
|
195
|
+
* This helper method constructs the input schema required to prompt the user for
|
|
196
|
+
* necessary inputs. It filters the predefined `wfInputsSchema` based on the
|
|
197
|
+
* specified fields and populates them with existing values from the workflow context.
|
|
198
|
+
*
|
|
199
|
+
* @param {Object} options - Configuration options for generating input schema.
|
|
200
|
+
* @param {string} [options.message] - An optional message to display on the input form.
|
|
201
|
+
* @param {Array<keyof TWfExampleContext>} options.fields - The fields to include in the input form.
|
|
202
|
+
* @param {TWfExampleInput} [options.values] - The current input values to pre-populate the form.
|
|
203
|
+
* @param {string} [options.errorMessage] - An optional error message to display if validation fails.
|
|
204
|
+
* @returns {Object} An object containing the `inputRequired` schema.
|
|
205
|
+
*/
|
|
206
|
+
getInputsRequired(options: {
|
|
207
|
+
message?: string;
|
|
208
|
+
fields: Array<keyof TWfExampleContext>;
|
|
209
|
+
values?: TWfExampleInput;
|
|
210
|
+
errorMessage?: string;
|
|
211
|
+
}): { inputRequired: TWfExampleInputSchema } {
|
|
212
|
+
const inputs = [] as TWfExampleInputSchema["inputs"];
|
|
213
|
+
for (const field of options.fields) {
|
|
214
|
+
const schema = wfInputsSchema.find((f) => f.name === field);
|
|
215
|
+
if (schema) {
|
|
216
|
+
inputs.push({
|
|
217
|
+
...schema,
|
|
218
|
+
value: (options.values?.[field] || this.ctx[field]) as string,
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
return {
|
|
223
|
+
inputRequired: {
|
|
224
|
+
inputs,
|
|
225
|
+
message: options.message,
|
|
226
|
+
errorMessage: options.errorMessage,
|
|
227
|
+
},
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
}
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Workflow State Encryption Module
|
|
3
|
+
*
|
|
4
|
+
* This module is responsible for encrypting and decrypting the workflow state,
|
|
5
|
+
* allowing secure sharing of state data between the backend and frontend.
|
|
6
|
+
*
|
|
7
|
+
* **Important:** This example is highly simplified and is intended solely for
|
|
8
|
+
* demonstration purposes. For production use, ensure that encryption keys are
|
|
9
|
+
* managed securely and consider using more robust encryption strategies.
|
|
10
|
+
*
|
|
11
|
+
* The module utilizes AES-256-GCM for encryption, providing confidentiality
|
|
12
|
+
* and integrity of the workflow state. The encrypted state is converted to a
|
|
13
|
+
* Base64 string for easy transmission and storage.
|
|
14
|
+
*
|
|
15
|
+
* For more information on Moost Workflows, visit: https://moost.org/wf/
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import crypto from "crypto";
|
|
19
|
+
|
|
20
|
+
import type { TWfState } from "./wf.types";
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Encryption configuration constants.
|
|
24
|
+
*
|
|
25
|
+
* - `KEY`: A randomly generated 32-byte key used for AES-256 encryption.
|
|
26
|
+
* - `ALGORITHM`: The encryption algorithm to use (AES-256-GCM).
|
|
27
|
+
* - `IV_LENGTH`: The length of the Initialization Vector (IV) in bytes.
|
|
28
|
+
* AES-GCM recommends a 12-byte IV for optimal security.
|
|
29
|
+
*/
|
|
30
|
+
const KEY = crypto.randomBytes(32);
|
|
31
|
+
const ALGORITHM = "aes-256-gcm";
|
|
32
|
+
const IV_LENGTH = 12; // Recommended IV length for GCM
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Encrypts the given workflow state object.
|
|
36
|
+
*
|
|
37
|
+
* This function serializes the workflow state to a JSON string, encrypts it using
|
|
38
|
+
* AES-256-GCM, and returns the encrypted data as a Base64-encoded string. The IV
|
|
39
|
+
* and authentication tag are prepended to the encrypted data to ensure successful
|
|
40
|
+
* decryption.
|
|
41
|
+
*
|
|
42
|
+
* **Note:** This implementation is simplified for demonstration purposes. In a
|
|
43
|
+
* real-world scenario, manage encryption keys securely and consider key rotation.
|
|
44
|
+
*
|
|
45
|
+
* @param {TWfState} state - The workflow state object to encrypt.
|
|
46
|
+
* @returns {string} The encrypted state as a Base64-encoded string.
|
|
47
|
+
*/
|
|
48
|
+
export function encryptState(state: TWfState): string {
|
|
49
|
+
// Generate a random Initialization Vector (IV)
|
|
50
|
+
const iv = crypto.randomBytes(IV_LENGTH);
|
|
51
|
+
|
|
52
|
+
// Create a Cipher instance using the specified algorithm, key, and IV
|
|
53
|
+
const cipher = crypto.createCipheriv(ALGORITHM, KEY, iv);
|
|
54
|
+
|
|
55
|
+
// Convert the state object to a JSON string
|
|
56
|
+
const stateString = JSON.stringify(state);
|
|
57
|
+
|
|
58
|
+
// Encrypt the state string
|
|
59
|
+
let encrypted = cipher.update(stateString, "utf8", "hex");
|
|
60
|
+
encrypted += cipher.final("hex");
|
|
61
|
+
|
|
62
|
+
// Retrieve the authentication tag generated during encryption
|
|
63
|
+
const authTag = cipher.getAuthTag();
|
|
64
|
+
|
|
65
|
+
// Combine IV, Auth Tag, and Encrypted Data into a single Buffer
|
|
66
|
+
const encryptedBuffer = Buffer.concat([
|
|
67
|
+
iv,
|
|
68
|
+
authTag,
|
|
69
|
+
Buffer.from(encrypted, "hex"),
|
|
70
|
+
]);
|
|
71
|
+
|
|
72
|
+
// Convert the combined Buffer to a Base64 string for transmission/storage
|
|
73
|
+
return encryptedBuffer.toString("base64");
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Decrypts the given Base64-encoded encrypted state string.
|
|
78
|
+
*
|
|
79
|
+
* This function decodes the Base64 string, extracts the IV and authentication tag,
|
|
80
|
+
* and decrypts the encrypted data to retrieve the original workflow state object.
|
|
81
|
+
*
|
|
82
|
+
* **Note:** This implementation is simplified for demonstration purposes. Ensure
|
|
83
|
+
* that decryption keys are managed securely and handle potential decryption errors
|
|
84
|
+
* appropriately in production environments.
|
|
85
|
+
*
|
|
86
|
+
* @param {string} encryptedState - The encrypted workflow state as a Base64 string.
|
|
87
|
+
* @returns {TWfState} The decrypted workflow state object.
|
|
88
|
+
* @throws {Error} Throws an error if decryption fails (e.g., due to invalid data).
|
|
89
|
+
*/
|
|
90
|
+
export function decryptState(encryptedState: string): TWfState {
|
|
91
|
+
try {
|
|
92
|
+
// Decode the Base64-encoded string to a Buffer
|
|
93
|
+
const encryptedBuffer = Buffer.from(encryptedState, "base64");
|
|
94
|
+
|
|
95
|
+
// Extract the IV from the beginning of the Buffer
|
|
96
|
+
const iv = encryptedBuffer.subarray(0, IV_LENGTH);
|
|
97
|
+
|
|
98
|
+
// Extract the authentication tag following the IV
|
|
99
|
+
const authTag = encryptedBuffer.subarray(IV_LENGTH, IV_LENGTH + 16); // GCM auth tag is 16 bytes
|
|
100
|
+
|
|
101
|
+
// Extract the actual encrypted text following the IV and auth tag
|
|
102
|
+
const encryptedText = encryptedBuffer.subarray(IV_LENGTH + 16);
|
|
103
|
+
|
|
104
|
+
// Create a Decipher instance using the specified algorithm, key, and IV
|
|
105
|
+
const decipher = crypto.createDecipheriv(ALGORITHM, KEY, iv);
|
|
106
|
+
|
|
107
|
+
// Set the authentication tag for verification during decryption
|
|
108
|
+
decipher.setAuthTag(authTag);
|
|
109
|
+
|
|
110
|
+
// Decrypt the encrypted text
|
|
111
|
+
let decrypted = decipher.update(encryptedText, undefined, "utf8");
|
|
112
|
+
decrypted += decipher.final("utf8");
|
|
113
|
+
|
|
114
|
+
// Parse the decrypted JSON string back to the workflow state object
|
|
115
|
+
return JSON.parse(decrypted) as TWfState;
|
|
116
|
+
} catch (error) {
|
|
117
|
+
// Handle decryption errors (e.g., invalid data or tampering)
|
|
118
|
+
throw new Error(
|
|
119
|
+
`Failed to decrypt workflow state: ${(error as Error).message}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Workflow Types Definition for Moost Workflow Template
|
|
3
|
+
*
|
|
4
|
+
* This file defines the TypeScript interfaces and types used to manage the workflow
|
|
5
|
+
* context, inputs, and input schemas within the Moost Workflow (MoostWf) framework.
|
|
6
|
+
* Given that MoostWf is a highly generic workflow handler, it's essential to tailor
|
|
7
|
+
* the workflow context and input schemas according to the specific use cases and
|
|
8
|
+
* application patterns of your project.
|
|
9
|
+
*
|
|
10
|
+
* The defined types include:
|
|
11
|
+
* - `TWfExampleContext`: Represents the workflow's context, storing necessary data
|
|
12
|
+
* throughout the workflow's lifecycle.
|
|
13
|
+
* - `TWfExampleInput`: Defines the structure of inputs that the workflow accepts.
|
|
14
|
+
* - `TWfExampleInputSchemaItem` & `TWfExampleInputSchema`: Describe the schema for
|
|
15
|
+
* input forms, detailing each input field's properties such as label, name, type,
|
|
16
|
+
* and options.
|
|
17
|
+
* - `TWfState`: Represents the state of the workflow, derived from Moost's `TFlowOutput`.
|
|
18
|
+
*
|
|
19
|
+
* Additionally, the `wfInputsSchema` constant provides a predefined schema for workflow
|
|
20
|
+
* inputs, facilitating the generation of HTML forms for user interactions.
|
|
21
|
+
*
|
|
22
|
+
* For more information on Moost Workflows, visit: https://moost.org/wf/
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { TFlowOutput } from "@moostjs/event-wf";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Defines the structure of the workflow's context.
|
|
29
|
+
*
|
|
30
|
+
* The workflow context holds all the necessary data that persists throughout the
|
|
31
|
+
* execution of the workflow. This includes user information, authentication details,
|
|
32
|
+
* and any other relevant state required for the workflow's operations.
|
|
33
|
+
*/
|
|
34
|
+
export interface TWfExampleContext {
|
|
35
|
+
/** The name of the user. */
|
|
36
|
+
name?: string;
|
|
37
|
+
|
|
38
|
+
/** The email address of the user. */
|
|
39
|
+
email?: string;
|
|
40
|
+
|
|
41
|
+
/** The email address of the user's supervisor. */
|
|
42
|
+
supervisorEmail?: string;
|
|
43
|
+
|
|
44
|
+
/** Indicates whether a one-time code (OTC) has been sent. */
|
|
45
|
+
otcSent?: string;
|
|
46
|
+
|
|
47
|
+
/** The received one-time code (OTC) from the user. */
|
|
48
|
+
otcReceived?: string;
|
|
49
|
+
|
|
50
|
+
/** The user's password. */
|
|
51
|
+
password?: string;
|
|
52
|
+
|
|
53
|
+
/** The age of the user. */
|
|
54
|
+
age?: number;
|
|
55
|
+
|
|
56
|
+
/** A greeting message for the user. */
|
|
57
|
+
greeting?: string;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Defines the structure of the workflow's input.
|
|
62
|
+
*
|
|
63
|
+
* `TWfExampleInput` is a generic type that maps string keys to values of various
|
|
64
|
+
* types, including strings, numbers, undefined, or objects. This flexibility allows
|
|
65
|
+
* the workflow to handle diverse input data based on different use cases.
|
|
66
|
+
*/
|
|
67
|
+
export type TWfExampleInput = Record<
|
|
68
|
+
string,
|
|
69
|
+
string | number | undefined | object
|
|
70
|
+
>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Represents a single item within the workflow's input schema.
|
|
74
|
+
*
|
|
75
|
+
* Each `TWfExampleInputSchemaItem` defines the properties of an input field
|
|
76
|
+
* that will be rendered in the HTML form. This includes the label, name, type,
|
|
77
|
+
* and any additional options for select-type inputs.
|
|
78
|
+
*/
|
|
79
|
+
export interface TWfExampleInputSchemaItem {
|
|
80
|
+
/** The display label for the input field. */
|
|
81
|
+
label: string;
|
|
82
|
+
|
|
83
|
+
/** The unique name identifier for the input field. */
|
|
84
|
+
name: string;
|
|
85
|
+
|
|
86
|
+
/** The type of the input field (e.g., text, number, select, password). */
|
|
87
|
+
type: "text" | "number" | "select" | "password";
|
|
88
|
+
|
|
89
|
+
/** Optional array of options for select-type input fields. */
|
|
90
|
+
options?: Array<{
|
|
91
|
+
/** The display label for the option. */
|
|
92
|
+
label: string;
|
|
93
|
+
|
|
94
|
+
/** The value associated with the option. */
|
|
95
|
+
value: string;
|
|
96
|
+
}>;
|
|
97
|
+
|
|
98
|
+
/** The default value of the input field, if any. */
|
|
99
|
+
value?: string | number;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Defines the schema for the workflow's input form.
|
|
104
|
+
*
|
|
105
|
+
* `TWfExampleInputSchema` aggregates multiple `TWfExampleInputSchemaItem` objects
|
|
106
|
+
* to define the complete structure of the input form. It may also include optional
|
|
107
|
+
* messages or error messages to be displayed to the user.
|
|
108
|
+
*/
|
|
109
|
+
export interface TWfExampleInputSchema {
|
|
110
|
+
/** An array of input schema items defining each form field. */
|
|
111
|
+
inputs: TWfExampleInputSchemaItem[];
|
|
112
|
+
|
|
113
|
+
/** An optional message to be displayed on the form. */
|
|
114
|
+
message?: string;
|
|
115
|
+
|
|
116
|
+
/** An optional error message to be displayed if form validation fails. */
|
|
117
|
+
errorMessage?: string;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Represents the state of the workflow.
|
|
122
|
+
*
|
|
123
|
+
* `TWfState` is derived from Moost's `TFlowOutput` and encapsulates the current
|
|
124
|
+
* state of the workflow, including the context, inputs, and input schema.
|
|
125
|
+
*/
|
|
126
|
+
export type TWfState = TFlowOutput<
|
|
127
|
+
TWfExampleContext,
|
|
128
|
+
TWfExampleInput,
|
|
129
|
+
TWfExampleInputSchema
|
|
130
|
+
>["state"];
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Defines the input schema for the workflow's HTML form.
|
|
134
|
+
*
|
|
135
|
+
* `wfInputsSchema` is an array of `TWfExampleInputSchemaItem` objects that specify
|
|
136
|
+
* the fields to be rendered in the HTML form. This schema is used by the `Wf2HtmlPage`
|
|
137
|
+
* interceptor to generate dynamic forms based on the workflow's requirements.
|
|
138
|
+
*/
|
|
139
|
+
export const wfInputsSchema: TWfExampleInputSchemaItem[] = [
|
|
140
|
+
{
|
|
141
|
+
label: "Name",
|
|
142
|
+
name: "name",
|
|
143
|
+
type: "text",
|
|
144
|
+
value: undefined,
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
label: "Email",
|
|
148
|
+
name: "email",
|
|
149
|
+
type: "text",
|
|
150
|
+
value: undefined,
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
label: "Password",
|
|
154
|
+
name: "password",
|
|
155
|
+
type: "password",
|
|
156
|
+
value: undefined,
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
label: "Age",
|
|
160
|
+
name: "age",
|
|
161
|
+
type: "number",
|
|
162
|
+
value: undefined,
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
label: "One Time Code",
|
|
166
|
+
name: "otcReceived",
|
|
167
|
+
type: "text",
|
|
168
|
+
value: undefined,
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
label: "Supervisor Email",
|
|
172
|
+
name: "supervisorEmail",
|
|
173
|
+
type: "text",
|
|
174
|
+
value: undefined,
|
|
175
|
+
},
|
|
176
|
+
];
|