@terreno/jobs 57.4.0 → 57.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/dist/activeJobExecution.js +7 -7
- package/dist/claimLock.js +12 -14
- package/dist/dispatchCompensation.js +29 -83
- package/dist/dispatchError.js +12 -28
- package/dist/jobExecutor.js +178 -297
- package/dist/jobsApp.js +124 -234
- package/dist/jobsService.js +261 -461
- package/dist/models/job.js +9 -9
- package/dist/models/jobSchedule.js +4 -4
- package/dist/retryBackoff.js +11 -14
- package/dist/routes/jobsAdmin.js +189 -370
- package/dist/routes/jobsExecute.js +41 -101
- package/dist/runners/gcpCloudTasks.js +116 -200
- package/dist/runners/mongoRunner.js +90 -184
- package/dist/runners/vercelQueues.js +105 -194
- package/dist/scheduleCron.js +18 -27
- package/dist/scheduler.js +68 -170
- package/package.json +4 -4
- package/src/models/job.ts +4 -4
- package/src/models/jobSchedule.ts +3 -2
- package/src/tests/packageExports.test.ts +19 -3
- package/tsconfig.json +6 -21
package/dist/scheduler.js
CHANGED
|
@@ -1,178 +1,76 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
-
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
-
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
-
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
-
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
-
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
-
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
12
|
-
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
13
|
-
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
14
|
-
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
15
|
-
function step(op) {
|
|
16
|
-
if (f) throw new TypeError("Generator is already executing.");
|
|
17
|
-
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
18
|
-
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
19
|
-
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
20
|
-
switch (op[0]) {
|
|
21
|
-
case 0: case 1: t = op; break;
|
|
22
|
-
case 4: _.label++; return { value: op[1], done: false };
|
|
23
|
-
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
24
|
-
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
25
|
-
default:
|
|
26
|
-
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
27
|
-
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
28
|
-
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
29
|
-
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
30
|
-
if (t[2]) _.ops.pop();
|
|
31
|
-
_.trys.pop(); continue;
|
|
32
|
-
}
|
|
33
|
-
op = body.call(thisArg, _);
|
|
34
|
-
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
35
|
-
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
var __values = (this && this.__values) || function(o) {
|
|
39
|
-
var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
|
|
40
|
-
if (m) return m.call(o);
|
|
41
|
-
if (o && typeof o.length === "number") return {
|
|
42
|
-
next: function () {
|
|
43
|
-
if (o && i >= o.length) o = void 0;
|
|
44
|
-
return { value: o && o[i++], done: !o };
|
|
45
|
-
}
|
|
46
|
-
};
|
|
47
|
-
throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
|
|
48
|
-
};
|
|
49
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
3
|
exports.tickDueSchedules = exports.buildScheduleRunIdempotencyKey = void 0;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
4
|
+
const api_1 = require("@terreno/api");
|
|
5
|
+
const luxon_1 = require("luxon");
|
|
6
|
+
const dispatchError_1 = require("./dispatchError");
|
|
7
|
+
const job_1 = require("./models/job");
|
|
8
|
+
const jobSchedule_1 = require("./models/jobSchedule");
|
|
9
|
+
const modelTypes_1 = require("./modelTypes");
|
|
10
|
+
const scheduleCron_1 = require("./scheduleCron");
|
|
58
11
|
/** @internal */
|
|
59
|
-
|
|
60
|
-
return "schedule:".concat(scheduleId, ":").concat(dueRunAt.toISOString());
|
|
61
|
-
};
|
|
12
|
+
const buildScheduleRunIdempotencyKey = (scheduleId, dueRunAt) => `schedule:${scheduleId}:${dueRunAt.toISOString()}`;
|
|
62
13
|
exports.buildScheduleRunIdempotencyKey = buildScheduleRunIdempotencyKey;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
claimed = _c.sent();
|
|
82
|
-
if (!claimed) {
|
|
83
|
-
return [2 /*return*/];
|
|
84
|
-
}
|
|
85
|
-
return [4 /*yield*/, job_1.Job.findOneOrNone({
|
|
86
|
-
scheduleId: claimed._id,
|
|
87
|
-
status: { $in: modelTypes_1.IN_FLIGHT_JOB_STATUSES },
|
|
88
|
-
})];
|
|
89
|
-
case 2:
|
|
90
|
-
inFlight = _c.sent();
|
|
91
|
-
if (inFlight) {
|
|
92
|
-
return [2 /*return*/];
|
|
93
|
-
}
|
|
94
|
-
idempotencyKey = (0, exports.buildScheduleRunIdempotencyKey)(claimed._id.toString(), claimed.nextRunAt);
|
|
95
|
-
_c.label = 3;
|
|
96
|
-
case 3:
|
|
97
|
-
_c.trys.push([3, 5, , 9]);
|
|
98
|
-
return [4 /*yield*/, jobsService.enqueue({
|
|
99
|
-
idempotencyKey: idempotencyKey,
|
|
100
|
-
name: claimed.handlerName,
|
|
101
|
-
payload: {},
|
|
102
|
-
runAt: claimed.nextRunAt,
|
|
103
|
-
scheduleId: claimed._id.toString(),
|
|
104
|
-
})];
|
|
105
|
-
case 4:
|
|
106
|
-
_c.sent();
|
|
107
|
-
return [3 /*break*/, 9];
|
|
108
|
-
case 5:
|
|
109
|
-
error_1 = _c.sent();
|
|
110
|
-
shouldRollbackSchedule = !(error_1 instanceof dispatchError_1.JobDispatchError) || error_1.compensationSucceeded;
|
|
111
|
-
if (!shouldRollbackSchedule) return [3 /*break*/, 7];
|
|
112
|
-
return [4 /*yield*/, jobSchedule_1.JobSchedule.updateOne({ _id: claimed._id, nextRunAt: advancedNextRunAt }, { $set: { nextRunAt: dueRunAt } })];
|
|
113
|
-
case 6:
|
|
114
|
-
_c.sent();
|
|
115
|
-
return [3 /*break*/, 8];
|
|
116
|
-
case 7:
|
|
117
|
-
api_1.logger.error("[JobSchedule] Dispatch compensation lost race for \"".concat(claimed.name, "\" (").concat(claimed._id.toString(), "); schedule nextRunAt left advanced"));
|
|
118
|
-
_c.label = 8;
|
|
119
|
-
case 8: throw error_1;
|
|
120
|
-
case 9: return [2 /*return*/];
|
|
121
|
-
}
|
|
14
|
+
const tickOneSchedule = async ({ jobsService, now, schedule, }) => {
|
|
15
|
+
const dueRunAt = schedule.nextRunAt;
|
|
16
|
+
const advancedNextRunAt = (0, scheduleCron_1.computeNextRunAtAfter)(schedule.cron, schedule.timezone, now);
|
|
17
|
+
const claimed = await jobSchedule_1.JobSchedule.findOneAndUpdate({
|
|
18
|
+
_id: schedule._id,
|
|
19
|
+
enabled: true,
|
|
20
|
+
nextRunAt: dueRunAt,
|
|
21
|
+
}, {
|
|
22
|
+
$set: {
|
|
23
|
+
nextRunAt: advancedNextRunAt,
|
|
24
|
+
},
|
|
25
|
+
}, { returnDocument: "before" });
|
|
26
|
+
if (!claimed) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const inFlight = await job_1.Job.findOneOrNone({
|
|
30
|
+
scheduleId: claimed._id,
|
|
31
|
+
status: { $in: modelTypes_1.IN_FLIGHT_JOB_STATUSES },
|
|
122
32
|
});
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
_e.label = 3;
|
|
141
|
-
case 3:
|
|
142
|
-
if (!!dueSchedules_1_1.done) return [3 /*break*/, 8];
|
|
143
|
-
schedule = dueSchedules_1_1.value;
|
|
144
|
-
scheduleLog = (0, api_1.createScopedLogger)({
|
|
145
|
-
labels: { scheduleName: schedule.name },
|
|
146
|
-
prefix: "[JobSchedule]",
|
|
147
|
-
});
|
|
148
|
-
_e.label = 4;
|
|
149
|
-
case 4:
|
|
150
|
-
_e.trys.push([4, 6, , 7]);
|
|
151
|
-
return [4 /*yield*/, tickOneSchedule({ jobsService: jobsService, now: now, schedule: schedule })];
|
|
152
|
-
case 5:
|
|
153
|
-
_e.sent();
|
|
154
|
-
return [3 /*break*/, 7];
|
|
155
|
-
case 6:
|
|
156
|
-
error_2 = _e.sent();
|
|
157
|
-
api_1.logger.error("[JobSchedule] Tick failed for \"".concat(schedule.name, "\": ").concat(error_2 instanceof Error ? error_2.message : String(error_2)));
|
|
158
|
-
scheduleLog.error("Tick failed: ".concat(error_2 instanceof Error ? error_2.message : String(error_2)));
|
|
159
|
-
return [3 /*break*/, 7];
|
|
160
|
-
case 7:
|
|
161
|
-
dueSchedules_1_1 = dueSchedules_1.next();
|
|
162
|
-
return [3 /*break*/, 3];
|
|
163
|
-
case 8: return [3 /*break*/, 11];
|
|
164
|
-
case 9:
|
|
165
|
-
e_1_1 = _e.sent();
|
|
166
|
-
e_1 = { error: e_1_1 };
|
|
167
|
-
return [3 /*break*/, 11];
|
|
168
|
-
case 10:
|
|
169
|
-
try {
|
|
170
|
-
if (dueSchedules_1_1 && !dueSchedules_1_1.done && (_c = dueSchedules_1.return)) _c.call(dueSchedules_1);
|
|
171
|
-
}
|
|
172
|
-
finally { if (e_1) throw e_1.error; }
|
|
173
|
-
return [7 /*endfinally*/];
|
|
174
|
-
case 11: return [2 /*return*/];
|
|
33
|
+
if (inFlight) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const idempotencyKey = (0, exports.buildScheduleRunIdempotencyKey)(claimed._id.toString(), claimed.nextRunAt);
|
|
37
|
+
try {
|
|
38
|
+
await jobsService.enqueue({
|
|
39
|
+
idempotencyKey,
|
|
40
|
+
name: claimed.handlerName,
|
|
41
|
+
payload: {},
|
|
42
|
+
runAt: claimed.nextRunAt,
|
|
43
|
+
scheduleId: claimed._id.toString(),
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
catch (error) {
|
|
47
|
+
const shouldRollbackSchedule = !(error instanceof dispatchError_1.JobDispatchError) || error.compensationSucceeded;
|
|
48
|
+
if (shouldRollbackSchedule) {
|
|
49
|
+
await jobSchedule_1.JobSchedule.updateOne({ _id: claimed._id, nextRunAt: advancedNextRunAt }, { $set: { nextRunAt: dueRunAt } });
|
|
175
50
|
}
|
|
176
|
-
|
|
177
|
-
});
|
|
51
|
+
else {
|
|
52
|
+
api_1.logger.error(`[JobSchedule] Dispatch compensation lost race for "${claimed.name}" (${claimed._id.toString()}); schedule nextRunAt left advanced`);
|
|
53
|
+
}
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
const tickDueSchedules = async ({ jobsService, now = luxon_1.DateTime.utc().toJSDate(), }) => {
|
|
58
|
+
const dueSchedules = await jobSchedule_1.JobSchedule.find({
|
|
59
|
+
enabled: true,
|
|
60
|
+
nextRunAt: { $lte: now },
|
|
61
|
+
}).sort({ nextRunAt: 1 });
|
|
62
|
+
for (const schedule of dueSchedules) {
|
|
63
|
+
const scheduleLog = (0, api_1.createScopedLogger)({
|
|
64
|
+
labels: { scheduleName: schedule.name },
|
|
65
|
+
prefix: "[JobSchedule]",
|
|
66
|
+
});
|
|
67
|
+
try {
|
|
68
|
+
await tickOneSchedule({ jobsService, now, schedule });
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
api_1.logger.error(`[JobSchedule] Tick failed for "${schedule.name}": ${error instanceof Error ? error.message : String(error)}`);
|
|
72
|
+
scheduleLog.error(`Tick failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
};
|
|
178
76
|
exports.tickDueSchedules = tickDueSchedules;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": "Josh Gachnang",
|
|
3
3
|
"bugs": {
|
|
4
|
-
"url": "https://github.com/
|
|
4
|
+
"url": "https://github.com/TerrenoLabs/terreno/issues"
|
|
5
5
|
},
|
|
6
6
|
"dependencies": {
|
|
7
7
|
"@terreno/api": "57.4.0",
|
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
"types": "./dist/runners/vercelQueues.d.ts"
|
|
36
36
|
}
|
|
37
37
|
},
|
|
38
|
-
"homepage": "https://github.com/
|
|
38
|
+
"homepage": "https://github.com/TerrenoLabs/terreno#readme",
|
|
39
39
|
"keywords": [
|
|
40
40
|
"background-jobs",
|
|
41
41
|
"queue",
|
|
@@ -64,7 +64,7 @@
|
|
|
64
64
|
},
|
|
65
65
|
"repository": {
|
|
66
66
|
"type": "git",
|
|
67
|
-
"url": "git+ssh://git@github.com/
|
|
67
|
+
"url": "git+ssh://git@github.com/TerrenoLabs/terreno.git"
|
|
68
68
|
},
|
|
69
69
|
"scripts": {
|
|
70
70
|
"compile": "bun tsc",
|
|
@@ -78,5 +78,5 @@
|
|
|
78
78
|
"test:coverage": "bun run ../scripts/check-coverage.ts"
|
|
79
79
|
},
|
|
80
80
|
"types": "dist/index.d.ts",
|
|
81
|
-
"version": "57.
|
|
81
|
+
"version": "57.6.0"
|
|
82
82
|
}
|
package/src/models/job.ts
CHANGED
|
@@ -80,12 +80,12 @@ const jobSchema: JobSchema = new mongoose.Schema<JobDocument, JobModel>(
|
|
|
80
80
|
},
|
|
81
81
|
retriedById: {
|
|
82
82
|
description: "Follow-up job created by an admin retry action",
|
|
83
|
-
ref: "
|
|
83
|
+
ref: "TerrenoJob",
|
|
84
84
|
type: mongoose.Schema.Types.ObjectId,
|
|
85
85
|
},
|
|
86
86
|
retriedFromId: {
|
|
87
87
|
description: "Original job row that this retry was created from",
|
|
88
|
-
ref: "
|
|
88
|
+
ref: "TerrenoJob",
|
|
89
89
|
type: mongoose.Schema.Types.ObjectId,
|
|
90
90
|
},
|
|
91
91
|
runAt: {
|
|
@@ -96,7 +96,7 @@ const jobSchema: JobSchema = new mongoose.Schema<JobDocument, JobModel>(
|
|
|
96
96
|
},
|
|
97
97
|
scheduleId: {
|
|
98
98
|
description: "Recurring schedule that enqueued this job, when applicable",
|
|
99
|
-
ref: "
|
|
99
|
+
ref: "TerrenoJobSchedule",
|
|
100
100
|
type: mongoose.Schema.Types.ObjectId,
|
|
101
101
|
},
|
|
102
102
|
status: {
|
|
@@ -126,4 +126,4 @@ jobSchema.index(
|
|
|
126
126
|
jobSchema.index({status: 1, runAt: 1});
|
|
127
127
|
jobSchema.index({scheduleId: 1, status: 1});
|
|
128
128
|
|
|
129
|
-
export const Job = mongoose.model<JobDocument, JobModel>("
|
|
129
|
+
export const Job = mongoose.model<JobDocument, JobModel>("TerrenoJob", jobSchema, "jobs");
|
|
@@ -52,6 +52,7 @@ jobScheduleSchema.plugin(findExactlyOne);
|
|
|
52
52
|
jobScheduleSchema.index({enabled: 1, nextRunAt: 1});
|
|
53
53
|
|
|
54
54
|
export const JobSchedule = mongoose.model<JobScheduleDocument, JobScheduleModel>(
|
|
55
|
-
"
|
|
56
|
-
jobScheduleSchema
|
|
55
|
+
"TerrenoJobSchedule",
|
|
56
|
+
jobScheduleSchema,
|
|
57
|
+
"jobschedules"
|
|
57
58
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import {describe, it} from "bun:test";
|
|
1
|
+
import {afterAll, describe, it} from "bun:test";
|
|
2
2
|
import {assert} from "chai";
|
|
3
|
+
import mongoose from "mongoose";
|
|
3
4
|
|
|
4
5
|
import {
|
|
5
6
|
getJobsService,
|
|
@@ -11,14 +12,29 @@ import {
|
|
|
11
12
|
unregisterJobsService,
|
|
12
13
|
} from "../index";
|
|
13
14
|
|
|
15
|
+
afterAll(() => {
|
|
16
|
+
for (const modelName of ["Job", "JobSchedule"]) {
|
|
17
|
+
if (mongoose.models[modelName]) {
|
|
18
|
+
mongoose.deleteModel(modelName);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
14
23
|
describe("package public exports", () => {
|
|
15
24
|
it("re-exports JobsApp, models, MongoJobRunner, and getJobsService", (): void => {
|
|
16
25
|
assert.equal(JobsApp.name, "JobsApp");
|
|
17
26
|
assert.equal(MongoJobRunner.name, "MongoJobRunner");
|
|
18
|
-
assert.equal(Job.modelName, "
|
|
19
|
-
assert.equal(
|
|
27
|
+
assert.equal(Job.modelName, "TerrenoJob");
|
|
28
|
+
assert.equal(Job.collection.collectionName, "jobs");
|
|
29
|
+
assert.equal(JobSchedule.modelName, "TerrenoJobSchedule");
|
|
30
|
+
assert.equal(JobSchedule.collection.collectionName, "jobschedules");
|
|
20
31
|
assert.equal(typeof getJobsService, "function");
|
|
21
32
|
assert.equal(typeof tryGetJobsService, "function");
|
|
22
33
|
assert.equal(typeof unregisterJobsService, "function");
|
|
23
34
|
});
|
|
35
|
+
|
|
36
|
+
it("allows consumers to register generic job model names", (): void => {
|
|
37
|
+
assert.doesNotThrow(() => mongoose.model("Job", new mongoose.Schema({})));
|
|
38
|
+
assert.doesNotThrow(() => mongoose.model("JobSchedule", new mongoose.Schema({})));
|
|
39
|
+
});
|
|
24
40
|
});
|
package/tsconfig.json
CHANGED
|
@@ -1,33 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
|
-
"allowJs": true,
|
|
4
|
-
"allowSyntheticDefaultImports": true,
|
|
5
|
-
"baseUrl": "./",
|
|
6
3
|
"declaration": true,
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
"
|
|
10
|
-
"ignoreDeprecations": "6.0",
|
|
11
|
-
"jsx": "react",
|
|
12
|
-
"lib": ["es2017", "dom", "es2017.object"],
|
|
13
|
-
"module": "commonjs",
|
|
14
|
-
"moduleResolution": "node",
|
|
15
|
-
"noEmit": false,
|
|
4
|
+
"isolatedModules": true,
|
|
5
|
+
"lib": ["es2023"],
|
|
6
|
+
"module": "nodenext",
|
|
16
7
|
"noImplicitAny": false,
|
|
17
8
|
"noImplicitReturns": true,
|
|
18
|
-
"noImplicitThis": true,
|
|
19
|
-
"noUnusedLocals": false,
|
|
20
|
-
"noUnusedParameters": false,
|
|
21
9
|
"outDir": "./dist",
|
|
22
10
|
"rootDir": "./src",
|
|
23
|
-
"preserveConstEnums": true,
|
|
24
|
-
"removeComments": false,
|
|
25
11
|
"skipLibCheck": true,
|
|
26
12
|
"strict": true,
|
|
27
|
-
"
|
|
28
|
-
"
|
|
29
|
-
"target": "es5"
|
|
13
|
+
"target": "es2023",
|
|
14
|
+
"types": ["node"]
|
|
30
15
|
},
|
|
31
16
|
"exclude": ["node_modules", "src/tests", "**/*.test.ts"],
|
|
32
|
-
"include": ["src
|
|
17
|
+
"include": ["src"]
|
|
33
18
|
}
|