alepha 0.12.1 → 0.13.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/dist/api-notifications/index.d.ts +111 -111
- package/dist/api-users/index.d.ts +1240 -1240
- package/dist/api-verifications/index.d.ts +94 -94
- package/dist/cli/{dist-Sz2EXvQX.cjs → dist-Dl9Vl7Ur.js} +17 -13
- package/dist/cli/{dist-BBPjuQ56.js.map → dist-Dl9Vl7Ur.js.map} +1 -1
- package/dist/cli/index.d.ts +3 -11
- package/dist/cli/index.js +106 -74
- package/dist/cli/index.js.map +1 -1
- package/dist/email/index.js +71 -73
- package/dist/email/index.js.map +1 -1
- package/dist/orm/index.d.ts +1 -1
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/index.d.ts +4 -4
- package/dist/redis/index.d.ts +10 -10
- package/dist/retry/index.d.ts +1 -1
- package/dist/retry/index.js +2 -2
- package/dist/retry/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +6 -6
- package/dist/server/index.js +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server-auth/index.d.ts +193 -193
- package/dist/server-health/index.d.ts +17 -17
- package/dist/server-links/index.d.ts +34 -34
- package/dist/server-metrics/index.js +170 -174
- package/dist/server-metrics/index.js.map +1 -1
- package/dist/server-security/index.d.ts +9 -9
- package/dist/vite/index.js +4 -5
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.d.ts +7 -7
- package/package.json +52 -103
- package/src/cli/apps/AlephaPackageBuilderCli.ts +7 -2
- package/src/cli/assets/appRouterTs.ts +9 -0
- package/src/cli/assets/indexHtml.ts +2 -1
- package/src/cli/assets/mainBrowserTs.ts +10 -0
- package/src/cli/commands/CoreCommands.ts +6 -5
- package/src/cli/commands/DrizzleCommands.ts +65 -57
- package/src/cli/commands/VerifyCommands.ts +1 -1
- package/src/cli/services/ProjectUtils.ts +44 -38
- package/src/orm/providers/DrizzleKitProvider.ts +1 -1
- package/src/retry/descriptors/$retry.ts +5 -3
- package/src/server/providers/NodeHttpServerProvider.ts +1 -1
- package/src/vite/helpers/boot.ts +3 -3
- package/dist/api-files/index.cjs +0 -1293
- package/dist/api-files/index.cjs.map +0 -1
- package/dist/api-files/index.d.cts +0 -829
- package/dist/api-jobs/index.cjs +0 -274
- package/dist/api-jobs/index.cjs.map +0 -1
- package/dist/api-jobs/index.d.cts +0 -654
- package/dist/api-notifications/index.cjs +0 -380
- package/dist/api-notifications/index.cjs.map +0 -1
- package/dist/api-notifications/index.d.cts +0 -289
- package/dist/api-parameters/index.cjs +0 -66
- package/dist/api-parameters/index.cjs.map +0 -1
- package/dist/api-parameters/index.d.cts +0 -84
- package/dist/api-users/index.cjs +0 -6009
- package/dist/api-users/index.cjs.map +0 -1
- package/dist/api-users/index.d.cts +0 -4740
- package/dist/api-verifications/index.cjs +0 -407
- package/dist/api-verifications/index.cjs.map +0 -1
- package/dist/api-verifications/index.d.cts +0 -207
- package/dist/batch/index.cjs +0 -408
- package/dist/batch/index.cjs.map +0 -1
- package/dist/batch/index.d.cts +0 -330
- package/dist/bin/index.cjs +0 -17
- package/dist/bin/index.cjs.map +0 -1
- package/dist/bin/index.d.cts +0 -1
- package/dist/bucket/index.cjs +0 -303
- package/dist/bucket/index.cjs.map +0 -1
- package/dist/bucket/index.d.cts +0 -355
- package/dist/cache/index.cjs +0 -241
- package/dist/cache/index.cjs.map +0 -1
- package/dist/cache/index.d.cts +0 -202
- package/dist/cache-redis/index.cjs +0 -84
- package/dist/cache-redis/index.cjs.map +0 -1
- package/dist/cache-redis/index.d.cts +0 -40
- package/dist/cli/chunk-DSlc6foC.cjs +0 -43
- package/dist/cli/dist-BBPjuQ56.js +0 -2778
- package/dist/cli/dist-Sz2EXvQX.cjs.map +0 -1
- package/dist/cli/index.cjs +0 -1241
- package/dist/cli/index.cjs.map +0 -1
- package/dist/cli/index.d.cts +0 -422
- package/dist/command/index.cjs +0 -693
- package/dist/command/index.cjs.map +0 -1
- package/dist/command/index.d.cts +0 -340
- package/dist/core/index.cjs +0 -2264
- package/dist/core/index.cjs.map +0 -1
- package/dist/core/index.d.cts +0 -1927
- package/dist/datetime/index.cjs +0 -318
- package/dist/datetime/index.cjs.map +0 -1
- package/dist/datetime/index.d.cts +0 -145
- package/dist/email/index.cjs +0 -10874
- package/dist/email/index.cjs.map +0 -1
- package/dist/email/index.d.cts +0 -186
- package/dist/fake/index.cjs +0 -34641
- package/dist/fake/index.cjs.map +0 -1
- package/dist/fake/index.d.cts +0 -74
- package/dist/file/index.cjs +0 -1212
- package/dist/file/index.cjs.map +0 -1
- package/dist/file/index.d.cts +0 -698
- package/dist/lock/index.cjs +0 -226
- package/dist/lock/index.cjs.map +0 -1
- package/dist/lock/index.d.cts +0 -361
- package/dist/lock-redis/index.cjs +0 -113
- package/dist/lock-redis/index.cjs.map +0 -1
- package/dist/lock-redis/index.d.cts +0 -24
- package/dist/logger/index.cjs +0 -521
- package/dist/logger/index.cjs.map +0 -1
- package/dist/logger/index.d.cts +0 -281
- package/dist/orm/index.cjs +0 -2986
- package/dist/orm/index.cjs.map +0 -1
- package/dist/orm/index.d.cts +0 -2213
- package/dist/queue/index.cjs +0 -1044
- package/dist/queue/index.cjs.map +0 -1
- package/dist/queue/index.d.cts +0 -1265
- package/dist/queue-redis/index.cjs +0 -873
- package/dist/queue-redis/index.cjs.map +0 -1
- package/dist/queue-redis/index.d.cts +0 -82
- package/dist/redis/index.cjs +0 -153
- package/dist/redis/index.cjs.map +0 -1
- package/dist/redis/index.d.cts +0 -82
- package/dist/retry/index.cjs +0 -146
- package/dist/retry/index.cjs.map +0 -1
- package/dist/retry/index.d.cts +0 -172
- package/dist/router/index.cjs +0 -111
- package/dist/router/index.cjs.map +0 -1
- package/dist/router/index.d.cts +0 -46
- package/dist/scheduler/index.cjs +0 -576
- package/dist/scheduler/index.cjs.map +0 -1
- package/dist/scheduler/index.d.cts +0 -145
- package/dist/security/index.cjs +0 -2402
- package/dist/security/index.cjs.map +0 -1
- package/dist/security/index.d.cts +0 -598
- package/dist/server/index.cjs +0 -1680
- package/dist/server/index.cjs.map +0 -1
- package/dist/server/index.d.cts +0 -810
- package/dist/server-auth/index.cjs +0 -3146
- package/dist/server-auth/index.cjs.map +0 -1
- package/dist/server-auth/index.d.cts +0 -1164
- package/dist/server-cache/index.cjs +0 -252
- package/dist/server-cache/index.cjs.map +0 -1
- package/dist/server-cache/index.d.cts +0 -164
- package/dist/server-compress/index.cjs +0 -141
- package/dist/server-compress/index.cjs.map +0 -1
- package/dist/server-compress/index.d.cts +0 -38
- package/dist/server-cookies/index.cjs +0 -234
- package/dist/server-cookies/index.cjs.map +0 -1
- package/dist/server-cookies/index.d.cts +0 -144
- package/dist/server-cors/index.cjs +0 -201
- package/dist/server-cors/index.cjs.map +0 -1
- package/dist/server-cors/index.d.cts +0 -140
- package/dist/server-health/index.cjs +0 -62
- package/dist/server-health/index.cjs.map +0 -1
- package/dist/server-health/index.d.cts +0 -58
- package/dist/server-helmet/index.cjs +0 -131
- package/dist/server-helmet/index.cjs.map +0 -1
- package/dist/server-helmet/index.d.cts +0 -97
- package/dist/server-links/index.cjs +0 -992
- package/dist/server-links/index.cjs.map +0 -1
- package/dist/server-links/index.d.cts +0 -513
- package/dist/server-metrics/index.cjs +0 -4535
- package/dist/server-metrics/index.cjs.map +0 -1
- package/dist/server-metrics/index.d.cts +0 -35
- package/dist/server-multipart/index.cjs +0 -237
- package/dist/server-multipart/index.cjs.map +0 -1
- package/dist/server-multipart/index.d.cts +0 -50
- package/dist/server-proxy/index.cjs +0 -186
- package/dist/server-proxy/index.cjs.map +0 -1
- package/dist/server-proxy/index.d.cts +0 -234
- package/dist/server-rate-limit/index.cjs +0 -241
- package/dist/server-rate-limit/index.cjs.map +0 -1
- package/dist/server-rate-limit/index.d.cts +0 -183
- package/dist/server-security/index.cjs +0 -316
- package/dist/server-security/index.cjs.map +0 -1
- package/dist/server-security/index.d.cts +0 -173
- package/dist/server-static/index.cjs +0 -170
- package/dist/server-static/index.cjs.map +0 -1
- package/dist/server-static/index.d.cts +0 -121
- package/dist/server-swagger/index.cjs +0 -1021
- package/dist/server-swagger/index.cjs.map +0 -1
- package/dist/server-swagger/index.d.cts +0 -382
- package/dist/sms/index.cjs +0 -221
- package/dist/sms/index.cjs.map +0 -1
- package/dist/sms/index.d.cts +0 -130
- package/dist/thread/index.cjs +0 -350
- package/dist/thread/index.cjs.map +0 -1
- package/dist/thread/index.d.cts +0 -260
- package/dist/topic/index.cjs +0 -282
- package/dist/topic/index.cjs.map +0 -1
- package/dist/topic/index.d.cts +0 -523
- package/dist/topic-redis/index.cjs +0 -71
- package/dist/topic-redis/index.cjs.map +0 -1
- package/dist/topic-redis/index.d.cts +0 -42
- package/dist/vite/index.cjs +0 -1077
- package/dist/vite/index.cjs.map +0 -1
- package/dist/vite/index.d.cts +0 -542
- package/dist/websocket/index.cjs +0 -1117
- package/dist/websocket/index.cjs.map +0 -1
- package/dist/websocket/index.d.cts +0 -861
package/dist/api-jobs/index.cjs
DELETED
|
@@ -1,274 +0,0 @@
|
|
|
1
|
-
let alepha = require("alepha");
|
|
2
|
-
let alepha_server = require("alepha/server");
|
|
3
|
-
let alepha_orm = require("alepha/orm");
|
|
4
|
-
let alepha_logger = require("alepha/logger");
|
|
5
|
-
let alepha_datetime = require("alepha/datetime");
|
|
6
|
-
let alepha_lock = require("alepha/lock");
|
|
7
|
-
let alepha_scheduler = require("alepha/scheduler");
|
|
8
|
-
|
|
9
|
-
//#region src/api-jobs/schemas/jobExecutionQuerySchema.ts
|
|
10
|
-
const jobExecutionQuerySchema = alepha.t.extend(alepha_orm.pageQuerySchema, {
|
|
11
|
-
status: alepha.t.optional(alepha.t.enum([
|
|
12
|
-
"STARTED",
|
|
13
|
-
"FAILED",
|
|
14
|
-
"COMPLETED"
|
|
15
|
-
])),
|
|
16
|
-
job: alepha.t.optional(alepha.t.text({ description: "Filter by job name" }))
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
//#endregion
|
|
20
|
-
//#region src/api-jobs/entities/jobExecutions.ts
|
|
21
|
-
const jobExecutions = (0, alepha_orm.$entity)({
|
|
22
|
-
name: "job_executions",
|
|
23
|
-
schema: alepha.t.object({
|
|
24
|
-
id: alepha_orm.pg.primaryKey(alepha.t.uuid()),
|
|
25
|
-
version: alepha_orm.pg.version(),
|
|
26
|
-
createdAt: alepha_orm.pg.createdAt(),
|
|
27
|
-
updatedAt: alepha_orm.pg.updatedAt(),
|
|
28
|
-
finishedAt: alepha.t.optional(alepha.t.datetime()),
|
|
29
|
-
job: alepha.t.string(),
|
|
30
|
-
status: alepha.t.enum([
|
|
31
|
-
"STARTED",
|
|
32
|
-
"FAILED",
|
|
33
|
-
"COMPLETED"
|
|
34
|
-
]),
|
|
35
|
-
error: alepha.t.optional(alepha.t.string()),
|
|
36
|
-
logs: alepha.t.optional(alepha.t.array(alepha_logger.logEntrySchema))
|
|
37
|
-
})
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
//#endregion
|
|
41
|
-
//#region src/api-jobs/schemas/jobExecutionResourceSchema.ts
|
|
42
|
-
const jobExecutionResourceSchema = alepha.t.extend(jobExecutions.schema, {}, {
|
|
43
|
-
title: "JobExecutionResource",
|
|
44
|
-
description: "A job execution resource representing the execution details of a job."
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
//#endregion
|
|
48
|
-
//#region src/api-jobs/schemas/triggerJobSchema.ts
|
|
49
|
-
const triggerJobSchema = alepha.t.object({ name: alepha.t.string() });
|
|
50
|
-
|
|
51
|
-
//#endregion
|
|
52
|
-
//#region src/api-jobs/providers/JobProvider.ts
|
|
53
|
-
const envSchema = alepha.t.object({ JOB_PREFIX: alepha.t.optional(alepha.t.text({ description: "Prefix for job lock keys" })) });
|
|
54
|
-
/**
|
|
55
|
-
* Provider for job management and execution.
|
|
56
|
-
* Handles job lifecycle, execution tracking, log capturing, and event emission.
|
|
57
|
-
*/
|
|
58
|
-
var JobProvider = class {
|
|
59
|
-
alepha = (0, alepha.$inject)(alepha.Alepha);
|
|
60
|
-
dateTimeProvider = (0, alepha.$inject)(alepha_datetime.DateTimeProvider);
|
|
61
|
-
cronProvider = (0, alepha.$inject)(alepha_scheduler.CronProvider);
|
|
62
|
-
executionRepository = (0, alepha_orm.$repository)(jobExecutions);
|
|
63
|
-
env = (0, alepha.$env)(envSchema);
|
|
64
|
-
logs = /* @__PURE__ */ new Map();
|
|
65
|
-
jobs = /* @__PURE__ */ new Map();
|
|
66
|
-
/**
|
|
67
|
-
* Register and set up a job for execution (called during descriptor initialization).
|
|
68
|
-
*/
|
|
69
|
-
registerJob(options) {
|
|
70
|
-
const jobName = options.name;
|
|
71
|
-
if (this.jobs.size === 0) this.alepha.events.on("log", ({ entry }) => {
|
|
72
|
-
const context = entry.context;
|
|
73
|
-
if (!context) return;
|
|
74
|
-
const entries = this.logs.get(context);
|
|
75
|
-
if (!entries) return;
|
|
76
|
-
entries.push(entry);
|
|
77
|
-
this.logs.set(context, entries);
|
|
78
|
-
});
|
|
79
|
-
const registration = {
|
|
80
|
-
name: jobName,
|
|
81
|
-
options,
|
|
82
|
-
lockDescriptor: options.lock !== false ? (0, alepha_lock.$lock)({
|
|
83
|
-
name: () => {
|
|
84
|
-
return `${this.env.JOB_PREFIX ? `${this.env.JOB_PREFIX}:` : ""}job:${jobName}`;
|
|
85
|
-
},
|
|
86
|
-
handler: async () => {
|
|
87
|
-
await this.executeJob(jobName, options.handler);
|
|
88
|
-
}
|
|
89
|
-
}) : null
|
|
90
|
-
};
|
|
91
|
-
this.jobs.set(jobName, registration);
|
|
92
|
-
if (options.cron) this.cronProvider.createCronJob(jobName, options.cron, () => this.triggerJob(jobName));
|
|
93
|
-
return registration;
|
|
94
|
-
}
|
|
95
|
-
/**
|
|
96
|
-
* Trigger a job by name.
|
|
97
|
-
*/
|
|
98
|
-
async triggerJob(jobName) {
|
|
99
|
-
const registration = this.jobs.get(jobName);
|
|
100
|
-
if (!registration) throw new Error(`Job not registered: ${jobName}`);
|
|
101
|
-
if (registration.options.lock !== false && registration.lockDescriptor) await registration.lockDescriptor.run();
|
|
102
|
-
else await this.executeJob(jobName, registration.options.handler);
|
|
103
|
-
}
|
|
104
|
-
/**
|
|
105
|
-
* Execute a job handler (called by the job descriptor).
|
|
106
|
-
*/
|
|
107
|
-
async executeJob(jobName, handler) {
|
|
108
|
-
if (!this.alepha.isStarted()) return;
|
|
109
|
-
const context = this.alepha.context.createContextId();
|
|
110
|
-
await this.alepha.context.run(async () => {
|
|
111
|
-
try {
|
|
112
|
-
const now = this.dateTimeProvider.now();
|
|
113
|
-
this.logs.set(context, []);
|
|
114
|
-
await this.executionRepository.create({
|
|
115
|
-
job: jobName,
|
|
116
|
-
status: "STARTED"
|
|
117
|
-
});
|
|
118
|
-
await this.alepha.events.emit("scheduler:begin", {
|
|
119
|
-
name: jobName,
|
|
120
|
-
now,
|
|
121
|
-
context
|
|
122
|
-
});
|
|
123
|
-
await handler({ now });
|
|
124
|
-
const logs = this.logs.get(context) || [];
|
|
125
|
-
const exec = await this.executionRepository.findOne({ where: {
|
|
126
|
-
job: jobName,
|
|
127
|
-
status: "STARTED"
|
|
128
|
-
} });
|
|
129
|
-
exec.status = "COMPLETED";
|
|
130
|
-
exec.logs = logs;
|
|
131
|
-
exec.finishedAt = this.dateTimeProvider.nowISOString();
|
|
132
|
-
await this.executionRepository.save(exec);
|
|
133
|
-
await this.alepha.events.emit("scheduler:success", {
|
|
134
|
-
name: jobName,
|
|
135
|
-
context
|
|
136
|
-
}, { catch: true });
|
|
137
|
-
} catch (error) {
|
|
138
|
-
const logs = this.logs.get(context) || [];
|
|
139
|
-
const exec = await this.executionRepository.findOne({ where: {
|
|
140
|
-
job: jobName,
|
|
141
|
-
status: "STARTED"
|
|
142
|
-
} });
|
|
143
|
-
exec.status = "FAILED";
|
|
144
|
-
exec.error = error.message;
|
|
145
|
-
exec.logs = logs;
|
|
146
|
-
exec.finishedAt = this.dateTimeProvider.nowISOString();
|
|
147
|
-
await this.executionRepository.save(exec);
|
|
148
|
-
await this.alepha.events.emit("scheduler:error", {
|
|
149
|
-
name: jobName,
|
|
150
|
-
error,
|
|
151
|
-
context
|
|
152
|
-
}, { catch: true });
|
|
153
|
-
}
|
|
154
|
-
this.logs.delete(context);
|
|
155
|
-
await this.alepha.events.emit("scheduler:end", {
|
|
156
|
-
name: jobName,
|
|
157
|
-
context
|
|
158
|
-
}, { catch: true });
|
|
159
|
-
}, { context });
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
|
|
163
|
-
//#endregion
|
|
164
|
-
//#region src/api-jobs/descriptors/$job.ts
|
|
165
|
-
/**
|
|
166
|
-
* Job descriptor - a drop-in replacement for $scheduler with built-in execution tracking.
|
|
167
|
-
*/
|
|
168
|
-
const $job = (options) => {
|
|
169
|
-
return (0, alepha.createDescriptor)(JobDescriptor, options);
|
|
170
|
-
};
|
|
171
|
-
var JobDescriptor = class extends alepha.Descriptor {
|
|
172
|
-
jobProvider = (0, alepha.$inject)(JobProvider);
|
|
173
|
-
get name() {
|
|
174
|
-
return this.options.name ?? `${this.config.service.name}.${this.config.propertyKey}`;
|
|
175
|
-
}
|
|
176
|
-
onInit() {
|
|
177
|
-
this.jobProvider.registerJob({
|
|
178
|
-
...this.options,
|
|
179
|
-
name: this.name
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
async trigger() {
|
|
183
|
-
await this.jobProvider.triggerJob(this.name);
|
|
184
|
-
}
|
|
185
|
-
};
|
|
186
|
-
$job[alepha.KIND] = JobDescriptor;
|
|
187
|
-
|
|
188
|
-
//#endregion
|
|
189
|
-
//#region src/api-jobs/services/JobService.ts
|
|
190
|
-
var JobService = class {
|
|
191
|
-
alepha = (0, alepha.$inject)(alepha.Alepha);
|
|
192
|
-
executionRepository = (0, alepha_orm.$repository)(jobExecutions);
|
|
193
|
-
async getJobs() {
|
|
194
|
-
return this.alepha.descriptors($job).map((job) => job.name);
|
|
195
|
-
}
|
|
196
|
-
async getJobExecutions(query = {}) {
|
|
197
|
-
query.sort ??= "-createdAt";
|
|
198
|
-
const where = this.executionRepository.createQueryWhere();
|
|
199
|
-
if (query.job) where.job = { eq: query.job };
|
|
200
|
-
if (query.status) where.status = { eq: query.status };
|
|
201
|
-
return await this.executionRepository.paginate(query, { where }, { count: true });
|
|
202
|
-
}
|
|
203
|
-
async triggerJob(name) {
|
|
204
|
-
const job = this.alepha.descriptors($job).find((j) => j.name === name);
|
|
205
|
-
if (!job) throw new Error(`Job not found: ${name}`);
|
|
206
|
-
await job.trigger();
|
|
207
|
-
return { ok: true };
|
|
208
|
-
}
|
|
209
|
-
};
|
|
210
|
-
|
|
211
|
-
//#endregion
|
|
212
|
-
//#region src/api-jobs/controllers/JobController.ts
|
|
213
|
-
var JobController = class {
|
|
214
|
-
url = "/jobs";
|
|
215
|
-
group = "jobs";
|
|
216
|
-
jobService = (0, alepha.$inject)(JobService);
|
|
217
|
-
getJobs = (0, alepha_server.$action)({
|
|
218
|
-
path: this.url,
|
|
219
|
-
group: this.group,
|
|
220
|
-
schema: { response: alepha.t.array(alepha.t.string()) },
|
|
221
|
-
handler: () => this.jobService.getJobs()
|
|
222
|
-
});
|
|
223
|
-
getJobExecutions = (0, alepha_server.$action)({
|
|
224
|
-
path: `${this.url}/executions`,
|
|
225
|
-
group: this.group,
|
|
226
|
-
schema: {
|
|
227
|
-
query: jobExecutionQuerySchema,
|
|
228
|
-
response: alepha.t.page(jobExecutionResourceSchema)
|
|
229
|
-
},
|
|
230
|
-
handler: ({ query }) => this.jobService.getJobExecutions(query)
|
|
231
|
-
});
|
|
232
|
-
triggerJob = (0, alepha_server.$action)({
|
|
233
|
-
method: "POST",
|
|
234
|
-
path: `${this.url}/trigger`,
|
|
235
|
-
group: this.group,
|
|
236
|
-
schema: {
|
|
237
|
-
body: triggerJobSchema,
|
|
238
|
-
response: alepha_server.okSchema
|
|
239
|
-
},
|
|
240
|
-
handler: ({ body }) => this.jobService.triggerJob(body.name)
|
|
241
|
-
});
|
|
242
|
-
};
|
|
243
|
-
|
|
244
|
-
//#endregion
|
|
245
|
-
//#region src/api-jobs/index.ts
|
|
246
|
-
/**
|
|
247
|
-
* Provides job management API endpoints for Alepha applications.
|
|
248
|
-
*
|
|
249
|
-
* This module includes job queue operations, job status monitoring,
|
|
250
|
-
* and background task management capabilities.
|
|
251
|
-
*
|
|
252
|
-
* @module alepha.api.jobs
|
|
253
|
-
*/
|
|
254
|
-
const AlephaApiJobs = (0, alepha.$module)({
|
|
255
|
-
name: "alepha.api.jobs",
|
|
256
|
-
services: [
|
|
257
|
-
JobController,
|
|
258
|
-
JobProvider,
|
|
259
|
-
JobService
|
|
260
|
-
]
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
//#endregion
|
|
264
|
-
exports.$job = $job;
|
|
265
|
-
exports.AlephaApiJobs = AlephaApiJobs;
|
|
266
|
-
exports.JobController = JobController;
|
|
267
|
-
exports.JobDescriptor = JobDescriptor;
|
|
268
|
-
exports.JobProvider = JobProvider;
|
|
269
|
-
exports.JobService = JobService;
|
|
270
|
-
exports.jobExecutionQuerySchema = jobExecutionQuerySchema;
|
|
271
|
-
exports.jobExecutionResourceSchema = jobExecutionResourceSchema;
|
|
272
|
-
exports.jobExecutions = jobExecutions;
|
|
273
|
-
exports.triggerJobSchema = triggerJobSchema;
|
|
274
|
-
//# sourceMappingURL=index.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["t","pageQuerySchema","t","pg","logEntrySchema","t","t","t","Alepha","DateTimeProvider","CronProvider","registration: JobRegistration","Descriptor","KIND","Alepha","t","okSchema"],"sources":["../../src/api-jobs/schemas/jobExecutionQuerySchema.ts","../../src/api-jobs/entities/jobExecutions.ts","../../src/api-jobs/schemas/jobExecutionResourceSchema.ts","../../src/api-jobs/schemas/triggerJobSchema.ts","../../src/api-jobs/providers/JobProvider.ts","../../src/api-jobs/descriptors/$job.ts","../../src/api-jobs/services/JobService.ts","../../src/api-jobs/controllers/JobController.ts","../../src/api-jobs/index.ts"],"sourcesContent":["import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\nimport { pageQuerySchema } from \"alepha/orm\";\n\nexport const jobExecutionQuerySchema = t.extend(pageQuerySchema, {\n status: t.optional(t.enum([\"STARTED\", \"FAILED\", \"COMPLETED\"])),\n job: t.optional(\n t.text({\n description: \"Filter by job name\",\n }),\n ),\n});\n\nexport type JobExecutionQuery = Static<typeof jobExecutionQuerySchema>;\n","import { type Static, t } from \"alepha\";\nimport { logEntrySchema } from \"alepha/logger\";\nimport { $entity, pg } from \"alepha/orm\";\n\nexport const jobExecutions = $entity({\n name: \"job_executions\",\n schema: t.object({\n id: pg.primaryKey(t.uuid()),\n version: pg.version(),\n createdAt: pg.createdAt(),\n updatedAt: pg.updatedAt(),\n finishedAt: t.optional(t.datetime()),\n job: t.string(),\n status: t.enum([\"STARTED\", \"FAILED\", \"COMPLETED\"]),\n error: t.optional(t.string()),\n logs: t.optional(t.array(logEntrySchema)),\n }),\n});\n\nexport type JobExecutionEntity = Static<typeof jobExecutions.schema>;\n","import { type Static, t } from \"alepha\";\nimport { jobExecutions } from \"../entities/jobExecutions.ts\";\n\nexport const jobExecutionResourceSchema = t.extend(\n jobExecutions.schema,\n {},\n {\n title: \"JobExecutionResource\",\n description:\n \"A job execution resource representing the execution details of a job.\",\n },\n);\n\nexport type JobExecutionResource = Static<typeof jobExecutionResourceSchema>;\n","import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\n\nexport const triggerJobSchema = t.object({\n name: t.string(),\n});\n\nexport type TriggerJob = Static<typeof triggerJobSchema>;\n","import { $env, $inject, Alepha, type Async, type Static, t } from \"alepha\";\nimport { type DateTime, DateTimeProvider } from \"alepha/datetime\";\nimport { $lock, type LockDescriptor } from \"alepha/lock\";\nimport type { LogEntry } from \"alepha/logger\";\nimport { $repository } from \"alepha/orm\";\nimport { CronProvider } from \"alepha/scheduler\";\nimport { jobExecutions } from \"../entities/jobExecutions.ts\";\n\nconst envSchema = t.object({\n JOB_PREFIX: t.optional(\n t.text({\n description: \"Prefix for job lock keys\",\n }),\n ),\n});\n\ndeclare module \"alepha\" {\n interface Env extends Partial<Static<typeof envSchema>> {}\n}\n\n/**\n * Provider for job management and execution.\n * Handles job lifecycle, execution tracking, log capturing, and event emission.\n */\nexport class JobProvider {\n protected readonly alepha = $inject(Alepha);\n protected readonly dateTimeProvider = $inject(DateTimeProvider);\n protected readonly cronProvider = $inject(CronProvider);\n protected readonly executionRepository = $repository(jobExecutions);\n protected readonly env = $env(envSchema);\n protected readonly logs = new Map<string, LogEntry[]>();\n protected readonly jobs = new Map<string, JobRegistration>();\n\n /**\n * Register and set up a job for execution (called during descriptor initialization).\n */\n public registerJob(options: Job): JobRegistration {\n const jobName = options.name;\n\n // Set up log capturing for this job (only once)\n if (this.jobs.size === 0) {\n this.alepha.events.on(\"log\", ({ entry }) => {\n const context = entry.context;\n if (!context) {\n return;\n }\n\n const entries = this.logs.get(context);\n if (!entries) {\n return;\n }\n\n entries.push(entry);\n this.logs.set(context, entries);\n });\n }\n\n // Create lock descriptor if locking is enabled\n const lockDescriptor =\n options.lock !== false\n ? $lock({\n name: () => {\n const prefix = this.env.JOB_PREFIX\n ? `${this.env.JOB_PREFIX}:`\n : \"\";\n return `${prefix}job:${jobName}`;\n },\n handler: async () => {\n await this.executeJob(jobName, options.handler);\n },\n })\n : null;\n\n const registration: JobRegistration = {\n name: jobName,\n options,\n lockDescriptor,\n };\n\n this.jobs.set(jobName, registration);\n\n // Set up cron scheduling if provided\n if (options.cron) {\n this.cronProvider.createCronJob(jobName, options.cron, () =>\n this.triggerJob(jobName),\n );\n }\n\n return registration;\n }\n\n /**\n * Trigger a job by name.\n */\n public async triggerJob(jobName: string): Promise<void> {\n const registration = this.jobs.get(jobName);\n if (!registration) {\n throw new Error(`Job not registered: ${jobName}`);\n }\n\n // Execute handler with or without lock\n if (registration.options.lock !== false && registration.lockDescriptor) {\n await registration.lockDescriptor.run();\n } else {\n await this.executeJob(jobName, registration.options.handler);\n }\n }\n\n /**\n * Execute a job handler (called by the job descriptor).\n */\n public async executeJob(\n jobName: string,\n handler: (args: { now: DateTime }) => Async<void>,\n ): Promise<void> {\n if (!this.alepha.isStarted()) {\n return;\n }\n\n const context = this.alepha.context.createContextId();\n\n await this.alepha.context.run(\n async () => {\n try {\n const now = this.dateTimeProvider.now();\n\n // Initialize log collection for this context\n this.logs.set(context, []);\n\n // Create execution record\n await this.executionRepository.create({\n job: jobName,\n status: \"STARTED\",\n });\n\n await this.alepha.events.emit(\"scheduler:begin\", {\n name: jobName,\n now,\n context,\n });\n\n // Execute the handler\n await handler({ now });\n\n // Update execution as completed\n const logs = this.logs.get(context) || [];\n const exec = await this.executionRepository.findOne({\n where: {\n job: jobName,\n status: \"STARTED\",\n },\n });\n\n exec.status = \"COMPLETED\";\n exec.logs = logs;\n exec.finishedAt = this.dateTimeProvider.nowISOString();\n\n await this.executionRepository.save(exec);\n\n await this.alepha.events.emit(\n \"scheduler:success\",\n {\n name: jobName,\n context,\n },\n {\n catch: true,\n },\n );\n } catch (error) {\n // Update execution as failed\n const logs = this.logs.get(context) || [];\n const exec = await this.executionRepository.findOne({\n where: {\n job: jobName,\n status: \"STARTED\",\n },\n });\n\n exec.status = \"FAILED\";\n exec.error = (error as Error).message;\n exec.logs = logs;\n exec.finishedAt = this.dateTimeProvider.nowISOString();\n\n await this.executionRepository.save(exec);\n\n await this.alepha.events.emit(\n \"scheduler:error\",\n {\n name: jobName,\n error: error as Error,\n context,\n },\n {\n catch: true,\n },\n );\n\n // Don't re-throw, jobs should handle errors gracefully\n }\n\n // Clean up logs\n this.logs.delete(context);\n\n await this.alepha.events.emit(\n \"scheduler:end\",\n {\n name: jobName,\n context,\n },\n {\n catch: true,\n },\n );\n },\n {\n context,\n },\n );\n }\n}\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface Job {\n /**\n * Name of the job.\n */\n name: string;\n\n /**\n * Optional description of the job.\n */\n description?: string;\n\n /**\n * Function to run on schedule.\n */\n handler: (args: { now: DateTime }) => Async<void>;\n\n /**\n * Cron expression to run the job.\n */\n cron?: string;\n\n /**\n * If true, the job will be locked and only one instance will run at a time.\n * You probably need to import {@link AlephaLockRedis} for distributed locking.\n *\n * @default true\n */\n lock?: boolean;\n\n /**\n * Optional prefix for job lock keys.\n */\n lockPrefix?: string;\n}\n\nexport interface JobRegistration {\n name: string;\n options: Job;\n lockDescriptor: LockDescriptor<() => Promise<void>> | null;\n}\n","import { $inject, createDescriptor, Descriptor, KIND } from \"alepha\";\nimport type { DateTime } from \"alepha/datetime\";\nimport { type Job, JobProvider } from \"../providers/JobProvider.ts\";\n\n/**\n * Job descriptor - a drop-in replacement for $scheduler with built-in execution tracking.\n */\nexport const $job = (options: JobDescriptorOptions): JobDescriptor => {\n return createDescriptor(JobDescriptor, options);\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport type JobDescriptorOptions = Omit<Job, \"name\"> & {\n /**\n * Name of the job. Defaults to the descriptor property name.\n */\n name?: string;\n};\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport class JobDescriptor extends Descriptor<JobDescriptorOptions> {\n protected readonly jobProvider = $inject(JobProvider);\n\n public get name(): string {\n return (\n this.options.name ??\n `${this.config.service.name}.${this.config.propertyKey}`\n );\n }\n\n protected onInit() {\n // Register job with JobProvider\n this.jobProvider.registerJob({\n ...this.options,\n name: this.name,\n });\n }\n\n public async trigger(): Promise<void> {\n await this.jobProvider.triggerJob(this.name);\n }\n}\n\n$job[KIND] = JobDescriptor;\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport interface JobHandlerArguments {\n now: DateTime;\n}\n","import { $inject, Alepha } from \"alepha\";\nimport { $repository } from \"alepha/orm\";\nimport { $job } from \"../descriptors/$job.ts\";\nimport { jobExecutions } from \"../entities/jobExecutions.ts\";\nimport type { JobExecutionQuery } from \"../schemas/jobExecutionQuerySchema.ts\";\n\nexport class JobService {\n protected readonly alepha = $inject(Alepha);\n protected readonly executionRepository = $repository(jobExecutions);\n\n public async getJobs(): Promise<string[]> {\n const jobDescriptors = this.alepha.descriptors($job);\n return jobDescriptors.map((job) => job.name);\n }\n\n public async getJobExecutions(query: JobExecutionQuery = {}) {\n query.sort ??= \"-createdAt\";\n\n const where = this.executionRepository.createQueryWhere();\n\n if (query.job) {\n where.job = { eq: query.job };\n }\n\n if (query.status) {\n where.status = { eq: query.status };\n }\n\n return await this.executionRepository.paginate(\n query,\n { where },\n { count: true },\n );\n }\n\n public async triggerJob(name: string): Promise<{ ok: boolean }> {\n const jobDescriptors = this.alepha.descriptors($job);\n const job = jobDescriptors.find((j) => j.name === name);\n\n if (!job) {\n throw new Error(`Job not found: ${name}`);\n }\n\n await job.trigger();\n return { ok: true };\n }\n}\n","import { $inject, t } from \"alepha\";\nimport { $action, okSchema } from \"alepha/server\";\nimport { jobExecutionQuerySchema } from \"../schemas/jobExecutionQuerySchema.ts\";\nimport { jobExecutionResourceSchema } from \"../schemas/jobExecutionResourceSchema.ts\";\nimport { triggerJobSchema } from \"../schemas/triggerJobSchema.ts\";\nimport { JobService } from \"../services/JobService.ts\";\n\nexport class JobController {\n protected readonly url: string = \"/jobs\";\n protected readonly group: string = \"jobs\";\n protected readonly jobService = $inject(JobService);\n\n public readonly getJobs = $action({\n path: this.url,\n group: this.group,\n schema: {\n response: t.array(t.string()),\n },\n handler: () => this.jobService.getJobs(),\n });\n\n public readonly getJobExecutions = $action({\n path: `${this.url}/executions`,\n group: this.group,\n schema: {\n query: jobExecutionQuerySchema,\n response: t.page(jobExecutionResourceSchema),\n },\n handler: ({ query }) => this.jobService.getJobExecutions(query),\n });\n\n public readonly triggerJob = $action({\n method: \"POST\",\n path: `${this.url}/trigger`,\n group: this.group,\n schema: {\n body: triggerJobSchema,\n response: okSchema,\n },\n handler: ({ body }) => this.jobService.triggerJob(body.name),\n });\n}\n","import { $module } from \"alepha\";\nimport { JobController } from \"./controllers/JobController.ts\";\nimport { JobProvider } from \"./providers/JobProvider.ts\";\nimport { JobService } from \"./services/JobService.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\nexport * from \"./controllers/JobController.ts\";\nexport * from \"./descriptors/$job.ts\";\nexport * from \"./entities/jobExecutions.ts\";\nexport * from \"./providers/JobProvider.ts\";\nexport * from \"./schemas/jobExecutionQuerySchema.ts\";\nexport * from \"./schemas/jobExecutionResourceSchema.ts\";\nexport * from \"./schemas/triggerJobSchema.ts\";\nexport * from \"./services/JobService.ts\";\n\n// ---------------------------------------------------------------------------------------------------------------------\n\n/**\n * Provides job management API endpoints for Alepha applications.\n *\n * This module includes job queue operations, job status monitoring,\n * and background task management capabilities.\n *\n * @module alepha.api.jobs\n */\nexport const AlephaApiJobs = $module({\n name: \"alepha.api.jobs\",\n services: [JobController, JobProvider, JobService],\n});\n"],"mappings":"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"}
|