@useparagon/core 0.0.1-canary.1
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/package.json +63 -0
- package/src/event/event.interface.ts +18 -0
- package/src/event/index.ts +1 -0
- package/src/execution/context.constants.ts +9 -0
- package/src/execution/context.interface.ts +39 -0
- package/src/execution/context.ts +72 -0
- package/src/execution/context.utils.ts +53 -0
- package/src/execution/index.ts +2 -0
- package/src/index.ts +6 -0
- package/src/integration/custom-integration.interface.ts +20 -0
- package/src/integration/index.ts +2 -0
- package/src/integration/integration-config.interface.ts +19 -0
- package/src/integration/integration.interface.ts +16 -0
- package/src/operator/index.ts +2 -0
- package/src/operator/operator.interface.ts +6 -0
- package/src/operator/operators/BooleanTrue.ts +20 -0
- package/src/operator/operators/StringContains.ts +27 -0
- package/src/resolvers/index.ts +2 -0
- package/src/resolvers/resolver.utils.ts +157 -0
- package/src/resolvers/resolvers.interface.ts +369 -0
- package/src/secret/index.ts +1 -0
- package/src/secret/secret.interface.ts +4 -0
- package/src/stateMachine/index.ts +2 -0
- package/src/stateMachine/stateMachine.constants.ts +12 -0
- package/src/stateMachine/stateMachine.interface.ts +145 -0
- package/src/stateMachine/stateMachine.utils.ts +733 -0
- package/src/steps/index.ts +3 -0
- package/src/steps/library/action/action.interface.ts +69 -0
- package/src/steps/library/action/action.step.ts +70 -0
- package/src/steps/library/action/index.ts +2 -0
- package/src/steps/library/conditional/conditional.interface.ts +82 -0
- package/src/steps/library/conditional/conditional.step.ts +96 -0
- package/src/steps/library/conditional/conditional.utils.ts +110 -0
- package/src/steps/library/conditional/index.ts +2 -0
- package/src/steps/library/delay/delay.interface.ts +71 -0
- package/src/steps/library/delay/delay.step.ts +51 -0
- package/src/steps/library/delay/index.ts +2 -0
- package/src/steps/library/fanout/fanout.interface.ts +46 -0
- package/src/steps/library/fanout/fanout.step.ts +68 -0
- package/src/steps/library/fanout/index.ts +2 -0
- package/src/steps/library/function/function.interface.ts +69 -0
- package/src/steps/library/function/function.step.ts +55 -0
- package/src/steps/library/function/index.ts +2 -0
- package/src/steps/library/index.ts +7 -0
- package/src/steps/library/integrationRequest/index.ts +2 -0
- package/src/steps/library/integrationRequest/integrationRequest.interface.ts +79 -0
- package/src/steps/library/integrationRequest/integrationRequest.step.ts +100 -0
- package/src/steps/library/request/index.ts +2 -0
- package/src/steps/library/request/request.interface.ts +159 -0
- package/src/steps/library/request/request.step.ts +117 -0
- package/src/steps/library/response/index.ts +2 -0
- package/src/steps/library/response/response.interface.ts +50 -0
- package/src/steps/library/response/response.step.ts +68 -0
- package/src/steps/step.constants.ts +4 -0
- package/src/steps/step.interface-base.ts +81 -0
- package/src/steps/step.interface.ts +31 -0
- package/src/steps/step.ts +136 -0
- package/src/steps/step.utils.ts +103 -0
- package/src/triggers/cron/cron.interface.ts +94 -0
- package/src/triggers/cron/cron.step.ts +52 -0
- package/src/triggers/cron/cron.utils.ts +117 -0
- package/src/triggers/cron/index.ts +3 -0
- package/src/triggers/endpoint/endpoint.interface.ts +66 -0
- package/src/triggers/endpoint/endpoint.step.ts +61 -0
- package/src/triggers/endpoint/index.ts +2 -0
- package/src/triggers/event/event.interface.ts +43 -0
- package/src/triggers/event/event.step.ts +41 -0
- package/src/triggers/event/index.ts +2 -0
- package/src/triggers/index.ts +4 -0
- package/src/triggers/integrationEnabled/index.ts +2 -0
- package/src/triggers/integrationEnabled/integrationEnabled.interface.ts +29 -0
- package/src/triggers/integrationEnabled/integrationEnabled.step.ts +33 -0
- package/src/triggers/trigger.interface.ts +28 -0
- package/src/triggers/trigger.ts +25 -0
- package/src/user/index.ts +2 -0
- package/src/user/user.interface.ts +4 -0
- package/src/user/user.ts +6 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/utils.ts +10 -0
- package/src/workflow/index.ts +2 -0
- package/src/workflow/workflow.interface.ts +50 -0
- package/src/workflow/workflow.ts +132 -0
- package/tsconfig.json +9 -0
- package/tsconfig.release.json +8 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { DataType, TokenizedSource } from '../../../resolvers';
|
|
2
|
+
import {
|
|
3
|
+
resolveParamsToSources,
|
|
4
|
+
resolveToSource,
|
|
5
|
+
} from '../../../resolvers/resolver.utils';
|
|
6
|
+
import { Step } from '../../step';
|
|
7
|
+
import { StepType } from '../../step.interface';
|
|
8
|
+
import {
|
|
9
|
+
IResponseStep,
|
|
10
|
+
IResponseStepInit,
|
|
11
|
+
IResponseStepParameters,
|
|
12
|
+
ResponseTypeEnum,
|
|
13
|
+
} from './response.interface';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* a step used for making HTTP Responses
|
|
17
|
+
*/
|
|
18
|
+
export class ResponseStep extends Step implements IResponseStep {
|
|
19
|
+
/**
|
|
20
|
+
* the step type
|
|
21
|
+
* @type {StepType}
|
|
22
|
+
* @memberof Step
|
|
23
|
+
*/
|
|
24
|
+
type: StepType.RESPONSE = StepType.RESPONSE;
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* configuration for the response step
|
|
28
|
+
* @type {IResponseStepParameters}
|
|
29
|
+
* @memberof ResponseStep
|
|
30
|
+
*/
|
|
31
|
+
parameters: IResponseStepParameters;
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* initialization parameters
|
|
35
|
+
* @type {IResponseStepInit}
|
|
36
|
+
* @memberof ResponseStep
|
|
37
|
+
*/
|
|
38
|
+
_parameters: IResponseStepInit;
|
|
39
|
+
|
|
40
|
+
constructor(params: IResponseStepInit) {
|
|
41
|
+
super(params);
|
|
42
|
+
this._parameters = params;
|
|
43
|
+
this.parameters = this.serializeParameters();
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* serialize parameters for storage
|
|
48
|
+
*/
|
|
49
|
+
serializeParameters(): IResponseStepParameters {
|
|
50
|
+
const initParams: IResponseStepInit = this._parameters;
|
|
51
|
+
|
|
52
|
+
if (initParams.responseType === ResponseTypeEnum.FILE) {
|
|
53
|
+
return {
|
|
54
|
+
statusCode: initParams.statusCode,
|
|
55
|
+
bodyData: [],
|
|
56
|
+
bodyFile: resolveToSource(
|
|
57
|
+
initParams.body,
|
|
58
|
+
DataType.FILE,
|
|
59
|
+
) as TokenizedSource<DataType.FILE>,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
statusCode: initParams.statusCode,
|
|
65
|
+
bodyData: resolveParamsToSources(initParams.body),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { IStep } from './step.interface';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* the supported step types
|
|
5
|
+
*/
|
|
6
|
+
export enum StepType {
|
|
7
|
+
ACTION = 'ACTION/CUSTOM',
|
|
8
|
+
ACTION_TRIGGER = 'TRIGGER/ACTION',
|
|
9
|
+
CRON = 'TRIGGER/CRON',
|
|
10
|
+
CUSTOM_INTEGRATION_REQUEST = 'ACTION/CUSTOM_INTEGRATION_REQUEST',
|
|
11
|
+
DELAY = 'ACTION/DELAY',
|
|
12
|
+
ENDPOINT = 'TRIGGER/ENDPOINT',
|
|
13
|
+
EVENT = 'TRIGGER/EVENT',
|
|
14
|
+
FUNCTION = 'ACTION/FUNCTION',
|
|
15
|
+
IFELSE = 'TRANSITION/IFELSE',
|
|
16
|
+
INTEGRATION_ENABLED = 'TRIGGER/INTEGRATION_ENABLED',
|
|
17
|
+
MAP = 'TRANSITION/MAP',
|
|
18
|
+
OAUTH = 'TRIGGER/OAUTH',
|
|
19
|
+
REDIRECT = 'ACTION/REDIRECT',
|
|
20
|
+
RESPONSE = 'ACTION/RESPONSE',
|
|
21
|
+
REQUEST = 'ACTION/REQUEST',
|
|
22
|
+
UNSELECTED_TRIGGER = 'TRIGGER/NONE',
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* step types that are valid triggers
|
|
27
|
+
*/
|
|
28
|
+
export const TRIGGER_TYPES = [
|
|
29
|
+
StepType.UNSELECTED_TRIGGER,
|
|
30
|
+
StepType.CRON,
|
|
31
|
+
StepType.ENDPOINT,
|
|
32
|
+
StepType.OAUTH,
|
|
33
|
+
StepType.ACTION_TRIGGER,
|
|
34
|
+
StepType.EVENT,
|
|
35
|
+
StepType.INTEGRATION_ENABLED,
|
|
36
|
+
];
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* parameters used to initialize a Step
|
|
40
|
+
*/
|
|
41
|
+
export interface IBaseStepParameters extends Record<string, unknown> {}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* a step used in a workflow
|
|
45
|
+
*/
|
|
46
|
+
export interface IBaseStep {
|
|
47
|
+
/**
|
|
48
|
+
* the id of the step
|
|
49
|
+
*/
|
|
50
|
+
id: string;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* the step type
|
|
54
|
+
*/
|
|
55
|
+
type: StepType;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* configuration for the step
|
|
59
|
+
*/
|
|
60
|
+
parameters: IBaseStepParameters;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* the id of the step after the current step
|
|
64
|
+
*/
|
|
65
|
+
next: string | null;
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* description of step
|
|
69
|
+
*/
|
|
70
|
+
description?: string;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* used for storing data used in migrations or (de)serialization transformations
|
|
74
|
+
*/
|
|
75
|
+
readonly _migrations?: Record<string, unknown>;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* key / value map of steps where the keys are the step ids
|
|
80
|
+
*/
|
|
81
|
+
export type StepMap = Record<string, IStep>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { ICronStep } from '../triggers/cron/cron.interface';
|
|
2
|
+
import { IEndpointStep } from '../triggers/endpoint/endpoint.interface';
|
|
3
|
+
import { IEventStep } from '../triggers/event/event.interface';
|
|
4
|
+
import { IIntegrationEnabledStep } from '../triggers/integrationEnabled/integrationEnabled.interface';
|
|
5
|
+
import { IActionStep } from './library/action/action.interface';
|
|
6
|
+
import { IConditionalStep } from './library/conditional/conditional.interface';
|
|
7
|
+
import { IDelayStep } from './library/delay/delay.interface';
|
|
8
|
+
import { IFanOutStep } from './library/fanout/fanout.interface';
|
|
9
|
+
import { IFunctionStep } from './library/function/function.interface';
|
|
10
|
+
import { IIntegrationRequestStep } from './library/integrationRequest/integrationRequest.interface';
|
|
11
|
+
import { IRequestStep } from './library/request/request.interface';
|
|
12
|
+
import { IResponseStep } from './library/response/response.interface';
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* a union type comprised of the different step types
|
|
16
|
+
*/
|
|
17
|
+
export type IStep =
|
|
18
|
+
| IActionStep
|
|
19
|
+
| IConditionalStep
|
|
20
|
+
| ICronStep
|
|
21
|
+
| IDelayStep
|
|
22
|
+
| IEndpointStep
|
|
23
|
+
| IEventStep
|
|
24
|
+
| IFanOutStep
|
|
25
|
+
| IFunctionStep
|
|
26
|
+
| IIntegrationEnabledStep
|
|
27
|
+
| IIntegrationRequestStep
|
|
28
|
+
| IRequestStep
|
|
29
|
+
| IResponseStep;
|
|
30
|
+
|
|
31
|
+
export * from './step.interface-base';
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { getRandomNumberInRange } from '../utils';
|
|
2
|
+
import { UNSET_STEP_ID } from './step.constants';
|
|
3
|
+
import {
|
|
4
|
+
IBaseStep,
|
|
5
|
+
IBaseStepParameters,
|
|
6
|
+
IStep,
|
|
7
|
+
StepType,
|
|
8
|
+
} from './step.interface';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* a step used in a workflow
|
|
12
|
+
*/
|
|
13
|
+
export abstract class Step<I = any, O extends IBaseStepParameters = any>
|
|
14
|
+
implements IBaseStep
|
|
15
|
+
{
|
|
16
|
+
/**
|
|
17
|
+
* the id of the step
|
|
18
|
+
*
|
|
19
|
+
* @type {string}
|
|
20
|
+
* @memberof Step
|
|
21
|
+
*/
|
|
22
|
+
id: string = `${UNSET_STEP_ID}${getRandomNumberInRange(10000, 99999)}`;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* configuration for the step
|
|
26
|
+
*
|
|
27
|
+
* @type {IBaseStepParameters}
|
|
28
|
+
* @memberof Step
|
|
29
|
+
*/
|
|
30
|
+
abstract parameters: IBaseStepParameters;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* the step type
|
|
34
|
+
*
|
|
35
|
+
* @abstract
|
|
36
|
+
* @type {StepType}
|
|
37
|
+
* @memberof Step
|
|
38
|
+
*/
|
|
39
|
+
abstract type: StepType;
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* the next step in the sequence
|
|
43
|
+
*
|
|
44
|
+
* @private
|
|
45
|
+
* @type {Step}
|
|
46
|
+
* @memberof Step
|
|
47
|
+
*/
|
|
48
|
+
private _next?: Step;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* some steps needed workflowId in param like endpoint trigger
|
|
52
|
+
*/
|
|
53
|
+
protected workflowId?: string;
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* used for storing data used in migrations or (de)serialization transformations
|
|
57
|
+
*
|
|
58
|
+
* @private
|
|
59
|
+
* @type {Record<string, unknown>}
|
|
60
|
+
* @memberof Step
|
|
61
|
+
*/
|
|
62
|
+
readonly _migrations: Record<string, unknown> = {};
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* returns the id of the next step in the sequence
|
|
66
|
+
*
|
|
67
|
+
* @readonly
|
|
68
|
+
* @type {(string | null)}
|
|
69
|
+
* @memberof Step
|
|
70
|
+
*/
|
|
71
|
+
get next(): string | null {
|
|
72
|
+
return this._next?.id ?? null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
constructor(_params: I) {}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* sets a value in the migrations
|
|
79
|
+
*
|
|
80
|
+
* @param key
|
|
81
|
+
* @param value
|
|
82
|
+
*/
|
|
83
|
+
setMigration(key: string, value: unknown): void {
|
|
84
|
+
this._migrations[key] = value;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* sets workflowid
|
|
89
|
+
* @param workflowId
|
|
90
|
+
*/
|
|
91
|
+
setWorkflowId(workflowId: string): void {
|
|
92
|
+
this.workflowId = workflowId;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* used to specify the next Step in the sequence
|
|
97
|
+
* @param step the next Step in the sequence
|
|
98
|
+
*/
|
|
99
|
+
nextStep(step: Step): Step {
|
|
100
|
+
this._next = step;
|
|
101
|
+
return step;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* serialize parameters for storage
|
|
106
|
+
*/
|
|
107
|
+
serializeParameters(): O {
|
|
108
|
+
return this.parameters as unknown as O;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* serializes (to object)
|
|
113
|
+
* @returns
|
|
114
|
+
*/
|
|
115
|
+
toObject(): IStep {
|
|
116
|
+
const step: IStep = {
|
|
117
|
+
id: this.id,
|
|
118
|
+
// @ts-ignore: ignore error; TODO: fix type conflicts
|
|
119
|
+
type: this.type,
|
|
120
|
+
// @ts-ignore: ignore error; TODO: fix type conflicts
|
|
121
|
+
parameters: this.serializeParameters(),
|
|
122
|
+
next: this._next?.id ?? null,
|
|
123
|
+
_migrations: this._migrations,
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
return step;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* serializes (to string)
|
|
131
|
+
* @returns
|
|
132
|
+
*/
|
|
133
|
+
toString(): string {
|
|
134
|
+
return JSON.stringify(this.toObject());
|
|
135
|
+
}
|
|
136
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { FanOutStep } from './library/fanout/fanout.step';
|
|
2
|
+
import { IStep, StepMap, StepType, TRIGGER_TYPES } from './step.interface';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* determines if a step is a valid trigger step
|
|
6
|
+
*
|
|
7
|
+
* @param step
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
export function isTrigger(step: IStep): boolean {
|
|
11
|
+
return TRIGGER_TYPES.includes(step.type);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* finds the first trigger step in an array of steps
|
|
16
|
+
*
|
|
17
|
+
* @param steps
|
|
18
|
+
* @returns
|
|
19
|
+
*/
|
|
20
|
+
export function getTriggerStep(steps: IStep[]): IStep | undefined {
|
|
21
|
+
return steps.find(isTrigger);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* determines if a step is a conditional
|
|
26
|
+
*
|
|
27
|
+
* @param step
|
|
28
|
+
* @returns
|
|
29
|
+
*/
|
|
30
|
+
export function isConditional(step: IStep): boolean {
|
|
31
|
+
return step.type === StepType.IFELSE;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* determines if a step is a fanout
|
|
36
|
+
*
|
|
37
|
+
* @param step
|
|
38
|
+
* @returns
|
|
39
|
+
*/
|
|
40
|
+
export function isFanout(step: IStep): step is FanOutStep {
|
|
41
|
+
return step.type === StepType.MAP;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* converts an array of steps to a map where the keys are the step ids
|
|
46
|
+
*
|
|
47
|
+
* @param steps
|
|
48
|
+
* @returns
|
|
49
|
+
*/
|
|
50
|
+
export function stepArrayToMap(steps: IStep[]): StepMap {
|
|
51
|
+
const stepMap: StepMap = {};
|
|
52
|
+
steps.forEach((step: IStep) => (stepMap[step.id] = step));
|
|
53
|
+
return stepMap;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* converts a map of steps to an array
|
|
58
|
+
*
|
|
59
|
+
* @param stepMap
|
|
60
|
+
* @returns
|
|
61
|
+
*/
|
|
62
|
+
export function stepMapToArray(stepMap: StepMap): IStep[] {
|
|
63
|
+
return Object.keys(stepMap).map((stepId: string) => stepMap[stepId]);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* given a step and an array of steps, it determines if the step is in the list
|
|
68
|
+
*
|
|
69
|
+
* @param step
|
|
70
|
+
* @param stepList
|
|
71
|
+
* @returns
|
|
72
|
+
*/
|
|
73
|
+
export function isStepInStepList(
|
|
74
|
+
step: IStep | undefined,
|
|
75
|
+
stepList: IStep[],
|
|
76
|
+
): boolean {
|
|
77
|
+
return step && stepList.filter((s: IStep) => s.id === step.id).length > 0
|
|
78
|
+
? true
|
|
79
|
+
: false;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* combines two arrays of steps and removes duplicates
|
|
84
|
+
*
|
|
85
|
+
* @param a
|
|
86
|
+
* @param b
|
|
87
|
+
* @param createNewArray if true, a new array is created; otherwise the first array is modified
|
|
88
|
+
* @returns
|
|
89
|
+
*/
|
|
90
|
+
export function concatAndDedupeStepLists(
|
|
91
|
+
a: IStep[],
|
|
92
|
+
b: IStep[],
|
|
93
|
+
createNewArray: boolean,
|
|
94
|
+
): IStep[] {
|
|
95
|
+
const c: IStep[] = createNewArray ? [...a] : a;
|
|
96
|
+
for (const step of b) {
|
|
97
|
+
if (c.filter((s: IStep) => s.id === step.id).length === 0) {
|
|
98
|
+
c.push(step);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
return c;
|
|
103
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { DataType, TokenizedSource } from '../../resolvers/';
|
|
2
|
+
import { IBaseStep, StepType } from '../../steps/step.interface';
|
|
3
|
+
import { ITriggerStepParameters } from '../trigger.interface';
|
|
4
|
+
|
|
5
|
+
export enum Unit {
|
|
6
|
+
SECONDS = 'SECONDS',
|
|
7
|
+
MINUTES = 'MINUTES',
|
|
8
|
+
HOURLY = 'HOURLY',
|
|
9
|
+
DAILY = 'DAILY',
|
|
10
|
+
WEEKLY = 'WEEKLY',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export enum Weekday {
|
|
14
|
+
MONDAY = 'MONDAY',
|
|
15
|
+
TUESDAY = 'TUESDAY',
|
|
16
|
+
WEDNESDAY = 'WEDNESDAY',
|
|
17
|
+
THURSDAY = 'THURSDAY',
|
|
18
|
+
FRIDAY = 'FRIDAY',
|
|
19
|
+
SATURDAY = 'SATURDAY',
|
|
20
|
+
SUNDAY = 'SUNDAY',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type Time = {
|
|
24
|
+
minutes: number;
|
|
25
|
+
timezone: TokenizedSource<DataType.STRING> | string;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
export type SecondsSchedule = { unit: Unit.SECONDS; seconds: number };
|
|
29
|
+
export type MinutesSchedule = { unit: Unit.MINUTES; minutes: number };
|
|
30
|
+
export type HourlySchedule = {
|
|
31
|
+
unit: Unit.HOURLY;
|
|
32
|
+
hours: number;
|
|
33
|
+
offset: number;
|
|
34
|
+
};
|
|
35
|
+
export type DailySchedule<T = Time> = {
|
|
36
|
+
unit: Unit.DAILY;
|
|
37
|
+
days: number;
|
|
38
|
+
time: T;
|
|
39
|
+
};
|
|
40
|
+
export type WeeklySchedule<T = Time> = {
|
|
41
|
+
unit: Unit.WEEKLY;
|
|
42
|
+
weekday: Weekday;
|
|
43
|
+
time: T;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
export type Schedule =
|
|
47
|
+
| SecondsSchedule
|
|
48
|
+
| MinutesSchedule
|
|
49
|
+
| HourlySchedule
|
|
50
|
+
| DailySchedule
|
|
51
|
+
| WeeklySchedule;
|
|
52
|
+
|
|
53
|
+
export type Timezone = {
|
|
54
|
+
offset: string;
|
|
55
|
+
label: string;
|
|
56
|
+
tzCode: string;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* parameters used for initializing a CronStep
|
|
61
|
+
*/
|
|
62
|
+
export interface ICronStepInitParameters extends ITriggerStepParameters {
|
|
63
|
+
/**
|
|
64
|
+
* cron expression
|
|
65
|
+
*/
|
|
66
|
+
cron: string;
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* timzone for cron
|
|
70
|
+
*/
|
|
71
|
+
timezone: string;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* parameters used for initializing a CronStep
|
|
76
|
+
*/
|
|
77
|
+
export interface ICronStepParameters extends ITriggerStepParameters {
|
|
78
|
+
schedule: Schedule;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* a step used for cron trigger
|
|
83
|
+
*/
|
|
84
|
+
export interface ICronStep extends IBaseStep {
|
|
85
|
+
/**
|
|
86
|
+
* the step type
|
|
87
|
+
*/
|
|
88
|
+
type: StepType.CRON;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* configuration for the cron step
|
|
92
|
+
*/
|
|
93
|
+
parameters: ICronStepParameters;
|
|
94
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { StepType } from '../../steps/step.interface';
|
|
2
|
+
import { TriggerStep } from '../trigger';
|
|
3
|
+
import {
|
|
4
|
+
ICronStep,
|
|
5
|
+
ICronStepInitParameters,
|
|
6
|
+
ICronStepParameters,
|
|
7
|
+
} from './cron.interface';
|
|
8
|
+
import { getSchedule } from './cron.utils';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* a step used for cron trigger
|
|
12
|
+
*/
|
|
13
|
+
export class CronStep extends TriggerStep implements ICronStep {
|
|
14
|
+
/**
|
|
15
|
+
* the step type
|
|
16
|
+
*
|
|
17
|
+
* @type {StepType}
|
|
18
|
+
* @memberof Step
|
|
19
|
+
*/
|
|
20
|
+
type: StepType.CRON = StepType.CRON;
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* configuraiton for the cron step
|
|
24
|
+
*
|
|
25
|
+
* @type {ICronStepInitParameters}
|
|
26
|
+
* @memberof CronStep
|
|
27
|
+
*/
|
|
28
|
+
private _parameters: ICronStepInitParameters;
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* configuration for the cron step
|
|
32
|
+
*/
|
|
33
|
+
parameters: ICronStepParameters;
|
|
34
|
+
|
|
35
|
+
constructor(params: ICronStepInitParameters) {
|
|
36
|
+
super(params);
|
|
37
|
+
this._parameters = params;
|
|
38
|
+
|
|
39
|
+
this.parameters = this.serializeParameters();
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* serialize parameters for storage
|
|
44
|
+
*/
|
|
45
|
+
serializeParameters(): ICronStepParameters {
|
|
46
|
+
const cronParameters: ICronStepInitParameters = this._parameters;
|
|
47
|
+
return {
|
|
48
|
+
...this.parameters,
|
|
49
|
+
schedule: getSchedule(cronParameters.cron, cronParameters.timezone),
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { parseExpression } from 'cron-parser';
|
|
2
|
+
|
|
3
|
+
import { Schedule, Unit, Weekday } from './cron.interface';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* get cron options from schedule
|
|
7
|
+
* @param schedule
|
|
8
|
+
* @returns
|
|
9
|
+
*/
|
|
10
|
+
export const getCronOptions = (
|
|
11
|
+
schedule: Schedule,
|
|
12
|
+
): { cron: string; timeZone?: string } => {
|
|
13
|
+
switch (schedule.unit) {
|
|
14
|
+
case Unit.SECONDS:
|
|
15
|
+
return { cron: `*/${schedule.seconds} * * * * *` };
|
|
16
|
+
case Unit.MINUTES:
|
|
17
|
+
return {
|
|
18
|
+
cron: `0 */${schedule.minutes} * * * *`,
|
|
19
|
+
};
|
|
20
|
+
case Unit.HOURLY:
|
|
21
|
+
return {
|
|
22
|
+
cron: `0 ${schedule.offset} */${schedule.hours} * * *`,
|
|
23
|
+
};
|
|
24
|
+
case Unit.DAILY:
|
|
25
|
+
const dailyMinutes: number = schedule.time.minutes % 60;
|
|
26
|
+
const dailyHours: number = Math.floor(schedule.time.minutes / 60);
|
|
27
|
+
return {
|
|
28
|
+
cron: `0 ${dailyMinutes} ${dailyHours} */${schedule.days} * *`,
|
|
29
|
+
timeZone: 'America/Los_Angeles',
|
|
30
|
+
};
|
|
31
|
+
case Unit.WEEKLY:
|
|
32
|
+
const weeklyMinutes: number = schedule.time.minutes % 60;
|
|
33
|
+
const weeklyHours: number = Math.floor(schedule.time.minutes / 60);
|
|
34
|
+
const weeklyWeekday: number =
|
|
35
|
+
Object.keys(Weekday).indexOf(schedule.weekday) + 1;
|
|
36
|
+
return {
|
|
37
|
+
cron: `0 ${weeklyMinutes} ${weeklyHours} * * ${weeklyWeekday}`,
|
|
38
|
+
timeZone: 'America/Los_Angeles',
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* get schedule from cron expression
|
|
45
|
+
* @param cron
|
|
46
|
+
*/
|
|
47
|
+
export const getSchedule = (
|
|
48
|
+
cron: string,
|
|
49
|
+
timezone: string = 'America/Los_Angeles',
|
|
50
|
+
): Schedule => {
|
|
51
|
+
const parser = parseExpression(cron);
|
|
52
|
+
const firstIteration: Date = parser.next().toDate();
|
|
53
|
+
const secondIteration: Date = parser.next().toDate();
|
|
54
|
+
|
|
55
|
+
const diffSeconds: number = Math.floor(
|
|
56
|
+
(secondIteration.getTime() - firstIteration.getTime()) / 1000,
|
|
57
|
+
);
|
|
58
|
+
if (diffSeconds < 60) {
|
|
59
|
+
return {
|
|
60
|
+
unit: Unit.SECONDS,
|
|
61
|
+
seconds: diffSeconds,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const diffMinutes: number = Math.floor(diffSeconds / 60);
|
|
66
|
+
if (diffMinutes < 60) {
|
|
67
|
+
return {
|
|
68
|
+
unit: Unit.MINUTES,
|
|
69
|
+
minutes: diffMinutes,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const diffHours: number = Math.floor(diffMinutes / 60);
|
|
74
|
+
if (diffHours < 24) {
|
|
75
|
+
return {
|
|
76
|
+
unit: Unit.HOURLY,
|
|
77
|
+
hours: diffHours,
|
|
78
|
+
offset: (diffMinutes / 60) % 60,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// update this
|
|
83
|
+
const diffDays: number = Math.floor(diffMinutes / 24);
|
|
84
|
+
|
|
85
|
+
if (diffDays < 7) {
|
|
86
|
+
return {
|
|
87
|
+
unit: Unit.DAILY,
|
|
88
|
+
days: diffDays,
|
|
89
|
+
time: {
|
|
90
|
+
minutes: 2,
|
|
91
|
+
timezone,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (diffDays > 7) {
|
|
97
|
+
throw new Error(`not supported crons with more than weekly interval.`);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
const weekday: Weekday = new Intl.DateTimeFormat('en-US', {
|
|
101
|
+
weekday: 'long',
|
|
102
|
+
})
|
|
103
|
+
.format(firstIteration)
|
|
104
|
+
.toUpperCase() as Weekday;
|
|
105
|
+
|
|
106
|
+
const minutes: number =
|
|
107
|
+
firstIteration.getHours() * 60 + firstIteration.getMinutes();
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
unit: Unit.WEEKLY,
|
|
111
|
+
weekday,
|
|
112
|
+
time: {
|
|
113
|
+
minutes,
|
|
114
|
+
timezone: timezone,
|
|
115
|
+
},
|
|
116
|
+
};
|
|
117
|
+
};
|