alepha 0.13.1 → 0.13.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/api-files/index.browser.js +80 -0
- package/dist/api-files/index.browser.js.map +1 -0
- package/dist/api-files/index.d.ts +28 -91
- package/dist/api-files/index.js +10 -755
- package/dist/api-files/index.js.map +1 -1
- package/dist/api-jobs/index.browser.js +56 -0
- package/dist/api-jobs/index.browser.js.map +1 -0
- package/dist/api-jobs/index.d.ts +46 -46
- package/dist/api-jobs/index.js +13 -13
- package/dist/api-jobs/index.js.map +1 -1
- package/dist/api-notifications/index.browser.js +382 -0
- package/dist/api-notifications/index.browser.js.map +1 -0
- package/dist/api-notifications/index.d.ts +231 -193
- package/dist/api-notifications/index.js +108 -78
- package/dist/api-notifications/index.js.map +1 -1
- package/dist/api-parameters/index.browser.js +29 -0
- package/dist/api-parameters/index.browser.js.map +1 -0
- package/dist/api-parameters/index.d.ts +21 -22
- package/dist/api-parameters/index.js +22 -22
- package/dist/api-parameters/index.js.map +1 -1
- package/dist/api-users/index.d.ts +237 -2001
- package/dist/api-users/index.js +969 -4795
- package/dist/api-users/index.js.map +1 -1
- package/dist/api-verifications/index.browser.js +52 -0
- package/dist/api-verifications/index.browser.js.map +1 -0
- package/dist/api-verifications/index.d.ts +119 -97
- package/dist/api-verifications/index.js +1 -1
- package/dist/api-verifications/index.js.map +1 -1
- package/dist/batch/index.d.ts +13 -13
- package/dist/batch/index.js +8 -13
- package/dist/batch/index.js.map +1 -1
- package/dist/bucket/index.d.ts +14 -14
- package/dist/bucket/index.js +19 -17
- package/dist/bucket/index.js.map +1 -1
- package/dist/cache/index.d.ts +11 -11
- package/dist/cache/index.js +9 -9
- package/dist/cache/index.js.map +1 -1
- package/dist/cli/{dist-Dl9Vl7Ur.js → dist-lGnqsKpu.js} +11 -15
- package/dist/cli/dist-lGnqsKpu.js.map +1 -0
- package/dist/cli/index.d.ts +32 -49
- package/dist/cli/index.js +90 -71
- package/dist/cli/index.js.map +1 -1
- package/dist/command/index.d.ts +20 -19
- package/dist/command/index.js +34 -25
- package/dist/command/index.js.map +1 -1
- package/dist/core/index.browser.js +218 -218
- package/dist/core/index.browser.js.map +1 -1
- package/dist/core/index.d.ts +232 -232
- package/dist/core/index.js +218 -218
- package/dist/core/index.js.map +1 -1
- package/dist/core/index.native.js +2113 -0
- package/dist/core/index.native.js.map +1 -0
- package/dist/datetime/index.d.ts +9 -9
- package/dist/datetime/index.js +7 -7
- package/dist/datetime/index.js.map +1 -1
- package/dist/email/index.d.ts +16 -16
- package/dist/email/index.js +14 -9
- package/dist/email/index.js.map +1 -1
- package/dist/file/index.js +1 -1
- package/dist/file/index.js.map +1 -1
- package/dist/lock/index.d.ts +9 -9
- package/dist/lock/index.js +8 -8
- package/dist/lock/index.js.map +1 -1
- package/dist/lock-redis/index.js +3 -66
- package/dist/lock-redis/index.js.map +1 -1
- package/dist/logger/index.d.ts +5 -5
- package/dist/logger/index.js +8 -8
- package/dist/logger/index.js.map +1 -1
- package/dist/orm/index.browser.js +114 -114
- package/dist/orm/index.browser.js.map +1 -1
- package/dist/orm/index.d.ts +218 -218
- package/dist/orm/index.js +49 -49
- package/dist/orm/index.js.map +1 -1
- package/dist/queue/index.d.ts +29 -29
- package/dist/queue/index.js +20 -20
- package/dist/queue/index.js.map +1 -1
- package/dist/queue-redis/index.d.ts +2 -2
- package/dist/redis/index.d.ts +4 -4
- package/dist/retry/index.d.ts +19 -19
- package/dist/retry/index.js +7 -7
- package/dist/retry/index.js.map +1 -1
- package/dist/scheduler/index.d.ts +16 -16
- package/dist/scheduler/index.js +9 -9
- package/dist/scheduler/index.js.map +1 -1
- package/dist/security/index.d.ts +53 -53
- package/dist/security/index.js +35 -35
- package/dist/security/index.js.map +1 -1
- package/dist/server/index.browser.js +1 -1
- package/dist/server/index.browser.js.map +1 -1
- package/dist/server/index.d.ts +92 -92
- package/dist/server/index.js +16 -16
- package/dist/server/index.js.map +1 -1
- package/dist/server-auth/index.browser.js +4 -982
- package/dist/server-auth/index.browser.js.map +1 -1
- package/dist/server-auth/index.d.ts +204 -785
- package/dist/server-auth/index.js +47 -1239
- package/dist/server-auth/index.js.map +1 -1
- package/dist/server-cache/index.d.ts +10 -10
- package/dist/server-cache/index.js +2 -2
- package/dist/server-cache/index.js.map +1 -1
- package/dist/server-compress/index.d.ts +4 -4
- package/dist/server-compress/index.js +1 -1
- package/dist/server-compress/index.js.map +1 -1
- package/dist/server-cookies/index.browser.js +8 -8
- package/dist/server-cookies/index.browser.js.map +1 -1
- package/dist/server-cookies/index.d.ts +17 -17
- package/dist/server-cookies/index.js +11 -11
- package/dist/server-cookies/index.js.map +1 -1
- package/dist/server-cors/index.d.ts +17 -17
- package/dist/server-cors/index.js +9 -9
- package/dist/server-cors/index.js.map +1 -1
- package/dist/server-health/index.d.ts +19 -19
- package/dist/server-helmet/index.d.ts +1 -1
- package/dist/server-links/index.browser.js +12 -12
- package/dist/server-links/index.browser.js.map +1 -1
- package/dist/server-links/index.d.ts +59 -251
- package/dist/server-links/index.js +23 -502
- package/dist/server-links/index.js.map +1 -1
- package/dist/server-metrics/index.d.ts +4 -4
- package/dist/server-multipart/index.d.ts +2 -2
- package/dist/server-proxy/index.d.ts +12 -12
- package/dist/server-proxy/index.js +10 -10
- package/dist/server-proxy/index.js.map +1 -1
- package/dist/server-rate-limit/index.d.ts +22 -22
- package/dist/server-rate-limit/index.js +12 -12
- package/dist/server-rate-limit/index.js.map +1 -1
- package/dist/server-security/index.d.ts +22 -22
- package/dist/server-security/index.js +15 -15
- package/dist/server-security/index.js.map +1 -1
- package/dist/server-static/index.d.ts +14 -14
- package/dist/server-static/index.js +26 -10
- package/dist/server-static/index.js.map +1 -1
- package/dist/server-swagger/index.d.ts +25 -184
- package/dist/server-swagger/index.js +21 -724
- package/dist/server-swagger/index.js.map +1 -1
- package/dist/sms/index.d.ts +14 -14
- package/dist/sms/index.js +9 -9
- package/dist/sms/index.js.map +1 -1
- package/dist/thread/index.d.ts +11 -11
- package/dist/thread/index.js +17 -17
- package/dist/thread/index.js.map +1 -1
- package/dist/topic/index.d.ts +26 -26
- package/dist/topic/index.js +16 -16
- package/dist/topic/index.js.map +1 -1
- package/dist/topic-redis/index.d.ts +1 -1
- package/dist/vite/index.d.ts +3 -3
- package/dist/vite/index.js +8 -8
- package/dist/vite/index.js.map +1 -1
- package/dist/websocket/index.browser.js +11 -11
- package/dist/websocket/index.browser.js.map +1 -1
- package/dist/websocket/index.d.ts +58 -58
- package/dist/websocket/index.js +13 -13
- package/dist/websocket/index.js.map +1 -1
- package/package.json +128 -57
- package/src/api-files/index.browser.ts +17 -0
- package/src/api-files/services/FileService.ts +5 -7
- package/src/api-jobs/index.browser.ts +15 -0
- package/src/api-jobs/index.ts +1 -1
- package/src/api-jobs/{descriptors → primitives}/$job.ts +8 -8
- package/src/api-jobs/providers/JobProvider.ts +9 -9
- package/src/api-jobs/services/JobService.ts +5 -5
- package/src/api-notifications/controllers/NotificationController.ts +26 -1
- package/src/api-notifications/index.browser.ts +17 -0
- package/src/api-notifications/index.ts +6 -15
- package/src/api-notifications/{descriptors → primitives}/$notification.ts +10 -10
- package/src/api-notifications/schemas/notificationQuerySchema.ts +13 -0
- package/src/api-notifications/services/NotificationSenderService.ts +3 -3
- package/src/api-notifications/services/NotificationService.ts +45 -2
- package/src/api-parameters/index.browser.ts +12 -0
- package/src/api-parameters/index.ts +1 -1
- package/src/api-parameters/{descriptors → primitives}/$config.ts +7 -12
- package/src/api-users/atoms/realmAuthSettingsAtom.ts +3 -1
- package/src/api-users/controllers/UserController.ts +21 -1
- package/src/api-users/index.ts +1 -1
- package/src/api-users/{descriptors → primitives}/$userRealm.ts +40 -17
- package/src/api-users/providers/UserRealmProvider.ts +2 -1
- package/src/api-users/services/SessionService.ts +2 -0
- package/src/api-users/services/UserService.ts +56 -16
- package/src/api-verifications/index.browser.ts +15 -0
- package/src/api-verifications/index.ts +1 -0
- package/src/batch/index.ts +3 -3
- package/src/batch/{descriptors → primitives}/$batch.ts +13 -16
- package/src/batch/providers/BatchProvider.ts +0 -7
- package/src/bucket/index.ts +15 -13
- package/src/bucket/{descriptors → primitives}/$bucket.ts +8 -8
- package/src/bucket/providers/LocalFileStorageProvider.ts +3 -3
- package/src/cache/index.ts +4 -4
- package/src/cache/{descriptors → primitives}/$cache.ts +15 -15
- package/src/cli/apps/AlephaCli.ts +27 -1
- package/src/cli/apps/AlephaPackageBuilderCli.ts +27 -2
- package/src/cli/commands/CoreCommands.ts +6 -2
- package/src/cli/commands/DrizzleCommands.ts +6 -6
- package/src/cli/commands/VerifyCommands.ts +1 -1
- package/src/cli/commands/ViteCommands.ts +8 -2
- package/src/cli/services/ProjectUtils.ts +74 -78
- package/src/command/helpers/Asker.ts +10 -0
- package/src/command/index.ts +5 -5
- package/src/command/{descriptors → primitives}/$command.ts +9 -12
- package/src/command/providers/CliProvider.ts +10 -10
- package/src/core/Alepha.ts +30 -33
- package/src/core/constants/KIND.ts +1 -1
- package/src/core/constants/OPTIONS.ts +1 -1
- package/src/core/helpers/{descriptor.ts → primitive.ts} +18 -18
- package/src/core/helpers/ref.ts +1 -1
- package/src/core/index.shared.ts +8 -8
- package/src/core/{descriptors → primitives}/$context.ts +5 -5
- package/src/core/{descriptors → primitives}/$hook.ts +4 -4
- package/src/core/{descriptors → primitives}/$inject.ts +2 -2
- package/src/core/{descriptors → primitives}/$module.ts +9 -9
- package/src/core/{descriptors → primitives}/$use.ts +2 -2
- package/src/core/providers/CodecManager.ts +1 -1
- package/src/core/providers/JsonSchemaCodec.ts +1 -1
- package/src/core/providers/StateManager.ts +2 -2
- package/src/datetime/index.ts +3 -3
- package/src/datetime/{descriptors → primitives}/$interval.ts +6 -6
- package/src/email/index.ts +17 -9
- package/src/email/{descriptors → primitives}/$email.ts +8 -8
- package/src/file/index.ts +1 -1
- package/src/lock/index.ts +3 -3
- package/src/lock/{descriptors → primitives}/$lock.ts +10 -10
- package/src/logger/index.ts +8 -8
- package/src/logger/{descriptors → primitives}/$logger.ts +2 -2
- package/src/logger/services/Logger.ts +1 -1
- package/src/orm/constants/PG_SYMBOLS.ts +2 -2
- package/src/orm/index.browser.ts +2 -2
- package/src/orm/index.ts +8 -8
- package/src/orm/{descriptors → primitives}/$entity.ts +11 -11
- package/src/orm/{descriptors → primitives}/$repository.ts +2 -2
- package/src/orm/{descriptors → primitives}/$sequence.ts +8 -8
- package/src/orm/{descriptors → primitives}/$transaction.ts +4 -4
- package/src/orm/providers/PostgresTypeProvider.ts +3 -3
- package/src/orm/providers/RepositoryProvider.ts +4 -4
- package/src/orm/providers/drivers/DatabaseProvider.ts +7 -7
- package/src/orm/providers/drivers/NodeSqliteProvider.ts +3 -3
- package/src/orm/services/ModelBuilder.ts +9 -9
- package/src/orm/services/PgRelationManager.ts +2 -2
- package/src/orm/services/PostgresModelBuilder.ts +5 -5
- package/src/orm/services/Repository.ts +7 -7
- package/src/orm/services/SqliteModelBuilder.ts +5 -5
- package/src/queue/index.ts +7 -7
- package/src/queue/{descriptors → primitives}/$consumer.ts +15 -15
- package/src/queue/{descriptors → primitives}/$queue.ts +12 -12
- package/src/queue/providers/WorkerProvider.ts +7 -7
- package/src/retry/index.ts +3 -3
- package/src/retry/{descriptors → primitives}/$retry.ts +14 -14
- package/src/scheduler/index.ts +3 -3
- package/src/scheduler/{descriptors → primitives}/$scheduler.ts +9 -9
- package/src/scheduler/providers/CronProvider.ts +1 -1
- package/src/security/index.ts +9 -9
- package/src/security/{descriptors → primitives}/$permission.ts +7 -7
- package/src/security/{descriptors → primitives}/$realm.ts +6 -12
- package/src/security/{descriptors → primitives}/$role.ts +12 -12
- package/src/security/{descriptors → primitives}/$serviceAccount.ts +8 -8
- package/src/server/index.browser.ts +1 -1
- package/src/server/index.ts +14 -14
- package/src/server/{descriptors → primitives}/$action.ts +13 -13
- package/src/server/{descriptors → primitives}/$route.ts +9 -9
- package/src/server/providers/NodeHttpServerProvider.ts +1 -1
- package/src/server/services/HttpClient.ts +1 -1
- package/src/server-auth/index.browser.ts +1 -1
- package/src/server-auth/index.ts +6 -6
- package/src/server-auth/{descriptors → primitives}/$auth.ts +10 -10
- package/src/server-auth/{descriptors → primitives}/$authCredentials.ts +4 -4
- package/src/server-auth/{descriptors → primitives}/$authGithub.ts +4 -4
- package/src/server-auth/{descriptors → primitives}/$authGoogle.ts +4 -4
- package/src/server-auth/providers/ServerAuthProvider.ts +4 -4
- package/src/server-cache/providers/ServerCacheProvider.ts +7 -7
- package/src/server-compress/providers/ServerCompressProvider.ts +3 -3
- package/src/server-cookies/index.browser.ts +2 -2
- package/src/server-cookies/index.ts +5 -5
- package/src/server-cookies/{descriptors → primitives}/$cookie.browser.ts +12 -12
- package/src/server-cookies/{descriptors → primitives}/$cookie.ts +13 -13
- package/src/server-cookies/providers/ServerCookiesProvider.ts +6 -5
- package/src/server-cookies/services/CookieParser.ts +1 -1
- package/src/server-cors/index.ts +3 -3
- package/src/server-cors/{descriptors → primitives}/$cors.ts +11 -13
- package/src/server-cors/providers/ServerCorsProvider.ts +5 -5
- package/src/server-links/index.browser.ts +5 -5
- package/src/server-links/index.ts +9 -9
- package/src/server-links/{descriptors → primitives}/$remote.ts +11 -11
- package/src/server-links/providers/LinkProvider.ts +7 -7
- package/src/server-links/providers/{RemoteDescriptorProvider.ts → RemotePrimitiveProvider.ts} +6 -6
- package/src/server-links/providers/ServerLinksProvider.ts +3 -3
- package/src/server-proxy/index.ts +3 -3
- package/src/server-proxy/{descriptors → primitives}/$proxy.ts +8 -8
- package/src/server-proxy/providers/ServerProxyProvider.ts +4 -4
- package/src/server-rate-limit/index.ts +6 -6
- package/src/server-rate-limit/{descriptors → primitives}/$rateLimit.ts +13 -13
- package/src/server-rate-limit/providers/ServerRateLimitProvider.ts +5 -5
- package/src/server-security/index.ts +3 -3
- package/src/server-security/{descriptors → primitives}/$basicAuth.ts +13 -13
- package/src/server-security/providers/ServerBasicAuthProvider.ts +5 -5
- package/src/server-security/providers/ServerSecurityProvider.ts +4 -4
- package/src/server-static/index.ts +3 -3
- package/src/server-static/{descriptors → primitives}/$serve.ts +8 -10
- package/src/server-static/providers/ServerStaticProvider.ts +24 -9
- package/src/server-swagger/index.ts +5 -5
- package/src/server-swagger/{descriptors → primitives}/$swagger.ts +9 -9
- package/src/server-swagger/providers/ServerSwaggerProvider.ts +11 -10
- package/src/sms/index.ts +4 -4
- package/src/sms/{descriptors → primitives}/$sms.ts +8 -8
- package/src/thread/index.ts +3 -3
- package/src/thread/{descriptors → primitives}/$thread.ts +13 -13
- package/src/thread/providers/ThreadProvider.ts +7 -9
- package/src/topic/index.ts +5 -5
- package/src/topic/{descriptors → primitives}/$subscriber.ts +14 -14
- package/src/topic/{descriptors → primitives}/$topic.ts +10 -10
- package/src/topic/providers/TopicProvider.ts +4 -4
- package/src/vite/tasks/copyAssets.ts +1 -1
- package/src/vite/tasks/generateSitemap.ts +3 -3
- package/src/vite/tasks/prerenderPages.ts +2 -2
- package/src/vite/tasks/runAlepha.ts +2 -2
- package/src/websocket/index.browser.ts +3 -3
- package/src/websocket/index.shared.ts +2 -2
- package/src/websocket/index.ts +4 -4
- package/src/websocket/interfaces/WebSocketInterfaces.ts +3 -3
- package/src/websocket/{descriptors → primitives}/$channel.ts +10 -10
- package/src/websocket/{descriptors → primitives}/$websocket.ts +8 -8
- package/src/websocket/providers/NodeWebSocketServerProvider.ts +7 -7
- package/src/websocket/providers/WebSocketServerProvider.ts +3 -3
- package/src/websocket/services/WebSocketClient.ts +5 -5
- package/dist/cli/dist-Dl9Vl7Ur.js.map +0 -1
- package/src/api-notifications/providers/MemorySmsProvider.ts +0 -20
- package/src/api-notifications/providers/SmsProvider.ts +0 -8
- /package/src/core/{descriptors → primitives}/$atom.ts +0 -0
- /package/src/core/{descriptors → primitives}/$env.ts +0 -0
- /package/src/server-auth/{descriptors → primitives}/$authApple.ts +0 -0
- /package/src/server-links/{descriptors → primitives}/$client.ts +0 -0
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { $module } from "alepha";
|
|
2
2
|
import { NotificationController } from "./controllers/NotificationController.ts";
|
|
3
|
-
import { $notification } from "./descriptors/$notification.ts";
|
|
4
3
|
import { NotificationJobs } from "./jobs/NotificationJobs.ts";
|
|
5
|
-
import {
|
|
6
|
-
import { SmsProvider } from "./providers/SmsProvider.ts";
|
|
4
|
+
import { $notification } from "./primitives/$notification.ts";
|
|
7
5
|
import { NotificationQueues } from "./queues/NotificationQueues.ts";
|
|
8
6
|
import { NotificationSenderService } from "./services/NotificationSenderService.ts";
|
|
9
7
|
import {
|
|
@@ -14,14 +12,13 @@ import {
|
|
|
14
12
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
15
13
|
|
|
16
14
|
export * from "./controllers/NotificationController.ts";
|
|
17
|
-
export * from "./descriptors/$notification.ts";
|
|
18
15
|
export * from "./entities/notifications.ts";
|
|
19
16
|
export * from "./jobs/NotificationJobs.ts";
|
|
20
|
-
export * from "./
|
|
21
|
-
export * from "./providers/SmsProvider.ts";
|
|
17
|
+
export * from "./primitives/$notification.ts";
|
|
22
18
|
export * from "./queues/NotificationQueues.ts";
|
|
23
19
|
export * from "./schemas/notificationContactPreferencesSchema.ts";
|
|
24
20
|
export * from "./schemas/notificationCreateSchema.ts";
|
|
21
|
+
export * from "./schemas/notificationQuerySchema.ts";
|
|
25
22
|
export * from "./services/NotificationSenderService.ts";
|
|
26
23
|
export * from "./services/NotificationService.ts";
|
|
27
24
|
|
|
@@ -33,27 +30,21 @@ export * from "./services/NotificationService.ts";
|
|
|
33
30
|
* This module includes notification sending, retrieval, status tracking,
|
|
34
31
|
* and user notification preferences management.
|
|
35
32
|
*
|
|
33
|
+
* Requires `AlephaSms` module to be loaded for SMS notifications.
|
|
34
|
+
*
|
|
36
35
|
* @module alepha.api.notifications
|
|
37
36
|
*/
|
|
38
37
|
export const AlephaApiNotifications = $module({
|
|
39
38
|
name: "alepha.api.notifications",
|
|
40
|
-
|
|
39
|
+
primitives: [$notification],
|
|
41
40
|
services: [
|
|
42
41
|
NotificationController,
|
|
43
42
|
NotificationService,
|
|
44
43
|
NotificationSenderService,
|
|
45
44
|
NotificationQueues,
|
|
46
45
|
NotificationJobs,
|
|
47
|
-
SmsProvider,
|
|
48
|
-
MemorySmsProvider,
|
|
49
46
|
],
|
|
50
47
|
register: (alepha) => {
|
|
51
|
-
alepha.with({
|
|
52
|
-
optional: true,
|
|
53
|
-
provide: SmsProvider,
|
|
54
|
-
use: MemorySmsProvider,
|
|
55
|
-
});
|
|
56
|
-
|
|
57
48
|
const env = alepha.parseEnv(notificationServiceEnvSchema);
|
|
58
49
|
if (env.NOTIFICATION_QUEUE) {
|
|
59
50
|
alepha.with(NotificationQueues);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import {
|
|
2
2
|
$inject,
|
|
3
|
-
|
|
4
|
-
Descriptor,
|
|
3
|
+
createPrimitive,
|
|
5
4
|
KIND,
|
|
5
|
+
Primitive,
|
|
6
6
|
type Static,
|
|
7
7
|
type StaticEncode,
|
|
8
8
|
type TObject,
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { NotificationService } from "../services/NotificationService.ts";
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
|
-
* Creates a notification
|
|
13
|
+
* Creates a notification primitive for managing email/SMS notification templates.
|
|
14
14
|
*
|
|
15
15
|
* Provides type-safe, reusable notification templates with multi-language support,
|
|
16
16
|
* variable substitution, and categorization for different notification channels.
|
|
@@ -38,12 +38,12 @@ import { NotificationService } from "../services/NotificationService.ts";
|
|
|
38
38
|
* ```
|
|
39
39
|
*/
|
|
40
40
|
export const $notification = <T extends TObject>(
|
|
41
|
-
options:
|
|
42
|
-
) =>
|
|
41
|
+
options: NotificationPrimitiveOptions<T>,
|
|
42
|
+
) => createPrimitive(NotificationPrimitive<T>, options);
|
|
43
43
|
|
|
44
44
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
45
45
|
|
|
46
|
-
export interface
|
|
46
|
+
export interface NotificationPrimitiveOptions<T extends TObject>
|
|
47
47
|
extends NotificationMessage<T> {
|
|
48
48
|
name?: string;
|
|
49
49
|
description?: string;
|
|
@@ -59,8 +59,8 @@ export interface NotificationDescriptorOptions<T extends TObject>
|
|
|
59
59
|
|
|
60
60
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
61
61
|
|
|
62
|
-
export class
|
|
63
|
-
|
|
62
|
+
export class NotificationPrimitive<T extends TObject> extends Primitive<
|
|
63
|
+
NotificationPrimitiveOptions<T>
|
|
64
64
|
> {
|
|
65
65
|
protected readonly notificationService = $inject(NotificationService);
|
|
66
66
|
|
|
@@ -78,12 +78,12 @@ export class NotificationDescriptor<T extends TObject> extends Descriptor<
|
|
|
78
78
|
}
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
public configure(options: Partial<
|
|
81
|
+
public configure(options: Partial<NotificationPrimitiveOptions<T>>) {
|
|
82
82
|
Object.assign(this.options, options);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
$notification[KIND] =
|
|
86
|
+
$notification[KIND] = NotificationPrimitive;
|
|
87
87
|
|
|
88
88
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
89
89
|
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Static } from "alepha";
|
|
2
|
+
import { t } from "alepha";
|
|
3
|
+
import { pageQuerySchema } from "alepha/orm";
|
|
4
|
+
|
|
5
|
+
export const notificationQuerySchema = t.extend(pageQuerySchema, {
|
|
6
|
+
type: t.optional(t.enum(["email", "sms"])),
|
|
7
|
+
template: t.optional(t.string()),
|
|
8
|
+
contact: t.optional(t.string()),
|
|
9
|
+
category: t.optional(t.string()),
|
|
10
|
+
status: t.optional(t.enum(["pending", "sent", "failed"])),
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
export type NotificationQuery = Static<typeof notificationQuerySchema>;
|
|
@@ -3,12 +3,12 @@ import { DateTimeProvider } from "alepha/datetime";
|
|
|
3
3
|
import { EmailProvider } from "alepha/email";
|
|
4
4
|
import { $logger } from "alepha/logger";
|
|
5
5
|
import { $repository } from "alepha/orm";
|
|
6
|
-
import {
|
|
6
|
+
import { SmsProvider } from "alepha/sms";
|
|
7
7
|
import {
|
|
8
8
|
type NotificationEntity,
|
|
9
9
|
notifications,
|
|
10
10
|
} from "../entities/notifications.ts";
|
|
11
|
-
import {
|
|
11
|
+
import { $notification } from "../primitives/$notification.ts";
|
|
12
12
|
|
|
13
13
|
export class NotificationSenderService {
|
|
14
14
|
protected readonly alepha = $inject(Alepha);
|
|
@@ -161,7 +161,7 @@ export class NotificationSenderService {
|
|
|
161
161
|
const variables = notification.variables || {};
|
|
162
162
|
const contact = notification.contact;
|
|
163
163
|
const template = this.alepha
|
|
164
|
-
.
|
|
164
|
+
.primitives($notification)
|
|
165
165
|
.find((it) => it.name === notification.template);
|
|
166
166
|
|
|
167
167
|
if (!template) {
|
|
@@ -2,13 +2,17 @@ import { $env, $inject, Alepha, type Static, t } from "alepha";
|
|
|
2
2
|
import { $batch } from "alepha/batch";
|
|
3
3
|
import { DateTimeProvider } from "alepha/datetime";
|
|
4
4
|
import { $logger } from "alepha/logger";
|
|
5
|
-
import { $repository } from "alepha/orm";
|
|
6
|
-
import {
|
|
5
|
+
import { $repository, type Page } from "alepha/orm";
|
|
6
|
+
import {
|
|
7
|
+
type NotificationEntity,
|
|
8
|
+
notifications,
|
|
9
|
+
} from "../entities/notifications.ts";
|
|
7
10
|
import { NotificationQueues } from "../queues/NotificationQueues.ts";
|
|
8
11
|
import {
|
|
9
12
|
type NotificationCreate,
|
|
10
13
|
notificationCreateSchema,
|
|
11
14
|
} from "../schemas/notificationCreateSchema.ts";
|
|
15
|
+
import type { NotificationQuery } from "../schemas/notificationQuerySchema.ts";
|
|
12
16
|
import { NotificationSenderService } from "./NotificationSenderService.ts";
|
|
13
17
|
|
|
14
18
|
export const notificationServiceEnvSchema = t.object({
|
|
@@ -65,6 +69,45 @@ export class NotificationService {
|
|
|
65
69
|
return this.notificationRepository.findOne({ where: { id } });
|
|
66
70
|
}
|
|
67
71
|
|
|
72
|
+
public async findNotifications(
|
|
73
|
+
q: NotificationQuery = {},
|
|
74
|
+
): Promise<Page<NotificationEntity>> {
|
|
75
|
+
this.log.trace("Finding notifications", { query: q });
|
|
76
|
+
q.sort ??= "-createdAt";
|
|
77
|
+
|
|
78
|
+
const where = this.notificationRepository.createQueryWhere();
|
|
79
|
+
|
|
80
|
+
if (q.type) {
|
|
81
|
+
where.type = { eq: q.type };
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
if (q.template) {
|
|
85
|
+
where.template = { like: `%${q.template}%` };
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
if (q.contact) {
|
|
89
|
+
where.contact = { like: `%${q.contact}%` };
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
if (q.category) {
|
|
93
|
+
where.category = { eq: q.category };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (q.status) {
|
|
97
|
+
if (q.status === "sent") {
|
|
98
|
+
where.sentAt = { isNotNull: true };
|
|
99
|
+
where.error = { isNull: true };
|
|
100
|
+
} else if (q.status === "failed") {
|
|
101
|
+
where.error = { isNotNull: true };
|
|
102
|
+
} else if (q.status === "pending") {
|
|
103
|
+
where.sentAt = { isNull: true };
|
|
104
|
+
where.error = { isNull: true };
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return this.notificationRepository.paginate(q, { where }, { count: true });
|
|
109
|
+
}
|
|
110
|
+
|
|
68
111
|
/**
|
|
69
112
|
* Create a new notification.
|
|
70
113
|
*/
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { $module } from "alepha";
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
export * from "./entities/parameters.ts";
|
|
6
|
+
|
|
7
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
8
|
+
|
|
9
|
+
export const AlephaApiParameters = $module({
|
|
10
|
+
name: "alepha.api.parameters",
|
|
11
|
+
services: [],
|
|
12
|
+
});
|
|
@@ -2,8 +2,8 @@ import { $module } from "alepha";
|
|
|
2
2
|
|
|
3
3
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
4
4
|
|
|
5
|
-
export * from "./descriptors/$config.ts";
|
|
6
5
|
export * from "./entities/parameters.ts";
|
|
6
|
+
export * from "./primitives/$config.ts";
|
|
7
7
|
|
|
8
8
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
9
9
|
|
|
@@ -1,13 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
createDescriptor,
|
|
3
|
-
Descriptor,
|
|
4
|
-
type Static,
|
|
5
|
-
type TObject,
|
|
6
|
-
} from "alepha";
|
|
1
|
+
import { createPrimitive, Primitive, type Static, type TObject } from "alepha";
|
|
7
2
|
import type { UserAccount } from "alepha/security";
|
|
8
3
|
|
|
9
4
|
/**
|
|
10
|
-
* Creates a configuration parameter
|
|
5
|
+
* Creates a configuration parameter primitive for managing application settings.
|
|
11
6
|
*
|
|
12
7
|
* Provides type-safe, versioned configuration with schema validation, default values,
|
|
13
8
|
* and scheduled activation. Useful for feature flags, system parameters, and runtime settings.
|
|
@@ -33,15 +28,15 @@ import type { UserAccount } from "alepha/security";
|
|
|
33
28
|
* }
|
|
34
29
|
* ```
|
|
35
30
|
*/
|
|
36
|
-
export interface
|
|
31
|
+
export interface ConfigPrimitiveOptions<T extends TObject> {
|
|
37
32
|
name?: string;
|
|
38
33
|
description?: string;
|
|
39
34
|
schema: T;
|
|
40
35
|
default: Static<T>;
|
|
41
36
|
}
|
|
42
37
|
|
|
43
|
-
export class
|
|
44
|
-
|
|
38
|
+
export class ConfigPrimitive<T extends TObject> extends Primitive<
|
|
39
|
+
ConfigPrimitiveOptions<T>
|
|
45
40
|
> {
|
|
46
41
|
public get name() {
|
|
47
42
|
return this.options.name || this.config.propertyKey;
|
|
@@ -78,7 +73,7 @@ export class ConfigDescriptor<T extends TObject> extends Descriptor<
|
|
|
78
73
|
}
|
|
79
74
|
|
|
80
75
|
export const $config = <T extends TObject>(
|
|
81
|
-
options:
|
|
76
|
+
options: ConfigPrimitiveOptions<T>,
|
|
82
77
|
) => {
|
|
83
|
-
return
|
|
78
|
+
return createPrimitive(ConfigPrimitive<T>, options);
|
|
84
79
|
};
|
|
@@ -60,10 +60,11 @@ export const realmAuthSettingsAtom = $atom({
|
|
|
60
60
|
}),
|
|
61
61
|
}),
|
|
62
62
|
default: {
|
|
63
|
+
// for a fresh hello world setup, we accept registration and email login
|
|
63
64
|
registrationAllowed: true,
|
|
64
65
|
emailEnabled: true,
|
|
65
66
|
emailRequired: true,
|
|
66
|
-
usernameEnabled:
|
|
67
|
+
usernameEnabled: false,
|
|
67
68
|
usernameRequired: false,
|
|
68
69
|
phoneEnabled: false,
|
|
69
70
|
phoneRequired: false,
|
|
@@ -72,6 +73,7 @@ export const realmAuthSettingsAtom = $atom({
|
|
|
72
73
|
resetPasswordAllowed: false,
|
|
73
74
|
firstNameLastNameEnabled: false,
|
|
74
75
|
firstNameLastNameRequired: false,
|
|
76
|
+
// TODO: not implemented yet
|
|
75
77
|
passwordPolicy: {
|
|
76
78
|
minLength: 8,
|
|
77
79
|
requireUppercase: true,
|
|
@@ -310,6 +310,8 @@ export class UserController {
|
|
|
310
310
|
/**
|
|
311
311
|
* Request email verification.
|
|
312
312
|
* Generates a verification token using verification service and sends an email to the user.
|
|
313
|
+
* @param method - The verification method: "code" (default) sends a 6-digit code, "link" sends a clickable verification link.
|
|
314
|
+
* @param verifyUrl - Required when method is "link". The base URL for the verification link. Token and email will be appended as query params.
|
|
313
315
|
*/
|
|
314
316
|
public requestEmailVerification = $action({
|
|
315
317
|
path: "/users/email-verification/request",
|
|
@@ -317,6 +319,19 @@ export class UserController {
|
|
|
317
319
|
schema: {
|
|
318
320
|
query: t.object({
|
|
319
321
|
userRealmName: t.optional(t.string()),
|
|
322
|
+
method: t.optional(
|
|
323
|
+
t.enum(["code", "link"], {
|
|
324
|
+
default: "code",
|
|
325
|
+
description:
|
|
326
|
+
'Verification method: "code" sends a 6-digit code, "link" sends a clickable verification link.',
|
|
327
|
+
}),
|
|
328
|
+
),
|
|
329
|
+
verifyUrl: t.optional(
|
|
330
|
+
t.string({
|
|
331
|
+
description:
|
|
332
|
+
'Base URL for verification link. Required when method is "link". Token and email will be appended as query params.',
|
|
333
|
+
}),
|
|
334
|
+
),
|
|
320
335
|
}),
|
|
321
336
|
body: t.object({
|
|
322
337
|
email: t.email(),
|
|
@@ -327,15 +342,20 @@ export class UserController {
|
|
|
327
342
|
}),
|
|
328
343
|
},
|
|
329
344
|
handler: async ({ body, query }) => {
|
|
345
|
+
const method = query.method ?? "code";
|
|
330
346
|
await this.userService.requestEmailVerification(
|
|
331
347
|
body.email,
|
|
332
348
|
query.userRealmName,
|
|
349
|
+
method,
|
|
350
|
+
query.verifyUrl,
|
|
333
351
|
);
|
|
334
352
|
|
|
335
353
|
return {
|
|
336
354
|
success: true,
|
|
337
355
|
message:
|
|
338
|
-
|
|
356
|
+
method === "link"
|
|
357
|
+
? "If an account exists with this email, a verification link has been sent."
|
|
358
|
+
: "If an account exists with this email, a verification code has been sent.",
|
|
339
359
|
};
|
|
340
360
|
},
|
|
341
361
|
});
|
package/src/api-users/index.ts
CHANGED
|
@@ -21,10 +21,10 @@ export * from "./controllers/IdentityController.ts";
|
|
|
21
21
|
export * from "./controllers/SessionController.ts";
|
|
22
22
|
export * from "./controllers/UserController.ts";
|
|
23
23
|
export * from "./controllers/UserRealmController.ts";
|
|
24
|
-
export * from "./descriptors/$userRealm.ts";
|
|
25
24
|
export * from "./entities/identities.ts";
|
|
26
25
|
export * from "./entities/sessions.ts";
|
|
27
26
|
export * from "./entities/users.ts";
|
|
27
|
+
export * from "./primitives/$userRealm.ts";
|
|
28
28
|
export * from "./providers/UserRealmProvider.ts";
|
|
29
29
|
export * from "./schemas/completePasswordResetRequestSchema.ts";
|
|
30
30
|
export * from "./schemas/completeRegistrationRequestSchema.ts";
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { $context } from "alepha";
|
|
2
|
+
import { AlephaApiFiles } from "alepha/api/files";
|
|
2
3
|
import type { Repository } from "alepha/orm";
|
|
3
4
|
import {
|
|
4
5
|
$realm,
|
|
5
|
-
type
|
|
6
|
-
type
|
|
6
|
+
type RealmPrimitive,
|
|
7
|
+
type RealmPrimitiveOptions,
|
|
7
8
|
SecurityProvider,
|
|
8
9
|
} from "alepha/security";
|
|
9
10
|
import {
|
|
10
11
|
$authCredentials,
|
|
11
12
|
$authGithub,
|
|
12
13
|
$authGoogle,
|
|
13
|
-
type
|
|
14
|
+
type AuthPrimitive,
|
|
14
15
|
type Credentials,
|
|
15
16
|
type LinkAccountOptions,
|
|
16
17
|
type WithLinkFn,
|
|
@@ -23,7 +24,7 @@ import { DEFAULT_USER_REALM_NAME, type users } from "../entities/users.ts";
|
|
|
23
24
|
import { UserRealmProvider } from "../providers/UserRealmProvider.ts";
|
|
24
25
|
import { SessionService } from "../services/SessionService.ts";
|
|
25
26
|
|
|
26
|
-
export type
|
|
27
|
+
export type UserRealmPrimitive = RealmPrimitive & WithLinkFn & WithLoginFn;
|
|
27
28
|
|
|
28
29
|
/**
|
|
29
30
|
* Already configured realm for user management.
|
|
@@ -41,16 +42,23 @@ export type UserRealmDescriptor = RealmDescriptor & WithLinkFn & WithLoginFn;
|
|
|
41
42
|
|
|
42
43
|
export const $userRealm = (
|
|
43
44
|
options: UserRealmOptions = {},
|
|
44
|
-
):
|
|
45
|
+
): UserRealmPrimitive => {
|
|
45
46
|
const { alepha } = $context();
|
|
46
47
|
const sessionService = alepha.inject(SessionService);
|
|
47
48
|
const securityProvider = alepha.inject(SecurityProvider);
|
|
48
49
|
const userRealmProvider = alepha.inject(UserRealmProvider);
|
|
49
50
|
const name = options.realm?.name ?? DEFAULT_USER_REALM_NAME;
|
|
50
51
|
|
|
51
|
-
userRealmProvider.register(name, options);
|
|
52
|
+
const userRealm = userRealmProvider.register(name, options);
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
if (options.modules?.audits) {
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if (options.modules?.files) {
|
|
58
|
+
alepha.with(AlephaApiFiles);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const realm: UserRealmPrimitive = $realm({
|
|
54
62
|
...options.realm,
|
|
55
63
|
name,
|
|
56
64
|
secret: options.secret ?? securityProvider.secretKey,
|
|
@@ -103,18 +111,28 @@ export const $userRealm = (
|
|
|
103
111
|
sessionService.login(name, credentials.username, credentials.password);
|
|
104
112
|
};
|
|
105
113
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
114
|
+
const identities = options.identities ?? {
|
|
115
|
+
credentials: true,
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
if (identities) {
|
|
119
|
+
const auth: Record<string, AuthPrimitive> = {};
|
|
120
|
+
if (identities.credentials) {
|
|
121
|
+
auth.credentials = $authCredentials(realm);
|
|
122
|
+
} else {
|
|
123
|
+
// if credentials auth is disabled, disable registration as well
|
|
124
|
+
userRealm.settings.registrationAllowed = false;
|
|
110
125
|
}
|
|
111
|
-
|
|
112
|
-
|
|
126
|
+
|
|
127
|
+
if (identities.google) {
|
|
128
|
+
auth.google = $authGoogle(realm);
|
|
113
129
|
}
|
|
114
|
-
|
|
115
|
-
|
|
130
|
+
|
|
131
|
+
if (identities.github) {
|
|
132
|
+
auth.github = $authGithub(realm);
|
|
116
133
|
}
|
|
117
|
-
|
|
134
|
+
|
|
135
|
+
alepha.with(() => auth);
|
|
118
136
|
}
|
|
119
137
|
|
|
120
138
|
return realm;
|
|
@@ -135,7 +153,7 @@ export interface UserRealmOptions {
|
|
|
135
153
|
*
|
|
136
154
|
* It's already pre-configured for user management with admin and user roles.
|
|
137
155
|
*/
|
|
138
|
-
realm?: Partial<
|
|
156
|
+
realm?: Partial<RealmPrimitiveOptions>;
|
|
139
157
|
|
|
140
158
|
/**
|
|
141
159
|
* Override entities.
|
|
@@ -153,4 +171,9 @@ export interface UserRealmOptions {
|
|
|
153
171
|
google?: true;
|
|
154
172
|
github?: true;
|
|
155
173
|
};
|
|
174
|
+
|
|
175
|
+
modules?: {
|
|
176
|
+
files?: boolean;
|
|
177
|
+
audits?: boolean;
|
|
178
|
+
};
|
|
156
179
|
}
|
|
@@ -40,7 +40,7 @@ export class UserRealmProvider {
|
|
|
40
40
|
protected readonly onConfigure = $hook({
|
|
41
41
|
on: "configure",
|
|
42
42
|
handler: () => {
|
|
43
|
-
this.alepha.
|
|
43
|
+
this.alepha.store.set("alepha.server.security.system.user", {
|
|
44
44
|
id: "00000000-0000-0000-0000-000000000000",
|
|
45
45
|
name: "system",
|
|
46
46
|
roles: ["admin"], // TODO: use realm config
|
|
@@ -70,6 +70,7 @@ export class UserRealmProvider {
|
|
|
70
70
|
},
|
|
71
71
|
},
|
|
72
72
|
});
|
|
73
|
+
return this.getRealm(userRealmName);
|
|
73
74
|
}
|
|
74
75
|
|
|
75
76
|
/**
|
|
@@ -290,6 +290,8 @@ export class SessionService {
|
|
|
290
290
|
realm: realm.name,
|
|
291
291
|
username: profile.email.split("@")[0],
|
|
292
292
|
email: profile.email,
|
|
293
|
+
// we trust the OAuth2 provider
|
|
294
|
+
emailVerified: true,
|
|
293
295
|
roles: ["user"], // TODO: make default roles configurable via realm settings
|
|
294
296
|
});
|
|
295
297
|
|
|
@@ -23,12 +23,22 @@ export class UserService {
|
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
25
|
* Request email verification for a user.
|
|
26
|
+
* @param email - The email address to verify.
|
|
27
|
+
* @param userRealmName - Optional realm name.
|
|
28
|
+
* @param method - The verification method: "code" (default) or "link".
|
|
29
|
+
* @param verifyUrl - Base URL for verification link (required when method is "link").
|
|
26
30
|
*/
|
|
27
31
|
public async requestEmailVerification(
|
|
28
32
|
email: string,
|
|
29
33
|
userRealmName?: string,
|
|
34
|
+
method: "code" | "link" = "code",
|
|
35
|
+
verifyUrl?: string,
|
|
30
36
|
): Promise<boolean> {
|
|
31
|
-
this.log.trace("Requesting email verification", {
|
|
37
|
+
this.log.trace("Requesting email verification", {
|
|
38
|
+
email,
|
|
39
|
+
userRealmName,
|
|
40
|
+
method,
|
|
41
|
+
});
|
|
32
42
|
|
|
33
43
|
const user = await this.users(userRealmName)
|
|
34
44
|
.findOne({
|
|
@@ -54,23 +64,47 @@ export class UserService {
|
|
|
54
64
|
try {
|
|
55
65
|
const verification =
|
|
56
66
|
await this.verificationController.requestVerificationCode({
|
|
57
|
-
params: { type:
|
|
67
|
+
params: { type: method },
|
|
58
68
|
body: { target: email },
|
|
59
69
|
});
|
|
60
70
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
71
|
+
if (method === "link") {
|
|
72
|
+
// Build verification URL with token
|
|
73
|
+
const url = new URL(verifyUrl || "/verify-email", "http://localhost");
|
|
74
|
+
url.searchParams.set("email", email);
|
|
75
|
+
url.searchParams.set("token", verification.token);
|
|
76
|
+
const fullVerifyUrl = verifyUrl
|
|
77
|
+
? `${verifyUrl}${url.search}`
|
|
78
|
+
: url.pathname + url.search;
|
|
79
|
+
|
|
80
|
+
await this.userNotifications.emailVerificationLink.push({
|
|
81
|
+
contact: email,
|
|
82
|
+
variables: {
|
|
83
|
+
email,
|
|
84
|
+
verifyUrl: fullVerifyUrl,
|
|
85
|
+
expiresInMinutes: Math.floor(verification.codeExpiration / 60),
|
|
86
|
+
},
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
this.log.debug("Email verification link sent", {
|
|
64
90
|
email,
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
91
|
+
userId: user.id,
|
|
92
|
+
});
|
|
93
|
+
} else {
|
|
94
|
+
await this.userNotifications.emailVerification.push({
|
|
95
|
+
contact: email,
|
|
96
|
+
variables: {
|
|
97
|
+
email,
|
|
98
|
+
code: verification.token,
|
|
99
|
+
expiresInMinutes: Math.floor(verification.codeExpiration / 60),
|
|
100
|
+
},
|
|
101
|
+
});
|
|
69
102
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
103
|
+
this.log.debug("Email verification code sent", {
|
|
104
|
+
email,
|
|
105
|
+
userId: user.id,
|
|
106
|
+
});
|
|
107
|
+
}
|
|
74
108
|
} catch (error) {
|
|
75
109
|
// Silent fail for security
|
|
76
110
|
this.log.warn("Failed to send email verification", { email, error });
|
|
@@ -81,6 +115,7 @@ export class UserService {
|
|
|
81
115
|
|
|
82
116
|
/**
|
|
83
117
|
* Verify a user's email using a valid verification token.
|
|
118
|
+
* Supports both code (6-digit) and link (UUID) verification tokens.
|
|
84
119
|
*/
|
|
85
120
|
public async verifyEmail(
|
|
86
121
|
email: string,
|
|
@@ -89,13 +124,18 @@ export class UserService {
|
|
|
89
124
|
): Promise<void> {
|
|
90
125
|
this.log.trace("Verifying email", { email, userRealmName });
|
|
91
126
|
|
|
127
|
+
// Detect verification type based on token format
|
|
128
|
+
// Codes are 6-digit numbers, links are UUIDs
|
|
129
|
+
const isCode = /^\d{6}$/.test(token);
|
|
130
|
+
const type = isCode ? "code" : "link";
|
|
131
|
+
|
|
92
132
|
const result = await this.verificationController
|
|
93
133
|
.validateVerificationCode({
|
|
94
|
-
params: { type
|
|
134
|
+
params: { type },
|
|
95
135
|
body: { target: email, token },
|
|
96
136
|
})
|
|
97
137
|
.catch(() => {
|
|
98
|
-
this.log.warn("Invalid email verification token", { email });
|
|
138
|
+
this.log.warn("Invalid email verification token", { email, type });
|
|
99
139
|
throw new BadRequestError("Invalid or expired verification token");
|
|
100
140
|
});
|
|
101
141
|
|
|
@@ -112,7 +152,7 @@ export class UserService {
|
|
|
112
152
|
emailVerified: true,
|
|
113
153
|
});
|
|
114
154
|
|
|
115
|
-
this.log.info("Email verified", { email, userId: user.id });
|
|
155
|
+
this.log.info("Email verified", { email, userId: user.id, type });
|
|
116
156
|
}
|
|
117
157
|
|
|
118
158
|
/**
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { $module } from "alepha";
|
|
2
|
+
|
|
3
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
4
|
+
|
|
5
|
+
export * from "./entities/verifications.ts";
|
|
6
|
+
export * from "./schemas/requestVerificationCodeResponseSchema.ts";
|
|
7
|
+
export * from "./schemas/validateVerificationCodeResponseSchema.ts";
|
|
8
|
+
export * from "./schemas/verificationTypeEnumSchema.ts";
|
|
9
|
+
|
|
10
|
+
// ---------------------------------------------------------------------------------------------------------------------
|
|
11
|
+
|
|
12
|
+
export const AlephaApiVerification = $module({
|
|
13
|
+
name: "alepha.api.verifications",
|
|
14
|
+
services: [],
|
|
15
|
+
});
|
|
@@ -6,6 +6,7 @@ import { VerificationService } from "./services/VerificationService.ts";
|
|
|
6
6
|
// ---------------------------------------------------------------------------------------------------------------------
|
|
7
7
|
|
|
8
8
|
export * from "./controllers/VerificationController.ts";
|
|
9
|
+
export * from "./entities/verifications.ts";
|
|
9
10
|
export * from "./schemas/requestVerificationCodeResponseSchema.ts";
|
|
10
11
|
export * from "./schemas/validateVerificationCodeResponseSchema.ts";
|
|
11
12
|
export * from "./schemas/verificationTypeEnumSchema.ts";
|