@cauth/core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,141 @@
1
+ # @cauth/core
2
+
3
+ Core authentication library for Node.js applications with TypeScript support.
4
+
5
+ ## Features
6
+
7
+ - **Type-Safe Authentication**: Built with TypeScript and Zod validation
8
+ - **JWT-Based Authentication**: Access and refresh token management
9
+ - **Role-Based Access Control**: Flexible role management system
10
+ - **Multi-Factor Authentication**: OTP-based two-factor authentication
11
+ - **Phone Number Support**: E.164 format validation using libphonenumber-js
12
+ - **Error Handling**: Comprehensive error types and handling
13
+ - **Modular Design**: Pluggable database and route contractors
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ npm install @cauth/core
19
+ # or
20
+ yarn add @cauth/core
21
+ # or
22
+ pnpm add @cauth/core
23
+ ```
24
+
25
+ ## Quick Start
26
+
27
+ ```typescript
28
+ import { CAuth } from '@cauth/core';
29
+ import { PrismaProvider } from '@cauth/prisma';
30
+ import { ExpressContractor } from '@cauth/express';
31
+
32
+ // Initialize authentication system
33
+ const auth = CAuth({
34
+ roles: ['USER', 'ADMIN'],
35
+ dbContractor: new PrismaProvider(prismaClient),
36
+ routeContractor: new ExpressContractor(),
37
+ jwtConfig: {
38
+ accessTokenSecret: process.env.ACCESS_TOKEN_SECRET!,
39
+ refreshTokenSecret: process.env.REFRESH_TOKEN_SECRET!,
40
+ accessTokenLifeSpan: '15m',
41
+ refreshTokenLifeSpan: '7d',
42
+ },
43
+ otpConfig: {
44
+ expiresIn: 300000, // 5 minutes
45
+ length: 6, // 6-digit OTP codes
46
+ },
47
+ });
48
+
49
+ // Use authentication functions
50
+ const result = await auth.FN.Login({
51
+ email: 'user@example.com',
52
+ //or phoneNumber: '+2659900000'
53
+ password: 'securepassword123',
54
+ });
55
+
56
+ if (result.success) {
57
+ console.log('Login successful:', result.value);
58
+ } else {
59
+ console.log('Login failed:', result.errors); // FNErrors[]
60
+ }
61
+ ```
62
+
63
+ ## Core Components
64
+
65
+ ### Authentication Functions
66
+
67
+ The `FN` namespace provides these authentication functions:
68
+
69
+ ```typescript
70
+ auth.FN.Login({ email?: string, phoneNumber?: string, password: string })
71
+ auth.FN.Register({ email?: string, phoneNumber?: string, password: string, role: string })
72
+ auth.FN.Logout({ refreshToken: string })
73
+ auth.FN.Refresh({ refreshToken: string })
74
+ auth.FN.ChangePassword({ oldPassword: string, newPassword: string })
75
+ auth.FN.RequestOTPCode({ email?: string, phoneNumber?: string, otpPurpose: OtpPurpose })
76
+ auth.FN.LoginWithOTP({ email?: string, phoneNumber?: string, code: string })
77
+ auth.FN.VerifyOTP({ id: string, code: string, otpPurpose: OtpPurpose })
78
+ ```
79
+
80
+ ### Token Management
81
+
82
+ The `Tokens` namespace provides these utilities:
83
+
84
+ ```typescript
85
+ auth.Tokens.GenerateAccessToken(payload: any): Promise<string>
86
+ auth.Tokens.GenerateRefreshToken(payload: any): Promise<string>
87
+ auth.Tokens.GenerateTokenPairs(payload: any): Promise<{ accessToken: string, refreshToken: string }>
88
+ auth.Tokens.VerifyAccessToken<T>(token: string): Promise<T | null>
89
+ auth.Tokens.VerifyRefreshToken<T>(token: string): Promise<T | null>
90
+ ```
91
+
92
+ ## Configuration
93
+
94
+ The `CAuthOptions` interface defines the configuration:
95
+
96
+ ```typescript
97
+ interface CAuthOptions {
98
+ dbContractor: DatabaseContract;
99
+ routeContractor: RoutesContract;
100
+ roles: string[];
101
+ jwtConfig: {
102
+ refreshTokenSecret: string;
103
+ accessTokenSecret: string;
104
+ accessTokenLifeSpan?: string | number; // ms string or number
105
+ refreshTokenLifeSpan?: string | number; // ms string or number
106
+ };
107
+ otpConfig?: {
108
+ expiresIn?: number; // milliseconds, default: 300000 (5 minutes)
109
+ length?: number; // 4-8 digits, default: 6
110
+ };
111
+ }
112
+ ```
113
+
114
+ ## Error Types
115
+
116
+ The library provides these error types:
117
+
118
+ - `CredentialMismatchError`: Invalid login credentials
119
+ - `InvalidDataError`: Validation failures
120
+ - `AccountNotFoundError`: Account not found
121
+ - `InvalidRoleError`: Invalid role assignment
122
+ - `InvalidRefreshTokenError`: Invalid/expired refresh token
123
+ - `DuplicateAccountError`: Account already exists
124
+ - `InvalidOTPCode`: Invalid/expired OTP code
125
+
126
+ ## Development
127
+
128
+ ### Prerequisites
129
+
130
+ - Node.js >= 18
131
+ - TypeScript >= 5.9
132
+
133
+
134
+
135
+ ## License
136
+
137
+ MIT License - see LICENSE file for details.
138
+
139
+ ## Support
140
+
141
+ For issues and feature requests, please visit the [GitHub repository](https://github.com/jonace-mpelule/cauth).
package/dist/index.cjs ADDED
@@ -0,0 +1 @@
1
+ var e=Object.create,t=Object.defineProperty,n=Object.getOwnPropertyDescriptor,r=Object.getOwnPropertyNames,i=Object.getPrototypeOf,a=Object.prototype.hasOwnProperty,o=(e,i,o,s)=>{if(i&&typeof i==`object`||typeof i==`function`)for(var c=r(i),l=0,u=c.length,d;l<u;l++)d=c[l],!a.call(e,d)&&d!==o&&t(e,d,{get:(e=>i[e]).bind(null,d),enumerable:!(s=n(i,d))||s.enumerable});return e},s=(n,r,a)=>(a=n==null?{}:e(i(n)),o(r||!n||!n.__esModule?t(a,`default`,{value:n,enumerable:!0}):a,n));let c=require(`zod`);c=s(c);let l=require(`libphonenumber-js`);l=s(l);let u=require(`bcrypt`);u=s(u);let d=require(`jsonwebtoken`);d=s(d);var f=class{static ValidationError=`validation-error`;static CredentialError=`credential-error`;static UnKnownError=`unknown-error`;static InvalidDataError=`invalid-data-error`},p=class{static ServerError=`internal-server-error`;static ServerErrorMessage=`Internal server error. We are working to fix this, please try again later`;static InvalidToken=`invalid-token`;static InvalidTokenMessage=`Invalid Token`;static ForbiddenResource=`forbidden-resource`;static ForbiddenResourceMessage=`You don't have sufficient permission for this action`;static InvalidOtp=`invalid-otp`;static InvalidOtpMessage=`Invalid Otp. Please check and try again`;static CredentialMismatch=`credential-mismatch`;static CredentialMismatchMessage=`Credential mismatch. Please check your credentials and try again.`;static InvalidData=`invalid-data`;static InvalidDataMessage=e=>`Invalid Body: ${e}`;static AccountNotFound=`account-not-found`;static AccountNotFoundMessage=`Account not found`;static InvalidRole=`invalid-role`;static InvalidRoleMessage=e=>`Role is invalid, please use one of the following roles: ${e.join(`, `)}`;static InvalidRefreshToken=`invalid-refresh-token`;static InvalidRefreshTokenMessage=`Invalid refresh token`;static DuplicateAccount=`account-already-exists`;static DuplicateAccountMessage=`Account with this credentials already exists`},m=class extends Error{code;static type=f.CredentialError;constructor(){super(p.CredentialMismatchMessage),this.code=p.CredentialMismatch,this.name=`CredentialMismatch`}},h=class extends Error{code;static type=f.ValidationError;constructor(e){super(p.InvalidDataMessage(e)),this.code=p.InvalidData,this.name=`InvalidDataError`}},g=class extends Error{code;static type=f.InvalidDataError;constructor(){super(p.AccountNotFoundMessage),this.code=p.AccountNotFound,this.name=`AccountNotFoundError`}},_=class extends Error{code;static type=f.ValidationError;constructor(e){super(p.InvalidRoleMessage(e)),this.code=p.InvalidRole,this.name=`InvalidRoleError`}},v=class extends Error{code;static type=f.ValidationError;constructor(){super(p.InvalidRefreshTokenMessage),this.code=p.InvalidRefreshToken,this.name=`InvalidRefreshTokenError`}},y=class extends Error{code;static type=f.ValidationError;constructor(){super(p.DuplicateAccountMessage),this.code=p.DuplicateAccount,this.name=`DuplicateAccountError`}},b=class extends Error{code;static type=f.ValidationError;constructor(){super(p.InvalidOtpMessage),this.code=p.InvalidOtp,this.name=`InvalidOTPCode`}},x=class{static LoginPurpose=`LOGIN`;static ResetPasswordPurpose=`RESET_PASSWORD`;static ActionPurpose=`ACTION`};const S=c.z.string().trim().refine(e=>{let t=(0,l.parsePhoneNumberFromString)(e);return!!t&&t.isValid()},{message:`Invalid phone number`}).transform(e=>(0,l.parsePhoneNumberFromString)(e)?.format(`E.164`)??e),C=c.z.object({email:c.z.email(),phoneNumber:c.z.never().optional(),password:c.z.string().min(6)}),w=c.z.object({phoneNumber:S,email:c.z.never().optional(),password:c.z.string().min(6)}),T=c.z.union([C,w]).superRefine((e,t)=>{e.email&&e.phoneNumber&&t.addIssue({code:c.z.ZodIssueCode.custom,message:`Provide either email or phoneNumber`,path:[`email`,`phoneNumber`]})}),E=c.z.object({phoneNumber:S.optional(),email:c.z.email().optional(),role:c.z.string(),password:c.z.string()}),D=E.superRefine((e,t)=>{!e.email&&!e.phoneNumber&&t.addIssue({code:c.z.ZodIssueCode.custom,message:`Provide either email or phoneNumber`,path:[`email`,`phoneNumber`]})}),O=c.z.object({refreshToken:c.z.string()}),k=c.z.object({refreshToken:c.z.string()}),A=c.z.object({accountId:c.z.string(),oldPassword:c.z.string(),newPassword:c.z.string()});function j(e){return`${e?.error?.issues[0].path}: ${e?.error?.issues[0].message}`}function M(e){return{success:!0,value:e}}function N(...e){return{success:!1,errors:e}}async function P({config:e},{...t}){let n=T.safeParse({email:t.email,phoneNumber:t.phoneNumber,password:``});if(!n.success)return N({type:h.type,error:new h(j(n))});let r=await e.dbContractor.findAccountWithCredential({phoneNumber:t.phoneNumber,email:t.email});if(!r||t.usePassword&&!await u.default.compare(String(t.password),String(r?.passwordHash)))return N({type:m.type,error:new m});let i=await e.dbContractor.createOTP({config:e},{id:r.id,purpose:t.otpPurpose});return M({id:r.id,code:i.code})}async function F({config:e,tokens:t},{...n}){let r=T.safeParse({email:n.email,phoneNumber:n.phoneNumber,password:``});if(!r.success)return N({type:h.type,error:new h(j(r))});let i=await e.dbContractor.findAccountWithCredential({email:n.email,phoneNumber:n.phoneNumber});if(!i)return N({type:m.type,error:new m});if(!(await e.dbContractor.verifyOTP({id:i.id,code:n.code,purpose:x.LoginPurpose})).isValid)return N({type:b.type,error:new b});let a=await t.GenerateTokenPairs({id:i.id,role:i.role});return await e.dbContractor.updateAccountLogin({id:i.id,refreshToken:a.refreshToken}),delete i.passwordHash,delete i.refreshTokens,M({account:i,tokens:a})}async function I({config:e},{...t}){return await e.dbContractor.verifyOTP({id:t.id,code:t.code,purpose:t.otpPurpose})}async function L({config:e},{...t}){let n=A.safeParse(t);if(!n.success)return N({type:h.type,error:new h(j(n))});let r=await e.dbContractor.findAccountById({id:t.accountId});if(!r)return N({type:g.type,error:new g});if(!u.default.compare(t.oldPassword,String(r.passwordHash)))return N({type:m.type,error:new m});let i=await u.default.hash(t.newPassword,10);return await e.dbContractor.updateAccount({id:r.id,data:{passwordHash:i}}),M({})}async function R({config:e,tokens:t},{...n}){let r=T.safeParse(n);if(!r.success)return N({type:h.type,error:new h(j(r))});let i=await e.dbContractor.findAccountWithCredential({email:n.email,phoneNumber:n.phoneNumber});if(!i||!await u.default.compare(String(n.password),String(i?.passwordHash)))return N({type:m.type,error:new m});let a=await t.GenerateTokenPairs({id:i.id,role:i.role});return await e.dbContractor.updateAccountLogin({id:i.id,refreshToken:a.refreshToken}),delete i.passwordHash,delete i.refreshTokens,M({account:i,tokens:a})}async function z(e){try{return{data:await e,error:null}}catch(e){return{data:null,error:e}}}async function B({config:e,tokens:t},{...n}){let r=k.safeParse(n);if(!r.success)return N({type:h.type,error:new h(j(r))});let i=await z(t.VerifyRefreshToken(n.refreshToken));return i.error||!i?N({type:v.type,error:new v}):(await e.dbContractor.removeAndAddRefreshToken({id:String(i.data?.id),refreshToken:n.refreshToken}),M({}))}async function V({config:e,tokens:t},{...n}){let r=O.safeParse(n);if(!r.success)return N({type:h.type,error:new h(j(r))});let i=await z(t.VerifyRefreshToken(n.refreshToken));if(i.error)return N({type:v.type,error:new v});let a=await e.dbContractor.findAccountById({id:String(i.data?.id)});if(!a)return N({type:g.type,error:new g});if(!a?.refreshTokens?.includes(n.refreshToken))return N({type:v.type,error:new v});let o=await t.GenerateTokenPairs({id:a.id,role:a.role});return await e.dbContractor.removeAndAddRefreshToken({id:a.id,refreshToken:n.refreshToken,newRefreshToken:o.refreshToken}),delete a.refreshTokens,delete a.passwordHash,M({account:a,tokens:o})}async function H({config:e,tokens:t},{...n}){let r=D.safeParse(n);if(!r.success)return N({type:h.type,error:new h(j(r))});if(!e.roles?.includes(n.role))return N({type:_.type,error:new _(e.roles)});if(await e.dbContractor.findAccountWithCredential({email:n.email,phoneNumber:n.phoneNumber}))return N({type:y.type,error:new y});let i=await u.default.hash(n.password,10),a=await e.dbContractor.createAccount({data:{email:n.email,phoneNumber:n.phoneNumber,passwordHash:i,role:n.role,lastLogin:new Date}}),o=await t.GenerateTokenPairs({id:a.id,role:a.role});return await e.dbContractor.updateAccountLogin({id:a.id,refreshToken:o.refreshToken}),M({account:a,tokens:o})}async function U({...e}){return d.default.sign(e.payload,e.config.jwtConfig.accessTokenSecret,{expiresIn:e.config.jwtConfig?.accessTokenLifeSpan??`15m`})}async function W({...e}){return d.default.sign(e.payload,e.config.jwtConfig.refreshTokenSecret,{expiresIn:e.config.jwtConfig?.refreshTokenLifeSpan??`30d`})}async function G({...e}){return{accessToken:d.default.sign(e.payload,e.config.jwtConfig.accessTokenSecret,{expiresIn:e.config.jwtConfig?.accessTokenLifeSpan??`15m`}),refreshToken:d.default.sign(e.payload,e.config.jwtConfig.refreshTokenSecret,{expiresIn:e.config.jwtConfig?.refreshTokenLifeSpan??`30d`})}}async function K({...e}){let t=d.default.verify(e.token,e.config.jwtConfig.refreshTokenSecret);return t instanceof String?null:t}async function q({...e}){let t=d.default.verify(e.token,e.config.jwtConfig.accessTokenSecret);return t instanceof String?null:t}const J=c.default.custom(()=>!0,{message:`Invalid dbContractor: must implement Database Contract interface`}),Y=c.default.custom(()=>!0,{message:`Invalid routeContractor: must implement RoutesContract interface`}),X=c.default.custom(),Z=c.default.object({dbContractor:J,routeContractor:Y,roles:c.default.array(c.default.string()).min(1),jwtConfig:c.default.object({refreshTokenSecret:c.default.string(),accessTokenSecret:c.default.string(),accessTokenLifeSpan:X.optional(),refreshTokenLifeSpan:X.optional()}),otpConfig:c.default.object({expiresIn:c.default.number().optional(),length:c.default.number().min(4).max(8).optional()})});var Q=class{#config;constructor(e){if(!Z.safeParse(e).success)throw Error(`❌ Failed to initiate CAuth. You provided an invalid config!`);this.#config=e}get RoleType(){return null}Guard=e=>this.#config.routeContractor.Guard({config:this.#config,tokens:this.Tokens,roles:e});Routes={Register:()=>this.#config.routeContractor.Register({config:this.#config,tokens:this.Tokens}),Login:()=>this.#config.routeContractor.Login({config:this.#config,tokens:this.Tokens}),Logout:()=>this.#config.routeContractor.Logout({config:this.#config,tokens:this.Tokens}),Refresh:()=>this.#config.routeContractor.Refresh({config:this.#config,tokens:this.Tokens}),ChangePassword:e=>this.#config.routeContractor.ChangePassword({config:this.#config,tokens:this.Tokens,userId:e})};FN={Login:({...e})=>R({config:this.#config,tokens:this.Tokens},e),Register:({...e})=>H({config:this.#config,tokens:this.Tokens},e),Logout:({...e})=>B({config:this.#config,tokens:this.Tokens},e),Refresh:({...e})=>V({config:this.#config,tokens:this.Tokens},e),ChangePassword:({...e})=>L({config:this.#config,tokens:this.Tokens},e),RequestOTPCode:({...e})=>P({config:this.#config,tokens:this.Tokens},e),LoginWithOTP:({...e})=>F({config:this.#config,tokens:this.Tokens},{...e}),VerifyOTP:({...e})=>I({config:this.#config,tokens:this.Tokens},e)};Tokens={GenerateRefreshToken:e=>W({payload:e,config:this.#config}),GenerateAccessToken:e=>U({payload:e,config:this.#config}),GenerateTokenPairs:e=>G({payload:e,config:this.#config}),VerifyRefreshToken:e=>K({token:e,config:this.#config}),VerifyAccessToken:e=>q({token:e,config:this.#config})}};function $(e){return new Q(e)}exports.AccountNotFoundError=g,exports.CAuth=$,exports.CredentialMismatchError=m,exports.DuplicateAccountError=y,exports.InvalidDataError=h,exports.InvalidOTPCode=b,exports.InvalidRefreshTokenError=v,exports.InvalidRoleError=_;
@@ -0,0 +1,361 @@
1
+ import z$1, { z } from "zod";
2
+ import ms from "ms";
3
+
4
+ //#region src/errors/errors.d.ts
5
+ declare class CError {
6
+ static type: string;
7
+ code: string;
8
+ }
9
+ /**
10
+ * @description Error thrown when the credentials provided do not match.
11
+ */
12
+ declare class CredentialMismatchError extends Error implements CError {
13
+ code: string;
14
+ static type: string;
15
+ constructor();
16
+ }
17
+ /**
18
+ * @description Error thrown when the data provided is invalid.
19
+ */
20
+ declare class InvalidDataError extends Error implements CError {
21
+ code: string;
22
+ static type: string;
23
+ constructor(reason: string);
24
+ }
25
+ /**
26
+ * @description Error thrown when the account is not found.
27
+ */
28
+ declare class AccountNotFoundError extends Error implements CError {
29
+ code: string;
30
+ static type: string;
31
+ constructor();
32
+ }
33
+ /**
34
+ * @description Error thrown when the role provided is invalid.
35
+ */
36
+ declare class InvalidRoleError extends Error implements CError {
37
+ code: string;
38
+ static type: string;
39
+ constructor(roles: string[]);
40
+ }
41
+ /**
42
+ * @description Error thrown when an invalid or expired refresh token is provided
43
+ */
44
+ declare class InvalidRefreshTokenError extends Error implements CError {
45
+ code: string;
46
+ static type: string;
47
+ constructor();
48
+ }
49
+ /**
50
+ * @description Error thrown when trying to create an account that already exists
51
+ */
52
+ declare class DuplicateAccountError extends Error implements CError {
53
+ code: string;
54
+ static type: string;
55
+ constructor();
56
+ }
57
+ /**
58
+ * @description Error thrown when an invalid or expired OTP is provided
59
+ */
60
+ declare class InvalidOTPCode extends Error implements CError {
61
+ code: string;
62
+ static type: string;
63
+ constructor();
64
+ }
65
+ //#endregion
66
+ //#region src/types/auth.t.d.ts
67
+ type Account = {
68
+ id: string;
69
+ phoneNumber: string;
70
+ email: string;
71
+ role: string;
72
+ lastLogin: Date;
73
+ createdAt: Date;
74
+ updatedAt: Date;
75
+ };
76
+ type Tokens = {
77
+ accessToken: string;
78
+ refreshToken: string;
79
+ };
80
+ declare const AuthModelSchema: z$1.ZodObject<{
81
+ id: z$1.ZodString;
82
+ phoneNumber: z$1.ZodString;
83
+ email: z$1.ZodString;
84
+ passwordHash: z$1.ZodOptional<z$1.ZodString>;
85
+ role: z$1.ZodString;
86
+ lastLogin: z$1.ZodDate;
87
+ refreshTokens: z$1.ZodOptional<z$1.ZodArray<z$1.ZodString>>;
88
+ createdAt: z$1.ZodDate;
89
+ updatedAt: z$1.ZodDate;
90
+ }, z$1.z.core.$strip>;
91
+ type AuthModel = z$1.infer<typeof AuthModelSchema>;
92
+ //#endregion
93
+ //#region src/types/result.t.d.ts
94
+ type FNError = {
95
+ type: string;
96
+ error: Error;
97
+ };
98
+ /**
99
+ * @description Core Result type.
100
+ * @template T - The type of the value.
101
+ * @template E - The type of the errors, which must extend { type: string; error: Error }.
102
+ */
103
+ type Result$1<T, E extends FNError = FNError> = {
104
+ success: true;
105
+ value: T;
106
+ } | {
107
+ success: false;
108
+ errors: E[];
109
+ };
110
+ //#endregion
111
+ //#region src/types/otp-purpose.t.d.ts
112
+ type OtpPurpose = 'LOGIN' | 'RESET_PASSWORD' | 'ACTION';
113
+ //#endregion
114
+ //#region src/types/database.contract.d.ts
115
+ interface DatabaseContract {
116
+ findAccountById<T = AuthModel>({
117
+ ...args
118
+ }: {
119
+ id: string;
120
+ select?: any;
121
+ }): Promise<T | undefined>;
122
+ findAccountWithCredential<T = AuthModel>({
123
+ ...args
124
+ }: {
125
+ email?: string | undefined;
126
+ phoneNumber?: string | undefined;
127
+ select?: any;
128
+ }): Promise<T | undefined>;
129
+ createAccount<T = AuthModel>({
130
+ ...args
131
+ }: {
132
+ data: any;
133
+ select?: any;
134
+ }): Promise<T>;
135
+ updateAccount<T = AuthModel>({
136
+ ...args
137
+ }: {
138
+ id: string;
139
+ data: any;
140
+ select?: any;
141
+ }): Promise<T>;
142
+ updateAccountLogin<T = AuthModel>({
143
+ ...args
144
+ }: {
145
+ id: string;
146
+ refreshToken: string;
147
+ select?: any;
148
+ }): Promise<T>;
149
+ removeAndAddRefreshToken({
150
+ ...args
151
+ }: {
152
+ id: string;
153
+ refreshToken: string;
154
+ newRefreshToken?: string;
155
+ select?: any;
156
+ }): Promise<any>;
157
+ deleteAccount({
158
+ ...args
159
+ }: {
160
+ id: string;
161
+ }): Promise<void>;
162
+ createOTP<T = {
163
+ code: string;
164
+ purpose: string;
165
+ expiresAt: Date;
166
+ }>({
167
+ config
168
+ }: {
169
+ config: CAuthOptions;
170
+ }, {
171
+ ...args
172
+ }: {
173
+ id: string;
174
+ purpose: OtpPurpose;
175
+ }): Promise<T>;
176
+ verifyOTP<T = {
177
+ isValid: boolean;
178
+ }>({
179
+ ...args
180
+ }: {
181
+ id: string;
182
+ code: string;
183
+ purpose: OtpPurpose;
184
+ }): Promise<T>;
185
+ }
186
+ //#endregion
187
+ //#region src/types/routes.contract.t.d.ts
188
+ type RouteDeps = {
189
+ config: CAuthOptions;
190
+ tokens: _CAuth<any>['Tokens'];
191
+ };
192
+ type AuthGuardDeps = {
193
+ config: CAuthOptions;
194
+ tokens: _CAuth<any>['Tokens'];
195
+ roles?: Array<string>;
196
+ };
197
+ interface RoutesContract {
198
+ Login({
199
+ ...config
200
+ }: RouteDeps): any;
201
+ Register({
202
+ ...config
203
+ }: RouteDeps): any;
204
+ Logout({
205
+ ...config
206
+ }: RouteDeps): any;
207
+ Guard({
208
+ ...config
209
+ }: AuthGuardDeps): any;
210
+ Refresh({
211
+ ...config
212
+ }: AuthGuardDeps): any;
213
+ ChangePassword({
214
+ ...config
215
+ }: RouteDeps & {
216
+ userId: string;
217
+ }): any;
218
+ }
219
+ //#endregion
220
+ //#region src/types/config.t.d.ts
221
+ declare const CAuthOptionsSchema: z$1.ZodObject<{
222
+ dbContractor: z$1.ZodCustom<DatabaseContract, DatabaseContract>;
223
+ routeContractor: z$1.ZodCustom<RoutesContract, RoutesContract>;
224
+ roles: z$1.ZodArray<z$1.ZodString>;
225
+ jwtConfig: z$1.ZodObject<{
226
+ refreshTokenSecret: z$1.ZodString;
227
+ accessTokenSecret: z$1.ZodString;
228
+ accessTokenLifeSpan: z$1.ZodOptional<z$1.ZodCustom<ms.StringValue, ms.StringValue>>;
229
+ refreshTokenLifeSpan: z$1.ZodOptional<z$1.ZodCustom<ms.StringValue, ms.StringValue>>;
230
+ }, z$1.z.core.$strip>;
231
+ otpConfig: z$1.ZodObject<{
232
+ expiresIn: z$1.ZodOptional<z$1.ZodNumber>;
233
+ length: z$1.ZodOptional<z$1.ZodNumber>;
234
+ }, z$1.z.core.$strip>;
235
+ }, z$1.z.core.$strip>;
236
+ type CAuthOptions = z$1.infer<typeof CAuthOptionsSchema>;
237
+ //#endregion
238
+ //#region src/types/dto-schemas.t.d.ts
239
+ declare const LoginSchema: z.ZodUnion<readonly [z.ZodObject<{
240
+ email: z.ZodEmail;
241
+ phoneNumber: z.ZodOptional<z.ZodNever>;
242
+ password: z.ZodString;
243
+ }, z.core.$strip>, z.ZodObject<{
244
+ phoneNumber: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
245
+ email: z.ZodOptional<z.ZodNever>;
246
+ password: z.ZodString;
247
+ }, z.core.$strip>]>;
248
+ type LoginSchemaType = z.infer<typeof LoginSchema>;
249
+ declare const RegisterSchema: z.ZodObject<{
250
+ phoneNumber: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
251
+ email: z.ZodOptional<z.ZodEmail>;
252
+ role: z.ZodString;
253
+ password: z.ZodString;
254
+ }, z.core.$strip>;
255
+ type RegisterSchemaType = z.infer<typeof RegisterSchema>;
256
+ declare const RefreshTokenSchema: z.ZodObject<{
257
+ refreshToken: z.ZodString;
258
+ }, z.core.$strip>;
259
+ type RefreshTokenSchemaType = z.infer<typeof RefreshTokenSchema>;
260
+ declare const LogoutSchema: z.ZodObject<{
261
+ refreshToken: z.ZodString;
262
+ }, z.core.$strip>;
263
+ type LogoutSchemaType = z.infer<typeof LogoutSchema>;
264
+ declare const ChangePasswordSchema: z.ZodObject<{
265
+ accountId: z.ZodString;
266
+ oldPassword: z.ZodString;
267
+ newPassword: z.ZodString;
268
+ }, z.core.$strip>;
269
+ type ChangePasswordSchemaType = z.infer<typeof ChangePasswordSchema>;
270
+ //#endregion
271
+ //#region src/cauth.d.ts
272
+ declare class _CAuth<T extends string[]> {
273
+ #private;
274
+ constructor(config: Omit<CAuthOptions, 'roles'> & {
275
+ roles: T;
276
+ });
277
+ get RoleType(): T[number];
278
+ /**
279
+ * @description Authentication Guard Middleware. Include 'roles' for a custom auth guard.
280
+ *
281
+ * If 'roles' is empty it allows all authenticated users, without respecting specific role
282
+ *
283
+ * @default undefined
284
+ */
285
+ Guard: (roles?: Array<T[number]>) => any;
286
+ Routes: {
287
+ Register: () => any;
288
+ Login: () => any;
289
+ Logout: () => any;
290
+ Refresh: () => any;
291
+ ChangePassword: (userId: string) => any;
292
+ };
293
+ FN: {
294
+ Login: ({
295
+ ...args
296
+ }: LoginSchemaType) => Promise<Result$1<{
297
+ account: Account;
298
+ tokens: Tokens;
299
+ }>>;
300
+ Register: ({
301
+ ...args
302
+ }: RegisterSchemaType) => Promise<Result<{
303
+ account: Account;
304
+ tokens: Tokens;
305
+ }>>;
306
+ Logout: ({
307
+ ...args
308
+ }: LogoutSchemaType) => Promise<Result<any>>;
309
+ Refresh: ({
310
+ ...args
311
+ }: RefreshTokenSchemaType) => Promise<Result$1<{
312
+ account: Account;
313
+ tokens: Tokens;
314
+ }>>;
315
+ ChangePassword: ({
316
+ ...args
317
+ }: ChangePasswordSchemaType) => Promise<Result<unknown>>;
318
+ RequestOTPCode: ({
319
+ ...args
320
+ }: Omit<LoginSchemaType, "password"> & {
321
+ password?: string;
322
+ usePassword?: boolean;
323
+ otpPurpose: OtpPurpose;
324
+ }) => Promise<Result<{
325
+ id: string;
326
+ code: string;
327
+ }>>;
328
+ LoginWithOTP: ({
329
+ ...args
330
+ }: Omit<LoginSchemaType, "password"> & {
331
+ code: string;
332
+ }) => Promise<Result<{
333
+ account: Account;
334
+ tokens: Tokens;
335
+ }>>;
336
+ VerifyOTP: ({
337
+ ...args
338
+ }: {
339
+ id: string;
340
+ code: string;
341
+ otpPurpose: OtpPurpose;
342
+ }) => Promise<{
343
+ isValid: boolean;
344
+ }>;
345
+ };
346
+ Tokens: {
347
+ GenerateRefreshToken: (payload: any) => Promise<string>;
348
+ GenerateAccessToken: (payload: any) => Promise<string>;
349
+ GenerateTokenPairs: (payload: any) => Promise<{
350
+ accessToken: string;
351
+ refreshToken: string;
352
+ }>;
353
+ VerifyRefreshToken: <T_1>(token: any) => Promise<T_1 | null>;
354
+ VerifyAccessToken: <T_1>(token: any) => Promise<T_1 | null>;
355
+ };
356
+ }
357
+ declare function CAuth<const T extends string[]>(options: Omit<CAuthOptions, 'roles'> & {
358
+ roles: T;
359
+ }): _CAuth<T>;
360
+ //#endregion
361
+ export { AccountNotFoundError, CAuth, type CAuthOptions, CredentialMismatchError, type DatabaseContract, DuplicateAccountError, InvalidDataError, InvalidOTPCode, InvalidRefreshTokenError, InvalidRoleError, type RoutesContract };
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "@cauth/core",
3
+ "version": "0.0.1",
4
+ "description": "",
5
+ "main": "./dist/index.cjs",
6
+ "types": "./dist/index.d.cts",
7
+ "type": "module",
8
+ "scripts": {
9
+ "build": "tsdown",
10
+ "patch": "npm version patch",
11
+ "minor": "npm version minor",
12
+ "major": "npm version major",
13
+ "publish": "npm publish"
14
+ },
15
+ "files": [
16
+ "dist/",
17
+ "README.md",
18
+ "package.json"
19
+ ],
20
+ "keywords": [
21
+ "authentication",
22
+ "node-auth",
23
+ "express auth",
24
+ "easy-auth"
25
+ ],
26
+ "author": "Jonace Mpelule <jonacempelule123@gmail.com> (https://github.com/jonace-mpelule)",
27
+ "license": "MIT",
28
+ "packageManager": "pnpm@10.13.1",
29
+ "devDependencies": {
30
+ "@types/bcrypt": "^6.0.0",
31
+ "@types/jsonwebtoken": "^9.0.10",
32
+ "@types/ms": "^2.1.0",
33
+ "tsdown": "^0.15.6",
34
+ "typescript": "^5.9.3"
35
+ },
36
+ "dependencies": {
37
+ "bcrypt": "^6.0.0",
38
+ "jsonwebtoken": "^9.0.2",
39
+ "libphonenumber-js": "^1.12.23",
40
+ "ms": "^2.1.3",
41
+ "zod": "^4.1.12"
42
+ },
43
+ "engines": {
44
+ "node": ">=18"
45
+ }
46
+ }