@veap/auth 0.1.7 → 0.1.9

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 (46) hide show
  1. package/README.md +2 -1
  2. package/dist/actions/auth.actions.d.ts +2 -18
  3. package/dist/actions/auth.actions.js +16 -4
  4. package/dist/common/context.d.ts +2 -0
  5. package/dist/common/logic.js +5 -2
  6. package/dist/common/types.d.ts +1 -0
  7. package/dist/composition.d.ts +9 -0
  8. package/dist/composition.js +5 -0
  9. package/dist/crypto/encryption.js +0 -2
  10. package/dist/crypto/password.d.ts +4 -4
  11. package/dist/crypto/password.js +41 -9
  12. package/dist/index.d.ts +2 -1
  13. package/dist/index.js +2 -1
  14. package/dist/models/User.d.ts +1 -0
  15. package/dist/models/User.js +3 -1
  16. package/dist/notifications/contracts.d.ts +29 -0
  17. package/dist/notifications/contracts.js +4 -0
  18. package/dist/notifications/default-notification.service.d.ts +30 -0
  19. package/dist/notifications/default-notification.service.js +105 -0
  20. package/dist/notifications/helpers.d.ts +16 -0
  21. package/dist/notifications/helpers.js +39 -0
  22. package/dist/notifications/index.d.ts +3 -0
  23. package/dist/notifications/index.js +3 -0
  24. package/dist/passwords/password-reset.facade.js +6 -4
  25. package/dist/passwords/password-reset.service.d.ts +3 -1
  26. package/dist/passwords/password-reset.service.js +9 -4
  27. package/dist/providers/auth.provider.js +19 -2
  28. package/dist/providers/setup.js +12 -1
  29. package/dist/rbac/rbac.facade.d.ts +2 -2
  30. package/dist/rbac/rbac.facade.js +6 -4
  31. package/dist/rbac/rbac.service.d.ts +2 -2
  32. package/dist/rbac/rbac.service.js +2 -2
  33. package/dist/server.d.ts +10 -1
  34. package/dist/server.js +10 -1
  35. package/dist/session/auth.service.js +3 -0
  36. package/dist/session/session.facade.js +6 -4
  37. package/dist/session/session.service.d.ts +1 -1
  38. package/dist/session/session.service.js +14 -3
  39. package/dist/users/user.facade.js +6 -4
  40. package/dist/users/user.service.d.ts +3 -1
  41. package/dist/users/user.service.js +12 -5
  42. package/dist/validation/index.js +1 -1
  43. package/dist/verification/verification.facade.js +6 -4
  44. package/dist/verification/verification.service.d.ts +3 -1
  45. package/dist/verification/verification.service.js +9 -4
  46. package/package.json +5 -5
package/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  [![CI](https://github.com/veapjs/veap-auth/actions/workflows/CI.yml/badge.svg)](https://github.com/veapjs/veap-auth/actions/workflows/CI.yml)
2
2
  [![Release](https://github.com/veapjs/veap-auth/actions/workflows/RELEASE.yml/badge.svg)](https://github.com/veapjs/veap-auth/actions/workflows/RELEASE.yml)
3
- [![Version](https://img.shields.io/npm/v/@veap/auth?style=flat&colorA=000000&colorB=000000)](https://www.npmjs.com/package/@veap/auth)
3
+ [![Version](https://img.shields.io/npm/v/@veap%2Fauth?style=flat-square&color=181717&logo=npm&logoColor=959da5)](https://www.npmjs.com/package/@veap/auth)
4
+ [![Discord](https://img.shields.io/badge/Discord-join-5865F2?style=flat-square&logo=discord&logoColor=959da5)](https://discord.gg/qTkrCwpMW)
4
5
 
5
6
  # @veap/auth
6
7
 
@@ -2,22 +2,6 @@ import { type Result } from "@veap/kernel";
2
2
  import type { AuthResponse, SessionFlags } from "../common/index.js";
3
3
  import type { LoginInput, RegisterInput } from "../validation/index.js";
4
4
  export declare function signIn(data: LoginInput): Promise<Result<AuthResponse>>;
5
- export declare function signUp(data: RegisterInput): Promise<{
6
- success: false;
7
- error: import("@veap/kernel").AppErrorJson;
8
- data?: never;
9
- } | {
10
- success: true;
11
- data: AuthResponse;
12
- error?: never;
13
- }>;
14
- export declare function finalizeLogin(userId: string, flags: SessionFlags): Promise<{
15
- success: false;
16
- error: import("@veap/kernel").AppErrorJson;
17
- data?: never;
18
- } | {
19
- success: true;
20
- data: AuthResponse;
21
- error?: never;
22
- }>;
5
+ export declare function signUp(data: RegisterInput): Promise<Result<AuthResponse>>;
6
+ export declare function finalizeLogin(userId: string, flags: SessionFlags): Promise<Result<AuthResponse>>;
23
7
  export declare function signOut(): Promise<Result<void>>;
@@ -1,10 +1,14 @@
1
1
  "use server";
2
- import { app, handleActionError, ok } from "@veap/kernel";
2
+ import { AppError, app, handleActionError, ok, } from "@veap/kernel";
3
3
  import { AuthService } from "../session/auth.service.js";
4
4
  export async function signIn(data) {
5
5
  try {
6
6
  const authService = await app(AuthService);
7
- return ok(await authService.signIn(data));
7
+ const response = await authService.signIn(data);
8
+ if (response.status === "ERROR") {
9
+ throw AppError.Unauthorized(response.message || "Invalid credentials");
10
+ }
11
+ return ok(response);
8
12
  }
9
13
  catch (e) {
10
14
  return handleActionError(e, "Auth:SignIn");
@@ -13,7 +17,11 @@ export async function signIn(data) {
13
17
  export async function signUp(data) {
14
18
  try {
15
19
  const authService = await app(AuthService);
16
- return ok(await authService.signUp(data));
20
+ const response = await authService.signUp(data);
21
+ if (response.status === "ERROR") {
22
+ throw AppError.Conflict(response.message || "Registration failed");
23
+ }
24
+ return ok(response);
17
25
  }
18
26
  catch (e) {
19
27
  return handleActionError(e, "Auth:SignUp");
@@ -22,7 +30,11 @@ export async function signUp(data) {
22
30
  export async function finalizeLogin(userId, flags) {
23
31
  try {
24
32
  const authService = await app(AuthService);
25
- return ok(await authService.finalizeLogin(userId, flags));
33
+ const response = await authService.finalizeLogin(userId, flags);
34
+ if (response.status === "ERROR") {
35
+ throw AppError.BadRequest(response.message || "Failed to finalize login");
36
+ }
37
+ return ok(response);
26
38
  }
27
39
  catch (e) {
28
40
  return handleActionError(e, "Auth:FinalizeLogin");
@@ -1,3 +1,4 @@
1
+ import type { IPasswordHasher } from "../crypto/contracts.js";
1
2
  import { type AuthRoutesConfig } from "./routes.js";
2
3
  export interface AuthContext {
3
4
  user: any;
@@ -6,6 +7,7 @@ export interface AuthContext {
6
7
  passwordReset: any;
7
8
  emailVerification: any;
8
9
  auth: any;
10
+ passwordHasher?: IPasswordHasher;
9
11
  routes?: AuthRoutesConfig;
10
12
  }
11
13
  /**
@@ -1,5 +1,5 @@
1
1
  import { augmentSession, augmentUser, registerIdentityAugmenter, registerPasswordResetSessionAugmenter, registerSessionAugmenter, unregisterIdentityAugmenter, unregisterPasswordResetSessionAugmenter, unregisterSessionAugmenter, } from "./augment.js";
2
- import { authContext, isAuthContextBound } from "./context.js";
2
+ import { authContext, getAuthRoutes, isAuthContextBound } from "./context.js";
3
3
  import { AuthCallbackRegistry } from "./registry.js";
4
4
  const globalForAuth = globalThis;
5
5
  export const authValidators = globalForAuth.__VEAP_AUTH_VALIDATORS__ ??
@@ -64,7 +64,10 @@ export async function checkSecurity(session, user, requiredRoles, requiredPermis
64
64
  path) {
65
65
  if (!user) {
66
66
  console.warn("User is required for security check");
67
- return { satisfied: false, redirect: fallbackRedirect ?? "/signin" };
67
+ return {
68
+ satisfied: false,
69
+ redirect: fallbackRedirect ?? getAuthRoutes().signIn,
70
+ };
68
71
  }
69
72
  const userRoles = Array.isArray(user.roles) ? user.roles : [];
70
73
  const userPermissions = Array.isArray(user.permissions)
@@ -70,6 +70,7 @@ export type AuthResponse = {
70
70
  status: "SUCCESS";
71
71
  session: Session;
72
72
  user: FullUser;
73
+ token?: string;
73
74
  redirect?: string;
74
75
  } | {
75
76
  status: "CHALLENGE_REQUIRED";
@@ -0,0 +1,9 @@
1
+ import type { AuthConfig } from "./common/types.js";
2
+ declare module "@veap/kernel" {
3
+ interface ApplicationBuilder {
4
+ /**
5
+ * Registers the {@link AuthServiceProvider} with the application.
6
+ */
7
+ withAuth(config?: AuthConfig): this;
8
+ }
9
+ }
@@ -0,0 +1,5 @@
1
+ import { ApplicationBuilder } from "@veap/kernel";
2
+ import { AuthServiceProvider } from "./providers/auth.provider.js";
3
+ ApplicationBuilder.prototype.withAuth = function (config) {
4
+ return this.use((c) => new AuthServiceProvider(c, config));
5
+ };
@@ -20,8 +20,6 @@ export function getAlgorithm(key) {
20
20
  ? "aes-192-gcm"
21
21
  : "aes-256-gcm";
22
22
  }
23
- // Configuration contract: validate key on module load
24
- getEncryptionKey();
25
23
  /**
26
24
  * Encrypts data using AES-GCM.
27
25
  */
@@ -1,18 +1,18 @@
1
1
  /**
2
- * Hashes the password using bcrypt.
2
+ * Hashes the password using the configured password hasher.
3
3
  * @param password Password to be hashed.
4
4
  * @returns Returns the hashed password.
5
5
  */
6
6
  export declare function hashPassword(password: string): Promise<string>;
7
7
  /**
8
- * Verifies the password hash.
9
- * @param hash bcrypt hash.
8
+ * Verifies the password hash using the configured password hasher.
9
+ * @param hash Stored password hash.
10
10
  * @param password Password for comparison.
11
11
  * @returns Returns true if the password is correct, false otherwise.
12
12
  */
13
13
  export declare function verifyPasswordHash(hash: string, password: string): Promise<boolean>;
14
14
  /**
15
- * Validates password strength.
15
+ * Validates password strength using the configured password hasher.
16
16
  * @param password Password to validate.
17
17
  * @returns Returns true if the password meets complexity requirements.
18
18
  */
@@ -1,27 +1,59 @@
1
- import bcrypt from "bcryptjs";
1
+ import { app } from "@veap/kernel";
2
+ import { authContext, isAuthContextBound } from "../common/context.js";
3
+ import { BcryptPasswordHasher } from "./bcrypt-hasher.js";
4
+ import { PASSWORD_HASHER } from "./contracts.js";
5
+ async function resolvePasswordHasher() {
6
+ if (isAuthContextBound()) {
7
+ const ctx = authContext();
8
+ if (ctx.passwordHasher) {
9
+ return ctx.passwordHasher;
10
+ }
11
+ }
12
+ const g = globalThis;
13
+ if (g.__VEAP_BOOTSTRAPPING_PROMISE__) {
14
+ try {
15
+ await g.__VEAP_BOOTSTRAPPING_PROMISE__;
16
+ }
17
+ catch { }
18
+ if (isAuthContextBound()) {
19
+ const ctx = authContext();
20
+ if (ctx.passwordHasher) {
21
+ return ctx.passwordHasher;
22
+ }
23
+ }
24
+ }
25
+ try {
26
+ return await app(PASSWORD_HASHER);
27
+ }
28
+ catch {
29
+ return new BcryptPasswordHasher();
30
+ }
31
+ }
2
32
  /**
3
- * Hashes the password using bcrypt.
33
+ * Hashes the password using the configured password hasher.
4
34
  * @param password Password to be hashed.
5
35
  * @returns Returns the hashed password.
6
36
  */
7
37
  export async function hashPassword(password) {
8
- const saltRounds = 10;
9
- return await bcrypt.hash(password, saltRounds);
38
+ const hasher = await resolvePasswordHasher();
39
+ return await hasher.hash(password);
10
40
  }
11
41
  /**
12
- * Verifies the password hash.
13
- * @param hash bcrypt hash.
42
+ * Verifies the password hash using the configured password hasher.
43
+ * @param hash Stored password hash.
14
44
  * @param password Password for comparison.
15
45
  * @returns Returns true if the password is correct, false otherwise.
16
46
  */
17
47
  export async function verifyPasswordHash(hash, password) {
18
- return await bcrypt.compare(password, hash);
48
+ const hasher = await resolvePasswordHasher();
49
+ return await hasher.verify(hash, password);
19
50
  }
20
51
  /**
21
- * Validates password strength.
52
+ * Validates password strength using the configured password hasher.
22
53
  * @param password Password to validate.
23
54
  * @returns Returns true if the password meets complexity requirements.
24
55
  */
25
56
  export async function verifyPasswordStrength(password) {
26
- return password.length >= 8 && password.length <= 255;
57
+ const hasher = await resolvePasswordHasher();
58
+ return await hasher.validateStrength(password);
27
59
  }
package/dist/index.d.ts CHANGED
@@ -1,7 +1,8 @@
1
1
  export * from "./actions/index.js";
2
- export { AuthProvider, useAuthRoutes, useUser } from "./client/index.js";
3
2
  export * from "./common/index.js";
3
+ export * from "./composition.js";
4
4
  export * from "./crypto/index.js";
5
+ export * from "./notifications/index.js";
5
6
  export * from "./passwords/index.js";
6
7
  export * from "./providers/index.js";
7
8
  export * from "./rbac/index.js";
package/dist/index.js CHANGED
@@ -1,7 +1,8 @@
1
1
  export * from "./actions/index.js";
2
- export { AuthProvider, useAuthRoutes, useUser } from "./client/index.js";
3
2
  export * from "./common/index.js";
3
+ export * from "./composition.js";
4
4
  export * from "./crypto/index.js";
5
+ export * from "./notifications/index.js";
5
6
  export * from "./passwords/index.js";
6
7
  export * from "./providers/index.js";
7
8
  export * from "./rbac/index.js";
@@ -15,6 +15,7 @@ export interface UserAttributes {
15
15
  }
16
16
  export declare class User extends Model<UserAttributes> {
17
17
  static table: string;
18
+ static morphAlias: string;
18
19
  static hidden: string[];
19
20
  static casts: Record<string, CastType>;
20
21
  /**
@@ -1,9 +1,10 @@
1
- import { Model } from "@veap/database";
1
+ import { Model, MorphMap } from "@veap/database";
2
2
  import { Permission } from "./Permission.js";
3
3
  import { Role } from "./Role.js";
4
4
  import { Session } from "./Session.js";
5
5
  export class User extends Model {
6
6
  static table = "users";
7
+ static morphAlias = "user";
7
8
  static hidden = ["password", "recovery_code"];
8
9
  static casts = {
9
10
  emailVerifiedAt: "datetime",
@@ -29,3 +30,4 @@ export class User extends Model {
29
30
  return this.belongsToMany(Permission, "users_to_permissions", "user_id", "permission_id", "id", "id");
30
31
  }
31
32
  }
33
+ MorphMap.register({ user: User });
@@ -0,0 +1,29 @@
1
+ import type { Token } from "@veap/kernel";
2
+ /**
3
+ * Port contract for authentication notifications (emails, SMS, security alerts).
4
+ *
5
+ * Decouples authentication use cases (password reset, email verification,
6
+ * recovery codes) from specific transport providers (SMTP, SendGrid, SES, etc.).
7
+ */
8
+ export interface IAuthNotificationService {
9
+ /**
10
+ * Sends an email verification request containing an OTP code.
11
+ */
12
+ sendVerificationEmail(email: string, code: string): Promise<void>;
13
+ /**
14
+ * Sends a password reset request containing an OTP code.
15
+ */
16
+ sendPasswordReset(email: string, code: string): Promise<void>;
17
+ /**
18
+ * Sends an initial or updated recovery code to the user.
19
+ */
20
+ sendRecoveryCode(email: string, code: string): Promise<void>;
21
+ /**
22
+ * Optional two-factor authentication challenge delivery.
23
+ */
24
+ send2FACode?(email: string, code: string): Promise<void>;
25
+ }
26
+ /**
27
+ * IoC Token for the authentication notification port.
28
+ */
29
+ export declare const AUTH_NOTIFICATION_SERVICE: Token<IAuthNotificationService>;
@@ -0,0 +1,4 @@
1
+ /**
2
+ * IoC Token for the authentication notification port.
3
+ */
4
+ export const AUTH_NOTIFICATION_SERVICE = Symbol.for("veap:auth:notification-service");
@@ -0,0 +1,30 @@
1
+ import type { IEventBus } from "@veap/kernel";
2
+ import type { IAuthNotificationService } from "./contracts.js";
3
+ export interface IMailerLike {
4
+ sendMail(message: {
5
+ to: string;
6
+ subject: string;
7
+ text?: string;
8
+ html?: string;
9
+ }): Promise<void>;
10
+ }
11
+ export type MailerResolver = () => Promise<IMailerLike | undefined> | IMailerLike | undefined;
12
+ export type EventBusResolver = () => Promise<IEventBus | undefined> | IEventBus | undefined;
13
+ /**
14
+ * Default implementation of the authentication notification port.
15
+ *
16
+ * If a mailer adapter is registered, it constructs and sends localized or
17
+ * templated emails. If an EventBus is available, it emits system auth events.
18
+ * In development or testing without a mailer, it logs codes safely.
19
+ */
20
+ export declare class DefaultAuthNotificationService implements IAuthNotificationService {
21
+ private readonly mailerResolver?;
22
+ private readonly eventBusResolver?;
23
+ constructor(mailerResolver?: MailerResolver | undefined, eventBusResolver?: EventBusResolver | undefined);
24
+ private getMailer;
25
+ private getEventBus;
26
+ sendVerificationEmail(email: string, code: string): Promise<void>;
27
+ sendPasswordReset(email: string, code: string): Promise<void>;
28
+ sendRecoveryCode(email: string, code: string): Promise<void>;
29
+ send2FACode(email: string, code: string): Promise<void>;
30
+ }
@@ -0,0 +1,105 @@
1
+ /**
2
+ * Default implementation of the authentication notification port.
3
+ *
4
+ * If a mailer adapter is registered, it constructs and sends localized or
5
+ * templated emails. If an EventBus is available, it emits system auth events.
6
+ * In development or testing without a mailer, it logs codes safely.
7
+ */
8
+ export class DefaultAuthNotificationService {
9
+ mailerResolver;
10
+ eventBusResolver;
11
+ constructor(mailerResolver, eventBusResolver) {
12
+ this.mailerResolver = mailerResolver;
13
+ this.eventBusResolver = eventBusResolver;
14
+ }
15
+ async getMailer() {
16
+ if (!this.mailerResolver)
17
+ return undefined;
18
+ return await this.mailerResolver();
19
+ }
20
+ async getEventBus() {
21
+ if (!this.eventBusResolver)
22
+ return undefined;
23
+ return await this.eventBusResolver();
24
+ }
25
+ async sendVerificationEmail(email, code) {
26
+ const mailer = await this.getMailer();
27
+ if (mailer) {
28
+ await mailer.sendMail({
29
+ to: email,
30
+ subject: "Verify Email",
31
+ text: `Verify your email address with your code: ${code}`,
32
+ });
33
+ }
34
+ else {
35
+ console.info(`[veap:auth] Verification email code for ${email}: ${code}`);
36
+ }
37
+ const eventBus = await this.getEventBus();
38
+ if (eventBus) {
39
+ await eventBus.publish("system:auth:verification-requested", {
40
+ email,
41
+ code,
42
+ });
43
+ }
44
+ }
45
+ async sendPasswordReset(email, code) {
46
+ const mailer = await this.getMailer();
47
+ if (mailer) {
48
+ await mailer.sendMail({
49
+ to: email,
50
+ subject: "Password Reset",
51
+ text: `Verify password reset with code: ${code}`,
52
+ });
53
+ }
54
+ else {
55
+ console.info(`[veap:auth] Password reset code for ${email}: ${code}`);
56
+ }
57
+ const eventBus = await this.getEventBus();
58
+ if (eventBus) {
59
+ await eventBus.publish("system:auth:password-reset:requested", {
60
+ email,
61
+ code,
62
+ });
63
+ }
64
+ }
65
+ async sendRecoveryCode(email, code) {
66
+ const mailer = await this.getMailer();
67
+ if (mailer) {
68
+ await mailer.sendMail({
69
+ to: email,
70
+ subject: "Recovery Code",
71
+ text: `Your recovery code is: ${code}`,
72
+ });
73
+ }
74
+ else {
75
+ console.info(`[veap:auth] Recovery code for ${email}: ${code}`);
76
+ }
77
+ const eventBus = await this.getEventBus();
78
+ if (eventBus) {
79
+ await eventBus.publish("system:auth:recovery-code:generated", {
80
+ email,
81
+ recoveryCode: code,
82
+ });
83
+ }
84
+ }
85
+ async send2FACode(email, code) {
86
+ const mailer = await this.getMailer();
87
+ if (mailer) {
88
+ await mailer.sendMail({
89
+ to: email,
90
+ subject: "Your 2FA Code",
91
+ text: `Your verification code is: ${code}. It will expire in 10 minutes.`,
92
+ });
93
+ }
94
+ else {
95
+ console.info(`[veap:auth] 2FA verification code for ${email}: ${code}`);
96
+ }
97
+ const eventBus = await this.getEventBus();
98
+ if (eventBus) {
99
+ await eventBus.publish("system:auth:2fa-code:requested", {
100
+ email,
101
+ code,
102
+ });
103
+ }
104
+ }
105
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Sends a verification email code using the registered auth notification service.
3
+ */
4
+ export declare function sendVerifyEmail(email: string, code: string): Promise<void>;
5
+ /**
6
+ * Sends a password reset code using the registered auth notification service.
7
+ */
8
+ export declare function sendResetPassword(email: string, code: string): Promise<void>;
9
+ /**
10
+ * Sends a recovery code using the registered auth notification service.
11
+ */
12
+ export declare function sendRecoveryCode(email: string, code: string): Promise<void>;
13
+ /**
14
+ * Sends a 2FA verification code using the registered auth notification service.
15
+ */
16
+ export declare function send2FACode(email: string, code: string): Promise<void>;
@@ -0,0 +1,39 @@
1
+ import { container } from "@veap/kernel";
2
+ import { AUTH_NOTIFICATION_SERVICE, } from "./contracts.js";
3
+ import { DefaultAuthNotificationService } from "./default-notification.service.js";
4
+ async function getNotificationService() {
5
+ if (container.has(AUTH_NOTIFICATION_SERVICE)) {
6
+ return await container.resolve(AUTH_NOTIFICATION_SERVICE);
7
+ }
8
+ return new DefaultAuthNotificationService();
9
+ }
10
+ /**
11
+ * Sends a verification email code using the registered auth notification service.
12
+ */
13
+ export async function sendVerifyEmail(email, code) {
14
+ const service = await getNotificationService();
15
+ return service.sendVerificationEmail(email, code);
16
+ }
17
+ /**
18
+ * Sends a password reset code using the registered auth notification service.
19
+ */
20
+ export async function sendResetPassword(email, code) {
21
+ const service = await getNotificationService();
22
+ return service.sendPasswordReset(email, code);
23
+ }
24
+ /**
25
+ * Sends a recovery code using the registered auth notification service.
26
+ */
27
+ export async function sendRecoveryCode(email, code) {
28
+ const service = await getNotificationService();
29
+ return service.sendRecoveryCode(email, code);
30
+ }
31
+ /**
32
+ * Sends a 2FA verification code using the registered auth notification service.
33
+ */
34
+ export async function send2FACode(email, code) {
35
+ const service = await getNotificationService();
36
+ if (service.send2FACode) {
37
+ return service.send2FACode(email, code);
38
+ }
39
+ }
@@ -0,0 +1,3 @@
1
+ export * from "./contracts.js";
2
+ export * from "./default-notification.service.js";
3
+ export * from "./helpers.js";
@@ -0,0 +1,3 @@
1
+ export * from "./contracts.js";
2
+ export * from "./default-notification.service.js";
3
+ export * from "./helpers.js";
@@ -1,17 +1,19 @@
1
- "use server";
2
1
  import { app } from "@veap/kernel";
3
2
  import { authContext, isAuthContextBound } from "../common/context.js";
4
3
  import { PasswordResetService } from "./password-reset.service.js";
5
4
  async function resolvePasswordResetService() {
5
+ if (isAuthContextBound()) {
6
+ return authContext().passwordReset;
7
+ }
6
8
  const g = globalThis;
7
9
  if (g.__VEAP_BOOTSTRAPPING_PROMISE__) {
8
10
  try {
9
11
  await g.__VEAP_BOOTSTRAPPING_PROMISE__;
10
12
  }
11
13
  catch { }
12
- }
13
- if (isAuthContextBound()) {
14
- return authContext().passwordReset;
14
+ if (isAuthContextBound()) {
15
+ return authContext().passwordReset;
16
+ }
15
17
  }
16
18
  return await app(PasswordResetService);
17
19
  }
@@ -1,14 +1,16 @@
1
1
  import { type ICacheProvider, type ICookieStore } from "@veap/kernel";
2
2
  import type { PasswordResetAuthSession, PasswordResetSession as PasswordResetSessionType } from "../common/index.js";
3
3
  import { type ITokenGenerator } from "../crypto/contracts.js";
4
+ import { type IAuthNotificationService } from "../notifications/contracts.js";
4
5
  import { type IPasswordResetRepository } from "./contracts.js";
5
6
  export declare class PasswordResetService {
6
7
  private readonly sessions;
7
8
  private readonly tokens;
8
9
  private readonly cookieStore;
9
10
  private readonly cache?;
11
+ private readonly notifier?;
10
12
  private inMemoryAttempts;
11
- constructor(sessions: IPasswordResetRepository, tokens: ITokenGenerator, cookieStore: ICookieStore, cache?: ICacheProvider | undefined);
13
+ constructor(sessions: IPasswordResetRepository, tokens: ITokenGenerator, cookieStore: ICookieStore, cache?: ICacheProvider | undefined, notifier?: IAuthNotificationService | undefined);
12
14
  createPasswordResetSession(token: string, userId: string, email: string): Promise<PasswordResetSessionType>;
13
15
  /**
14
16
  * Creates an ephemeral dummy reset session for an unregistered email.
@@ -11,11 +11,11 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
13
  import { CACHE_PROVIDER, COOKIE_STORE, Inject, Injectable, } from "@veap/kernel";
14
- import { sendResetPassword } from "@veap/mail";
15
14
  import { addMinutes } from "date-fns";
16
15
  import { augmentPasswordResetSession } from "../common/augment.js";
17
16
  import { performFullUserAugmentation } from "../common/logic.js";
18
17
  import { TOKEN_GENERATOR } from "../crypto/contracts.js";
18
+ import { AUTH_NOTIFICATION_SERVICE, } from "../notifications/contracts.js";
19
19
  import { PASSWORD_RESET_REPOSITORY, } from "./contracts.js";
20
20
  const dummySessions = new Map();
21
21
  let PasswordResetService = class PasswordResetService {
@@ -23,12 +23,14 @@ let PasswordResetService = class PasswordResetService {
23
23
  tokens;
24
24
  cookieStore;
25
25
  cache;
26
+ notifier;
26
27
  inMemoryAttempts = new Map();
27
- constructor(sessions, tokens, cookieStore, cache) {
28
+ constructor(sessions, tokens, cookieStore, cache, notifier) {
28
29
  this.sessions = sessions;
29
30
  this.tokens = tokens;
30
31
  this.cookieStore = cookieStore;
31
32
  this.cache = cache;
33
+ this.notifier = notifier;
32
34
  }
33
35
  async createPasswordResetSession(token, userId, email) {
34
36
  const sessionId = this.tokens.hashToken(token);
@@ -228,7 +230,9 @@ let PasswordResetService = class PasswordResetService {
228
230
  return true;
229
231
  }
230
232
  async sendPasswordResetEmail(email, code) {
231
- await sendResetPassword(email, code);
233
+ if (this.notifier) {
234
+ await this.notifier.sendPasswordReset(email, code);
235
+ }
232
236
  }
233
237
  };
234
238
  PasswordResetService = __decorate([
@@ -237,6 +241,7 @@ PasswordResetService = __decorate([
237
241
  __param(1, Inject(TOKEN_GENERATOR)),
238
242
  __param(2, Inject(COOKIE_STORE)),
239
243
  __param(3, Inject(CACHE_PROVIDER)),
240
- __metadata("design:paramtypes", [Object, Object, Object, Object])
244
+ __param(4, Inject(AUTH_NOTIFICATION_SERVICE)),
245
+ __metadata("design:paramtypes", [Object, Object, Object, Object, Object])
241
246
  ], PasswordResetService);
242
247
  export { PasswordResetService };
@@ -1,5 +1,5 @@
1
1
  import { isDatabaseInitialized } from "@veap/database";
2
- import { ConfigService, Container, container as defaultContainer, logger, ServiceProvider, } from "@veap/kernel";
2
+ import { ConfigService, Container, container as defaultContainer, EVENT_BUS, logger, ServiceProvider, } from "@veap/kernel";
3
3
  import { bindAuthContext } from "../common/context.js";
4
4
  import { AUTH_ROUTES, DEFAULT_AUTH_ROUTES, ROUTER_SERVICE, } from "../common/routes.js";
5
5
  import { AesSecretCipher } from "../crypto/aes-cipher.js";
@@ -7,6 +7,7 @@ import { BcryptPasswordHasher } from "../crypto/bcrypt-hasher.js";
7
7
  import { PASSWORD_HASHER, SECRET_CIPHER, TOKEN_GENERATOR, } from "../crypto/contracts.js";
8
8
  import { OsloTokenGenerator } from "../crypto/token-generator.js";
9
9
  import { runAuthMigrations } from "../migrations/index.js";
10
+ import { AUTH_NOTIFICATION_SERVICE, DefaultAuthNotificationService, } from "../notifications/index.js";
10
11
  import { PASSWORD_RESET_REPOSITORY } from "../passwords/contracts.js";
11
12
  import { ActiveRecordPasswordResetRepository } from "../passwords/password-reset.repository.js";
12
13
  import { PasswordResetService } from "../passwords/password-reset.service.js";
@@ -103,6 +104,20 @@ export class AuthServiceProvider extends ServiceProvider {
103
104
  useClass: ActiveRecordEmailVerificationRepository,
104
105
  singleton: true,
105
106
  });
107
+ if (!this.container.has(AUTH_NOTIFICATION_SERVICE)) {
108
+ this.container.register({
109
+ token: AUTH_NOTIFICATION_SERVICE,
110
+ useFactory: () => {
111
+ const mailerToken = Symbol.for("veap:communication:mailer");
112
+ return new DefaultAuthNotificationService(() => this.container.has(mailerToken)
113
+ ? this.container.resolve(mailerToken)
114
+ : undefined, () => this.container.has(EVENT_BUS)
115
+ ? this.container.resolve(EVENT_BUS)
116
+ : undefined);
117
+ },
118
+ singleton: true,
119
+ });
120
+ }
106
121
  // Services
107
122
  this.container.register({
108
123
  token: UserService,
@@ -138,7 +153,7 @@ export class AuthServiceProvider extends ServiceProvider {
138
153
  async boot() {
139
154
  // 0. Auto-bootstrap setup state
140
155
  try {
141
- isSystemInstalled();
156
+ await isSystemInstalled();
142
157
  }
143
158
  catch { }
144
159
  // 1. Resolve domain services and bind singleton auth context
@@ -148,6 +163,7 @@ export class AuthServiceProvider extends ServiceProvider {
148
163
  const passwordReset = await this.container.resolve(PasswordResetService);
149
164
  const emailVerification = await this.container.resolve(EmailVerificationService);
150
165
  const auth = await this.container.resolve(AuthService);
166
+ const passwordHasher = await this.container.resolve(PASSWORD_HASHER);
151
167
  bindAuthContext({
152
168
  user,
153
169
  session,
@@ -155,6 +171,7 @@ export class AuthServiceProvider extends ServiceProvider {
155
171
  passwordReset,
156
172
  emailVerification,
157
173
  auth,
174
+ passwordHasher,
158
175
  routes: this.resolveRoutes(),
159
176
  });
160
177
  // 2. Register route rewrites if RouterService is available
@@ -8,7 +8,18 @@ import { User } from "../models/User.js";
8
8
  */
9
9
  export async function isSystemInstalled() {
10
10
  try {
11
- const count = await User.query().count();
11
+ const res = await User.query().count();
12
+ let count = 0;
13
+ if (Array.isArray(res) && res.length > 0) {
14
+ const first = res[0];
15
+ const rawVal = typeof first === "object" && first !== null
16
+ ? Object.values(first)[0]
17
+ : first;
18
+ count = Number(rawVal) || 0;
19
+ }
20
+ else if (typeof res === "number") {
21
+ count = res;
22
+ }
12
23
  if (count === 0) {
13
24
  logger.debug("veap:setup", "System not installed. Publishing event.");
14
25
  await eventBus.publish("system:not-installed", { timestamp: Date.now() });
@@ -1,10 +1,10 @@
1
1
  export declare function getRoles(): Promise<import("./contracts.js").RoleRecord[]>;
2
2
  export declare function getRoleById(roleId: string): Promise<import("./contracts.js").RoleRecord | undefined>;
3
- export declare function createRole(name: string, description?: string): Promise<import("./contracts.js").RoleRecord[]>;
3
+ export declare function createRole(name: string, description?: string): Promise<import("./contracts.js").RoleRecord>;
4
4
  export declare function deleteRole(roleId: string): Promise<void>;
5
5
  export declare function getPermissions(): Promise<import("./contracts.js").PermissionRecord[]>;
6
6
  export declare function getPermissionById(permissionId: string): Promise<import("./contracts.js").PermissionRecord | undefined>;
7
- export declare function createPermission(name: string, description?: string): Promise<import("./contracts.js").PermissionRecord[]>;
7
+ export declare function createPermission(name: string, description?: string): Promise<import("./contracts.js").PermissionRecord>;
8
8
  export declare function deletePermission(permissionId: string): Promise<void>;
9
9
  export declare function getRolePermissions(roleId: string): Promise<import("./contracts.js").AccessGrant[]>;
10
10
  export declare function assignPermissionToRole(roleId: string, permissionId: string): Promise<void>;
@@ -1,17 +1,19 @@
1
- "use server";
2
1
  import { app } from "@veap/kernel";
3
2
  import { authContext, isAuthContextBound } from "../common/context.js";
4
3
  import { RbacService } from "./rbac.service.js";
5
4
  async function resolveRbacService() {
5
+ if (isAuthContextBound()) {
6
+ return authContext().rbac;
7
+ }
6
8
  const g = globalThis;
7
9
  if (g.__VEAP_BOOTSTRAPPING_PROMISE__) {
8
10
  try {
9
11
  await g.__VEAP_BOOTSTRAPPING_PROMISE__;
10
12
  }
11
13
  catch { }
12
- }
13
- if (isAuthContextBound()) {
14
- return authContext().rbac;
14
+ if (isAuthContextBound()) {
15
+ return authContext().rbac;
16
+ }
15
17
  }
16
18
  return await app(RbacService);
17
19
  }
@@ -10,11 +10,11 @@ export declare class RbacService {
10
10
  constructor(roles: IRoleRepository, permissions: IPermissionRepository);
11
11
  getRoles(): Promise<RoleRecord[]>;
12
12
  getRoleById(roleId: string): Promise<RoleRecord | undefined>;
13
- createRole(name: string, description?: string): Promise<RoleRecord[]>;
13
+ createRole(name: string, description?: string): Promise<RoleRecord>;
14
14
  deleteRole(roleId: string): Promise<void>;
15
15
  getPermissions(): Promise<PermissionRecord[]>;
16
16
  getPermissionById(permissionId: string): Promise<PermissionRecord | undefined>;
17
- createPermission(name: string, description?: string): Promise<PermissionRecord[]>;
17
+ createPermission(name: string, description?: string): Promise<PermissionRecord>;
18
18
  deletePermission(permissionId: string): Promise<void>;
19
19
  getRolePermissions(roleId: string): Promise<AccessGrant[]>;
20
20
  assignPermissionToRole(roleId: string, permissionId: string): Promise<void>;
@@ -31,7 +31,7 @@ let RbacService = class RbacService {
31
31
  }
32
32
  async createRole(name, description) {
33
33
  const role = await this.roles.create({ name, description });
34
- return [role];
34
+ return role;
35
35
  }
36
36
  async deleteRole(roleId) {
37
37
  await this.roles.remove(roleId);
@@ -44,7 +44,7 @@ let RbacService = class RbacService {
44
44
  }
45
45
  async createPermission(name, description) {
46
46
  const permission = await this.permissions.create({ name, description });
47
- return [permission];
47
+ return permission;
48
48
  }
49
49
  async deletePermission(permissionId) {
50
50
  await this.permissions.remove(permissionId);
package/dist/server.d.ts CHANGED
@@ -1,3 +1,12 @@
1
1
  export * from "./actions/index.js";
2
+ export * from "./common/index.js";
3
+ export * from "./composition.js";
2
4
  export * from "./crypto/index.js";
3
- export * from "./index.js";
5
+ export * from "./notifications/index.js";
6
+ export * from "./passwords/index.js";
7
+ export * from "./providers/index.js";
8
+ export * from "./rbac/index.js";
9
+ export * from "./session/index.js";
10
+ export * from "./users/index.js";
11
+ export * from "./validation/index.js";
12
+ export * from "./verification/index.js";
package/dist/server.js CHANGED
@@ -1,3 +1,12 @@
1
1
  export * from "./actions/index.js";
2
+ export * from "./common/index.js";
3
+ export * from "./composition.js";
2
4
  export * from "./crypto/index.js";
3
- export * from "./index.js";
5
+ export * from "./notifications/index.js";
6
+ export * from "./passwords/index.js";
7
+ export * from "./providers/index.js";
8
+ export * from "./rbac/index.js";
9
+ export * from "./session/index.js";
10
+ export * from "./users/index.js";
11
+ export * from "./validation/index.js";
12
+ export * from "./verification/index.js";
@@ -128,6 +128,7 @@ let AuthService = class AuthService {
128
128
  status: "SUCCESS",
129
129
  session: { ...session },
130
130
  user: { ...fullUser },
131
+ token: sessionToken,
131
132
  };
132
133
  }
133
134
  /**
@@ -162,6 +163,7 @@ let AuthService = class AuthService {
162
163
  status: "SUCCESS",
163
164
  session: { ...session },
164
165
  user: { ...fullUser },
166
+ token: sessionToken,
165
167
  };
166
168
  }
167
169
  /**
@@ -184,6 +186,7 @@ let AuthService = class AuthService {
184
186
  status: "SUCCESS",
185
187
  session: { ...session },
186
188
  user: { ...fullUser },
189
+ token: sessionToken,
187
190
  };
188
191
  }
189
192
  /**
@@ -1,18 +1,20 @@
1
- "use server";
2
1
  import { app } from "@veap/kernel";
3
2
  import { cache } from "react";
4
3
  import { authContext, isAuthContextBound } from "../common/context.js";
5
4
  import { SessionService } from "./session.service.js";
6
5
  async function resolveSessionService() {
6
+ if (isAuthContextBound()) {
7
+ return authContext().session;
8
+ }
7
9
  const g = globalThis;
8
10
  if (g.__VEAP_BOOTSTRAPPING_PROMISE__) {
9
11
  try {
10
12
  await g.__VEAP_BOOTSTRAPPING_PROMISE__;
11
13
  }
12
14
  catch { }
13
- }
14
- if (isAuthContextBound()) {
15
- return authContext().session;
15
+ if (isAuthContextBound()) {
16
+ return authContext().session;
17
+ }
16
18
  }
17
19
  return await app(SessionService);
18
20
  }
@@ -17,7 +17,7 @@ export declare class SessionService {
17
17
  */
18
18
  validateSessionToken(token: string): Promise<AuthSession>;
19
19
  /**
20
- * Returns the current user session from cookies.
20
+ * Returns the current user session from Bearer token or cookies.
21
21
  */
22
22
  getCurrentSession(): Promise<AuthSession>;
23
23
  /**
@@ -94,11 +94,22 @@ let SessionService = class SessionService {
94
94
  };
95
95
  }
96
96
  /**
97
- * Returns the current user session from cookies.
97
+ * Returns the current user session from Bearer token or cookies.
98
98
  */
99
99
  async getCurrentSession() {
100
- const token = await this.cookieStore.get("session");
101
- if (token === null) {
100
+ let token = null;
101
+ const authHeader = (await this.requestContext.getHeader("authorization")) ??
102
+ (await this.requestContext.getHeader("Authorization"));
103
+ if (authHeader) {
104
+ const match = authHeader.match(/^Bearer\s+(.+)$/i);
105
+ if (match?.[1]) {
106
+ token = match[1].trim();
107
+ }
108
+ }
109
+ if (!token) {
110
+ token = await this.cookieStore.get("session");
111
+ }
112
+ if (token === null || token === "") {
102
113
  return { session: null, user: null };
103
114
  }
104
115
  return await this.validateSessionToken(token);
@@ -1,17 +1,19 @@
1
- "use server";
2
1
  import { app } from "@veap/kernel";
3
2
  import { authContext, isAuthContextBound } from "../common/context.js";
4
3
  import { UserService } from "./user.service.js";
5
4
  async function resolveUserService() {
5
+ if (isAuthContextBound()) {
6
+ return authContext().user;
7
+ }
6
8
  const g = globalThis;
7
9
  if (g.__VEAP_BOOTSTRAPPING_PROMISE__) {
8
10
  try {
9
11
  await g.__VEAP_BOOTSTRAPPING_PROMISE__;
10
12
  }
11
13
  catch { }
12
- }
13
- if (isAuthContextBound()) {
14
- return authContext().user;
14
+ if (isAuthContextBound()) {
15
+ return authContext().user;
16
+ }
15
17
  }
16
18
  return await app(UserService);
17
19
  }
@@ -1,5 +1,6 @@
1
1
  import type { User } from "../common/index.js";
2
2
  import { type IPasswordHasher, type ISecretCipher, type ITokenGenerator } from "../crypto/contracts.js";
3
+ import { type IAuthNotificationService } from "../notifications/contracts.js";
3
4
  import { type IRoleRepository } from "../rbac/contracts.js";
4
5
  import { type IUserRepository } from "./contracts.js";
5
6
  export declare class UserService {
@@ -8,7 +9,8 @@ export declare class UserService {
8
9
  private readonly hasher;
9
10
  private readonly tokens;
10
11
  private readonly cipher;
11
- constructor(users: IUserRepository, roles: IRoleRepository, hasher: IPasswordHasher, tokens: ITokenGenerator, cipher: ISecretCipher);
12
+ private readonly notifier?;
13
+ constructor(users: IUserRepository, roles: IRoleRepository, hasher: IPasswordHasher, tokens: ITokenGenerator, cipher: ISecretCipher, notifier?: IAuthNotificationService | undefined);
12
14
  /**
13
15
  * Validates the username input.
14
16
  */
@@ -11,8 +11,8 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
13
  import { AppError, Inject, Injectable } from "@veap/kernel";
14
- import { sendRecoveryCode } from "@veap/mail";
15
14
  import { PASSWORD_HASHER, SECRET_CIPHER, TOKEN_GENERATOR, } from "../crypto/contracts.js";
15
+ import { AUTH_NOTIFICATION_SERVICE, } from "../notifications/contracts.js";
16
16
  import { ROLE_REPOSITORY } from "../rbac/contracts.js";
17
17
  import { USER_REPOSITORY } from "./contracts.js";
18
18
  const DEFAULT_ROLE = "user";
@@ -22,12 +22,14 @@ let UserService = class UserService {
22
22
  hasher;
23
23
  tokens;
24
24
  cipher;
25
- constructor(users, roles, hasher, tokens, cipher) {
25
+ notifier;
26
+ constructor(users, roles, hasher, tokens, cipher, notifier) {
26
27
  this.users = users;
27
28
  this.roles = roles;
28
29
  this.hasher = hasher;
29
30
  this.tokens = tokens;
30
31
  this.cipher = cipher;
32
+ this.notifier = notifier;
31
33
  }
32
34
  /**
33
35
  * Validates the username input.
@@ -57,7 +59,9 @@ let UserService = class UserService {
57
59
  });
58
60
  await this.assignDefaultRole(user.id);
59
61
  try {
60
- await sendRecoveryCode(user.email, recoveryCode);
62
+ if (this.notifier) {
63
+ await this.notifier.sendRecoveryCode(user.email, recoveryCode);
64
+ }
61
65
  }
62
66
  catch (error) {
63
67
  console.warn(`[veap:auth] Failed to send recovery code email to ${user.email}:`, error?.message || error);
@@ -112,7 +116,9 @@ let UserService = class UserService {
112
116
  const recoveryCode = this.tokens.generateRecoveryCode();
113
117
  await this.users.setRecoveryCode(userId, this.cipher.encrypt(recoveryCode));
114
118
  try {
115
- await sendRecoveryCode(user.email, recoveryCode);
119
+ if (this.notifier) {
120
+ await this.notifier.sendRecoveryCode(user.email, recoveryCode);
121
+ }
116
122
  }
117
123
  catch (error) {
118
124
  console.warn(`[veap:auth] Failed to send recovery code email to ${user.email}:`, error?.message || error);
@@ -196,6 +202,7 @@ UserService = __decorate([
196
202
  __param(2, Inject(PASSWORD_HASHER)),
197
203
  __param(3, Inject(TOKEN_GENERATOR)),
198
204
  __param(4, Inject(SECRET_CIPHER)),
199
- __metadata("design:paramtypes", [Object, Object, Object, Object, Object])
205
+ __param(5, Inject(AUTH_NOTIFICATION_SERVICE)),
206
+ __metadata("design:paramtypes", [Object, Object, Object, Object, Object, Object])
200
207
  ], UserService);
201
208
  export { UserService };
@@ -12,7 +12,7 @@ export const loginSchema = z.object({
12
12
  remember: z.boolean().optional(),
13
13
  });
14
14
  export const registerSchema = z.object({
15
- username: z.string().min(3, "Name must be at least 2 characters"),
15
+ username: z.string().min(3, "Name must be at least 3 characters"),
16
16
  email: z.string().email("Invalid email address"),
17
17
  password: z.string().min(8, "Password must be at least 8 characters"),
18
18
  terms: z
@@ -1,17 +1,19 @@
1
- "use server";
2
1
  import { app } from "@veap/kernel";
3
2
  import { authContext, isAuthContextBound } from "../common/context.js";
4
3
  import { EmailVerificationService, } from "./verification.service.js";
5
4
  async function resolveVerificationService() {
5
+ if (isAuthContextBound()) {
6
+ return authContext().emailVerification;
7
+ }
6
8
  const g = globalThis;
7
9
  if (g.__VEAP_BOOTSTRAPPING_PROMISE__) {
8
10
  try {
9
11
  await g.__VEAP_BOOTSTRAPPING_PROMISE__;
10
12
  }
11
13
  catch { }
12
- }
13
- if (isAuthContextBound()) {
14
- return authContext().emailVerification;
14
+ if (isAuthContextBound()) {
15
+ return authContext().emailVerification;
16
+ }
15
17
  }
16
18
  return await app(EmailVerificationService);
17
19
  }
@@ -1,5 +1,6 @@
1
1
  import { type ICookieStore } from "@veap/kernel";
2
2
  import { type ITokenGenerator } from "../crypto/contracts.js";
3
+ import { type IAuthNotificationService } from "../notifications/contracts.js";
3
4
  import { SessionService } from "../session/session.service.js";
4
5
  import { type EmailVerificationRecord, type IEmailVerificationRepository } from "./contracts.js";
5
6
  export type EmailVerificationRequestType = EmailVerificationRecord;
@@ -8,7 +9,8 @@ export declare class EmailVerificationService {
8
9
  private readonly tokens;
9
10
  private readonly cookieStore;
10
11
  private readonly sessions;
11
- constructor(verifications: IEmailVerificationRepository, tokens: ITokenGenerator, cookieStore: ICookieStore, sessions: SessionService);
12
+ private readonly notifier?;
13
+ constructor(verifications: IEmailVerificationRepository, tokens: ITokenGenerator, cookieStore: ICookieStore, sessions: SessionService, notifier?: IAuthNotificationService | undefined);
12
14
  /**
13
15
  * Register Email Verification as a Core Security Requirement.
14
16
  */
@@ -11,11 +11,11 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
11
11
  return function (target, key) { decorator(target, key, paramIndex); }
12
12
  };
13
13
  import { COOKIE_STORE, Inject, Injectable, } from "@veap/kernel";
14
- import { sendVerifyEmail } from "@veap/mail";
15
14
  import { addMinutes } from "date-fns";
16
15
  import { getAuthRoutes } from "../common/context.js";
17
16
  import { registerSecurityRequirement } from "../common/logic.js";
18
17
  import { TOKEN_GENERATOR } from "../crypto/contracts.js";
18
+ import { AUTH_NOTIFICATION_SERVICE, } from "../notifications/contracts.js";
19
19
  import { SessionService } from "../session/session.service.js";
20
20
  import { EMAIL_VERIFICATION_REPOSITORY, } from "./contracts.js";
21
21
  let EmailVerificationService = class EmailVerificationService {
@@ -23,11 +23,13 @@ let EmailVerificationService = class EmailVerificationService {
23
23
  tokens;
24
24
  cookieStore;
25
25
  sessions;
26
- constructor(verifications, tokens, cookieStore, sessions) {
26
+ notifier;
27
+ constructor(verifications, tokens, cookieStore, sessions, notifier) {
27
28
  this.verifications = verifications;
28
29
  this.tokens = tokens;
29
30
  this.cookieStore = cookieStore;
30
31
  this.sessions = sessions;
32
+ this.notifier = notifier;
31
33
  }
32
34
  /**
33
35
  * Register Email Verification as a Core Security Requirement.
@@ -72,7 +74,9 @@ let EmailVerificationService = class EmailVerificationService {
72
74
  * Sends a verification email with the OTP code.
73
75
  */
74
76
  async sendVerificationEmail(email, code) {
75
- await sendVerifyEmail(email, code);
77
+ if (this.notifier) {
78
+ await this.notifier.sendVerificationEmail(email, code);
79
+ }
76
80
  }
77
81
  /**
78
82
  * Sets the email verification request ID in a cookie.
@@ -117,6 +121,7 @@ EmailVerificationService = __decorate([
117
121
  __param(1, Inject(TOKEN_GENERATOR)),
118
122
  __param(2, Inject(COOKIE_STORE)),
119
123
  __param(3, Inject(SessionService)),
120
- __metadata("design:paramtypes", [Object, Object, Object, SessionService])
124
+ __param(4, Inject(AUTH_NOTIFICATION_SERVICE)),
125
+ __metadata("design:paramtypes", [Object, Object, Object, SessionService, Object])
121
126
  ], EmailVerificationService);
122
127
  export { EmailVerificationService };
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "@veap/auth",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "description": "Authentication, session management, RBAC, and crypto adapters for Veap",
5
5
  "bugs": "https://github.com/veapjs/veap-auth/issues",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/veapjs/veap-auth.git"
8
+ "url": "https://github.com/veapjs/veap.git",
9
+ "directory": "packages/veap-auth"
9
10
  },
10
11
  "type": "module",
11
12
  "license": "MIT",
@@ -55,9 +56,8 @@
55
56
  "@oslojs/binary": "^1.0.0",
56
57
  "@oslojs/crypto": "^1.0.1",
57
58
  "@oslojs/encoding": "^1.1.0",
58
- "@veap/database": "0.1.7",
59
- "@veap/kernel": "0.2.0",
60
- "@veap/mail": "0.1.7",
59
+ "@veap/database": "0.1.9",
60
+ "@veap/kernel": "0.2.2",
61
61
  "bcryptjs": "^3.0.3",
62
62
  "date-fns": "^4.4.0",
63
63
  "zod": "^3.24.2"