mstate-cli 0.0.2 → 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/dist/index.js CHANGED
@@ -1,21 +1,45 @@
1
1
  #!/usr/bin/env node
2
2
  "use strict";
3
3
  Object.defineProperty(exports, "__esModule", { value: true });
4
- const workflow_action_1 = require("./actions/workflow.action");
4
+ const action_handler_1 = require("./handlers/action.handler");
5
+ const workflow_handler_1 = require("./handlers/workflow.handler");
5
6
  const enum_1 = require("./common/enum");
6
- const [action, ...params] = process.argv.slice(2);
7
+ const mobioffice_handler_1 = require("./handlers/mobioffice.handler");
8
+ const utils_1 = require("./common/utils");
9
+ const environment_handler_1 = require("./handlers/environment.handler");
10
+ const [action] = process.argv.slice(2);
7
11
  switch (action) {
8
12
  case enum_1.CmdAction.LINK:
13
+ case enum_1.CmdAction.UNLINK:
14
+ mobioffice_handler_1.mobiofficeHandler.linkToMobioffice(action);
9
15
  break;
10
16
  case enum_1.CmdAction.CLONE:
11
- workflow_action_1.workflowAction.cloneWorkflow(params);
17
+ workflow_handler_1.workflowHandler.cloneWorkflow().then(() => {
18
+ action_handler_1.actionHandler.cloneActions();
19
+ environment_handler_1.environmentHandler.cloneEnvironments();
20
+ });
12
21
  break;
13
22
  case enum_1.CmdAction.ADD:
14
- workflow_action_1.workflowAction.saveToDB(params);
23
+ workflow_handler_1.workflowHandler.saveToDB();
15
24
  break;
16
- case enum_1.CmdAction.UPDATE:
17
- workflow_action_1.workflowAction.updateWorkflowToDB(params);
25
+ case enum_1.CmdAction.PUSH:
26
+ workflow_handler_1.workflowHandler.updateWorkflowToDB().then(() => {
27
+ action_handler_1.actionHandler.saveToDB();
28
+ environment_handler_1.environmentHandler.saveToDB();
29
+ });
30
+ break;
31
+ case enum_1.CmdAction.HELP:
32
+ case enum_1.CmdAction.HELP_FLAG:
33
+ console.log('\n\nUsage: mstate [cmd] [parameter]="[value]"\n');
34
+ console.log('Commands:');
35
+ utils_1.customLog.info(enum_1.CmdAction.ADD, 'Add new workflow');
36
+ utils_1.customLog.info(enum_1.CmdAction.CLONE, 'Clone workflow with actions and environments');
37
+ utils_1.customLog.info(enum_1.CmdAction.PUSH, 'Update the changes one in cloned workflow');
38
+ utils_1.customLog.info(enum_1.CmdAction.LINK, 'add workflow and allow user to view workflow to mobioffice application');
39
+ utils_1.customLog.info(enum_1.CmdAction.UNLINK, 'add workflow and remove user to view workflow to mobioffice application');
18
40
  break;
19
41
  default:
20
- console.error(`Mstate`, 'error', `Missing script: "${action}"`);
42
+ utils_1.customLog.error(`${action ? 'Invalid' : 'Missing'} script: "${action !== null && action !== void 0 ? action : ''}"`);
43
+ console.log('use `mstate help, -h` for getting allowed action');
21
44
  }
45
+ console.log('\n');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mstate-cli",
3
- "version": "0.0.2",
3
+ "version": "0.1.0",
4
4
  "main": "index.js",
5
5
  "bin": {
6
6
  "mstate": "./dist/index.js"
@@ -1,2 +1,3 @@
1
1
  export const MSTATE_URL = 'https://dev.mstate.mobioffice.io/api';
2
- // export const MSTATE_URL = "https://api.mstate.mobioffice.io/api";
2
+ // export const MSTATE_URL = 'https://api.mstate.mobioffice.io/api';
3
+ export const MOBIOFFICE_URL = 'https://server.mobioffice.io/api';
@@ -1,6 +1,9 @@
1
1
  export enum CmdAction {
2
2
  LINK = 'link',
3
+ UNLINK = 'unlink',
3
4
  ADD = 'add',
4
5
  CLONE = 'clone',
5
- UPDATE = 'update',
6
+ PUSH = 'push',
7
+ HELP = 'help',
8
+ HELP_FLAG = '-h',
6
9
  }
@@ -0,0 +1,27 @@
1
+ export function getValueFromArgs(args: string[], key: string) {
2
+ return args.find((str) => str.includes(key))?.replace(key, '') ?? '';
3
+ }
4
+
5
+ export const customLog = {
6
+ error(...message: string[]) {
7
+ const RED_COLOR = '\x1b[31m'; // ANSI code for red
8
+ const RESET_COLOR = '\x1b[0m'; // ANSI code to reset to default color
9
+
10
+ console.error(`${RED_COLOR}[MSTATE][ERROR] ${RESET_COLOR}`, ...message);
11
+ },
12
+
13
+ success(...message: string[]) {
14
+ const GREEN_COLOR = '\x1b[32m'; // ANSI code for green
15
+ const RESET_COLOR = '\x1b[0m'; // ANSI code to reset to default color
16
+
17
+ console.log(`${GREEN_COLOR}[MSTATE] ${RESET_COLOR}`, ...message);
18
+ },
19
+ info(key: string, desc: string) {
20
+ const optionPadding = 30; // Define spacing width for the option column
21
+ const descriptionPadding = 60; // Define spacing width for the description column
22
+ console.log(
23
+ ' ',
24
+ key.padEnd(optionPadding) + desc.padEnd(descriptionPadding),
25
+ );
26
+ },
27
+ };
@@ -0,0 +1,127 @@
1
+ import * as fs from 'fs';
2
+ import path from 'path';
3
+ import { MSTATE_URL } from '../common/constant';
4
+ import { customLog, getValueFromArgs } from '../common/utils';
5
+
6
+ enum Key {
7
+ WORKFLOW = 'workflow=',
8
+ SECRET_KEY = 'secret=',
9
+ }
10
+
11
+ class ActionHandler {
12
+ constructor() {}
13
+
14
+ async cloneActions() {
15
+ try {
16
+ const args = process.argv;
17
+ const dirPath = getValueFromArgs(args, Key.WORKFLOW);
18
+ const workflowName = dirPath.replace(/\//g, '__');
19
+ const secretKey = getValueFromArgs(args, Key.SECRET_KEY);
20
+
21
+ if (!secretKey) {
22
+ customLog.error(`Parameter secret is required`);
23
+ return;
24
+ }
25
+
26
+ if (!workflowName) {
27
+ customLog.error(`Parameter workflow is required`);
28
+ return;
29
+ }
30
+
31
+ try {
32
+ const url = `${MSTATE_URL}/action/config/all/?workflow=${workflowName}`;
33
+
34
+ const responseJSON = await fetch(url, {
35
+ headers: {
36
+ 'Content-Type': 'application/json',
37
+ 'secret-key': secretKey,
38
+ },
39
+ });
40
+
41
+ const response = await responseJSON.json();
42
+ if (response?.errors) {
43
+ customLog.error('Invalid Parameters: ', response?.errors);
44
+ } else {
45
+ const actionConfigs = response?.data;
46
+
47
+ const folderPath = path.resolve(dirPath, 'actions');
48
+ fs.mkdirSync(folderPath, { recursive: true });
49
+
50
+ actionConfigs.forEach((config: ActionConfig) => {
51
+ const file = path.join(folderPath, `${config?.name}.json`);
52
+ fs.writeFileSync(file, JSON.stringify(config, null, 2));
53
+
54
+ customLog.success(
55
+ 'file created at',
56
+ folderPath,
57
+ `${config?.name}.json`,
58
+ );
59
+ });
60
+ }
61
+ } catch (error: any) {
62
+ customLog.error('Error in cloning action', error.message);
63
+ }
64
+ } catch (error: any) {
65
+ customLog.error('Error in cloning action', error.message);
66
+ }
67
+ }
68
+
69
+ async saveToDB() {
70
+ try {
71
+ const args = process.argv;
72
+ const dirPath = getValueFromArgs(args, Key.WORKFLOW);
73
+ const workflowName = dirPath.replace(/\//g, '__');
74
+ const secretKey = getValueFromArgs(args, Key.SECRET_KEY);
75
+
76
+ if (!secretKey) {
77
+ customLog.error(`Parameter secret is required`);
78
+ return;
79
+ }
80
+
81
+ if (!workflowName) {
82
+ customLog.error(`Parameter workflow is required`);
83
+ return;
84
+ }
85
+
86
+ const folderPath = path.resolve(dirPath, 'actions');
87
+
88
+ // loop to every folder to publish workflow
89
+ fs.readdir(folderPath, (err, files) => {
90
+ if (!files) return;
91
+
92
+ files.forEach(async (fileName) => {
93
+ try {
94
+ const filePath = path.join(folderPath, fileName);
95
+ const data = fs.readFileSync(filePath, 'utf8');
96
+
97
+ const url = `${MSTATE_URL}/action/config/?workflow=${workflowName}`;
98
+ const responseJSON = await fetch(url, {
99
+ method: 'PUT',
100
+ headers: {
101
+ 'secret-key': secretKey,
102
+ 'Content-Type': 'application/json',
103
+ },
104
+ body: data,
105
+ });
106
+ const response = await responseJSON.json();
107
+
108
+ if (response?.errors) {
109
+ customLog.error(
110
+ `Invalid Parameters for Action ${fileName}: `,
111
+ response?.errors,
112
+ );
113
+ } else {
114
+ customLog.success(`Action ${fileName} Updated successfully`);
115
+ }
116
+ } catch (error: any) {
117
+ customLog.error(error.message);
118
+ }
119
+ });
120
+ });
121
+ } catch (error: any) {
122
+ customLog.error(error.message);
123
+ }
124
+ }
125
+ }
126
+
127
+ export const actionHandler = new ActionHandler();
@@ -0,0 +1,110 @@
1
+ import * as fs from 'fs';
2
+ import path from 'path';
3
+ import { MSTATE_URL } from '../common/constant';
4
+ import { customLog, getValueFromArgs } from '../common/utils';
5
+
6
+ enum Key {
7
+ WORKFLOW = 'workflow=',
8
+ SECRET_KEY = 'secret=',
9
+ }
10
+
11
+ class EnvironmentHandler {
12
+ constructor() {}
13
+
14
+ async cloneEnvironments() {
15
+ try {
16
+ const args = process.argv;
17
+ const dirPath = getValueFromArgs(args, Key.WORKFLOW);
18
+ const workflowName = dirPath.replace(/\//g, '__');
19
+ const secretKey = getValueFromArgs(args, Key.SECRET_KEY);
20
+
21
+ if (!secretKey) {
22
+ customLog.error(`Parameter secret is required`);
23
+ return;
24
+ }
25
+
26
+ if (!workflowName) {
27
+ customLog.error(`Parameter workflow is required`);
28
+ return;
29
+ }
30
+
31
+ try {
32
+ const url = `${MSTATE_URL}/env/?workflow=${workflowName}`;
33
+
34
+ const responseJSON = await fetch(url, {
35
+ headers: {
36
+ 'Content-Type': 'application/json',
37
+ 'secret-key': secretKey,
38
+ },
39
+ });
40
+
41
+ const response = await responseJSON.json();
42
+ if (response?.errors) {
43
+ customLog.error('Invalid Parameters: ', response?.errors);
44
+ } else {
45
+ const config = response?.data;
46
+
47
+ const filePath = path.resolve(dirPath, 'environment.json');
48
+ fs.writeFileSync(filePath, JSON.stringify(config, null, 2));
49
+ }
50
+ } catch (error: any) {
51
+ customLog.error('Error in cloning action', error.message);
52
+ }
53
+ } catch (error: any) {
54
+ customLog.error('Error in cloning action', error.message);
55
+ }
56
+ }
57
+
58
+ async saveToDB() {
59
+ try {
60
+ const args = process.argv;
61
+
62
+ const dirPath = getValueFromArgs(args, Key.WORKFLOW);
63
+ const workflowName = dirPath.replace(/\//g, '__');
64
+ const secretKey = getValueFromArgs(args, Key.SECRET_KEY);
65
+
66
+ if (!secretKey) {
67
+ customLog.error(`Parameter secret is required`);
68
+ return;
69
+ }
70
+
71
+ if (!workflowName) {
72
+ customLog.error(`Parameter workflow is required`);
73
+ return;
74
+ }
75
+
76
+ const filePath = path.resolve(dirPath, 'environment.json');
77
+
78
+ const data = fs.readFileSync(filePath, 'utf8');
79
+ const environments = JSON.parse(data);
80
+
81
+ try {
82
+ const url = `${MSTATE_URL}/env`;
83
+ const responseJSON = await fetch(url, {
84
+ method: 'POST',
85
+ headers: {
86
+ 'secret-key': secretKey,
87
+ 'Content-Type': 'application/json',
88
+ },
89
+ body: JSON.stringify({
90
+ workflow: workflowName,
91
+ env: environments,
92
+ }),
93
+ });
94
+
95
+ const response = await responseJSON.json();
96
+ if (response?.errors) {
97
+ customLog.error(`Updating environment:`, response?.errors);
98
+ } else {
99
+ customLog.success(`Environments Updated successfully`);
100
+ }
101
+ } catch (error: any) {
102
+ customLog.error(error.message);
103
+ }
104
+ } catch (error) {
105
+ customLog.error('Something went wrong');
106
+ }
107
+ }
108
+ }
109
+
110
+ export const environmentHandler = new EnvironmentHandler();
@@ -0,0 +1,73 @@
1
+ import { MOBIOFFICE_URL } from '../common/constant';
2
+ import { CmdAction } from '../common/enum';
3
+ import { customLog, getValueFromArgs } from '../common/utils';
4
+
5
+ enum Key {
6
+ WORKFLOW = 'workflow=',
7
+ SECRET_KEY = 'secret=',
8
+ COMPANY_ID = 'company=',
9
+ USER_ID = 'user=',
10
+ }
11
+
12
+ class MobiofficeHandler {
13
+ constructor() {}
14
+
15
+ async linkToMobioffice(action: CmdAction.LINK | CmdAction.UNLINK) {
16
+ try {
17
+ const args = process.argv;
18
+
19
+ const dirPath = getValueFromArgs(args, Key.WORKFLOW);
20
+ const workflowName = dirPath.replace(/\//g, '__');
21
+ const secretKey = getValueFromArgs(args, Key.SECRET_KEY);
22
+ const companyID = getValueFromArgs(args, Key.COMPANY_ID);
23
+ const user = getValueFromArgs(args, Key.USER_ID);
24
+
25
+ if (!workflowName) {
26
+ customLog.error(`Parameter workflow is required`);
27
+ return;
28
+ }
29
+
30
+ if (!secretKey) {
31
+ customLog.error(`Parameter secret is required`);
32
+ return;
33
+ }
34
+
35
+ if (!companyID) {
36
+ customLog.error(`Parameter company is required`);
37
+ return;
38
+ }
39
+
40
+ if (!user) {
41
+ customLog.error(`Parameter user is required`);
42
+ return;
43
+ }
44
+
45
+ const url = `${MOBIOFFICE_URL}/Mstate/workFlow/user`;
46
+ const responseJSON = await fetch(url, {
47
+ method: 'POST',
48
+ headers: {
49
+ 'secret-key': secretKey,
50
+ 'Content-Type': 'application/json',
51
+ },
52
+ body: JSON.stringify({
53
+ action: action.toUpperCase(),
54
+ workflow: workflowName,
55
+ secret: secretKey,
56
+ companyID,
57
+ user,
58
+ }),
59
+ });
60
+
61
+ const response = await responseJSON.json();
62
+ if (responseJSON.status >= 400) {
63
+ customLog.error('Invalid Parameters: ', responseJSON.statusText);
64
+ } else {
65
+ customLog.success('Workflow Added successfully', response?.message);
66
+ }
67
+ } catch (error: any) {
68
+ customLog.error(error.message);
69
+ }
70
+ }
71
+ }
72
+
73
+ export const mobiofficeHandler = new MobiofficeHandler();
@@ -0,0 +1,163 @@
1
+ import * as fs from 'fs';
2
+ import path from 'path';
3
+ import { MSTATE_URL } from '../common/constant';
4
+ import { customLog, getValueFromArgs } from '../common/utils';
5
+
6
+ enum Key {
7
+ PATH = 'path=',
8
+ FILE = 'file=',
9
+ SECRET_KEY = 'secret=',
10
+ WORKFLOW = 'workflow=',
11
+ }
12
+
13
+ class WorkflowHandler {
14
+ constructor() {}
15
+
16
+ async saveToDB() {
17
+ try {
18
+ const args = process.argv;
19
+
20
+ const dirPath = getValueFromArgs(args, Key.PATH);
21
+ const workflowPath = dirPath.replace(/\//g, '__');
22
+ const file = getValueFromArgs(args, Key.FILE);
23
+ const secretKey = getValueFromArgs(args, Key.SECRET_KEY);
24
+
25
+ if (!file) {
26
+ customLog.error(`Parameter file is required`);
27
+ return;
28
+ }
29
+
30
+ if (!secretKey) {
31
+ customLog.error(`Parameter secret is required`);
32
+ return;
33
+ }
34
+
35
+ const filePath = path.resolve(file);
36
+ const workflowJSON = fs.readFileSync(filePath, 'utf8');
37
+
38
+ let query = '';
39
+ if (workflowPath) {
40
+ query += `path=${workflowPath}`;
41
+ }
42
+
43
+ if (query.length) {
44
+ query = '?' + query;
45
+ }
46
+
47
+ const url = `${MSTATE_URL}/workflow/config/new${query}`;
48
+ const responseJSON = await fetch(url, {
49
+ method: 'POST',
50
+ headers: {
51
+ 'secret-key': secretKey,
52
+ 'Content-Type': 'application/json',
53
+ },
54
+ body: workflowJSON,
55
+ });
56
+
57
+ const response = await responseJSON.json();
58
+ if (response?.errors) {
59
+ customLog.error('Invalid Parameters: ', response?.errors);
60
+ } else {
61
+ customLog.success('Workflow Added successfully', response?.data);
62
+ }
63
+ } catch (error: any) {
64
+ customLog.error(error.message);
65
+ }
66
+ }
67
+
68
+ async updateWorkflowToDB() {
69
+ try {
70
+ const args = process.argv;
71
+
72
+ const dirPath = getValueFromArgs(args, Key.WORKFLOW);
73
+ const workflowName = dirPath.replace(/\//g, '__');
74
+ const secretKey = getValueFromArgs(args, Key.SECRET_KEY);
75
+
76
+ if (!secretKey) {
77
+ customLog.error(`Parameter secret is required`);
78
+ return;
79
+ }
80
+
81
+ if (!workflowName) {
82
+ customLog.error(`Parameter workflow is required`);
83
+ return;
84
+ }
85
+
86
+ const folderPath = path.resolve(dirPath);
87
+ const filePath = path.join(folderPath, 'workflow.json');
88
+
89
+ const workflowJSON = fs.readFileSync(filePath, 'utf8');
90
+
91
+ let query = `?workflow=${workflowName}`;
92
+
93
+ const url = `${MSTATE_URL}/workflow/config${query}`;
94
+ const responseJSON = await fetch(url, {
95
+ method: 'PUT',
96
+ headers: {
97
+ 'secret-key': secretKey,
98
+ 'Content-Type': 'application/json',
99
+ },
100
+ body: workflowJSON,
101
+ });
102
+
103
+ const response = await responseJSON.json();
104
+ if (response?.errors) {
105
+ customLog.error('Invalid Parameters: ', response?.errors);
106
+ } else {
107
+ customLog.success('Workflow Uploaded successfully \n', response?.data);
108
+ }
109
+
110
+ return response;
111
+ } catch (error: any) {
112
+ customLog.error(error.message);
113
+ }
114
+ }
115
+
116
+ async cloneWorkflow() {
117
+ try {
118
+ const args = process.argv;
119
+
120
+ const dirPath = getValueFromArgs(args, Key.WORKFLOW);
121
+ const workflowName = dirPath.replace(/\//g, '__');
122
+ const secretKey = getValueFromArgs(args, Key.SECRET_KEY);
123
+
124
+ if (!secretKey) {
125
+ customLog.error(`Parameter secret is required`);
126
+ return;
127
+ }
128
+
129
+ if (!workflowName) {
130
+ customLog.error(`Parameter workflow is required`);
131
+ return;
132
+ }
133
+
134
+ const url = `${MSTATE_URL}/workflow/config/${workflowName}`;
135
+ const responseJSON = await fetch(url, {
136
+ method: 'GET',
137
+ headers: {
138
+ 'Content-Type': 'application/json',
139
+ 'secret-key': secretKey,
140
+ },
141
+ });
142
+
143
+ const response = await responseJSON.json();
144
+ if (response?.errors) {
145
+ customLog.error('Invalid Parameters: ', response?.errors);
146
+ } else {
147
+ const workflowConfig = response?.data;
148
+
149
+ const folderPath = path.resolve(dirPath);
150
+ fs.mkdirSync(folderPath, { recursive: true });
151
+
152
+ const filePath = path.join(folderPath, 'workflow.json');
153
+ fs.writeFileSync(filePath, JSON.stringify(workflowConfig, null, 2));
154
+
155
+ customLog.success(`Workflow cloned successfully`);
156
+ }
157
+ } catch (error: any) {
158
+ customLog.error('Error in cloning workflow', error.message);
159
+ }
160
+ }
161
+ }
162
+
163
+ export const workflowHandler = new WorkflowHandler();
package/src/index.ts CHANGED
@@ -1,23 +1,61 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { workflowAction } from './actions/workflow.action';
3
+ import { actionHandler } from './handlers/action.handler';
4
+ import { workflowHandler } from './handlers/workflow.handler';
4
5
  import { CmdAction } from './common/enum';
6
+ import { mobiofficeHandler } from './handlers/mobioffice.handler';
7
+ import { customLog } from './common/utils';
8
+ import { environmentHandler } from './handlers/environment.handler';
5
9
 
6
- const [action, ...params] = process.argv.slice(2);
10
+ const [action] = process.argv.slice(2);
7
11
 
8
12
  switch (action as CmdAction) {
9
13
  case CmdAction.LINK:
14
+ case CmdAction.UNLINK:
15
+ mobiofficeHandler.linkToMobioffice(
16
+ action as CmdAction.LINK | CmdAction.UNLINK,
17
+ );
10
18
  break;
11
19
  case CmdAction.CLONE:
12
- workflowAction.cloneWorkflow(params);
20
+ workflowHandler.cloneWorkflow().then(() => {
21
+ actionHandler.cloneActions();
22
+ environmentHandler.cloneEnvironments();
23
+ });
13
24
  break;
14
25
  case CmdAction.ADD:
15
- workflowAction.saveToDB(params);
26
+ workflowHandler.saveToDB();
16
27
  break;
17
- case CmdAction.UPDATE:
18
- workflowAction.updateWorkflowToDB(params);
28
+ case CmdAction.PUSH:
29
+ workflowHandler.updateWorkflowToDB().then(() => {
30
+ actionHandler.saveToDB();
31
+ environmentHandler.saveToDB();
32
+ });
19
33
  break;
34
+ case CmdAction.HELP:
35
+ case CmdAction.HELP_FLAG:
36
+ console.log('\n\nUsage: mstate [cmd] [parameter]="[value]"\n');
20
37
 
38
+ console.log('Commands:');
39
+ customLog.info(CmdAction.ADD, 'Add new workflow');
40
+ customLog.info(
41
+ CmdAction.CLONE,
42
+ 'Clone workflow with actions and environments',
43
+ );
44
+ customLog.info(CmdAction.PUSH, 'Update the changes one in cloned workflow');
45
+ customLog.info(
46
+ CmdAction.LINK,
47
+ 'add workflow and allow user to view workflow to mobioffice application',
48
+ );
49
+ customLog.info(
50
+ CmdAction.UNLINK,
51
+ 'add workflow and remove user to view workflow to mobioffice application',
52
+ );
53
+ break;
21
54
  default:
22
- console.error(`Mstate`, 'error', `Missing script: "${action}"`);
55
+ customLog.error(
56
+ `${action ? 'Invalid' : 'Missing'} script: "${action ?? ''}"`,
57
+ );
58
+ console.log('use `mstate help, -h` for getting allowed action');
23
59
  }
60
+
61
+ console.log('\n');
@@ -28,8 +28,8 @@ interface Action {
28
28
  }
29
29
 
30
30
  interface ActionConfig {
31
- version: string;
32
31
  name: string;
32
+ version: string;
33
33
  meta?: unknown;
34
34
  type: 'MANUAL' | 'AUTO' | 'CHAINED';
35
35
  steps: Step[];