alepha 0.13.0 → 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.
Files changed (195) hide show
  1. package/dist/api-jobs/index.d.ts +26 -26
  2. package/dist/api-users/index.d.ts +1 -1
  3. package/dist/cli/{dist-Sz2EXvQX.cjs → dist-Dl9Vl7Ur.js} +17 -13
  4. package/dist/cli/{dist-BBPjuQ56.js.map → dist-Dl9Vl7Ur.js.map} +1 -1
  5. package/dist/cli/index.d.ts +3 -11
  6. package/dist/cli/index.js +106 -74
  7. package/dist/cli/index.js.map +1 -1
  8. package/dist/email/index.js +71 -73
  9. package/dist/email/index.js.map +1 -1
  10. package/dist/orm/index.d.ts +1 -1
  11. package/dist/orm/index.js.map +1 -1
  12. package/dist/queue/index.d.ts +4 -4
  13. package/dist/retry/index.d.ts +1 -1
  14. package/dist/retry/index.js +2 -2
  15. package/dist/retry/index.js.map +1 -1
  16. package/dist/scheduler/index.d.ts +6 -6
  17. package/dist/security/index.d.ts +28 -28
  18. package/dist/server/index.js +1 -1
  19. package/dist/server/index.js.map +1 -1
  20. package/dist/server-health/index.d.ts +17 -17
  21. package/dist/server-metrics/index.js +170 -174
  22. package/dist/server-metrics/index.js.map +1 -1
  23. package/dist/server-security/index.d.ts +9 -9
  24. package/dist/vite/index.js +4 -5
  25. package/dist/vite/index.js.map +1 -1
  26. package/dist/websocket/index.d.ts +7 -7
  27. package/package.json +52 -103
  28. package/src/cli/apps/AlephaPackageBuilderCli.ts +7 -2
  29. package/src/cli/assets/appRouterTs.ts +9 -0
  30. package/src/cli/assets/indexHtml.ts +2 -1
  31. package/src/cli/assets/mainBrowserTs.ts +10 -0
  32. package/src/cli/commands/CoreCommands.ts +6 -5
  33. package/src/cli/commands/DrizzleCommands.ts +65 -57
  34. package/src/cli/commands/VerifyCommands.ts +1 -1
  35. package/src/cli/services/ProjectUtils.ts +44 -38
  36. package/src/orm/providers/DrizzleKitProvider.ts +1 -1
  37. package/src/retry/descriptors/$retry.ts +5 -3
  38. package/src/server/providers/NodeHttpServerProvider.ts +1 -1
  39. package/src/vite/helpers/boot.ts +3 -3
  40. package/dist/api-files/index.cjs +0 -1293
  41. package/dist/api-files/index.cjs.map +0 -1
  42. package/dist/api-files/index.d.cts +0 -829
  43. package/dist/api-jobs/index.cjs +0 -274
  44. package/dist/api-jobs/index.cjs.map +0 -1
  45. package/dist/api-jobs/index.d.cts +0 -654
  46. package/dist/api-notifications/index.cjs +0 -380
  47. package/dist/api-notifications/index.cjs.map +0 -1
  48. package/dist/api-notifications/index.d.cts +0 -289
  49. package/dist/api-parameters/index.cjs +0 -66
  50. package/dist/api-parameters/index.cjs.map +0 -1
  51. package/dist/api-parameters/index.d.cts +0 -84
  52. package/dist/api-users/index.cjs +0 -6009
  53. package/dist/api-users/index.cjs.map +0 -1
  54. package/dist/api-users/index.d.cts +0 -4740
  55. package/dist/api-verifications/index.cjs +0 -407
  56. package/dist/api-verifications/index.cjs.map +0 -1
  57. package/dist/api-verifications/index.d.cts +0 -207
  58. package/dist/batch/index.cjs +0 -408
  59. package/dist/batch/index.cjs.map +0 -1
  60. package/dist/batch/index.d.cts +0 -330
  61. package/dist/bin/index.cjs +0 -17
  62. package/dist/bin/index.cjs.map +0 -1
  63. package/dist/bin/index.d.cts +0 -1
  64. package/dist/bucket/index.cjs +0 -303
  65. package/dist/bucket/index.cjs.map +0 -1
  66. package/dist/bucket/index.d.cts +0 -355
  67. package/dist/cache/index.cjs +0 -241
  68. package/dist/cache/index.cjs.map +0 -1
  69. package/dist/cache/index.d.cts +0 -202
  70. package/dist/cache-redis/index.cjs +0 -84
  71. package/dist/cache-redis/index.cjs.map +0 -1
  72. package/dist/cache-redis/index.d.cts +0 -40
  73. package/dist/cli/chunk-DSlc6foC.cjs +0 -43
  74. package/dist/cli/dist-BBPjuQ56.js +0 -2778
  75. package/dist/cli/dist-Sz2EXvQX.cjs.map +0 -1
  76. package/dist/cli/index.cjs +0 -1241
  77. package/dist/cli/index.cjs.map +0 -1
  78. package/dist/cli/index.d.cts +0 -422
  79. package/dist/command/index.cjs +0 -693
  80. package/dist/command/index.cjs.map +0 -1
  81. package/dist/command/index.d.cts +0 -340
  82. package/dist/core/index.cjs +0 -2264
  83. package/dist/core/index.cjs.map +0 -1
  84. package/dist/core/index.d.cts +0 -1927
  85. package/dist/datetime/index.cjs +0 -318
  86. package/dist/datetime/index.cjs.map +0 -1
  87. package/dist/datetime/index.d.cts +0 -145
  88. package/dist/email/index.cjs +0 -10874
  89. package/dist/email/index.cjs.map +0 -1
  90. package/dist/email/index.d.cts +0 -186
  91. package/dist/fake/index.cjs +0 -34641
  92. package/dist/fake/index.cjs.map +0 -1
  93. package/dist/fake/index.d.cts +0 -74
  94. package/dist/file/index.cjs +0 -1212
  95. package/dist/file/index.cjs.map +0 -1
  96. package/dist/file/index.d.cts +0 -698
  97. package/dist/lock/index.cjs +0 -226
  98. package/dist/lock/index.cjs.map +0 -1
  99. package/dist/lock/index.d.cts +0 -361
  100. package/dist/lock-redis/index.cjs +0 -113
  101. package/dist/lock-redis/index.cjs.map +0 -1
  102. package/dist/lock-redis/index.d.cts +0 -24
  103. package/dist/logger/index.cjs +0 -521
  104. package/dist/logger/index.cjs.map +0 -1
  105. package/dist/logger/index.d.cts +0 -281
  106. package/dist/orm/index.cjs +0 -2986
  107. package/dist/orm/index.cjs.map +0 -1
  108. package/dist/orm/index.d.cts +0 -2213
  109. package/dist/queue/index.cjs +0 -1044
  110. package/dist/queue/index.cjs.map +0 -1
  111. package/dist/queue/index.d.cts +0 -1265
  112. package/dist/queue-redis/index.cjs +0 -873
  113. package/dist/queue-redis/index.cjs.map +0 -1
  114. package/dist/queue-redis/index.d.cts +0 -82
  115. package/dist/redis/index.cjs +0 -153
  116. package/dist/redis/index.cjs.map +0 -1
  117. package/dist/redis/index.d.cts +0 -82
  118. package/dist/retry/index.cjs +0 -146
  119. package/dist/retry/index.cjs.map +0 -1
  120. package/dist/retry/index.d.cts +0 -172
  121. package/dist/router/index.cjs +0 -111
  122. package/dist/router/index.cjs.map +0 -1
  123. package/dist/router/index.d.cts +0 -46
  124. package/dist/scheduler/index.cjs +0 -576
  125. package/dist/scheduler/index.cjs.map +0 -1
  126. package/dist/scheduler/index.d.cts +0 -145
  127. package/dist/security/index.cjs +0 -2402
  128. package/dist/security/index.cjs.map +0 -1
  129. package/dist/security/index.d.cts +0 -598
  130. package/dist/server/index.cjs +0 -1680
  131. package/dist/server/index.cjs.map +0 -1
  132. package/dist/server/index.d.cts +0 -810
  133. package/dist/server-auth/index.cjs +0 -3146
  134. package/dist/server-auth/index.cjs.map +0 -1
  135. package/dist/server-auth/index.d.cts +0 -1164
  136. package/dist/server-cache/index.cjs +0 -252
  137. package/dist/server-cache/index.cjs.map +0 -1
  138. package/dist/server-cache/index.d.cts +0 -164
  139. package/dist/server-compress/index.cjs +0 -141
  140. package/dist/server-compress/index.cjs.map +0 -1
  141. package/dist/server-compress/index.d.cts +0 -38
  142. package/dist/server-cookies/index.cjs +0 -234
  143. package/dist/server-cookies/index.cjs.map +0 -1
  144. package/dist/server-cookies/index.d.cts +0 -144
  145. package/dist/server-cors/index.cjs +0 -201
  146. package/dist/server-cors/index.cjs.map +0 -1
  147. package/dist/server-cors/index.d.cts +0 -140
  148. package/dist/server-health/index.cjs +0 -62
  149. package/dist/server-health/index.cjs.map +0 -1
  150. package/dist/server-health/index.d.cts +0 -58
  151. package/dist/server-helmet/index.cjs +0 -131
  152. package/dist/server-helmet/index.cjs.map +0 -1
  153. package/dist/server-helmet/index.d.cts +0 -97
  154. package/dist/server-links/index.cjs +0 -992
  155. package/dist/server-links/index.cjs.map +0 -1
  156. package/dist/server-links/index.d.cts +0 -513
  157. package/dist/server-metrics/index.cjs +0 -4535
  158. package/dist/server-metrics/index.cjs.map +0 -1
  159. package/dist/server-metrics/index.d.cts +0 -35
  160. package/dist/server-multipart/index.cjs +0 -237
  161. package/dist/server-multipart/index.cjs.map +0 -1
  162. package/dist/server-multipart/index.d.cts +0 -50
  163. package/dist/server-proxy/index.cjs +0 -186
  164. package/dist/server-proxy/index.cjs.map +0 -1
  165. package/dist/server-proxy/index.d.cts +0 -234
  166. package/dist/server-rate-limit/index.cjs +0 -241
  167. package/dist/server-rate-limit/index.cjs.map +0 -1
  168. package/dist/server-rate-limit/index.d.cts +0 -183
  169. package/dist/server-security/index.cjs +0 -316
  170. package/dist/server-security/index.cjs.map +0 -1
  171. package/dist/server-security/index.d.cts +0 -173
  172. package/dist/server-static/index.cjs +0 -170
  173. package/dist/server-static/index.cjs.map +0 -1
  174. package/dist/server-static/index.d.cts +0 -121
  175. package/dist/server-swagger/index.cjs +0 -1021
  176. package/dist/server-swagger/index.cjs.map +0 -1
  177. package/dist/server-swagger/index.d.cts +0 -382
  178. package/dist/sms/index.cjs +0 -221
  179. package/dist/sms/index.cjs.map +0 -1
  180. package/dist/sms/index.d.cts +0 -130
  181. package/dist/thread/index.cjs +0 -350
  182. package/dist/thread/index.cjs.map +0 -1
  183. package/dist/thread/index.d.cts +0 -260
  184. package/dist/topic/index.cjs +0 -282
  185. package/dist/topic/index.cjs.map +0 -1
  186. package/dist/topic/index.d.cts +0 -523
  187. package/dist/topic-redis/index.cjs +0 -71
  188. package/dist/topic-redis/index.cjs.map +0 -1
  189. package/dist/topic-redis/index.d.cts +0 -42
  190. package/dist/vite/index.cjs +0 -1077
  191. package/dist/vite/index.cjs.map +0 -1
  192. package/dist/vite/index.d.cts +0 -542
  193. package/dist/websocket/index.cjs +0 -1117
  194. package/dist/websocket/index.cjs.map +0 -1
  195. package/dist/websocket/index.d.cts +0 -861
@@ -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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"}