alepha 0.19.4 → 0.19.5

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 (104) hide show
  1. package/dist/api/audits/index.d.ts +8 -8
  2. package/dist/api/issues/index.d.ts +810 -0
  3. package/dist/api/issues/index.d.ts.map +1 -0
  4. package/dist/api/issues/index.js +447 -0
  5. package/dist/api/issues/index.js.map +1 -0
  6. package/dist/api/keys/index.d.ts +5 -5
  7. package/dist/api/users/index.d.ts +6 -0
  8. package/dist/api/users/index.d.ts.map +1 -1
  9. package/dist/api/users/index.js +10 -3
  10. package/dist/api/users/index.js.map +1 -1
  11. package/dist/api/workflows/index.d.ts +3 -3
  12. package/dist/captcha/index.d.ts +142 -0
  13. package/dist/captcha/index.d.ts.map +1 -0
  14. package/dist/captcha/index.js +177 -0
  15. package/dist/captcha/index.js.map +1 -0
  16. package/dist/cli/core/index.d.ts +82 -2
  17. package/dist/cli/core/index.d.ts.map +1 -1
  18. package/dist/cli/core/index.js +90 -6
  19. package/dist/cli/core/index.js.map +1 -1
  20. package/dist/cli/platform/index.d.ts +84 -10
  21. package/dist/cli/platform/index.d.ts.map +1 -1
  22. package/dist/cli/platform/index.js +92 -4
  23. package/dist/cli/platform/index.js.map +1 -1
  24. package/dist/cli/vendor/index.d.ts +30 -3
  25. package/dist/cli/vendor/index.d.ts.map +1 -1
  26. package/dist/cli/vendor/index.js +98 -21
  27. package/dist/cli/vendor/index.js.map +1 -1
  28. package/dist/command/index.d.ts.map +1 -1
  29. package/dist/command/index.js +2 -3
  30. package/dist/command/index.js.map +1 -1
  31. package/dist/orm/core/index.bun.js +6 -6
  32. package/dist/orm/core/index.bun.js.map +1 -1
  33. package/dist/orm/core/index.d.ts.map +1 -1
  34. package/dist/orm/core/index.js +6 -6
  35. package/dist/orm/core/index.js.map +1 -1
  36. package/dist/react/i18n/index.d.ts +1 -0
  37. package/dist/react/i18n/index.d.ts.map +1 -1
  38. package/dist/react/i18n/index.js +8 -4
  39. package/dist/react/i18n/index.js.map +1 -1
  40. package/dist/security/index.d.ts.map +1 -1
  41. package/dist/security/index.js.map +1 -1
  42. package/dist/server/auth/index.d.ts +145 -2
  43. package/dist/server/auth/index.d.ts.map +1 -1
  44. package/dist/server/auth/index.js +364 -63
  45. package/dist/server/auth/index.js.map +1 -1
  46. package/dist/server/cookies/index.d.ts.map +1 -1
  47. package/dist/server/cookies/index.js.map +1 -1
  48. package/dist/websocket/index.d.ts.map +1 -1
  49. package/dist/websocket/index.js.map +1 -1
  50. package/package.json +11 -1
  51. package/src/api/issues/__tests__/IssueService.spec.ts +263 -0
  52. package/src/api/issues/controllers/AdminIssueController.ts +149 -0
  53. package/src/api/issues/controllers/IssueController.ts +44 -0
  54. package/src/api/issues/entities/issues.ts +49 -0
  55. package/src/api/issues/index.ts +53 -0
  56. package/src/api/issues/schemas/createIssueSchema.ts +13 -0
  57. package/src/api/issues/schemas/issueConfigAtom.ts +13 -0
  58. package/src/api/issues/schemas/issueQuerySchema.ts +18 -0
  59. package/src/api/issues/schemas/issueResourceSchema.ts +6 -0
  60. package/src/api/issues/schemas/myIssueQuerySchema.ts +10 -0
  61. package/src/api/issues/schemas/updateIssueSchema.ts +13 -0
  62. package/src/api/issues/services/IssueService.ts +264 -0
  63. package/src/api/users/primitives/$realm.ts +24 -0
  64. package/src/api/users/services/CredentialService.ts +6 -3
  65. package/src/api/users/services/RegistrationService.ts +15 -5
  66. package/src/api/users/services/SessionService.ts +2 -0
  67. package/src/captcha/__tests__/MemoryCaptchaProvider.spec.ts +74 -0
  68. package/src/captcha/index.ts +33 -0
  69. package/src/captcha/providers/CaptchaProvider.ts +17 -0
  70. package/src/captcha/providers/MemoryCaptchaProvider.ts +65 -0
  71. package/src/captcha/providers/TurnstileCaptchaProvider.ts +125 -0
  72. package/src/cli/core/atoms/buildOptions.ts +57 -0
  73. package/src/cli/core/commands/build.ts +2 -0
  74. package/src/cli/core/providers/ViteDevServerProvider.ts +1 -1
  75. package/src/cli/core/services/ViteUtils.ts +5 -2
  76. package/src/cli/core/tasks/BuildClientTask.ts +3 -1
  77. package/src/cli/core/tasks/BuildCloudflareTask.ts +4 -0
  78. package/src/cli/core/tasks/BuildPwaTask.ts +81 -0
  79. package/src/cli/platform/adapters/CloudflareAdapter.ts +24 -0
  80. package/src/cli/platform/atoms/platformOptions.ts +19 -3
  81. package/src/cli/platform/hooks/PlatformHook.ts +51 -0
  82. package/src/cli/platform/index.ts +1 -0
  83. package/src/cli/platform/services/CloudflareApi.ts +22 -1
  84. package/src/cli/platform/services/PlatformOrchestrator.ts +67 -2
  85. package/src/cli/vendor/__tests__/VendorService.spec.ts +40 -1
  86. package/src/cli/vendor/commands/VendorCommand.ts +41 -38
  87. package/src/cli/vendor/services/VendorService.ts +108 -4
  88. package/src/command/__tests__/CliProvider.spec.ts +45 -0
  89. package/src/command/providers/CliProvider.ts +3 -4
  90. package/src/orm/core/services/Repository.ts +20 -6
  91. package/src/react/i18n/__tests__/I18nProvider.spec.ts +83 -0
  92. package/src/react/i18n/providers/I18nProvider.ts +12 -10
  93. package/src/security/primitives/$issuer.ts +3 -1
  94. package/src/server/auth/index.ts +7 -0
  95. package/src/server/auth/primitives/$auth.ts +37 -3
  96. package/src/server/auth/primitives/$authApple.ts +114 -4
  97. package/src/server/auth/primitives/$authFacebook.ts +98 -0
  98. package/src/server/auth/primitives/$authFranceConnect.ts +105 -0
  99. package/src/server/auth/primitives/$authGithub.ts +22 -16
  100. package/src/server/auth/primitives/$authMicrosoft.ts +88 -0
  101. package/src/server/auth/providers/ServerAuthProvider.ts +197 -72
  102. package/src/server/cookies/providers/ServerCookiesProvider.ts +3 -0
  103. package/src/server/core/__tests__/ServerRouterProvider-errorHandler.spec.ts +1 -1
  104. package/src/websocket/providers/NodeWebSocketServerProvider.ts +3 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../../../src/api/issues/entities/issues.ts","../../../src/orm/core/schemas/insertSchema.ts","../../../src/orm/core/schemas/updateSchema.ts","../../../src/orm/core/primitives/$entity.ts","../../../src/orm/core/constants/PG_SYMBOLS.ts","../../../src/orm/core/helpers/pgAttr.ts","../../../src/orm/core/schemas/databaseEnvSchema.ts","../../../src/api/issues/schemas/createIssueSchema.ts","../../../src/api/issues/schemas/issueQuerySchema.ts","../../../src/api/issues/schemas/myIssueQuerySchema.ts","../../../src/api/issues/schemas/updateIssueSchema.ts","../../../src/api/issues/services/IssueService.ts","../../../src/api/issues/controllers/AdminIssueController.ts","../../../src/api/issues/controllers/IssueController.ts","../../../src/api/issues/schemas/issueConfigAtom.ts","../../../src/api/issues/schemas/issueResourceSchema.ts","../../../src/api/issues/index.ts"],"mappings":"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"}
@@ -0,0 +1,447 @@
1
+ import { $atom, $inject, $module, Alepha, t } from "alepha";
2
+ import { $secure } from "alepha/security";
3
+ import { $action, BadRequestError, okSchema } from "alepha/server";
4
+ import { $entity, $repository, db, pageQuerySchema } from "alepha/orm";
5
+ import { users } from "alepha/api/users";
6
+ import { DateTimeProvider } from "alepha/datetime";
7
+ import { $logger } from "alepha/logger";
8
+ //#region ../../src/api/issues/entities/issues.ts
9
+ const issueTypeSchema = t.enum([
10
+ "bug",
11
+ "feature",
12
+ "improvement"
13
+ ], { default: "bug" });
14
+ const issuePrioritySchema = t.enum([
15
+ "low",
16
+ "medium",
17
+ "high",
18
+ "urgent"
19
+ ], { default: "medium" });
20
+ const issueStatusSchema = t.enum([
21
+ "open",
22
+ "assigned",
23
+ "completed",
24
+ "archived"
25
+ ]);
26
+ const issues = $entity({
27
+ name: "issues",
28
+ schema: t.object({
29
+ id: db.primaryKey(t.uuid()),
30
+ version: db.version(),
31
+ createdAt: db.createdAt(),
32
+ updatedAt: db.updatedAt(),
33
+ createdBy: db.ref(t.uuid(), () => users.cols.id, { onDelete: "cascade" }),
34
+ title: t.text({ maxLength: 255 }),
35
+ type: db.default(issueTypeSchema, "bug"),
36
+ priority: db.default(issuePrioritySchema, "medium"),
37
+ status: db.default(issueStatusSchema, "open"),
38
+ description: t.optional(t.text({ maxLength: 65535 })),
39
+ pageUrl: t.optional(t.string({ format: "uri" })),
40
+ assigneeId: t.optional(db.ref(t.uuid(), () => users.cols.id)),
41
+ assignedAt: t.optional(t.datetime()),
42
+ resolution: t.optional(t.text({ maxLength: 65535 })),
43
+ completedAt: t.optional(t.datetime()),
44
+ reopenReason: t.optional(t.text({ maxLength: 1024 })),
45
+ archivedAt: t.optional(t.datetime())
46
+ }),
47
+ indexes: [
48
+ "status",
49
+ "createdBy",
50
+ "assigneeId",
51
+ { columns: ["type", "status"] }
52
+ ]
53
+ });
54
+ //#endregion
55
+ //#region ../../src/api/issues/schemas/issueQuerySchema.ts
56
+ const issueQuerySchema = t.extend(pageQuerySchema, {
57
+ status: t.optional(issueStatusSchema),
58
+ type: t.optional(issueTypeSchema),
59
+ priority: t.optional(issuePrioritySchema),
60
+ assigneeId: t.optional(t.uuid({ description: "Filter by assignee" })),
61
+ search: t.optional(t.text({ description: "Search in title" }))
62
+ });
63
+ //#endregion
64
+ //#region ../../src/api/issues/schemas/issueResourceSchema.ts
65
+ const issueResourceSchema = issues.schema;
66
+ //#endregion
67
+ //#region ../../src/api/issues/schemas/updateIssueSchema.ts
68
+ const updateIssueSchema = t.object({
69
+ title: t.optional(t.text({ maxLength: 255 })),
70
+ type: t.optional(issueTypeSchema),
71
+ priority: t.optional(issuePrioritySchema),
72
+ description: t.optional(t.text({ maxLength: 65535 })),
73
+ pageUrl: t.optional(t.string({ format: "uri" }))
74
+ });
75
+ //#endregion
76
+ //#region ../../src/api/issues/schemas/issueConfigAtom.ts
77
+ const issueConfigAtom = $atom({
78
+ name: "alepha.api.issues.config",
79
+ schema: t.object({
80
+ enabled: t.boolean(),
81
+ maxOpenPerUser: t.integer({
82
+ minimum: 1,
83
+ maximum: 1e3
84
+ })
85
+ }),
86
+ default: {
87
+ enabled: true,
88
+ maxOpenPerUser: 50
89
+ }
90
+ });
91
+ //#endregion
92
+ //#region ../../src/api/issues/services/IssueService.ts
93
+ var IssueService = class {
94
+ alepha = $inject(Alepha);
95
+ log = $logger();
96
+ repo = $repository(issues);
97
+ dateTime = $inject(DateTimeProvider);
98
+ /**
99
+ * Get an issue by ID.
100
+ */
101
+ async getById(id) {
102
+ return this.repo.getById(id);
103
+ }
104
+ /**
105
+ * Create a new issue.
106
+ */
107
+ async create(data, createdBy) {
108
+ const config = this.alepha.store.get(issueConfigAtom);
109
+ if (!config.enabled) throw new BadRequestError("Issue submission is disabled");
110
+ if (await this.repo.count({
111
+ createdBy: { eq: createdBy.id },
112
+ status: { inArray: ["open", "assigned"] }
113
+ }) >= config.maxOpenPerUser) throw new BadRequestError(`Maximum open issues per user reached (${config.maxOpenPerUser})`);
114
+ const entity = await this.repo.create({
115
+ createdBy: createdBy.id,
116
+ title: data.title,
117
+ type: data.type ?? "bug",
118
+ priority: data.priority ?? "medium",
119
+ status: "open",
120
+ description: data.description,
121
+ pageUrl: data.pageUrl
122
+ });
123
+ this.log.info("Issue created", {
124
+ id: entity.id,
125
+ createdBy: createdBy.id
126
+ });
127
+ await this.alepha.events.emit("issue:created", { issue: entity });
128
+ return entity;
129
+ }
130
+ /**
131
+ * Find issues for the current user.
132
+ */
133
+ async findMine(userId, query = {}) {
134
+ query.sort ??= "-createdAt";
135
+ const where = this.repo.createQueryWhere();
136
+ where.createdBy = { eq: userId };
137
+ if (query.status) where.status = { eq: query.status };
138
+ return this.repo.paginate(query, { where }, { count: true });
139
+ }
140
+ /**
141
+ * Find issues with pagination and filtering (admin).
142
+ */
143
+ async find(query = {}) {
144
+ query.sort ??= "-createdAt";
145
+ const where = this.repo.createQueryWhere();
146
+ if (query.status) where.status = { eq: query.status };
147
+ if (query.type) where.type = { eq: query.type };
148
+ if (query.priority) where.priority = { eq: query.priority };
149
+ if (query.assigneeId) where.assigneeId = { eq: query.assigneeId };
150
+ if (query.search) where.title = { ilike: `%${query.search}%` };
151
+ return this.repo.paginate(query, { where }, { count: true });
152
+ }
153
+ /**
154
+ * Update issue fields (admin).
155
+ */
156
+ async update(id, data) {
157
+ return this.repo.updateById(id, data);
158
+ }
159
+ /**
160
+ * Assign an issue to a user.
161
+ */
162
+ async assign(id, assigneeId) {
163
+ const issue = await this.repo.getById(id);
164
+ if (issue.status !== "open") throw new BadRequestError(`Cannot assign issue in "${issue.status}" status (must be "open")`);
165
+ const updated = await this.repo.updateById(id, {
166
+ status: "assigned",
167
+ assigneeId,
168
+ assignedAt: this.dateTime.nowISOString()
169
+ });
170
+ this.log.info("Issue assigned", {
171
+ id,
172
+ assigneeId
173
+ });
174
+ await this.alepha.events.emit("issue:assigned", {
175
+ issue: updated,
176
+ assigneeId
177
+ });
178
+ return updated;
179
+ }
180
+ /**
181
+ * Complete an issue with resolution notes.
182
+ */
183
+ async complete(id, resolution) {
184
+ const issue = await this.repo.getById(id);
185
+ if (issue.status !== "assigned") throw new BadRequestError(`Cannot complete issue in "${issue.status}" status (must be "assigned")`);
186
+ const updated = await this.repo.updateById(id, {
187
+ status: "completed",
188
+ resolution,
189
+ completedAt: this.dateTime.nowISOString()
190
+ });
191
+ this.log.info("Issue completed", { id });
192
+ await this.alepha.events.emit("issue:completed", { issue: updated });
193
+ return updated;
194
+ }
195
+ /**
196
+ * Reopen a completed issue.
197
+ */
198
+ async reopen(id, reason) {
199
+ const issue = await this.repo.getById(id);
200
+ if (issue.status !== "completed") throw new BadRequestError(`Cannot reopen issue in "${issue.status}" status (must be "completed")`);
201
+ const updated = await this.repo.updateById(id, {
202
+ status: "open",
203
+ reopenReason: reason,
204
+ assigneeId: void 0,
205
+ assignedAt: void 0,
206
+ resolution: void 0,
207
+ completedAt: void 0
208
+ });
209
+ this.log.info("Issue reopened", {
210
+ id,
211
+ reason
212
+ });
213
+ await this.alepha.events.emit("issue:reopened", {
214
+ issue: updated,
215
+ reason
216
+ });
217
+ return updated;
218
+ }
219
+ /**
220
+ * Archive a completed issue.
221
+ */
222
+ async archive(id) {
223
+ const issue = await this.repo.getById(id);
224
+ if (issue.status !== "completed") throw new BadRequestError(`Cannot archive issue in "${issue.status}" status (must be "completed")`);
225
+ const updated = await this.repo.updateById(id, {
226
+ status: "archived",
227
+ archivedAt: this.dateTime.nowISOString()
228
+ });
229
+ this.log.info("Issue archived", { id });
230
+ await this.alepha.events.emit("issue:archived", { issue: updated });
231
+ return updated;
232
+ }
233
+ /**
234
+ * Delete an issue.
235
+ */
236
+ async deleteIssue(id) {
237
+ const issue = await this.repo.getById(id);
238
+ await this.repo.deleteById(id);
239
+ this.log.info("Issue deleted", { id });
240
+ await this.alepha.events.emit("issue:deleted", { issue });
241
+ }
242
+ };
243
+ //#endregion
244
+ //#region ../../src/api/issues/controllers/AdminIssueController.ts
245
+ var AdminIssueController = class {
246
+ url = "/issues";
247
+ group = "admin:issues";
248
+ issueService = $inject(IssueService);
249
+ /**
250
+ * Find issues with pagination and filtering.
251
+ */
252
+ findIssues = $action({
253
+ path: this.url,
254
+ group: this.group,
255
+ use: [$secure({ permissions: ["admin:issue:read"] })],
256
+ description: "Find issues with pagination and filtering",
257
+ schema: {
258
+ query: issueQuerySchema,
259
+ response: t.page(issueResourceSchema)
260
+ },
261
+ handler: ({ query }) => this.issueService.find(query)
262
+ });
263
+ /**
264
+ * Get an issue by ID.
265
+ */
266
+ getIssue = $action({
267
+ path: `${this.url}/:id`,
268
+ group: this.group,
269
+ use: [$secure({ permissions: ["admin:issue:read"] })],
270
+ description: "Get an issue by ID",
271
+ schema: {
272
+ params: t.object({ id: t.uuid() }),
273
+ response: issueResourceSchema
274
+ },
275
+ handler: ({ params }) => this.issueService.getById(params.id)
276
+ });
277
+ /**
278
+ * Update issue fields.
279
+ */
280
+ updateIssue = $action({
281
+ method: "PATCH",
282
+ path: `${this.url}/:id`,
283
+ group: this.group,
284
+ use: [$secure({ permissions: ["admin:issue:update"] })],
285
+ description: "Update issue fields",
286
+ schema: {
287
+ params: t.object({ id: t.uuid() }),
288
+ body: updateIssueSchema,
289
+ response: issueResourceSchema
290
+ },
291
+ handler: ({ params, body }) => this.issueService.update(params.id, body)
292
+ });
293
+ /**
294
+ * Assign an issue to a user.
295
+ */
296
+ assignIssue = $action({
297
+ method: "POST",
298
+ path: `${this.url}/:id/assign`,
299
+ group: this.group,
300
+ use: [$secure({ permissions: ["admin:issue:update"] })],
301
+ description: "Assign an issue to a user",
302
+ schema: {
303
+ params: t.object({ id: t.uuid() }),
304
+ body: t.object({ assigneeId: t.uuid() }),
305
+ response: issueResourceSchema
306
+ },
307
+ handler: ({ params, body }) => this.issueService.assign(params.id, body.assigneeId)
308
+ });
309
+ /**
310
+ * Mark an issue as completed.
311
+ */
312
+ completeIssue = $action({
313
+ method: "POST",
314
+ path: `${this.url}/:id/complete`,
315
+ group: this.group,
316
+ use: [$secure({ permissions: ["admin:issue:update"] })],
317
+ description: "Mark an issue as completed with resolution notes",
318
+ schema: {
319
+ params: t.object({ id: t.uuid() }),
320
+ body: t.object({ resolution: t.text({ minLength: 1 }) }),
321
+ response: issueResourceSchema
322
+ },
323
+ handler: ({ params, body }) => this.issueService.complete(params.id, body.resolution)
324
+ });
325
+ /**
326
+ * Reopen a completed issue.
327
+ */
328
+ reopenIssue = $action({
329
+ method: "POST",
330
+ path: `${this.url}/:id/reopen`,
331
+ group: this.group,
332
+ use: [$secure({ permissions: ["admin:issue:update"] })],
333
+ description: "Reopen a completed issue with a reason",
334
+ schema: {
335
+ params: t.object({ id: t.uuid() }),
336
+ body: t.object({ reason: t.text({ minLength: 1 }) }),
337
+ response: issueResourceSchema
338
+ },
339
+ handler: ({ params, body }) => this.issueService.reopen(params.id, body.reason)
340
+ });
341
+ /**
342
+ * Archive a completed issue.
343
+ */
344
+ archiveIssue = $action({
345
+ method: "POST",
346
+ path: `${this.url}/:id/archive`,
347
+ group: this.group,
348
+ use: [$secure({ permissions: ["admin:issue:update"] })],
349
+ description: "Archive a completed issue",
350
+ schema: {
351
+ params: t.object({ id: t.uuid() }),
352
+ response: issueResourceSchema
353
+ },
354
+ handler: ({ params }) => this.issueService.archive(params.id)
355
+ });
356
+ /**
357
+ * Delete an issue.
358
+ */
359
+ deleteIssue = $action({
360
+ method: "DELETE",
361
+ path: `${this.url}/:id`,
362
+ group: this.group,
363
+ use: [$secure({ permissions: ["admin:issue:delete"] })],
364
+ description: "Delete an issue",
365
+ schema: {
366
+ params: t.object({ id: t.uuid() }),
367
+ response: okSchema
368
+ },
369
+ handler: async ({ params }) => {
370
+ await this.issueService.deleteIssue(params.id);
371
+ return {
372
+ ok: true,
373
+ id: params.id
374
+ };
375
+ }
376
+ });
377
+ };
378
+ //#endregion
379
+ //#region ../../src/api/issues/schemas/createIssueSchema.ts
380
+ const createIssueSchema = t.object({
381
+ title: t.text({ maxLength: 255 }),
382
+ type: t.optional(issueTypeSchema),
383
+ priority: t.optional(issuePrioritySchema),
384
+ description: t.optional(t.text({ maxLength: 65535 })),
385
+ pageUrl: t.optional(t.string({ format: "uri" }))
386
+ });
387
+ //#endregion
388
+ //#region ../../src/api/issues/schemas/myIssueQuerySchema.ts
389
+ const myIssueQuerySchema = t.extend(pageQuerySchema, { status: t.optional(issueStatusSchema) });
390
+ //#endregion
391
+ //#region ../../src/api/issues/controllers/IssueController.ts
392
+ var IssueController = class {
393
+ url = "/issues";
394
+ group = "issues";
395
+ issueService = $inject(IssueService);
396
+ /**
397
+ * Submit a new issue.
398
+ */
399
+ createIssue = $action({
400
+ method: "POST",
401
+ path: this.url,
402
+ group: this.group,
403
+ use: [$secure({ permissions: ["issue:create"] })],
404
+ description: "Submit a new issue",
405
+ schema: {
406
+ body: createIssueSchema,
407
+ response: issueResourceSchema
408
+ },
409
+ handler: ({ body, user }) => this.issueService.create(body, user)
410
+ });
411
+ /**
412
+ * List issues for the current user.
413
+ */
414
+ getMyIssues = $action({
415
+ path: `${this.url}/mine`,
416
+ group: this.group,
417
+ use: [$secure({ permissions: ["issue:read"] })],
418
+ description: "List issues submitted by the current user",
419
+ schema: {
420
+ query: myIssueQuerySchema,
421
+ response: t.page(issueResourceSchema)
422
+ },
423
+ handler: ({ query, user }) => this.issueService.findMine(user.id, query)
424
+ });
425
+ };
426
+ //#endregion
427
+ //#region ../../src/api/issues/index.ts
428
+ /**
429
+ * Issue tracking module — submit, assign, complete, reopen, and archive issues.
430
+ *
431
+ * @module alepha.api.issues
432
+ */
433
+ const AlephaApiIssues = $module({
434
+ name: "alepha.api.issues",
435
+ services: [
436
+ IssueService,
437
+ IssueController,
438
+ AdminIssueController
439
+ ],
440
+ register: (alepha) => {
441
+ alepha.with(IssueService).with(IssueController).with(AdminIssueController);
442
+ }
443
+ });
444
+ //#endregion
445
+ export { AdminIssueController, AlephaApiIssues, IssueController, IssueService, createIssueSchema, issueConfigAtom, issuePrioritySchema, issueQuerySchema, issueResourceSchema, issueStatusSchema, issueTypeSchema, issues, myIssueQuerySchema, updateIssueSchema };
446
+
447
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../../src/api/issues/entities/issues.ts","../../../src/api/issues/schemas/issueQuerySchema.ts","../../../src/api/issues/schemas/issueResourceSchema.ts","../../../src/api/issues/schemas/updateIssueSchema.ts","../../../src/api/issues/schemas/issueConfigAtom.ts","../../../src/api/issues/services/IssueService.ts","../../../src/api/issues/controllers/AdminIssueController.ts","../../../src/api/issues/schemas/createIssueSchema.ts","../../../src/api/issues/schemas/myIssueQuerySchema.ts","../../../src/api/issues/controllers/IssueController.ts","../../../src/api/issues/index.ts"],"sourcesContent":["import { type Static, t } from \"alepha\";\nimport { users } from \"alepha/api/users\";\nimport { $entity, db } from \"alepha/orm\";\n\nexport const issueTypeSchema = t.enum([\"bug\", \"feature\", \"improvement\"], {\n default: \"bug\",\n});\n\nexport const issuePrioritySchema = t.enum([\"low\", \"medium\", \"high\", \"urgent\"], {\n default: \"medium\",\n});\n\nexport const issueStatusSchema = t.enum([\n \"open\",\n \"assigned\",\n \"completed\",\n \"archived\",\n]);\n\nexport const issues = $entity({\n name: \"issues\",\n schema: t.object({\n id: db.primaryKey(t.uuid()),\n version: db.version(),\n createdAt: db.createdAt(),\n updatedAt: db.updatedAt(),\n createdBy: db.ref(t.uuid(), () => users.cols.id, { onDelete: \"cascade\" }),\n title: t.text({ maxLength: 255 }),\n type: db.default(issueTypeSchema, \"bug\"),\n priority: db.default(issuePrioritySchema, \"medium\"),\n status: db.default(issueStatusSchema, \"open\"),\n description: t.optional(t.text({ maxLength: 65535 })),\n pageUrl: t.optional(t.string({ format: \"uri\" })),\n assigneeId: t.optional(db.ref(t.uuid(), () => users.cols.id)),\n assignedAt: t.optional(t.datetime()),\n resolution: t.optional(t.text({ maxLength: 65535 })),\n completedAt: t.optional(t.datetime()),\n reopenReason: t.optional(t.text({ maxLength: 1024 })),\n archivedAt: t.optional(t.datetime()),\n }),\n indexes: [\n \"status\",\n \"createdBy\",\n \"assigneeId\",\n { columns: [\"type\", \"status\"] },\n ],\n});\n\nexport type IssueEntity = Static<typeof issues.schema>;\n","import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\nimport { pageQuerySchema } from \"alepha/orm\";\nimport {\n issuePrioritySchema,\n issueStatusSchema,\n issueTypeSchema,\n} from \"../entities/issues.ts\";\n\nexport const issueQuerySchema = t.extend(pageQuerySchema, {\n status: t.optional(issueStatusSchema),\n type: t.optional(issueTypeSchema),\n priority: t.optional(issuePrioritySchema),\n assigneeId: t.optional(t.uuid({ description: \"Filter by assignee\" })),\n search: t.optional(t.text({ description: \"Search in title\" })),\n});\n\nexport type IssueQuery = Static<typeof issueQuerySchema>;\n","import type { Static } from \"alepha\";\nimport { issues } from \"../entities/issues.ts\";\n\nexport const issueResourceSchema = issues.schema;\n\nexport type IssueResource = Static<typeof issueResourceSchema>;\n","import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\nimport { issuePrioritySchema, issueTypeSchema } from \"../entities/issues.ts\";\n\nexport const updateIssueSchema = t.object({\n title: t.optional(t.text({ maxLength: 255 })),\n type: t.optional(issueTypeSchema),\n priority: t.optional(issuePrioritySchema),\n description: t.optional(t.text({ maxLength: 65535 })),\n pageUrl: t.optional(t.string({ format: \"uri\" })),\n});\n\nexport type UpdateIssue = Static<typeof updateIssueSchema>;\n","import { $atom, t } from \"alepha\";\n\nexport const issueConfigAtom = $atom({\n name: \"alepha.api.issues.config\",\n schema: t.object({\n enabled: t.boolean(),\n maxOpenPerUser: t.integer({ minimum: 1, maximum: 1000 }),\n }),\n default: {\n enabled: true,\n maxOpenPerUser: 50,\n },\n});\n","import { $inject, Alepha } from \"alepha\";\nimport { DateTimeProvider } from \"alepha/datetime\";\nimport { $logger } from \"alepha/logger\";\nimport { $repository, type Page } from \"alepha/orm\";\nimport { BadRequestError } from \"alepha/server\";\nimport { type IssueEntity, issues } from \"../entities/issues.ts\";\nimport type { CreateIssue } from \"../schemas/createIssueSchema.ts\";\nimport { issueConfigAtom } from \"../schemas/issueConfigAtom.ts\";\nimport type { IssueQuery } from \"../schemas/issueQuerySchema.ts\";\nimport type { MyIssueQuery } from \"../schemas/myIssueQuerySchema.ts\";\nimport type { UpdateIssue } from \"../schemas/updateIssueSchema.ts\";\n\nexport class IssueService {\n protected readonly alepha = $inject(Alepha);\n protected readonly log = $logger();\n protected readonly repo = $repository(issues);\n protected readonly dateTime = $inject(DateTimeProvider);\n\n // -----------------------------------------------------------------------------------------------------------------\n\n /**\n * Get an issue by ID.\n */\n public async getById(id: string): Promise<IssueEntity> {\n return this.repo.getById(id);\n }\n\n // -----------------------------------------------------------------------------------------------------------------\n\n /**\n * Create a new issue.\n */\n public async create(\n data: CreateIssue,\n createdBy: { id: string },\n ): Promise<IssueEntity> {\n const config = this.alepha.store.get(issueConfigAtom);\n\n if (!config.enabled) {\n throw new BadRequestError(\"Issue submission is disabled\");\n }\n\n const openCount = await this.repo.count({\n createdBy: { eq: createdBy.id },\n status: { inArray: [\"open\", \"assigned\"] },\n });\n\n if (openCount >= config.maxOpenPerUser) {\n throw new BadRequestError(\n `Maximum open issues per user reached (${config.maxOpenPerUser})`,\n );\n }\n\n const entity = await this.repo.create({\n createdBy: createdBy.id,\n title: data.title,\n type: data.type ?? \"bug\",\n priority: data.priority ?? \"medium\",\n status: \"open\",\n description: data.description,\n pageUrl: data.pageUrl,\n });\n\n this.log.info(\"Issue created\", { id: entity.id, createdBy: createdBy.id });\n\n await this.alepha.events.emit(\"issue:created\", { issue: entity });\n\n return entity;\n }\n\n // -----------------------------------------------------------------------------------------------------------------\n\n /**\n * Find issues for the current user.\n */\n public async findMine(\n userId: string,\n query: MyIssueQuery = {},\n ): Promise<Page<IssueEntity>> {\n query.sort ??= \"-createdAt\";\n\n const where = this.repo.createQueryWhere();\n where.createdBy = { eq: userId };\n\n if (query.status) {\n where.status = { eq: query.status };\n }\n\n return this.repo.paginate(query, { where }, { count: true });\n }\n\n // -----------------------------------------------------------------------------------------------------------------\n\n /**\n * Find issues with pagination and filtering (admin).\n */\n public async find(query: IssueQuery = {}): Promise<Page<IssueEntity>> {\n query.sort ??= \"-createdAt\";\n\n const where = this.repo.createQueryWhere();\n\n if (query.status) {\n where.status = { eq: query.status };\n }\n\n if (query.type) {\n where.type = { eq: query.type };\n }\n\n if (query.priority) {\n where.priority = { eq: query.priority };\n }\n\n if (query.assigneeId) {\n where.assigneeId = { eq: query.assigneeId };\n }\n\n if (query.search) {\n where.title = { ilike: `%${query.search}%` };\n }\n\n return this.repo.paginate(query, { where }, { count: true });\n }\n\n // -----------------------------------------------------------------------------------------------------------------\n\n /**\n * Update issue fields (admin).\n */\n public async update(id: string, data: UpdateIssue): Promise<IssueEntity> {\n return this.repo.updateById(id, data);\n }\n\n // -----------------------------------------------------------------------------------------------------------------\n\n /**\n * Assign an issue to a user.\n */\n public async assign(id: string, assigneeId: string): Promise<IssueEntity> {\n const issue = await this.repo.getById(id);\n\n if (issue.status !== \"open\") {\n throw new BadRequestError(\n `Cannot assign issue in \"${issue.status}\" status (must be \"open\")`,\n );\n }\n\n const updated = await this.repo.updateById(id, {\n status: \"assigned\",\n assigneeId,\n assignedAt: this.dateTime.nowISOString(),\n });\n\n this.log.info(\"Issue assigned\", { id, assigneeId });\n\n await this.alepha.events.emit(\"issue:assigned\", {\n issue: updated,\n assigneeId,\n });\n\n return updated;\n }\n\n // -----------------------------------------------------------------------------------------------------------------\n\n /**\n * Complete an issue with resolution notes.\n */\n public async complete(id: string, resolution: string): Promise<IssueEntity> {\n const issue = await this.repo.getById(id);\n\n if (issue.status !== \"assigned\") {\n throw new BadRequestError(\n `Cannot complete issue in \"${issue.status}\" status (must be \"assigned\")`,\n );\n }\n\n const updated = await this.repo.updateById(id, {\n status: \"completed\",\n resolution,\n completedAt: this.dateTime.nowISOString(),\n });\n\n this.log.info(\"Issue completed\", { id });\n\n await this.alepha.events.emit(\"issue:completed\", { issue: updated });\n\n return updated;\n }\n\n // -----------------------------------------------------------------------------------------------------------------\n\n /**\n * Reopen a completed issue.\n */\n public async reopen(id: string, reason: string): Promise<IssueEntity> {\n const issue = await this.repo.getById(id);\n\n if (issue.status !== \"completed\") {\n throw new BadRequestError(\n `Cannot reopen issue in \"${issue.status}\" status (must be \"completed\")`,\n );\n }\n\n const updated = await this.repo.updateById(id, {\n status: \"open\",\n reopenReason: reason,\n assigneeId: undefined,\n assignedAt: undefined,\n resolution: undefined,\n completedAt: undefined,\n });\n\n this.log.info(\"Issue reopened\", { id, reason });\n\n await this.alepha.events.emit(\"issue:reopened\", {\n issue: updated,\n reason,\n });\n\n return updated;\n }\n\n // -----------------------------------------------------------------------------------------------------------------\n\n /**\n * Archive a completed issue.\n */\n public async archive(id: string): Promise<IssueEntity> {\n const issue = await this.repo.getById(id);\n\n if (issue.status !== \"completed\") {\n throw new BadRequestError(\n `Cannot archive issue in \"${issue.status}\" status (must be \"completed\")`,\n );\n }\n\n const updated = await this.repo.updateById(id, {\n status: \"archived\",\n archivedAt: this.dateTime.nowISOString(),\n });\n\n this.log.info(\"Issue archived\", { id });\n\n await this.alepha.events.emit(\"issue:archived\", { issue: updated });\n\n return updated;\n }\n\n // -----------------------------------------------------------------------------------------------------------------\n\n /**\n * Delete an issue.\n */\n public async deleteIssue(id: string): Promise<void> {\n const issue = await this.repo.getById(id);\n\n await this.repo.deleteById(id);\n\n this.log.info(\"Issue deleted\", { id });\n\n await this.alepha.events.emit(\"issue:deleted\", { issue });\n }\n}\n","import { $inject, t } from \"alepha\";\nimport { $secure } from \"alepha/security\";\nimport { $action, okSchema } from \"alepha/server\";\nimport { issueQuerySchema } from \"../schemas/issueQuerySchema.ts\";\nimport { issueResourceSchema } from \"../schemas/issueResourceSchema.ts\";\nimport { updateIssueSchema } from \"../schemas/updateIssueSchema.ts\";\nimport { IssueService } from \"../services/IssueService.ts\";\n\nexport class AdminIssueController {\n protected readonly url = \"/issues\";\n protected readonly group = \"admin:issues\";\n protected readonly issueService = $inject(IssueService);\n\n /**\n * Find issues with pagination and filtering.\n */\n public readonly findIssues = $action({\n path: this.url,\n group: this.group,\n use: [$secure({ permissions: [\"admin:issue:read\"] })],\n description: \"Find issues with pagination and filtering\",\n schema: {\n query: issueQuerySchema,\n response: t.page(issueResourceSchema),\n },\n handler: ({ query }) => this.issueService.find(query),\n });\n\n /**\n * Get an issue by ID.\n */\n public readonly getIssue = $action({\n path: `${this.url}/:id`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:issue:read\"] })],\n description: \"Get an issue by ID\",\n schema: {\n params: t.object({ id: t.uuid() }),\n response: issueResourceSchema,\n },\n handler: ({ params }) => this.issueService.getById(params.id),\n });\n\n /**\n * Update issue fields.\n */\n public readonly updateIssue = $action({\n method: \"PATCH\",\n path: `${this.url}/:id`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:issue:update\"] })],\n description: \"Update issue fields\",\n schema: {\n params: t.object({ id: t.uuid() }),\n body: updateIssueSchema,\n response: issueResourceSchema,\n },\n handler: ({ params, body }) => this.issueService.update(params.id, body),\n });\n\n /**\n * Assign an issue to a user.\n */\n public readonly assignIssue = $action({\n method: \"POST\",\n path: `${this.url}/:id/assign`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:issue:update\"] })],\n description: \"Assign an issue to a user\",\n schema: {\n params: t.object({ id: t.uuid() }),\n body: t.object({ assigneeId: t.uuid() }),\n response: issueResourceSchema,\n },\n handler: ({ params, body }) =>\n this.issueService.assign(params.id, body.assigneeId),\n });\n\n /**\n * Mark an issue as completed.\n */\n public readonly completeIssue = $action({\n method: \"POST\",\n path: `${this.url}/:id/complete`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:issue:update\"] })],\n description: \"Mark an issue as completed with resolution notes\",\n schema: {\n params: t.object({ id: t.uuid() }),\n body: t.object({ resolution: t.text({ minLength: 1 }) }),\n response: issueResourceSchema,\n },\n handler: ({ params, body }) =>\n this.issueService.complete(params.id, body.resolution),\n });\n\n /**\n * Reopen a completed issue.\n */\n public readonly reopenIssue = $action({\n method: \"POST\",\n path: `${this.url}/:id/reopen`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:issue:update\"] })],\n description: \"Reopen a completed issue with a reason\",\n schema: {\n params: t.object({ id: t.uuid() }),\n body: t.object({ reason: t.text({ minLength: 1 }) }),\n response: issueResourceSchema,\n },\n handler: ({ params, body }) =>\n this.issueService.reopen(params.id, body.reason),\n });\n\n /**\n * Archive a completed issue.\n */\n public readonly archiveIssue = $action({\n method: \"POST\",\n path: `${this.url}/:id/archive`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:issue:update\"] })],\n description: \"Archive a completed issue\",\n schema: {\n params: t.object({ id: t.uuid() }),\n response: issueResourceSchema,\n },\n handler: ({ params }) => this.issueService.archive(params.id),\n });\n\n /**\n * Delete an issue.\n */\n public readonly deleteIssue = $action({\n method: \"DELETE\",\n path: `${this.url}/:id`,\n group: this.group,\n use: [$secure({ permissions: [\"admin:issue:delete\"] })],\n description: \"Delete an issue\",\n schema: {\n params: t.object({ id: t.uuid() }),\n response: okSchema,\n },\n handler: async ({ params }) => {\n await this.issueService.deleteIssue(params.id);\n return { ok: true, id: params.id };\n },\n });\n}\n","import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\nimport { issuePrioritySchema, issueTypeSchema } from \"../entities/issues.ts\";\n\nexport const createIssueSchema = t.object({\n title: t.text({ maxLength: 255 }),\n type: t.optional(issueTypeSchema),\n priority: t.optional(issuePrioritySchema),\n description: t.optional(t.text({ maxLength: 65535 })),\n pageUrl: t.optional(t.string({ format: \"uri\" })),\n});\n\nexport type CreateIssue = Static<typeof createIssueSchema>;\n","import type { Static } from \"alepha\";\nimport { t } from \"alepha\";\nimport { pageQuerySchema } from \"alepha/orm\";\nimport { issueStatusSchema } from \"../entities/issues.ts\";\n\nexport const myIssueQuerySchema = t.extend(pageQuerySchema, {\n status: t.optional(issueStatusSchema),\n});\n\nexport type MyIssueQuery = Static<typeof myIssueQuerySchema>;\n","import { $inject, t } from \"alepha\";\nimport { $secure } from \"alepha/security\";\nimport { $action } from \"alepha/server\";\nimport { createIssueSchema } from \"../schemas/createIssueSchema.ts\";\nimport { issueResourceSchema } from \"../schemas/issueResourceSchema.ts\";\nimport { myIssueQuerySchema } from \"../schemas/myIssueQuerySchema.ts\";\nimport { IssueService } from \"../services/IssueService.ts\";\n\nexport class IssueController {\n protected readonly url = \"/issues\";\n protected readonly group = \"issues\";\n protected readonly issueService = $inject(IssueService);\n\n /**\n * Submit a new issue.\n */\n public readonly createIssue = $action({\n method: \"POST\",\n path: this.url,\n group: this.group,\n use: [$secure({ permissions: [\"issue:create\"] })],\n description: \"Submit a new issue\",\n schema: {\n body: createIssueSchema,\n response: issueResourceSchema,\n },\n handler: ({ body, user }) => this.issueService.create(body, user),\n });\n\n /**\n * List issues for the current user.\n */\n public readonly getMyIssues = $action({\n path: `${this.url}/mine`,\n group: this.group,\n use: [$secure({ permissions: [\"issue:read\"] })],\n description: \"List issues submitted by the current user\",\n schema: {\n query: myIssueQuerySchema,\n response: t.page(issueResourceSchema),\n },\n handler: ({ query, user }) => this.issueService.findMine(user.id, query),\n });\n}\n","import { $module } from \"alepha\";\nimport { AdminIssueController } from \"./controllers/AdminIssueController.ts\";\nimport { IssueController } from \"./controllers/IssueController.ts\";\nimport { IssueService } from \"./services/IssueService.ts\";\n\nexport * from \"./controllers/AdminIssueController.ts\";\nexport * from \"./controllers/IssueController.ts\";\nexport * from \"./entities/issues.ts\";\nexport * from \"./schemas/createIssueSchema.ts\";\nexport * from \"./schemas/issueConfigAtom.ts\";\nexport * from \"./schemas/issueQuerySchema.ts\";\nexport * from \"./schemas/issueResourceSchema.ts\";\nexport * from \"./schemas/myIssueQuerySchema.ts\";\nexport * from \"./schemas/updateIssueSchema.ts\";\nexport * from \"./services/IssueService.ts\";\n\ndeclare module \"alepha\" {\n interface Hooks {\n \"issue:created\": {\n issue: import(\"./entities/issues.ts\").IssueEntity;\n };\n \"issue:assigned\": {\n issue: import(\"./entities/issues.ts\").IssueEntity;\n assigneeId: string;\n };\n \"issue:completed\": {\n issue: import(\"./entities/issues.ts\").IssueEntity;\n };\n \"issue:reopened\": {\n issue: import(\"./entities/issues.ts\").IssueEntity;\n reason: string;\n };\n \"issue:archived\": {\n issue: import(\"./entities/issues.ts\").IssueEntity;\n };\n \"issue:deleted\": {\n issue: import(\"./entities/issues.ts\").IssueEntity;\n };\n }\n}\n\n/**\n * Issue tracking module — submit, assign, complete, reopen, and archive issues.\n *\n * @module alepha.api.issues\n */\nexport const AlephaApiIssues = $module({\n name: \"alepha.api.issues\",\n services: [IssueService, IssueController, AdminIssueController],\n register: (alepha) => {\n alepha.with(IssueService).with(IssueController).with(AdminIssueController);\n },\n});\n"],"mappings":"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"}
@@ -58,16 +58,16 @@ declare class ApiKeyService {
58
58
  lastUsedIp?: string | undefined;
59
59
  expiresAt?: string | undefined;
60
60
  revokedAt?: string | undefined;
61
- id: string;
62
- createdAt: string;
63
- updatedAt: string;
64
- userId: string;
65
61
  name: string;
66
- tokenHash: string;
62
+ userId: string;
63
+ id: string;
67
64
  tokenPrefix: string;
68
65
  tokenSuffix: string;
69
66
  roles: string[];
67
+ createdAt: string;
70
68
  usageCount: number;
69
+ updatedAt: string;
70
+ tokenHash: string;
71
71
  } | null>;
72
72
  /**
73
73
  * Create an issuer resolver for API key authentication.
@@ -13,6 +13,7 @@ import { OAuth2Profile, ServerAuthProvider, WithLinkFn, WithLoginFn } from "alep
13
13
  import * as _$alepha_cache0 from "alepha/cache";
14
14
  import { CacheProvider } from "alepha/cache";
15
15
  import { DateTime, DateTimeProvider } from "alepha/datetime";
16
+ import { CaptchaProvider } from "alepha/captcha";
16
17
  import * as _$alepha_api_jobs0 from "alepha/api/jobs";
17
18
  import { FileSystemProvider } from "alepha/system";
18
19
  import { ParameterPrimitive } from "alepha/api/parameters";
@@ -6994,6 +6995,10 @@ interface RealmOptions {
6994
6995
  credentials?: true;
6995
6996
  google?: true;
6996
6997
  github?: true;
6998
+ apple?: true;
6999
+ facebook?: true;
7000
+ microsoft?: true;
7001
+ franceconnect?: true;
6997
7002
  };
6998
7003
  /**
6999
7004
  * Enable or disable realm features.
@@ -7869,6 +7874,7 @@ declare class RegistrationService {
7869
7874
  protected readonly verificationController: _$alepha_server_links0.HttpVirtualClient<VerificationController>;
7870
7875
  protected readonly realmProvider: RealmProvider;
7871
7876
  protected readonly credentialService: CredentialService;
7877
+ protected readonly captchaProvider: CaptchaProvider;
7872
7878
  protected readonly intentCache: _$alepha_cache0.CacheMiddlewareFn<RegistrationIntent>;
7873
7879
  protected readonly rateLimitCache: _$alepha_cache0.CacheMiddlewareFn<number>;
7874
7880
  protected userAudits(realmName?: string): UserAudits | undefined;