@cauth/core 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -281,48 +281,36 @@ declare class _CAuth<T extends string[], TContractor extends RoutesContract<any>
281
281
  });
282
282
  get RoleType(): T[number];
283
283
  /**
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
284
+ * @description Auth guard middleware roles optional.
285
+ * Automatically typed as the handler type from the contractor (e.g. Express.RequestHandler).
289
286
  */
290
287
  Guard: (roles?: Array<T[number]>) => (...args: any[]) => any;
288
+ /**
289
+ * Route Handlers — typed from the contractor automatically.
290
+ */
291
291
  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;
292
+ Register: () => ReturnType<TContractor["Register"]>;
293
+ Login: () => ReturnType<TContractor["Login"]>;
294
+ Logout: () => ReturnType<TContractor["Logout"]>;
295
+ Refresh: () => ReturnType<TContractor["Refresh"]>;
296
+ ChangePassword: (userId: string) => ReturnType<TContractor["ChangePassword"]>;
297
297
  };
298
298
  FN: {
299
- Login: ({
300
- ...args
301
- }: LoginSchemaType) => Promise<Result$1<{
299
+ Login: (args: LoginSchemaType) => Promise<Result$1<{
302
300
  account: Account;
303
301
  tokens: Tokens;
304
302
  }>>;
305
- Register: ({
306
- ...args
307
- }: RegisterSchemaType) => Promise<Result<{
303
+ Register: (args: RegisterSchemaType) => Promise<Result<{
308
304
  account: Account;
309
305
  tokens: Tokens;
310
306
  }>>;
311
- Logout: ({
312
- ...args
313
- }: LogoutSchemaType) => Promise<Result<any>>;
314
- Refresh: ({
315
- ...args
316
- }: RefreshTokenSchemaType) => Promise<Result$1<{
307
+ Logout: (args: LogoutSchemaType) => Promise<Result<any>>;
308
+ Refresh: (args: RefreshTokenSchemaType) => Promise<Result$1<{
317
309
  account: Account;
318
310
  tokens: Tokens;
319
311
  }>>;
320
- ChangePassword: ({
321
- ...args
322
- }: ChangePasswordSchemaType) => Promise<Result<unknown>>;
323
- RequestOTPCode: ({
324
- ...args
325
- }: Omit<LoginSchemaType, "password"> & {
312
+ ChangePassword: (args: ChangePasswordSchemaType) => Promise<Result<unknown>>;
313
+ RequestOTPCode: (args: Omit<LoginSchemaType, "password"> & {
326
314
  password?: string;
327
315
  usePassword?: boolean;
328
316
  otpPurpose: OtpPurpose;
@@ -330,17 +318,13 @@ declare class _CAuth<T extends string[], TContractor extends RoutesContract<any>
330
318
  id: string;
331
319
  code: string;
332
320
  }>>;
333
- LoginWithOTP: ({
334
- ...args
335
- }: Omit<LoginSchemaType, "password"> & {
321
+ LoginWithOTP: (args: Omit<LoginSchemaType, "password"> & {
336
322
  code: string;
337
323
  }) => Promise<Result<{
338
324
  account: Account;
339
325
  tokens: Tokens;
340
326
  }>>;
341
- VerifyOTP: ({
342
- ...args
343
- }: {
327
+ VerifyOTP: (args: {
344
328
  id: string;
345
329
  code: string;
346
330
  otpPurpose: OtpPurpose;
@@ -355,13 +339,16 @@ declare class _CAuth<T extends string[], TContractor extends RoutesContract<any>
355
339
  accessToken: string;
356
340
  refreshToken: string;
357
341
  }>;
358
- VerifyRefreshToken: <T_1>(token: any) => Promise<T_1 | null>;
359
- VerifyAccessToken: <T_1>(token: any) => Promise<T_1 | null>;
342
+ VerifyRefreshToken: <R>(token: any) => Promise<R | null>;
343
+ VerifyAccessToken: <R>(token: any) => Promise<R | null>;
360
344
  };
361
345
  }
346
+ /**
347
+ * return typed instance of `_CAuth` while preserving contractor type.
348
+ */
362
349
  declare function CAuth<const T extends string[], const TContractor extends RoutesContract<any>>(options: Omit<CAuthOptions, 'roles'> & {
363
350
  roles: T;
364
351
  routeContractor: TContractor;
365
- }): _CAuth<T, RoutesContract<(...args: any[]) => any> & TContractor>;
352
+ }): _CAuth<T, TContractor>;
366
353
  //#endregion
367
354
  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 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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cauth/core",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",