Initial commit: add .gitignore and README

This commit is contained in:
defiQUG
2026-02-09 21:51:55 -08:00
commit d904c04c2d
52 changed files with 1613 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
{
"name": "@workspace/shared-auth",
"version": "1.0.0",
"description": "Shared authentication and authorization utilities",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"test": "vitest",
"lint": "eslint src",
"type-check": "tsc --noEmit",
"clean": "rm -rf dist"
},
"dependencies": {
"jsonwebtoken": "^9.0.2",
"bcryptjs": "^2.4.3"
},
"devDependencies": {
"typescript": "^5.5.4",
"@types/jsonwebtoken": "^9.0.4",
"@types/bcryptjs": "^2.4.6",
"vitest": "^1.2.0"
},
"files": [
"dist"
],
"publishConfig": {
"access": "restricted"
}
}

View File

@@ -0,0 +1,10 @@
/**
* @workspace/shared-auth
* Shared authentication and authorization utilities
*/
export * from './jwt';
export * from './password';
export * from './permissions';
export * from './types';

View File

@@ -0,0 +1,55 @@
/**
* JWT token utilities
*/
import jwt from 'jsonwebtoken';
export interface TokenPayload {
userId: string;
email: string;
roles?: string[];
[key: string]: unknown;
}
export interface TokenOptions {
expiresIn?: string | number;
issuer?: string;
audience?: string;
}
/**
* Generate JWT token
*/
export function generateToken(
payload: TokenPayload,
secret: string,
options?: TokenOptions
): string {
return jwt.sign(payload, secret, {
expiresIn: options?.expiresIn || '24h',
issuer: options?.issuer,
audience: options?.audience,
});
}
/**
* Verify JWT token
*/
export function verifyToken<T extends TokenPayload>(
token: string,
secret: string
): T {
return jwt.verify(token, secret) as T;
}
/**
* Decode JWT token (without verification)
*/
export function decodeToken<T extends TokenPayload>(token: string): T | null {
try {
return jwt.decode(token) as T;
} catch {
return null;
}
}

View File

@@ -0,0 +1,25 @@
/**
* Password hashing utilities
*/
import bcrypt from 'bcryptjs';
const SALT_ROUNDS = 10;
/**
* Hash password
*/
export async function hashPassword(password: string): Promise<string> {
return bcrypt.hash(password, SALT_ROUNDS);
}
/**
* Verify password
*/
export async function verifyPassword(
password: string,
hash: string
): Promise<boolean> {
return bcrypt.compare(password, hash);
}

View File

@@ -0,0 +1,63 @@
/**
* Permission checking utilities
*/
export type Permission = string;
export type Role = string;
export interface UserPermissions {
roles: Role[];
permissions: Permission[];
}
/**
* Check if user has role
*/
export function hasRole(user: UserPermissions, role: Role): boolean {
return user.roles.includes(role);
}
/**
* Check if user has permission
*/
export function hasPermission(
user: UserPermissions,
permission: Permission
): boolean {
return user.permissions.includes(permission);
}
/**
* Check if user has any of the required roles
*/
export function hasAnyRole(user: UserPermissions, roles: Role[]): boolean {
return roles.some((role) => hasRole(user, role));
}
/**
* Check if user has all required roles
*/
export function hasAllRoles(user: UserPermissions, roles: Role[]): boolean {
return roles.every((role) => hasRole(user, role));
}
/**
* Check if user has any of the required permissions
*/
export function hasAnyPermission(
user: UserPermissions,
permissions: Permission[]
): boolean {
return permissions.some((permission) => hasPermission(user, permission));
}
/**
* Check if user has all required permissions
*/
export function hasAllPermissions(
user: UserPermissions,
permissions: Permission[]
): boolean {
return permissions.every((permission) => hasPermission(user, permission));
}

View File

@@ -0,0 +1,23 @@
/**
* Authentication and authorization types
*/
export interface User {
id: string;
email: string;
roles: string[];
permissions: string[];
}
export interface AuthContext {
user: User | null;
isAuthenticated: boolean;
}
export interface Session {
userId: string;
token: string;
expiresAt: Date;
refreshToken?: string;
}

View File

@@ -0,0 +1,20 @@
{
"compilerOptions": {
"target": "ES2022",
"module": "ESNext",
"lib": ["ES2022"],
"declaration": true,
"declarationMap": true,
"outDir": "./dist",
"rootDir": "./src",
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"moduleResolution": "node",
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "**/*.test.ts"]
}