@cauth/core 0.0.4 → 0.0.6

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/dist/index.d.ts CHANGED
@@ -272,6 +272,19 @@ declare const ChangePasswordSchema: z.ZodObject<{
272
272
  }, z.core.$strip>;
273
273
  type ChangePasswordSchemaType = z.infer<typeof ChangePasswordSchema>;
274
274
  //#endregion
275
+ //#region src/fn/authenticate.fn.d.ts
276
+ type AuthCodeResult = {
277
+ id: string;
278
+ code: string;
279
+ };
280
+ type LoginWithCodeResult = {
281
+ account: Account;
282
+ tokens: Tokens;
283
+ };
284
+ type VerifyAuthCodeResult = {
285
+ isValid: boolean;
286
+ };
287
+ //#endregion
275
288
  //#region src/cauth.d.ts
276
289
  declare class _CAuth<T extends string[], TContractor extends RoutesContract<any> = RoutesContract<any>> {
277
290
  #private;
@@ -281,19 +294,19 @@ declare class _CAuth<T extends string[], TContractor extends RoutesContract<any>
281
294
  });
282
295
  get RoleType(): T[number];
283
296
  /**
284
- * @description Authentication Guard Middleware. Include 'roles' for a custom auth guard.
285
- *
286
- * If 'roles' is empty it allows all authenticated users, without respecting specific role
287
- *
288
- * @default undefined
297
+ * @description Auth guard middleware roles optional.
298
+ * Automatically typed as the handler type from the contractor (e.g. Express.RequestHandler).
289
299
  */
290
300
  Guard: (roles?: Array<T[number]>) => (...args: any[]) => any;
301
+ /**
302
+ * Route Handlers — typed from the contractor automatically.
303
+ */
291
304
  Routes: {
292
- Register: () => (...args: any[]) => any;
293
- Login: () => (...args: any[]) => any;
294
- Logout: () => (...args: any[]) => any;
295
- Refresh: () => (...args: any[]) => any;
296
- ChangePassword: (userId: string) => (...args: any[]) => any;
305
+ Register: () => ReturnType<TContractor["Register"]>;
306
+ Login: () => ReturnType<TContractor["Login"]>;
307
+ Logout: () => ReturnType<TContractor["Logout"]>;
308
+ Refresh: () => ReturnType<TContractor["Refresh"]>;
309
+ ChangePassword: (userId: string) => ReturnType<TContractor["ChangePassword"]>;
297
310
  };
298
311
  FN: {
299
312
  Login: ({
@@ -326,27 +339,15 @@ declare class _CAuth<T extends string[], TContractor extends RoutesContract<any>
326
339
  password?: string;
327
340
  usePassword?: boolean;
328
341
  otpPurpose: OtpPurpose;
329
- }) => Promise<Result<{
330
- id: string;
331
- code: string;
332
- }>>;
333
- LoginWithOTP: ({
334
- ...args
335
- }: Omit<LoginSchemaType, "password"> & {
342
+ }) => Promise<Result<AuthCodeResult>>;
343
+ LoginWithOTP: (args: Omit<LoginSchemaType, "password"> & {
336
344
  code: string;
337
- }) => Promise<Result<{
338
- account: Account;
339
- tokens: Tokens;
340
- }>>;
341
- VerifyOTP: ({
342
- ...args
343
- }: {
345
+ }) => Promise<Result<LoginWithCodeResult>>;
346
+ VerifyOTP: (args: {
344
347
  id: string;
345
348
  code: string;
346
349
  otpPurpose: OtpPurpose;
347
- }) => Promise<{
348
- isValid: boolean;
349
- }>;
350
+ }) => Promise<Result<VerifyAuthCodeResult>>;
350
351
  };
351
352
  Tokens: {
352
353
  GenerateRefreshToken: (payload: any) => Promise<string>;
@@ -355,13 +356,16 @@ declare class _CAuth<T extends string[], TContractor extends RoutesContract<any>
355
356
  accessToken: string;
356
357
  refreshToken: string;
357
358
  }>;
358
- VerifyRefreshToken: <T_1>(token: any) => Promise<T_1 | null>;
359
- VerifyAccessToken: <T_1>(token: any) => Promise<T_1 | null>;
359
+ VerifyRefreshToken: <R>(token: any) => Promise<R | null>;
360
+ VerifyAccessToken: <R>(token: any) => Promise<R | null>;
360
361
  };
361
362
  }
363
+ /**
364
+ * return typed instance of `_CAuth` while preserving contractor type.
365
+ */
362
366
  declare function CAuth<const T extends string[], const TContractor extends RoutesContract<any>>(options: Omit<CAuthOptions, 'roles'> & {
363
367
  roles: T;
364
368
  routeContractor: TContractor;
365
- }): _CAuth<T, RoutesContract<(...args: any[]) => any> & TContractor>;
369
+ }): _CAuth<T, TContractor>;
366
370
  //#endregion
367
371
  export { AccountNotFoundError, CAuth, type CAuthOptions, CredentialMismatchError, type DatabaseContract, DuplicateAccountError, InvalidDataError, InvalidOTPCode, InvalidRefreshTokenError, InvalidRoleError, type RoutesContract };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- import e,{z as t}from"zod";import{parsePhoneNumberFromString as n}from"libphonenumber-js";import r from"bcrypt";import i from"jsonwebtoken";var a=class{static ValidationError=`validation-error`;static CredentialError=`credential-error`;static UnKnownError=`unknown-error`;static InvalidDataError=`invalid-data-error`},o=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`},s=class extends Error{code;static type=a.CredentialError;constructor(){super(o.CredentialMismatchMessage),this.code=o.CredentialMismatch,this.name=`CredentialMismatch`}},c=class extends Error{code;static type=a.ValidationError;constructor(e){super(o.InvalidDataMessage(e)),this.code=o.InvalidData,this.name=`InvalidDataError`}},l=class extends Error{code;static type=a.InvalidDataError;constructor(){super(o.AccountNotFoundMessage),this.code=o.AccountNotFound,this.name=`AccountNotFoundError`}},u=class extends Error{code;static type=a.ValidationError;constructor(e){super(o.InvalidRoleMessage(e)),this.code=o.InvalidRole,this.name=`InvalidRoleError`}},d=class extends Error{code;static type=a.ValidationError;constructor(){super(o.InvalidRefreshTokenMessage),this.code=o.InvalidRefreshToken,this.name=`InvalidRefreshTokenError`}},f=class extends Error{code;static type=a.ValidationError;constructor(){super(o.DuplicateAccountMessage),this.code=o.DuplicateAccount,this.name=`DuplicateAccountError`}},p=class extends Error{code;static type=a.ValidationError;constructor(){super(o.InvalidOtpMessage),this.code=o.InvalidOtp,this.name=`InvalidOTPCode`}},m=class{static LoginPurpose=`LOGIN`;static ResetPasswordPurpose=`RESET_PASSWORD`;static ActionPurpose=`ACTION`};const h=t.string().trim().refine(e=>{let t=n(e);return!!t&&t.isValid()},{message:`Invalid phone number`}).transform(e=>n(e)?.format(`E.164`)??e),g=t.object({email:t.email(),phoneNumber:t.never().optional(),password:t.string().min(6)}),_=t.object({phoneNumber:h,email:t.never().optional(),password:t.string().min(6)}),v=t.union([g,_]).superRefine((e,n)=>{e.email&&e.phoneNumber&&n.addIssue({code:t.ZodIssueCode.custom,message:`Provide either email or phoneNumber`,path:[`email`,`phoneNumber`]})}),y=t.object({phoneNumber:h.optional(),email:t.email().optional(),role:t.string(),password:t.string()}).superRefine((e,n)=>{!e.email&&!e.phoneNumber&&n.addIssue({code:t.ZodIssueCode.custom,message:`Provide either email or phoneNumber`,path:[`email`,`phoneNumber`]})}),b=t.object({refreshToken:t.string()}),x=t.object({refreshToken:t.string()}),S=t.object({accountId:t.string(),oldPassword:t.string(),newPassword:t.string()});function C(e){return`${e?.error?.issues[0].path}: ${e?.error?.issues[0].message}`}function w(e){return{success:!0,value:e}}function T(...e){return{success:!1,errors:e}}async function E({config:e},{...t}){let n=v.safeParse({email:t.email,phoneNumber:t.phoneNumber,password:``});if(!n.success)return T({type:c.type,error:new c(C(n))});let i=await e.dbContractor.findAccountWithCredential({phoneNumber:t.phoneNumber,email:t.email});if(!i||t.usePassword&&!await r.compare(String(t.password),String(i?.passwordHash)))return T({type:s.type,error:new s});let a=await e.dbContractor.createOTP({config:e},{id:i.id,purpose:t.otpPurpose});return w({id:i.id,code:a.code})}async function D({config:e,tokens:t},{...n}){let r=v.safeParse({email:n.email,phoneNumber:n.phoneNumber,password:``});if(!r.success)return T({type:c.type,error:new c(C(r))});let i=await e.dbContractor.findAccountWithCredential({email:n.email,phoneNumber:n.phoneNumber});if(!i)return T({type:s.type,error:new s});if(!(await e.dbContractor.verifyOTP({id:i.id,code:n.code,purpose:m.LoginPurpose})).isValid)return T({type:p.type,error:new p});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,w({account:i,tokens:a})}async function O({config:e},{...t}){return await e.dbContractor.verifyOTP({id:t.id,code:t.code,purpose:t.otpPurpose})}async function k({config:e},{...t}){let n=S.safeParse(t);if(!n.success)return T({type:c.type,error:new c(C(n))});let i=await e.dbContractor.findAccountById({id:t.accountId});if(!i)return T({type:l.type,error:new l});if(!r.compare(t.oldPassword,String(i.passwordHash)))return T({type:s.type,error:new s});let a=await r.hash(t.newPassword,10);return await e.dbContractor.updateAccount({id:i.id,data:{passwordHash:a}}),w({})}async function A({config:e,tokens:t},{...n}){let i=v.safeParse(n);if(!i.success)return T({type:c.type,error:new c(C(i))});let a=await e.dbContractor.findAccountWithCredential({email:n.email,phoneNumber:n.phoneNumber});if(!a||!await r.compare(String(n.password),String(a?.passwordHash)))return T({type:s.type,error:new s});let o=await t.GenerateTokenPairs({id:a.id,role:a.role});return await e.dbContractor.updateAccountLogin({id:a.id,refreshToken:o.refreshToken}),delete a.passwordHash,delete a.refreshTokens,w({account:a,tokens:o})}async function j(e){try{return{data:await e,error:null}}catch(e){return{data:null,error:e}}}async function M({config:e,tokens:t},{...n}){let r=x.safeParse(n);if(!r.success)return T({type:c.type,error:new c(C(r))});let i=await j(t.VerifyRefreshToken(n.refreshToken));return i.error||!i?T({type:d.type,error:new d}):(await e.dbContractor.removeAndAddRefreshToken({id:String(i.data?.id),refreshToken:n.refreshToken}),w({}))}async function N({config:e,tokens:t},{...n}){let r=b.safeParse(n);if(!r.success)return T({type:c.type,error:new c(C(r))});let i=await j(t.VerifyRefreshToken(n.refreshToken));if(i.error)return T({type:d.type,error:new d});let a=await e.dbContractor.findAccountById({id:String(i.data?.id)});if(!a)return T({type:l.type,error:new l});if(!a?.refreshTokens?.includes(n.refreshToken))return T({type:d.type,error:new d});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,w({account:a,tokens:o})}async function P({config:e,tokens:t},{...n}){let i=y.safeParse(n);if(!i.success)return T({type:c.type,error:new c(C(i))});if(!e.roles?.includes(n.role))return T({type:u.type,error:new u(e.roles)});if(await e.dbContractor.findAccountWithCredential({email:n.email,phoneNumber:n.phoneNumber}))return T({type:f.type,error:new f});let a=await r.hash(n.password,10),o=await e.dbContractor.createAccount({data:{email:n.email,phoneNumber:n.phoneNumber,passwordHash:a,role:n.role,lastLogin:new Date}}),s=await t.GenerateTokenPairs({id:o.id,role:o.role});return await e.dbContractor.updateAccountLogin({id:o.id,refreshToken:s.refreshToken}),w({account:o,tokens:s})}async function F({...e}){return i.sign(e.payload,e.config.jwtConfig.accessTokenSecret,{expiresIn:e.config.jwtConfig?.accessTokenLifeSpan??`15m`})}async function I({...e}){return i.sign(e.payload,e.config.jwtConfig.refreshTokenSecret,{expiresIn:e.config.jwtConfig?.refreshTokenLifeSpan??`30d`})}async function L({...e}){return{accessToken:i.sign(e.payload,e.config.jwtConfig.accessTokenSecret,{expiresIn:e.config.jwtConfig?.accessTokenLifeSpan??`15m`}),refreshToken:i.sign(e.payload,e.config.jwtConfig.refreshTokenSecret,{expiresIn:e.config.jwtConfig?.refreshTokenLifeSpan??`30d`})}}async function R({...e}){let t=i.verify(e.token,e.config.jwtConfig.refreshTokenSecret);return t instanceof String?null:t}async function z({...e}){let t=i.verify(e.token,e.config.jwtConfig.accessTokenSecret);return t instanceof String?null:t}const B=e.custom(()=>!0,{message:`Invalid dbContractor: must implement Database Contract interface`}),V=e.custom(()=>!0,{message:`Invalid routeContractor: must implement RoutesContract interface`}),H=e.custom(),U=e.object({dbContractor:B,routeContractor:V,roles:e.array(e.string()).min(1),jwtConfig:e.object({refreshTokenSecret:e.string(),accessTokenSecret:e.string(),accessTokenLifeSpan:H.optional(),refreshTokenLifeSpan:H.optional()}),otpConfig:e.object({expiresIn:e.number().optional(),length:e.number().min(4).max(8).optional()})});var W=class{#config;constructor(e){if(!U.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})=>A({config:this.#config,tokens:this.Tokens},e),Register:({...e})=>P({config:this.#config,tokens:this.Tokens},e),Logout:({...e})=>M({config:this.#config,tokens:this.Tokens},e),Refresh:({...e})=>N({config:this.#config,tokens:this.Tokens},e),ChangePassword:({...e})=>k({config:this.#config,tokens:this.Tokens},e),RequestOTPCode:({...e})=>E({config:this.#config,tokens:this.Tokens},e),LoginWithOTP:({...e})=>D({config:this.#config,tokens:this.Tokens},{...e}),VerifyOTP:({...e})=>O({config:this.#config,tokens:this.Tokens},e)};Tokens={GenerateRefreshToken:e=>I({payload:e,config:this.#config}),GenerateAccessToken:e=>F({payload:e,config:this.#config}),GenerateTokenPairs:e=>L({payload:e,config:this.#config}),VerifyRefreshToken:e=>R({token:e,config:this.#config}),VerifyAccessToken:e=>z({token:e,config:this.#config})}};function G(e){return new W(e)}export{l as AccountNotFoundError,G as CAuth,s as CredentialMismatchError,f as DuplicateAccountError,c as InvalidDataError,p as InvalidOTPCode,d as InvalidRefreshTokenError,u as InvalidRoleError};
1
+ import e,{z as t}from"zod";import{parsePhoneNumberFromString as n}from"libphonenumber-js";import r from"bcrypt";import i from"jsonwebtoken";var a=class{static ValidationError=`validation-error`;static CredentialError=`credential-error`;static UnKnownError=`unknown-error`;static InvalidDataError=`invalid-data-error`},o=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`},s=class extends Error{code;static type=a.CredentialError;constructor(){super(o.CredentialMismatchMessage),this.code=o.CredentialMismatch,this.name=`CredentialMismatch`}},c=class extends Error{code;static type=a.ValidationError;constructor(e){super(o.InvalidDataMessage(e)),this.code=o.InvalidData,this.name=`InvalidDataError`}},l=class extends Error{code;static type=a.InvalidDataError;constructor(){super(o.AccountNotFoundMessage),this.code=o.AccountNotFound,this.name=`AccountNotFoundError`}},u=class extends Error{code;static type=a.ValidationError;constructor(e){super(o.InvalidRoleMessage(e)),this.code=o.InvalidRole,this.name=`InvalidRoleError`}},d=class extends Error{code;static type=a.ValidationError;constructor(){super(o.InvalidRefreshTokenMessage),this.code=o.InvalidRefreshToken,this.name=`InvalidRefreshTokenError`}},f=class extends Error{code;static type=a.ValidationError;constructor(){super(o.DuplicateAccountMessage),this.code=o.DuplicateAccount,this.name=`DuplicateAccountError`}},p=class extends Error{code;static type=a.ValidationError;constructor(){super(o.InvalidOtpMessage),this.code=o.InvalidOtp,this.name=`InvalidOTPCode`}},m=class{static LoginPurpose=`LOGIN`;static ResetPasswordPurpose=`RESET_PASSWORD`;static ActionPurpose=`ACTION`};const h=t.string().trim().refine(e=>{let t=n(e);return!!t&&t.isValid()},{message:`Invalid phone number`}).transform(e=>n(e)?.format(`E.164`)??e),g=t.object({email:t.email(),phoneNumber:t.never().optional(),password:t.string().min(6)}),_=t.object({phoneNumber:h,email:t.never().optional(),password:t.string().min(6)}),v=t.union([g,_]).superRefine((e,n)=>{e.email&&e.phoneNumber&&n.addIssue({code:t.ZodIssueCode.custom,message:`Provide either email or phoneNumber`,path:[`email`,`phoneNumber`]})}),y=t.object({phoneNumber:h.optional(),email:t.email().optional(),role:t.string(),password:t.string()}).superRefine((e,n)=>{!e.email&&!e.phoneNumber&&n.addIssue({code:t.ZodIssueCode.custom,message:`Provide either email or phoneNumber`,path:[`email`,`phoneNumber`]})}),b=t.object({refreshToken:t.string()}),x=t.object({refreshToken:t.string()}),S=t.object({accountId:t.string(),oldPassword:t.string(),newPassword:t.string()});function C(e){return`${e?.error?.issues[0].path}: ${e?.error?.issues[0].message}`}function w(e){return{success:!0,value:e}}function T(...e){return{success:!1,errors:e}}async function E({config:e},t){let n=v.safeParse({email:t.email,phoneNumber:t.phoneNumber,password:``});if(!n.success)return T({type:c.type,error:new c(C(n))});let i=await e.dbContractor.findAccountWithCredential({phoneNumber:t.phoneNumber,email:t.email});if(!i||t.usePassword&&!await r.compare(String(t.password),String(i?.passwordHash)))return T({type:s.type,error:new s});let a=await e.dbContractor.createOTP({config:e},{id:i.id,purpose:t.otpPurpose});return w({id:i.id,code:a.code})}async function D({config:e,tokens:t},n){let r=v.safeParse({email:n.email,phoneNumber:n.phoneNumber,password:``});if(!r.success)return T({type:c.type,error:new c(C(r))});let i=await e.dbContractor.findAccountWithCredential({email:n.email,phoneNumber:n.phoneNumber});if(!i)return T({type:s.type,error:new s});if(!(await e.dbContractor.verifyOTP({id:i.id,code:n.code,purpose:m.LoginPurpose})).isValid)return T({type:p.type,error:new p});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,w({account:i,tokens:a})}async function O({config:e},t){return w({isValid:(await e.dbContractor.verifyOTP({id:t.id,code:t.code,purpose:t.otpPurpose})).isValid})}async function k({config:e},{...t}){let n=S.safeParse(t);if(!n.success)return T({type:c.type,error:new c(C(n))});let i=await e.dbContractor.findAccountById({id:t.accountId});if(!i)return T({type:l.type,error:new l});if(!r.compare(t.oldPassword,String(i.passwordHash)))return T({type:s.type,error:new s});let a=await r.hash(t.newPassword,10);return await e.dbContractor.updateAccount({id:i.id,data:{passwordHash:a}}),w({})}async function A({config:e,tokens:t},{...n}){let i=v.safeParse(n);if(!i.success)return T({type:c.type,error:new c(C(i))});let a=await e.dbContractor.findAccountWithCredential({email:n.email,phoneNumber:n.phoneNumber});if(!a||!await r.compare(String(n.password),String(a?.passwordHash)))return T({type:s.type,error:new s});let o=await t.GenerateTokenPairs({id:a.id,role:a.role});return await e.dbContractor.updateAccountLogin({id:a.id,refreshToken:o.refreshToken}),delete a.passwordHash,delete a.refreshTokens,w({account:a,tokens:o})}async function j(e){try{return{data:await e,error:null}}catch(e){return{data:null,error:e}}}async function M({config:e,tokens:t},{...n}){let r=x.safeParse(n);if(!r.success)return T({type:c.type,error:new c(C(r))});let i=await j(t.VerifyRefreshToken(n.refreshToken));return i.error||!i?T({type:d.type,error:new d}):(await e.dbContractor.removeAndAddRefreshToken({id:String(i.data?.id),refreshToken:n.refreshToken}),w({}))}async function N({config:e,tokens:t},{...n}){let r=b.safeParse(n);if(!r.success)return T({type:c.type,error:new c(C(r))});let i=await j(t.VerifyRefreshToken(n.refreshToken));if(i.error)return T({type:d.type,error:new d});let a=await e.dbContractor.findAccountById({id:String(i.data?.id)});if(!a)return T({type:l.type,error:new l});if(!a?.refreshTokens?.includes(n.refreshToken))return T({type:d.type,error:new d});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,w({account:a,tokens:o})}async function P({config:e,tokens:t},{...n}){let i=y.safeParse(n);if(!i.success)return T({type:c.type,error:new c(C(i))});if(!e.roles?.includes(n.role))return T({type:u.type,error:new u(e.roles)});if(await e.dbContractor.findAccountWithCredential({email:n.email,phoneNumber:n.phoneNumber}))return T({type:f.type,error:new f});let a=await r.hash(n.password,10),o=await e.dbContractor.createAccount({data:{email:n.email,phoneNumber:n.phoneNumber,passwordHash:a,role:n.role,lastLogin:new Date}}),s=await t.GenerateTokenPairs({id:o.id,role:o.role});return await e.dbContractor.updateAccountLogin({id:o.id,refreshToken:s.refreshToken}),w({account:o,tokens:s})}async function F({...e}){return i.sign(e.payload,e.config.jwtConfig.accessTokenSecret,{expiresIn:e.config.jwtConfig?.accessTokenLifeSpan??`15m`})}async function I({...e}){return i.sign(e.payload,e.config.jwtConfig.refreshTokenSecret,{expiresIn:e.config.jwtConfig?.refreshTokenLifeSpan??`30d`})}async function L({...e}){return{accessToken:i.sign(e.payload,e.config.jwtConfig.accessTokenSecret,{expiresIn:e.config.jwtConfig?.accessTokenLifeSpan??`15m`}),refreshToken:i.sign(e.payload,e.config.jwtConfig.refreshTokenSecret,{expiresIn:e.config.jwtConfig?.refreshTokenLifeSpan??`30d`})}}async function R({...e}){let t=i.verify(e.token,e.config.jwtConfig.refreshTokenSecret);return t instanceof String?null:t}async function z({...e}){let t=i.verify(e.token,e.config.jwtConfig.accessTokenSecret);return t instanceof String?null:t}const B=e.custom(()=>!0,{message:`Invalid dbContractor: must implement Database Contract interface`}),V=e.custom(()=>!0,{message:`Invalid routeContractor: must implement RoutesContract interface`}),H=e.custom(),U=e.object({dbContractor:B,routeContractor:V,roles:e.array(e.string()).min(1),jwtConfig:e.object({refreshTokenSecret:e.string(),accessTokenSecret:e.string(),accessTokenLifeSpan:H.optional(),refreshTokenLifeSpan:H.optional()}),otpConfig:e.object({expiresIn:e.number().optional(),length:e.number().min(4).max(8).optional()})});var W=class{#config;constructor(e){if(!U.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})=>A({config:this.#config,tokens:this.Tokens},e),Register:({...e})=>P({config:this.#config,tokens:this.Tokens},e),Logout:({...e})=>M({config:this.#config,tokens:this.Tokens},e),Refresh:({...e})=>N({config:this.#config,tokens:this.Tokens},e),ChangePassword:({...e})=>k({config:this.#config,tokens:this.Tokens},e),RequestOTPCode:({...e})=>E({config:this.#config,tokens:this.Tokens},e),LoginWithOTP:e=>D({config:this.#config,tokens:this.Tokens},e),VerifyOTP:e=>O({config:this.#config,tokens:this.Tokens},e)};Tokens={GenerateRefreshToken:e=>I({payload:e,config:this.#config}),GenerateAccessToken:e=>F({payload:e,config:this.#config}),GenerateTokenPairs:e=>L({payload:e,config:this.#config}),VerifyRefreshToken:e=>R({token:e,config:this.#config}),VerifyAccessToken:e=>z({token:e,config:this.#config})}};function G(e){return new W(e)}export{l as AccountNotFoundError,G as CAuth,s as CredentialMismatchError,f as DuplicateAccountError,c as InvalidDataError,p as InvalidOTPCode,d as InvalidRefreshTokenError,u as InvalidRoleError};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cauth/core",
3
- "version": "0.0.4",
3
+ "version": "0.0.6",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",