@guanghechen/task 1.0.0-alpha.1 → 1.0.0-alpha.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/lib/cjs/index.cjs +81 -104
- package/lib/esm/index.mjs +82 -102
- package/lib/types/index.d.ts +10 -91
- package/package.json +8 -5
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,28 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
# [1.0.0-alpha.3](https://github.com/guanghechen/sora/compare/@guanghechen/task@1.0.0-alpha.2...@guanghechen/task@1.0.0-alpha.3) (2023-08-30)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Performance Improvements
|
|
10
|
+
|
|
11
|
+
* 🎨 reuse constants and types ([5efb70e](https://github.com/guanghechen/sora/commit/5efb70e6df130dc870ccb5add632291dcbd94809))
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# [1.0.0-alpha.2](https://github.com/guanghechen/sora/compare/@guanghechen/task@1.0.0-alpha.1...@guanghechen/task@1.0.0-alpha.2) (2023-08-28)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
### Features
|
|
21
|
+
|
|
22
|
+
* ✨ add @guanghechen/error & refactor other sub packages ([c50e94d](https://github.com/guanghechen/sora/commit/c50e94de4b9e6d7fd635c10e202eb8bdc4f4f8dd))
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
|
|
6
28
|
# 1.0.0-alpha.1 (2023-08-27)
|
|
7
29
|
|
|
8
30
|
|
package/lib/cjs/index.cjs
CHANGED
|
@@ -1,51 +1,35 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
var constant = require('@guanghechen/constant');
|
|
4
|
+
var error = require('@guanghechen/error');
|
|
3
5
|
var monitor = require('@guanghechen/monitor');
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
(function (TaskStatus) {
|
|
7
|
-
TaskStatus[TaskStatus["PENDING"] = 1] = "PENDING";
|
|
8
|
-
TaskStatus[TaskStatus["RUNNING"] = 2] = "RUNNING";
|
|
9
|
-
TaskStatus[TaskStatus["SUSPENDED"] = 4] = "SUSPENDED";
|
|
10
|
-
TaskStatus[TaskStatus["CANCELLED"] = 8] = "CANCELLED";
|
|
11
|
-
TaskStatus[TaskStatus["FAILED"] = 16] = "FAILED";
|
|
12
|
-
TaskStatus[TaskStatus["FINISHED"] = 32] = "FINISHED";
|
|
13
|
-
TaskStatus[TaskStatus["ATTEMPT_SUSPENDING"] = 64] = "ATTEMPT_SUSPENDING";
|
|
14
|
-
TaskStatus[TaskStatus["ATTEMPT_RESUMING"] = 128] = "ATTEMPT_RESUMING";
|
|
15
|
-
TaskStatus[TaskStatus["ATTEMPT_CANCELING"] = 256] = "ATTEMPT_CANCELING";
|
|
16
|
-
TaskStatus[TaskStatus["ATTEMPT_FINISHING"] = 512] = "ATTEMPT_FINISHING";
|
|
17
|
-
})(exports.TaskStatus || (exports.TaskStatus = {}));
|
|
18
|
-
exports.TaskStrategy = void 0;
|
|
19
|
-
(function (TaskStrategy) {
|
|
20
|
-
TaskStrategy[TaskStrategy["ABORT_ON_ERROR"] = 1] = "ABORT_ON_ERROR";
|
|
21
|
-
TaskStrategy[TaskStrategy["CONTINUE_ON_ERROR"] = 2] = "CONTINUE_ON_ERROR";
|
|
22
|
-
})(exports.TaskStrategy || (exports.TaskStrategy = {}));
|
|
23
|
-
const active = exports.TaskStatus.RUNNING |
|
|
24
|
-
exports.TaskStatus.ATTEMPT_SUSPENDING |
|
|
25
|
-
exports.TaskStatus.ATTEMPT_RESUMING;
|
|
26
|
-
const alive = exports.TaskStatus.PENDING |
|
|
27
|
-
exports.TaskStatus.RUNNING |
|
|
28
|
-
exports.TaskStatus.SUSPENDED |
|
|
29
|
-
exports.TaskStatus.ATTEMPT_SUSPENDING |
|
|
30
|
-
exports.TaskStatus.ATTEMPT_RESUMING;
|
|
31
|
-
const terminated = exports.TaskStatus.CANCELLED |
|
|
32
|
-
exports.TaskStatus.FAILED |
|
|
33
|
-
exports.TaskStatus.FINISHED;
|
|
7
|
+
function noop(..._args) { }
|
|
34
8
|
|
|
35
|
-
const
|
|
9
|
+
const active = constant.TaskStatusEnum.RUNNING |
|
|
10
|
+
constant.TaskStatusEnum.ATTEMPT_SUSPENDING |
|
|
11
|
+
constant.TaskStatusEnum.ATTEMPT_RESUMING;
|
|
12
|
+
const alive = constant.TaskStatusEnum.PENDING |
|
|
13
|
+
constant.TaskStatusEnum.RUNNING |
|
|
14
|
+
constant.TaskStatusEnum.SUSPENDED |
|
|
15
|
+
constant.TaskStatusEnum.ATTEMPT_SUSPENDING |
|
|
16
|
+
constant.TaskStatusEnum.ATTEMPT_RESUMING;
|
|
17
|
+
const terminated = constant.TaskStatusEnum.CANCELLED |
|
|
18
|
+
constant.TaskStatusEnum.FAILED |
|
|
19
|
+
constant.TaskStatusEnum.FINISHED;
|
|
36
20
|
class TaskState {
|
|
37
21
|
name;
|
|
22
|
+
_errorCollector;
|
|
38
23
|
_monitors;
|
|
39
|
-
_errorDetails;
|
|
40
24
|
_status;
|
|
41
25
|
constructor(name) {
|
|
42
26
|
this.name = name;
|
|
27
|
+
this._errorCollector = new error.SoraErrorCollector(name);
|
|
43
28
|
this._monitors = {
|
|
44
29
|
onAddError: new monitor.Monitor('onAddError'),
|
|
45
30
|
onStatusChange: new monitor.Monitor('onStatusChange'),
|
|
46
31
|
};
|
|
47
|
-
this.
|
|
48
|
-
this._status = exports.TaskStatus.PENDING;
|
|
32
|
+
this._status = constant.TaskStatusEnum.PENDING;
|
|
49
33
|
}
|
|
50
34
|
get status() {
|
|
51
35
|
return this._status;
|
|
@@ -60,12 +44,12 @@ class TaskState {
|
|
|
60
44
|
return (this._status & terminated) > 0;
|
|
61
45
|
}
|
|
62
46
|
get hasError() {
|
|
63
|
-
return this.
|
|
47
|
+
return this._errorCollector.size > 0;
|
|
64
48
|
}
|
|
65
49
|
get error() {
|
|
66
|
-
if (this.
|
|
50
|
+
if (this._errorCollector.size === 0)
|
|
67
51
|
return undefined;
|
|
68
|
-
return { from: this.name, details: this.
|
|
52
|
+
return { from: this.name, details: this._errorCollector.errors };
|
|
69
53
|
}
|
|
70
54
|
set status(status) {
|
|
71
55
|
const curStatus = this._status;
|
|
@@ -84,12 +68,8 @@ class TaskState {
|
|
|
84
68
|
if (this.terminated)
|
|
85
69
|
return noop;
|
|
86
70
|
const { onAddError, onStatusChange } = monitor;
|
|
87
|
-
const unsubscribeOnAddError = onAddError
|
|
88
|
-
|
|
89
|
-
: noop;
|
|
90
|
-
const unsubscribeOnStatusChange = onStatusChange
|
|
91
|
-
? this._monitors.onStatusChange.subscribe(onStatusChange)
|
|
92
|
-
: noop;
|
|
71
|
+
const unsubscribeOnAddError = this._monitors.onAddError.subscribe(onAddError);
|
|
72
|
+
const unsubscribeOnStatusChange = this._monitors.onStatusChange.subscribe(onStatusChange);
|
|
93
73
|
return () => {
|
|
94
74
|
unsubscribeOnAddError();
|
|
95
75
|
unsubscribeOnStatusChange();
|
|
@@ -98,30 +78,30 @@ class TaskState {
|
|
|
98
78
|
check(nextStatus) {
|
|
99
79
|
const status = this._status;
|
|
100
80
|
switch (nextStatus) {
|
|
101
|
-
case
|
|
81
|
+
case constant.TaskStatusEnum.PENDING:
|
|
102
82
|
return false;
|
|
103
|
-
case
|
|
104
|
-
return status ===
|
|
105
|
-
case
|
|
106
|
-
return status ===
|
|
107
|
-
case
|
|
108
|
-
return status ===
|
|
109
|
-
case
|
|
110
|
-
return (status !==
|
|
111
|
-
status !==
|
|
83
|
+
case constant.TaskStatusEnum.RUNNING:
|
|
84
|
+
return status === constant.TaskStatusEnum.PENDING || status === constant.TaskStatusEnum.ATTEMPT_RESUMING;
|
|
85
|
+
case constant.TaskStatusEnum.SUSPENDED:
|
|
86
|
+
return status === constant.TaskStatusEnum.ATTEMPT_SUSPENDING;
|
|
87
|
+
case constant.TaskStatusEnum.CANCELLED:
|
|
88
|
+
return status === constant.TaskStatusEnum.ATTEMPT_CANCELING;
|
|
89
|
+
case constant.TaskStatusEnum.FAILED:
|
|
90
|
+
return (status !== constant.TaskStatusEnum.PENDING &&
|
|
91
|
+
status !== constant.TaskStatusEnum.SUSPENDED &&
|
|
112
92
|
(status & terminated) === 0);
|
|
113
|
-
case
|
|
114
|
-
return (status !==
|
|
115
|
-
status !==
|
|
93
|
+
case constant.TaskStatusEnum.FINISHED:
|
|
94
|
+
return (status !== constant.TaskStatusEnum.PENDING &&
|
|
95
|
+
status !== constant.TaskStatusEnum.SUSPENDED &&
|
|
116
96
|
(status & terminated) === 0);
|
|
117
|
-
case
|
|
118
|
-
return status ===
|
|
119
|
-
case
|
|
120
|
-
return status ===
|
|
121
|
-
case
|
|
97
|
+
case constant.TaskStatusEnum.ATTEMPT_SUSPENDING:
|
|
98
|
+
return status === constant.TaskStatusEnum.RUNNING;
|
|
99
|
+
case constant.TaskStatusEnum.ATTEMPT_RESUMING:
|
|
100
|
+
return status === constant.TaskStatusEnum.SUSPENDED;
|
|
101
|
+
case constant.TaskStatusEnum.ATTEMPT_CANCELING:
|
|
122
102
|
return (status & alive) > 0;
|
|
123
|
-
case
|
|
124
|
-
return status !==
|
|
103
|
+
case constant.TaskStatusEnum.ATTEMPT_FINISHING:
|
|
104
|
+
return status !== constant.TaskStatusEnum.PENDING && (status & alive) > 0;
|
|
125
105
|
default:
|
|
126
106
|
return false;
|
|
127
107
|
}
|
|
@@ -129,13 +109,13 @@ class TaskState {
|
|
|
129
109
|
cleanup() {
|
|
130
110
|
if (!this.terminated)
|
|
131
111
|
throw new Error(`[cleanup] task(${this.name}) is not terminated`);
|
|
132
|
-
this.
|
|
112
|
+
this._errorCollector.cleanup();
|
|
133
113
|
this._monitors.onStatusChange.destroy();
|
|
134
114
|
this._monitors.onAddError.destroy();
|
|
135
115
|
}
|
|
136
|
-
_addError(type, error) {
|
|
137
|
-
this.
|
|
138
|
-
this._monitors.onAddError.notify(type, error);
|
|
116
|
+
_addError(type, error, level = constant.ErrorLevelEnum.ERROR) {
|
|
117
|
+
this._errorCollector.add(type, error, level);
|
|
118
|
+
this._monitors.onAddError.notify(type, error, level);
|
|
139
119
|
}
|
|
140
120
|
}
|
|
141
121
|
|
|
@@ -146,15 +126,15 @@ class AtomicTask extends TaskState {
|
|
|
146
126
|
this._promise = undefined;
|
|
147
127
|
}
|
|
148
128
|
async start() {
|
|
149
|
-
if (this.status ===
|
|
150
|
-
this.status =
|
|
129
|
+
if (this.status === constant.TaskStatusEnum.PENDING) {
|
|
130
|
+
this.status = constant.TaskStatusEnum.RUNNING;
|
|
151
131
|
this._promise = this.run()
|
|
152
132
|
.then(() => {
|
|
153
|
-
this.status =
|
|
133
|
+
this.status = constant.TaskStatusEnum.FINISHED;
|
|
154
134
|
})
|
|
155
135
|
.catch(error => {
|
|
156
|
-
this.status = exports.TaskStatus.FAILED;
|
|
157
136
|
this._addError('AtomicTaskError', error);
|
|
137
|
+
this.status = constant.TaskStatusEnum.FAILED;
|
|
158
138
|
});
|
|
159
139
|
}
|
|
160
140
|
return this._promise;
|
|
@@ -166,20 +146,20 @@ class AtomicTask extends TaskState {
|
|
|
166
146
|
await this._promise;
|
|
167
147
|
}
|
|
168
148
|
async cancel() {
|
|
169
|
-
if (this.status ===
|
|
170
|
-
this.status =
|
|
171
|
-
this.status =
|
|
149
|
+
if (this.status === constant.TaskStatusEnum.PENDING) {
|
|
150
|
+
this.status = constant.TaskStatusEnum.ATTEMPT_CANCELING;
|
|
151
|
+
this.status = constant.TaskStatusEnum.CANCELLED;
|
|
172
152
|
return;
|
|
173
153
|
}
|
|
174
154
|
if (this.alive)
|
|
175
|
-
this.status =
|
|
155
|
+
this.status = constant.TaskStatusEnum.ATTEMPT_CANCELING;
|
|
176
156
|
await this._promise;
|
|
177
157
|
}
|
|
178
158
|
async finish() {
|
|
179
|
-
if (this.status ===
|
|
159
|
+
if (this.status === constant.TaskStatusEnum.PENDING)
|
|
180
160
|
await this.start();
|
|
181
161
|
if (this.alive)
|
|
182
|
-
this.status =
|
|
162
|
+
this.status = constant.TaskStatusEnum.ATTEMPT_FINISHING;
|
|
183
163
|
await this._promise;
|
|
184
164
|
}
|
|
185
165
|
}
|
|
@@ -197,63 +177,63 @@ class ResumableTask extends TaskState {
|
|
|
197
177
|
this._step = undefined;
|
|
198
178
|
}
|
|
199
179
|
async start() {
|
|
200
|
-
if (this.status ===
|
|
201
|
-
this.status =
|
|
180
|
+
if (this.status === constant.TaskStatusEnum.PENDING) {
|
|
181
|
+
this.status = constant.TaskStatusEnum.RUNNING;
|
|
202
182
|
this._execution = this.run();
|
|
203
183
|
this.launchStep();
|
|
204
184
|
await this._step;
|
|
205
185
|
}
|
|
206
186
|
}
|
|
207
187
|
async pause() {
|
|
208
|
-
if (this.status ===
|
|
209
|
-
this.status =
|
|
188
|
+
if (this.status === constant.TaskStatusEnum.RUNNING) {
|
|
189
|
+
this.status = constant.TaskStatusEnum.ATTEMPT_SUSPENDING;
|
|
210
190
|
await this._step;
|
|
211
|
-
if (this.status ===
|
|
212
|
-
this.status =
|
|
191
|
+
if (this.status === constant.TaskStatusEnum.ATTEMPT_SUSPENDING) {
|
|
192
|
+
this.status = constant.TaskStatusEnum.SUSPENDED;
|
|
213
193
|
}
|
|
214
194
|
}
|
|
215
195
|
}
|
|
216
196
|
async resume() {
|
|
217
|
-
if (this.status ===
|
|
218
|
-
this.status =
|
|
197
|
+
if (this.status === constant.TaskStatusEnum.SUSPENDED) {
|
|
198
|
+
this.status = constant.TaskStatusEnum.ATTEMPT_RESUMING;
|
|
219
199
|
await this._step;
|
|
220
|
-
if (this.status ===
|
|
221
|
-
this.status =
|
|
200
|
+
if (this.status === constant.TaskStatusEnum.ATTEMPT_RESUMING) {
|
|
201
|
+
this.status = constant.TaskStatusEnum.RUNNING;
|
|
222
202
|
this.queueStep();
|
|
223
203
|
}
|
|
224
204
|
}
|
|
225
205
|
}
|
|
226
206
|
async cancel() {
|
|
227
207
|
if (this.alive) {
|
|
228
|
-
this.status =
|
|
208
|
+
this.status = constant.TaskStatusEnum.ATTEMPT_CANCELING;
|
|
229
209
|
await this._step;
|
|
230
|
-
if (this.status ===
|
|
231
|
-
this.status =
|
|
210
|
+
if (this.status === constant.TaskStatusEnum.ATTEMPT_CANCELING) {
|
|
211
|
+
this.status = constant.TaskStatusEnum.CANCELLED;
|
|
232
212
|
}
|
|
233
213
|
}
|
|
234
214
|
}
|
|
235
215
|
async finish() {
|
|
236
|
-
if (this.status ===
|
|
216
|
+
if (this.status === constant.TaskStatusEnum.PENDING)
|
|
237
217
|
await this.start();
|
|
238
218
|
if (this.alive) {
|
|
239
|
-
this.status =
|
|
219
|
+
this.status = constant.TaskStatusEnum.ATTEMPT_FINISHING;
|
|
240
220
|
await this._step;
|
|
241
221
|
const execution = this._execution;
|
|
242
222
|
if (execution) {
|
|
243
|
-
while (this.status ===
|
|
223
|
+
while (this.status === constant.TaskStatusEnum.ATTEMPT_FINISHING) {
|
|
244
224
|
const step = execution.next();
|
|
245
225
|
if (step.done) {
|
|
246
|
-
this.status = this.hasError ?
|
|
226
|
+
this.status = this.hasError ? constant.TaskStatusEnum.FAILED : constant.TaskStatusEnum.FINISHED;
|
|
247
227
|
break;
|
|
248
228
|
}
|
|
249
229
|
await step.value.catch(error => {
|
|
250
230
|
this._addError('ResumableTaskError', error);
|
|
251
231
|
switch (this.strategy) {
|
|
252
|
-
case
|
|
232
|
+
case constant.TaskStrategyEnum.ABORT_ON_ERROR:
|
|
253
233
|
if (!this.terminated)
|
|
254
|
-
this.status =
|
|
234
|
+
this.status = constant.TaskStatusEnum.FAILED;
|
|
255
235
|
break;
|
|
256
|
-
case
|
|
236
|
+
case constant.TaskStrategyEnum.CONTINUE_ON_ERROR:
|
|
257
237
|
break;
|
|
258
238
|
}
|
|
259
239
|
});
|
|
@@ -262,10 +242,10 @@ class ResumableTask extends TaskState {
|
|
|
262
242
|
}
|
|
263
243
|
}
|
|
264
244
|
launchStep() {
|
|
265
|
-
if (this.status ===
|
|
245
|
+
if (this.status === constant.TaskStatusEnum.RUNNING && this._step === undefined && this._execution) {
|
|
266
246
|
const step = this._execution.next();
|
|
267
247
|
if (step.done) {
|
|
268
|
-
this.status = this.hasError ?
|
|
248
|
+
this.status = this.hasError ? constant.TaskStatusEnum.FAILED : constant.TaskStatusEnum.FINISHED;
|
|
269
249
|
return;
|
|
270
250
|
}
|
|
271
251
|
this._step = step.value
|
|
@@ -277,11 +257,11 @@ class ResumableTask extends TaskState {
|
|
|
277
257
|
this._step = undefined;
|
|
278
258
|
this._addError('ResumableTaskError', error);
|
|
279
259
|
switch (this.strategy) {
|
|
280
|
-
case
|
|
260
|
+
case constant.TaskStrategyEnum.ABORT_ON_ERROR:
|
|
281
261
|
if (!this.terminated)
|
|
282
|
-
this.status =
|
|
262
|
+
this.status = constant.TaskStatusEnum.FAILED;
|
|
283
263
|
break;
|
|
284
|
-
case
|
|
264
|
+
case constant.TaskStrategyEnum.CONTINUE_ON_ERROR:
|
|
285
265
|
this.queueStep();
|
|
286
266
|
break;
|
|
287
267
|
}
|
|
@@ -296,6 +276,3 @@ class ResumableTask extends TaskState {
|
|
|
296
276
|
exports.AtomicTask = AtomicTask;
|
|
297
277
|
exports.ResumableTask = ResumableTask;
|
|
298
278
|
exports.TaskState = TaskState;
|
|
299
|
-
exports.active = active;
|
|
300
|
-
exports.alive = alive;
|
|
301
|
-
exports.terminated = terminated;
|
package/lib/esm/index.mjs
CHANGED
|
@@ -1,49 +1,33 @@
|
|
|
1
|
+
import { TaskStatusEnum, ErrorLevelEnum, TaskStrategyEnum } from '@guanghechen/constant';
|
|
2
|
+
import { SoraErrorCollector } from '@guanghechen/error';
|
|
1
3
|
import { Monitor } from '@guanghechen/monitor';
|
|
2
4
|
|
|
3
|
-
|
|
4
|
-
(function (TaskStatus) {
|
|
5
|
-
TaskStatus[TaskStatus["PENDING"] = 1] = "PENDING";
|
|
6
|
-
TaskStatus[TaskStatus["RUNNING"] = 2] = "RUNNING";
|
|
7
|
-
TaskStatus[TaskStatus["SUSPENDED"] = 4] = "SUSPENDED";
|
|
8
|
-
TaskStatus[TaskStatus["CANCELLED"] = 8] = "CANCELLED";
|
|
9
|
-
TaskStatus[TaskStatus["FAILED"] = 16] = "FAILED";
|
|
10
|
-
TaskStatus[TaskStatus["FINISHED"] = 32] = "FINISHED";
|
|
11
|
-
TaskStatus[TaskStatus["ATTEMPT_SUSPENDING"] = 64] = "ATTEMPT_SUSPENDING";
|
|
12
|
-
TaskStatus[TaskStatus["ATTEMPT_RESUMING"] = 128] = "ATTEMPT_RESUMING";
|
|
13
|
-
TaskStatus[TaskStatus["ATTEMPT_CANCELING"] = 256] = "ATTEMPT_CANCELING";
|
|
14
|
-
TaskStatus[TaskStatus["ATTEMPT_FINISHING"] = 512] = "ATTEMPT_FINISHING";
|
|
15
|
-
})(TaskStatus || (TaskStatus = {}));
|
|
16
|
-
var TaskStrategy;
|
|
17
|
-
(function (TaskStrategy) {
|
|
18
|
-
TaskStrategy[TaskStrategy["ABORT_ON_ERROR"] = 1] = "ABORT_ON_ERROR";
|
|
19
|
-
TaskStrategy[TaskStrategy["CONTINUE_ON_ERROR"] = 2] = "CONTINUE_ON_ERROR";
|
|
20
|
-
})(TaskStrategy || (TaskStrategy = {}));
|
|
21
|
-
const active = TaskStatus.RUNNING |
|
|
22
|
-
TaskStatus.ATTEMPT_SUSPENDING |
|
|
23
|
-
TaskStatus.ATTEMPT_RESUMING;
|
|
24
|
-
const alive = TaskStatus.PENDING |
|
|
25
|
-
TaskStatus.RUNNING |
|
|
26
|
-
TaskStatus.SUSPENDED |
|
|
27
|
-
TaskStatus.ATTEMPT_SUSPENDING |
|
|
28
|
-
TaskStatus.ATTEMPT_RESUMING;
|
|
29
|
-
const terminated = TaskStatus.CANCELLED |
|
|
30
|
-
TaskStatus.FAILED |
|
|
31
|
-
TaskStatus.FINISHED;
|
|
5
|
+
function noop(..._args) { }
|
|
32
6
|
|
|
33
|
-
const
|
|
7
|
+
const active = TaskStatusEnum.RUNNING |
|
|
8
|
+
TaskStatusEnum.ATTEMPT_SUSPENDING |
|
|
9
|
+
TaskStatusEnum.ATTEMPT_RESUMING;
|
|
10
|
+
const alive = TaskStatusEnum.PENDING |
|
|
11
|
+
TaskStatusEnum.RUNNING |
|
|
12
|
+
TaskStatusEnum.SUSPENDED |
|
|
13
|
+
TaskStatusEnum.ATTEMPT_SUSPENDING |
|
|
14
|
+
TaskStatusEnum.ATTEMPT_RESUMING;
|
|
15
|
+
const terminated = TaskStatusEnum.CANCELLED |
|
|
16
|
+
TaskStatusEnum.FAILED |
|
|
17
|
+
TaskStatusEnum.FINISHED;
|
|
34
18
|
class TaskState {
|
|
35
19
|
name;
|
|
20
|
+
_errorCollector;
|
|
36
21
|
_monitors;
|
|
37
|
-
_errorDetails;
|
|
38
22
|
_status;
|
|
39
23
|
constructor(name) {
|
|
40
24
|
this.name = name;
|
|
25
|
+
this._errorCollector = new SoraErrorCollector(name);
|
|
41
26
|
this._monitors = {
|
|
42
27
|
onAddError: new Monitor('onAddError'),
|
|
43
28
|
onStatusChange: new Monitor('onStatusChange'),
|
|
44
29
|
};
|
|
45
|
-
this.
|
|
46
|
-
this._status = TaskStatus.PENDING;
|
|
30
|
+
this._status = TaskStatusEnum.PENDING;
|
|
47
31
|
}
|
|
48
32
|
get status() {
|
|
49
33
|
return this._status;
|
|
@@ -58,12 +42,12 @@ class TaskState {
|
|
|
58
42
|
return (this._status & terminated) > 0;
|
|
59
43
|
}
|
|
60
44
|
get hasError() {
|
|
61
|
-
return this.
|
|
45
|
+
return this._errorCollector.size > 0;
|
|
62
46
|
}
|
|
63
47
|
get error() {
|
|
64
|
-
if (this.
|
|
48
|
+
if (this._errorCollector.size === 0)
|
|
65
49
|
return undefined;
|
|
66
|
-
return { from: this.name, details: this.
|
|
50
|
+
return { from: this.name, details: this._errorCollector.errors };
|
|
67
51
|
}
|
|
68
52
|
set status(status) {
|
|
69
53
|
const curStatus = this._status;
|
|
@@ -82,12 +66,8 @@ class TaskState {
|
|
|
82
66
|
if (this.terminated)
|
|
83
67
|
return noop;
|
|
84
68
|
const { onAddError, onStatusChange } = monitor;
|
|
85
|
-
const unsubscribeOnAddError = onAddError
|
|
86
|
-
|
|
87
|
-
: noop;
|
|
88
|
-
const unsubscribeOnStatusChange = onStatusChange
|
|
89
|
-
? this._monitors.onStatusChange.subscribe(onStatusChange)
|
|
90
|
-
: noop;
|
|
69
|
+
const unsubscribeOnAddError = this._monitors.onAddError.subscribe(onAddError);
|
|
70
|
+
const unsubscribeOnStatusChange = this._monitors.onStatusChange.subscribe(onStatusChange);
|
|
91
71
|
return () => {
|
|
92
72
|
unsubscribeOnAddError();
|
|
93
73
|
unsubscribeOnStatusChange();
|
|
@@ -96,30 +76,30 @@ class TaskState {
|
|
|
96
76
|
check(nextStatus) {
|
|
97
77
|
const status = this._status;
|
|
98
78
|
switch (nextStatus) {
|
|
99
|
-
case
|
|
79
|
+
case TaskStatusEnum.PENDING:
|
|
100
80
|
return false;
|
|
101
|
-
case
|
|
102
|
-
return status ===
|
|
103
|
-
case
|
|
104
|
-
return status ===
|
|
105
|
-
case
|
|
106
|
-
return status ===
|
|
107
|
-
case
|
|
108
|
-
return (status !==
|
|
109
|
-
status !==
|
|
81
|
+
case TaskStatusEnum.RUNNING:
|
|
82
|
+
return status === TaskStatusEnum.PENDING || status === TaskStatusEnum.ATTEMPT_RESUMING;
|
|
83
|
+
case TaskStatusEnum.SUSPENDED:
|
|
84
|
+
return status === TaskStatusEnum.ATTEMPT_SUSPENDING;
|
|
85
|
+
case TaskStatusEnum.CANCELLED:
|
|
86
|
+
return status === TaskStatusEnum.ATTEMPT_CANCELING;
|
|
87
|
+
case TaskStatusEnum.FAILED:
|
|
88
|
+
return (status !== TaskStatusEnum.PENDING &&
|
|
89
|
+
status !== TaskStatusEnum.SUSPENDED &&
|
|
110
90
|
(status & terminated) === 0);
|
|
111
|
-
case
|
|
112
|
-
return (status !==
|
|
113
|
-
status !==
|
|
91
|
+
case TaskStatusEnum.FINISHED:
|
|
92
|
+
return (status !== TaskStatusEnum.PENDING &&
|
|
93
|
+
status !== TaskStatusEnum.SUSPENDED &&
|
|
114
94
|
(status & terminated) === 0);
|
|
115
|
-
case
|
|
116
|
-
return status ===
|
|
117
|
-
case
|
|
118
|
-
return status ===
|
|
119
|
-
case
|
|
95
|
+
case TaskStatusEnum.ATTEMPT_SUSPENDING:
|
|
96
|
+
return status === TaskStatusEnum.RUNNING;
|
|
97
|
+
case TaskStatusEnum.ATTEMPT_RESUMING:
|
|
98
|
+
return status === TaskStatusEnum.SUSPENDED;
|
|
99
|
+
case TaskStatusEnum.ATTEMPT_CANCELING:
|
|
120
100
|
return (status & alive) > 0;
|
|
121
|
-
case
|
|
122
|
-
return status !==
|
|
101
|
+
case TaskStatusEnum.ATTEMPT_FINISHING:
|
|
102
|
+
return status !== TaskStatusEnum.PENDING && (status & alive) > 0;
|
|
123
103
|
default:
|
|
124
104
|
return false;
|
|
125
105
|
}
|
|
@@ -127,13 +107,13 @@ class TaskState {
|
|
|
127
107
|
cleanup() {
|
|
128
108
|
if (!this.terminated)
|
|
129
109
|
throw new Error(`[cleanup] task(${this.name}) is not terminated`);
|
|
130
|
-
this.
|
|
110
|
+
this._errorCollector.cleanup();
|
|
131
111
|
this._monitors.onStatusChange.destroy();
|
|
132
112
|
this._monitors.onAddError.destroy();
|
|
133
113
|
}
|
|
134
|
-
_addError(type, error) {
|
|
135
|
-
this.
|
|
136
|
-
this._monitors.onAddError.notify(type, error);
|
|
114
|
+
_addError(type, error, level = ErrorLevelEnum.ERROR) {
|
|
115
|
+
this._errorCollector.add(type, error, level);
|
|
116
|
+
this._monitors.onAddError.notify(type, error, level);
|
|
137
117
|
}
|
|
138
118
|
}
|
|
139
119
|
|
|
@@ -144,15 +124,15 @@ class AtomicTask extends TaskState {
|
|
|
144
124
|
this._promise = undefined;
|
|
145
125
|
}
|
|
146
126
|
async start() {
|
|
147
|
-
if (this.status ===
|
|
148
|
-
this.status =
|
|
127
|
+
if (this.status === TaskStatusEnum.PENDING) {
|
|
128
|
+
this.status = TaskStatusEnum.RUNNING;
|
|
149
129
|
this._promise = this.run()
|
|
150
130
|
.then(() => {
|
|
151
|
-
this.status =
|
|
131
|
+
this.status = TaskStatusEnum.FINISHED;
|
|
152
132
|
})
|
|
153
133
|
.catch(error => {
|
|
154
|
-
this.status = TaskStatus.FAILED;
|
|
155
134
|
this._addError('AtomicTaskError', error);
|
|
135
|
+
this.status = TaskStatusEnum.FAILED;
|
|
156
136
|
});
|
|
157
137
|
}
|
|
158
138
|
return this._promise;
|
|
@@ -164,20 +144,20 @@ class AtomicTask extends TaskState {
|
|
|
164
144
|
await this._promise;
|
|
165
145
|
}
|
|
166
146
|
async cancel() {
|
|
167
|
-
if (this.status ===
|
|
168
|
-
this.status =
|
|
169
|
-
this.status =
|
|
147
|
+
if (this.status === TaskStatusEnum.PENDING) {
|
|
148
|
+
this.status = TaskStatusEnum.ATTEMPT_CANCELING;
|
|
149
|
+
this.status = TaskStatusEnum.CANCELLED;
|
|
170
150
|
return;
|
|
171
151
|
}
|
|
172
152
|
if (this.alive)
|
|
173
|
-
this.status =
|
|
153
|
+
this.status = TaskStatusEnum.ATTEMPT_CANCELING;
|
|
174
154
|
await this._promise;
|
|
175
155
|
}
|
|
176
156
|
async finish() {
|
|
177
|
-
if (this.status ===
|
|
157
|
+
if (this.status === TaskStatusEnum.PENDING)
|
|
178
158
|
await this.start();
|
|
179
159
|
if (this.alive)
|
|
180
|
-
this.status =
|
|
160
|
+
this.status = TaskStatusEnum.ATTEMPT_FINISHING;
|
|
181
161
|
await this._promise;
|
|
182
162
|
}
|
|
183
163
|
}
|
|
@@ -195,63 +175,63 @@ class ResumableTask extends TaskState {
|
|
|
195
175
|
this._step = undefined;
|
|
196
176
|
}
|
|
197
177
|
async start() {
|
|
198
|
-
if (this.status ===
|
|
199
|
-
this.status =
|
|
178
|
+
if (this.status === TaskStatusEnum.PENDING) {
|
|
179
|
+
this.status = TaskStatusEnum.RUNNING;
|
|
200
180
|
this._execution = this.run();
|
|
201
181
|
this.launchStep();
|
|
202
182
|
await this._step;
|
|
203
183
|
}
|
|
204
184
|
}
|
|
205
185
|
async pause() {
|
|
206
|
-
if (this.status ===
|
|
207
|
-
this.status =
|
|
186
|
+
if (this.status === TaskStatusEnum.RUNNING) {
|
|
187
|
+
this.status = TaskStatusEnum.ATTEMPT_SUSPENDING;
|
|
208
188
|
await this._step;
|
|
209
|
-
if (this.status ===
|
|
210
|
-
this.status =
|
|
189
|
+
if (this.status === TaskStatusEnum.ATTEMPT_SUSPENDING) {
|
|
190
|
+
this.status = TaskStatusEnum.SUSPENDED;
|
|
211
191
|
}
|
|
212
192
|
}
|
|
213
193
|
}
|
|
214
194
|
async resume() {
|
|
215
|
-
if (this.status ===
|
|
216
|
-
this.status =
|
|
195
|
+
if (this.status === TaskStatusEnum.SUSPENDED) {
|
|
196
|
+
this.status = TaskStatusEnum.ATTEMPT_RESUMING;
|
|
217
197
|
await this._step;
|
|
218
|
-
if (this.status ===
|
|
219
|
-
this.status =
|
|
198
|
+
if (this.status === TaskStatusEnum.ATTEMPT_RESUMING) {
|
|
199
|
+
this.status = TaskStatusEnum.RUNNING;
|
|
220
200
|
this.queueStep();
|
|
221
201
|
}
|
|
222
202
|
}
|
|
223
203
|
}
|
|
224
204
|
async cancel() {
|
|
225
205
|
if (this.alive) {
|
|
226
|
-
this.status =
|
|
206
|
+
this.status = TaskStatusEnum.ATTEMPT_CANCELING;
|
|
227
207
|
await this._step;
|
|
228
|
-
if (this.status ===
|
|
229
|
-
this.status =
|
|
208
|
+
if (this.status === TaskStatusEnum.ATTEMPT_CANCELING) {
|
|
209
|
+
this.status = TaskStatusEnum.CANCELLED;
|
|
230
210
|
}
|
|
231
211
|
}
|
|
232
212
|
}
|
|
233
213
|
async finish() {
|
|
234
|
-
if (this.status ===
|
|
214
|
+
if (this.status === TaskStatusEnum.PENDING)
|
|
235
215
|
await this.start();
|
|
236
216
|
if (this.alive) {
|
|
237
|
-
this.status =
|
|
217
|
+
this.status = TaskStatusEnum.ATTEMPT_FINISHING;
|
|
238
218
|
await this._step;
|
|
239
219
|
const execution = this._execution;
|
|
240
220
|
if (execution) {
|
|
241
|
-
while (this.status ===
|
|
221
|
+
while (this.status === TaskStatusEnum.ATTEMPT_FINISHING) {
|
|
242
222
|
const step = execution.next();
|
|
243
223
|
if (step.done) {
|
|
244
|
-
this.status = this.hasError ?
|
|
224
|
+
this.status = this.hasError ? TaskStatusEnum.FAILED : TaskStatusEnum.FINISHED;
|
|
245
225
|
break;
|
|
246
226
|
}
|
|
247
227
|
await step.value.catch(error => {
|
|
248
228
|
this._addError('ResumableTaskError', error);
|
|
249
229
|
switch (this.strategy) {
|
|
250
|
-
case
|
|
230
|
+
case TaskStrategyEnum.ABORT_ON_ERROR:
|
|
251
231
|
if (!this.terminated)
|
|
252
|
-
this.status =
|
|
232
|
+
this.status = TaskStatusEnum.FAILED;
|
|
253
233
|
break;
|
|
254
|
-
case
|
|
234
|
+
case TaskStrategyEnum.CONTINUE_ON_ERROR:
|
|
255
235
|
break;
|
|
256
236
|
}
|
|
257
237
|
});
|
|
@@ -260,10 +240,10 @@ class ResumableTask extends TaskState {
|
|
|
260
240
|
}
|
|
261
241
|
}
|
|
262
242
|
launchStep() {
|
|
263
|
-
if (this.status ===
|
|
243
|
+
if (this.status === TaskStatusEnum.RUNNING && this._step === undefined && this._execution) {
|
|
264
244
|
const step = this._execution.next();
|
|
265
245
|
if (step.done) {
|
|
266
|
-
this.status = this.hasError ?
|
|
246
|
+
this.status = this.hasError ? TaskStatusEnum.FAILED : TaskStatusEnum.FINISHED;
|
|
267
247
|
return;
|
|
268
248
|
}
|
|
269
249
|
this._step = step.value
|
|
@@ -275,11 +255,11 @@ class ResumableTask extends TaskState {
|
|
|
275
255
|
this._step = undefined;
|
|
276
256
|
this._addError('ResumableTaskError', error);
|
|
277
257
|
switch (this.strategy) {
|
|
278
|
-
case
|
|
258
|
+
case TaskStrategyEnum.ABORT_ON_ERROR:
|
|
279
259
|
if (!this.terminated)
|
|
280
|
-
this.status =
|
|
260
|
+
this.status = TaskStatusEnum.FAILED;
|
|
281
261
|
break;
|
|
282
|
-
case
|
|
262
|
+
case TaskStrategyEnum.CONTINUE_ON_ERROR:
|
|
283
263
|
this.queueStep();
|
|
284
264
|
break;
|
|
285
265
|
}
|
|
@@ -291,4 +271,4 @@ class ResumableTask extends TaskState {
|
|
|
291
271
|
}
|
|
292
272
|
}
|
|
293
273
|
|
|
294
|
-
export { AtomicTask, ResumableTask, TaskState
|
|
274
|
+
export { AtomicTask, ResumableTask, TaskState };
|
package/lib/types/index.d.ts
CHANGED
|
@@ -1,104 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
RUNNING = 2,
|
|
4
|
-
SUSPENDED = 4,
|
|
5
|
-
CANCELLED = 8,
|
|
6
|
-
FAILED = 16,
|
|
7
|
-
FINISHED = 32,
|
|
8
|
-
ATTEMPT_SUSPENDING = 64,
|
|
9
|
-
ATTEMPT_RESUMING = 128,
|
|
10
|
-
ATTEMPT_CANCELING = 256,
|
|
11
|
-
ATTEMPT_FINISHING = 512
|
|
12
|
-
}
|
|
13
|
-
declare enum TaskStrategy {
|
|
14
|
-
ABORT_ON_ERROR = 1,
|
|
15
|
-
CONTINUE_ON_ERROR = 2
|
|
16
|
-
}
|
|
17
|
-
declare const active: number;
|
|
18
|
-
declare const alive: number;
|
|
19
|
-
declare const terminated: number;
|
|
20
|
-
|
|
21
|
-
interface ITaskErrorDetail {
|
|
22
|
-
type: string;
|
|
23
|
-
error: unknown;
|
|
24
|
-
}
|
|
25
|
-
interface ITaskError {
|
|
26
|
-
from: string;
|
|
27
|
-
details: ITaskErrorDetail[];
|
|
28
|
-
}
|
|
29
|
-
interface ITaskMonitor {
|
|
30
|
-
onAddError(type: string, error: unknown): void;
|
|
31
|
-
onStatusChange(status: TaskStatus, prevStatus: TaskStatus): void;
|
|
32
|
-
}
|
|
33
|
-
type IUnMonitorTask = () => void;
|
|
34
|
-
interface ITaskState {
|
|
35
|
-
readonly status: TaskStatus;
|
|
36
|
-
readonly active: boolean;
|
|
37
|
-
readonly alive: boolean;
|
|
38
|
-
readonly terminated: boolean;
|
|
39
|
-
}
|
|
40
|
-
interface ITask extends ITaskState {
|
|
41
|
-
/**
|
|
42
|
-
* Task name.
|
|
43
|
-
*/
|
|
44
|
-
readonly name: string;
|
|
45
|
-
/**
|
|
46
|
-
* Task error.
|
|
47
|
-
*/
|
|
48
|
-
readonly error: ITaskError | undefined;
|
|
49
|
-
/**
|
|
50
|
-
* Indicate if the task has error.
|
|
51
|
-
*/
|
|
52
|
-
readonly hasError: boolean;
|
|
53
|
-
/**
|
|
54
|
-
* Start the task.
|
|
55
|
-
*/
|
|
56
|
-
start(): Promise<void>;
|
|
57
|
-
/**
|
|
58
|
-
* Pause the task.
|
|
59
|
-
*/
|
|
60
|
-
pause(): Promise<void>;
|
|
61
|
-
/**
|
|
62
|
-
* Resume the task.
|
|
63
|
-
*/
|
|
64
|
-
resume(): Promise<void>;
|
|
65
|
-
/**
|
|
66
|
-
* Cancel the task.
|
|
67
|
-
*/
|
|
68
|
-
cancel(): Promise<void>;
|
|
69
|
-
/**
|
|
70
|
-
* finish the task: run to completed no matter if the task started or not.
|
|
71
|
-
*/
|
|
72
|
-
finish(): Promise<void>;
|
|
73
|
-
/**
|
|
74
|
-
* Perform a clean up.
|
|
75
|
-
* Will thrown an error if the task is not terminated.
|
|
76
|
-
*/
|
|
77
|
-
cleanup(): void;
|
|
78
|
-
/**
|
|
79
|
-
* Register a monitor to subscribe the task changes.
|
|
80
|
-
* @param monitor
|
|
81
|
-
*/
|
|
82
|
-
monitor(monitor: Partial<ITaskMonitor>): IUnMonitorTask;
|
|
83
|
-
}
|
|
1
|
+
import { ITaskState, ISoraErrorCollector, ITaskError, ITaskMonitor, IUnMonitorTask, ITask } from '@guanghechen/types';
|
|
2
|
+
import { TaskStatusEnum, ErrorLevelEnum, TaskStrategyEnum } from '@guanghechen/constant';
|
|
84
3
|
|
|
85
4
|
declare class TaskState implements ITaskState {
|
|
86
5
|
readonly name: string;
|
|
6
|
+
protected readonly _errorCollector: ISoraErrorCollector;
|
|
87
7
|
private readonly _monitors;
|
|
88
|
-
private readonly _errorDetails;
|
|
89
8
|
private _status;
|
|
90
9
|
constructor(name: string);
|
|
91
|
-
get status():
|
|
10
|
+
get status(): TaskStatusEnum;
|
|
92
11
|
get active(): boolean;
|
|
93
12
|
get alive(): boolean;
|
|
94
13
|
get terminated(): boolean;
|
|
95
14
|
get hasError(): boolean;
|
|
96
15
|
get error(): ITaskError | undefined;
|
|
97
|
-
set status(status:
|
|
16
|
+
set status(status: TaskStatusEnum);
|
|
98
17
|
monitor(monitor: Partial<ITaskMonitor>): IUnMonitorTask;
|
|
99
|
-
check(nextStatus:
|
|
18
|
+
check(nextStatus: TaskStatusEnum): boolean;
|
|
100
19
|
cleanup(): void;
|
|
101
|
-
protected _addError(type: string, error: unknown): void;
|
|
20
|
+
protected _addError(type: string, error: unknown, level?: ErrorLevelEnum): void;
|
|
102
21
|
}
|
|
103
22
|
|
|
104
23
|
declare abstract class AtomicTask extends TaskState implements ITask {
|
|
@@ -114,11 +33,11 @@ declare abstract class AtomicTask extends TaskState implements ITask {
|
|
|
114
33
|
|
|
115
34
|
interface IResumableTaskProps {
|
|
116
35
|
name: string;
|
|
117
|
-
strategy:
|
|
36
|
+
strategy: TaskStrategyEnum;
|
|
118
37
|
pollInterval: number;
|
|
119
38
|
}
|
|
120
39
|
declare abstract class ResumableTask extends TaskState implements ITask {
|
|
121
|
-
readonly strategy:
|
|
40
|
+
readonly strategy: TaskStrategyEnum;
|
|
122
41
|
private readonly _pollInterval;
|
|
123
42
|
private _execution;
|
|
124
43
|
private _step;
|
|
@@ -133,4 +52,4 @@ declare abstract class ResumableTask extends TaskState implements ITask {
|
|
|
133
52
|
private queueStep;
|
|
134
53
|
}
|
|
135
54
|
|
|
136
|
-
export { AtomicTask,
|
|
55
|
+
export { AtomicTask, ResumableTask, TaskState };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@guanghechen/task",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.3",
|
|
4
4
|
"description": "Atomic and resumable tasks",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "guanghechen",
|
|
@@ -8,10 +8,10 @@
|
|
|
8
8
|
},
|
|
9
9
|
"repository": {
|
|
10
10
|
"type": "git",
|
|
11
|
-
"url": "https://github.com/guanghechen/sora/tree/@guanghechen/task@
|
|
11
|
+
"url": "https://github.com/guanghechen/sora/tree/@guanghechen/task@1.0.0-alpha.2",
|
|
12
12
|
"directory": "packages/task"
|
|
13
13
|
},
|
|
14
|
-
"homepage": "https://github.com/guanghechen/sora/tree/@guanghechen/task@
|
|
14
|
+
"homepage": "https://github.com/guanghechen/sora/tree/@guanghechen/task@1.0.0-alpha.2/packages/task#readme",
|
|
15
15
|
"type": "module",
|
|
16
16
|
"main": "./lib/cjs/index.cjs",
|
|
17
17
|
"module": "./lib/esm/index.mjs",
|
|
@@ -39,13 +39,16 @@
|
|
|
39
39
|
"test": "node --experimental-vm-modules ../../node_modules/.bin/jest --config ../../jest.config.mjs --rootDir ."
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
|
-
"@guanghechen/
|
|
42
|
+
"@guanghechen/constant": "^1.0.0-alpha.1",
|
|
43
|
+
"@guanghechen/error": "^1.0.0-alpha.3",
|
|
44
|
+
"@guanghechen/monitor": "^1.0.0-alpha.3"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
47
|
+
"@guanghechen/shared": "^1.0.0-alpha.3",
|
|
45
48
|
"cross-env": "^7.0.3",
|
|
46
49
|
"jest": "^29.6.4",
|
|
47
50
|
"rimraf": "^5.0.1",
|
|
48
51
|
"rollup": "^3.28.1"
|
|
49
52
|
},
|
|
50
|
-
"gitHead": "
|
|
53
|
+
"gitHead": "6209b28c7340c77e5954b697dddfa2893d8f30df"
|
|
51
54
|
}
|