feat: implement account settings and API tokens management

- Added SettingsComponent for user profile management, including display name and password change functionality.
- Introduced TokensComponent for managing API tokens, including creation and revocation.
- Created LayoutComponent for consistent application layout with navigation and user information.
- Established main application structure in index.html and main.ts.
- Integrated Tailwind CSS for styling and responsive design.
- Configured TypeScript settings for strict type checking and module resolution.
This commit is contained in:
2025-11-27 22:15:38 +00:00
parent a6c6ea1393
commit ab88ac896f
71 changed files with 9446 additions and 0 deletions

View File

@@ -0,0 +1,152 @@
/**
* Audit logging interfaces
*/
// =============================================================================
// Audit Action Types
// =============================================================================
export type TAuditAction =
// Authentication
| 'AUTH_LOGIN'
| 'AUTH_LOGOUT'
| 'AUTH_FAILED'
| 'AUTH_MFA_ENABLED'
| 'AUTH_MFA_DISABLED'
| 'AUTH_PASSWORD_CHANGED'
| 'AUTH_PASSWORD_RESET'
// API Tokens
| 'TOKEN_CREATED'
| 'TOKEN_USED'
| 'TOKEN_REVOKED'
| 'TOKEN_EXPIRED'
// User Management
| 'USER_CREATED'
| 'USER_UPDATED'
| 'USER_DELETED'
| 'USER_SUSPENDED'
| 'USER_ACTIVATED'
// Organization Management
| 'ORG_CREATED'
| 'ORG_UPDATED'
| 'ORG_DELETED'
| 'ORG_MEMBER_ADDED'
| 'ORG_MEMBER_REMOVED'
| 'ORG_MEMBER_ROLE_CHANGED'
// Team Management
| 'TEAM_CREATED'
| 'TEAM_UPDATED'
| 'TEAM_DELETED'
| 'TEAM_MEMBER_ADDED'
| 'TEAM_MEMBER_REMOVED'
// Repository Management
| 'REPO_CREATED'
| 'REPO_UPDATED'
| 'REPO_DELETED'
| 'REPO_VISIBILITY_CHANGED'
| 'REPO_PERMISSION_GRANTED'
| 'REPO_PERMISSION_REVOKED'
// Package Operations
| 'PACKAGE_PUSHED'
| 'PACKAGE_PULLED'
| 'PACKAGE_DELETED'
| 'PACKAGE_DEPRECATED'
// Security Events
| 'SECURITY_SCAN_COMPLETED'
| 'SECURITY_VULNERABILITY_FOUND'
| 'SECURITY_IP_BLOCKED'
| 'SECURITY_RATE_LIMITED';
export type TAuditResourceType =
| 'user'
| 'organization'
| 'team'
| 'repository'
| 'package'
| 'api_token'
| 'session'
| 'system';
// =============================================================================
// Audit Log Entry
// =============================================================================
export interface IAuditLog {
id: string;
actorId?: string;
actorType: 'user' | 'api_token' | 'system' | 'anonymous';
actorTokenId?: string;
actorIp?: string;
actorUserAgent?: string;
action: TAuditAction;
resourceType: TAuditResourceType;
resourceId?: string;
resourceName?: string;
organizationId?: string;
repositoryId?: string;
metadata: Record<string, unknown>;
success: boolean;
errorCode?: string;
errorMessage?: string;
durationMs?: number;
timestamp: Date;
}
// =============================================================================
// Audit Query Types
// =============================================================================
export interface IAuditQuery {
actorId?: string;
organizationId?: string;
repositoryId?: string;
resourceType?: TAuditResourceType;
action?: TAuditAction[];
success?: boolean;
startDate?: Date;
endDate?: Date;
offset?: number;
limit?: number;
}
export interface IAuditQueryResult {
logs: IAuditLog[];
total: number;
offset: number;
limit: number;
}
// =============================================================================
// Audit Event (for logging)
// =============================================================================
export interface IAuditEvent {
actorId?: string;
actorType?: 'user' | 'api_token' | 'system' | 'anonymous';
actorTokenId?: string;
actorIp?: string;
actorUserAgent?: string;
action: TAuditAction;
resourceType: TAuditResourceType;
resourceId?: string;
resourceName?: string;
organizationId?: string;
repositoryId?: string;
metadata?: Record<string, unknown>;
success?: boolean;
errorCode?: string;
errorMessage?: string;
durationMs?: number;
}
// =============================================================================
// Token Activity
// =============================================================================
export interface ITokenActivitySummary {
tokenId: string;
totalActions: number;
lastUsed?: Date;
actionBreakdown: Record<string, number>;
ipAddresses: string[];
}

View File

@@ -0,0 +1,282 @@
/**
* Authentication and authorization interfaces
*/
// =============================================================================
// User Types
// =============================================================================
export type TUserStatus = 'active' | 'suspended' | 'pending_verification';
export interface IUser {
id: string;
email: string;
username: string;
passwordHash: string;
displayName: string;
avatarUrl?: string;
status: TUserStatus;
emailVerified: boolean;
mfaEnabled: boolean;
mfaSecret?: string;
lastLoginAt?: Date;
lastLoginIp?: string;
failedLoginAttempts: number;
lockedUntil?: Date;
isPlatformAdmin: boolean;
createdAt: Date;
updatedAt: Date;
}
// =============================================================================
// Organization Types
// =============================================================================
export type TOrganizationPlan = 'free' | 'team' | 'enterprise';
export type TOrganizationRole = 'owner' | 'admin' | 'member';
export interface IOrganizationSettings {
requireMfa: boolean;
allowPublicRepositories: boolean;
defaultRepositoryVisibility: TRepositoryVisibility;
allowedProtocols: TRegistryProtocol[];
}
export interface IOrganization {
id: string;
name: string; // URL-safe slug
displayName: string;
description?: string;
avatarUrl?: string;
plan: TOrganizationPlan;
settings: IOrganizationSettings;
billingEmail?: string;
isVerified: boolean;
verifiedDomains: string[];
storageQuotaBytes: number;
usedStorageBytes: number;
createdAt: Date;
updatedAt: Date;
createdById: string;
}
export interface IOrganizationMember {
id: string;
organizationId: string;
userId: string;
role: TOrganizationRole;
invitedBy?: string;
joinedAt: Date;
createdAt: Date;
}
// =============================================================================
// Team Types
// =============================================================================
export type TTeamRole = 'maintainer' | 'member';
export interface ITeam {
id: string;
organizationId: string;
name: string;
description?: string;
isDefaultTeam: boolean;
createdAt: Date;
updatedAt: Date;
}
export interface ITeamMember {
id: string;
teamId: string;
userId: string;
role: TTeamRole;
createdAt: Date;
}
// =============================================================================
// Repository Types
// =============================================================================
export type TRepositoryVisibility = 'public' | 'private' | 'internal';
export type TRepositoryRole = 'admin' | 'maintainer' | 'developer' | 'reader';
export type TRegistryProtocol = 'oci' | 'npm' | 'maven' | 'cargo' | 'composer' | 'pypi' | 'rubygems';
export interface IRepository {
id: string;
organizationId: string;
name: string;
description?: string;
protocol: TRegistryProtocol;
visibility: TRepositoryVisibility;
storageNamespace: string;
downloadCount: number;
starCount: number;
createdAt: Date;
updatedAt: Date;
createdById: string;
}
export interface IRepositoryPermission {
id: string;
repositoryId: string;
teamId?: string;
userId?: string;
role: TRepositoryRole;
createdAt: Date;
grantedById: string;
}
// =============================================================================
// Token Types
// =============================================================================
export interface ITokenScope {
protocol: TRegistryProtocol | '*';
organizationId?: string;
repositoryId?: string;
actions: TTokenAction[];
}
export type TTokenAction = 'read' | 'write' | 'delete' | '*';
export interface IApiToken {
id: string;
userId: string;
name: string;
tokenHash: string;
tokenPrefix: string;
protocols: TRegistryProtocol[];
scopes: ITokenScope[];
expiresAt?: Date;
lastUsedAt?: Date;
lastUsedIp?: string;
usageCount: number;
isRevoked: boolean;
revokedAt?: Date;
revokedReason?: string;
createdAt: Date;
createdIp?: string;
}
// =============================================================================
// Session Types
// =============================================================================
export interface ISession {
id: string;
userId: string;
userAgent: string;
ipAddress: string;
isValid: boolean;
invalidatedAt?: Date;
invalidatedReason?: string;
lastActivityAt: Date;
createdAt: Date;
}
// =============================================================================
// JWT Types
// =============================================================================
export interface IJwtPayload {
sub: string; // User ID
iss: string; // Issuer
aud: string; // Audience
exp: number; // Expiration
iat: number; // Issued at
nbf: number; // Not before
type: 'access' | 'refresh';
email: string;
username: string;
orgs: Array<{
id: string;
name: string;
role: TOrganizationRole;
}>;
sessionId: string;
}
// =============================================================================
// Auth Results
// =============================================================================
export interface IAuthResult {
accessToken: string;
refreshToken: string;
expiresIn: number;
user: IUser;
}
export interface IValidatedToken {
tokenId: string;
userId: string;
username: string;
protocols: TRegistryProtocol[];
scopes: ITokenScope[];
}
export interface IAuthorizationResult {
authorized: boolean;
reason?: string;
userId?: string;
}
// =============================================================================
// Permission Types
// =============================================================================
export type TPermissionAction =
| 'repo:read'
| 'repo:write'
| 'repo:delete'
| 'repo:admin'
| 'team:read'
| 'team:write'
| 'team:admin'
| 'org:read'
| 'org:write'
| 'org:admin'
| 'token:create'
| 'token:revoke';
export interface IResource {
type: 'repository' | 'organization' | 'team' | 'user';
id: string;
}
// =============================================================================
// Create/Update DTOs
// =============================================================================
export interface ICreateUserDto {
email: string;
username: string;
password: string;
displayName?: string;
}
export interface ICreateOrganizationDto {
name: string;
displayName: string;
description?: string;
}
export interface ICreateTeamDto {
name: string;
description?: string;
}
export interface ICreateRepositoryDto {
name: string;
description?: string;
protocol: TRegistryProtocol;
visibility?: TRepositoryVisibility;
}
export interface ICreateTokenDto {
name: string;
protocols: TRegistryProtocol[];
scopes: ITokenScope[];
expiresAt?: Date;
}

7
ts/interfaces/index.ts Normal file
View File

@@ -0,0 +1,7 @@
/**
* Type definitions for Stack.Gallery Registry
*/
export * from './auth.interfaces.ts';
export * from './package.interfaces.ts';
export * from './audit.interfaces.ts';

View File

@@ -0,0 +1,202 @@
/**
* Package and artifact interfaces
*/
import type { TRegistryProtocol } from './auth.interfaces.ts';
// =============================================================================
// Package Types
// =============================================================================
export interface IPackage {
id: string; // {protocol}:{org}:{name}
organizationId: string;
repositoryId: string;
protocol: TRegistryProtocol;
name: string;
description?: string;
versions: Record<string, IPackageVersion>;
distTags: Record<string, string>; // npm dist-tags, e.g., { latest: "1.0.0" }
metadata: IProtocolMetadata;
isPrivate: boolean;
storageBytes: number;
downloadCount: number;
starCount: number;
cacheExpiresAt?: Date;
createdAt: Date;
updatedAt: Date;
createdById: string;
}
export interface IPackageVersion {
version: string;
digest?: string; // Content-addressable digest (sha256:...)
size: number;
publishedAt: Date;
publishedById: string;
deprecated?: boolean;
deprecationMessage?: string;
downloads: number;
metadata: IVersionMetadata;
}
// =============================================================================
// Protocol-Specific Metadata
// =============================================================================
export type IProtocolMetadata =
| INpmMetadata
| IOciMetadata
| IMavenMetadata
| ICargoMetadata
| IComposerMetadata
| IPypiMetadata
| IRubygemsMetadata;
export interface INpmMetadata {
type: 'npm';
scope?: string;
keywords?: string[];
license?: string;
repository?: {
type: string;
url: string;
};
homepage?: string;
bugs?: string;
author?: string | { name: string; email?: string; url?: string };
maintainers?: Array<{ name: string; email?: string }>;
}
export interface IOciMetadata {
type: 'oci';
mediaType: string;
tags: string[];
architecture?: string;
os?: string;
annotations?: Record<string, string>;
}
export interface IMavenMetadata {
type: 'maven';
groupId: string;
artifactId: string;
packaging: string;
classifier?: string;
parent?: {
groupId: string;
artifactId: string;
version: string;
};
}
export interface ICargoMetadata {
type: 'cargo';
features: Record<string, string[]>;
dependencies: Array<{
name: string;
req: string;
features: string[];
optional: boolean;
defaultFeatures: boolean;
target?: string;
kind: 'normal' | 'dev' | 'build';
}>;
keywords?: string[];
categories?: string[];
license?: string;
links?: string;
}
export interface IComposerMetadata {
type: 'composer';
vendor: string;
packageType?: string;
license?: string | string[];
require?: Record<string, string>;
requireDev?: Record<string, string>;
autoload?: Record<string, unknown>;
}
export interface IPypiMetadata {
type: 'pypi';
classifiers?: string[];
requiresPython?: string;
requiresDist?: string[];
providesExtra?: string[];
projectUrls?: Record<string, string>;
}
export interface IRubygemsMetadata {
type: 'rubygems';
platform?: string;
requiredRubyVersion?: string;
requiredRubygemsVersion?: string;
dependencies?: Array<{
name: string;
requirements: string;
type: 'runtime' | 'development';
}>;
}
// =============================================================================
// Version Metadata
// =============================================================================
export interface IVersionMetadata {
readme?: string;
changelog?: string;
dependencies?: Record<string, string>;
devDependencies?: Record<string, string>;
peerDependencies?: Record<string, string>;
engines?: Record<string, string>;
files?: string[];
checksum?: {
sha256?: string;
sha512?: string;
md5?: string;
};
}
// =============================================================================
// Search Types
// =============================================================================
export interface IPackageSearchParams {
query?: string;
protocol?: TRegistryProtocol;
organizationId?: string;
visibility?: 'public' | 'private' | 'internal';
sort?: 'downloads' | 'stars' | 'updated' | 'name';
order?: 'asc' | 'desc';
offset?: number;
limit?: number;
}
export interface IPackageSearchResult {
packages: IPackage[];
total: number;
offset: number;
limit: number;
}
// =============================================================================
// Stats Types
// =============================================================================
export interface IPackageStats {
packageId: string;
totalDownloads: number;
downloadsByVersion: Record<string, number>;
downloadsByDay: Array<{ date: string; count: number }>;
downloadsByCountry?: Record<string, number>;
}
export interface IOrganizationStats {
organizationId: string;
totalPackages: number;
totalDownloads: number;
storageUsedBytes: number;
storageQuotaBytes: number;
packagesByProtocol: Record<TRegistryProtocol, number>;
}