refactor: front end code to unified design

Signed-off-by: Sebastian Krupinski <krupinski01@gmail.com>
This commit is contained in:
2026-06-28 12:21:09 -04:00
parent 08c1de9723
commit 80a8dac2fd
21 changed files with 1087 additions and 1151 deletions
+103 -175
View File
@@ -1,196 +1,124 @@
/**
* Identity implementation classes for Mail Manager services
* Identity models for Chrono Manager services
*/
import type {
ServiceIdentity,
ServiceIdentityNone,
ServiceIdentityBasic,
ServiceIdentityToken,
ServiceIdentityOAuth,
ServiceIdentityCertificate
ServiceIdentity,
ServiceIdentityBasic,
ServiceIdentityCertificate,
ServiceIdentityNone,
ServiceIdentityOAuth,
ServiceIdentityToken
} from '@/types/service';
import { clonePlain } from './clone-plain';
import { MutationProxy } from './mutation-proxy';
/**
* Base Identity class
*/
export abstract class Identity {
abstract toJson(): ServiceIdentity;
static fromJson(data: ServiceIdentity): Identity {
switch (data.type) {
case 'NA':
return IdentityNone.fromJson(data);
case 'BA':
return IdentityBasic.fromJson(data);
case 'TA':
return IdentityToken.fromJson(data);
case 'OA':
return IdentityOAuth.fromJson(data);
case 'CC':
return IdentityCertificate.fromJson(data);
default:
throw new Error(`Unknown identity type: ${(data as any).type}`);
export abstract class Identity<T extends ServiceIdentity = ServiceIdentity> {
protected _original: T;
protected _mutated: Partial<T>;
protected _mutationProxy: MutationProxy<T>;
protected _data: T;
protected constructor(initial: T) {
this._original = clonePlain(initial);
this._mutated = {};
this._mutationProxy = new MutationProxy<T>(() => this._original, () => this._mutated);
this._data = this._mutationProxy.create();
}
protected load(data: T): this {
this._original = clonePlain(data);
this._mutated = {};
this._data = this._mutationProxy.create();
return this;
}
toJSON(): ServiceIdentity { return this.toJson(); }
toJson(): T;
toJson(delta: true): Partial<T>;
toJson(delta?: boolean): T | Partial<T> {
return delta
? clonePlain(this._mutated)
: { ...clonePlain(this._original), ...clonePlain(this._mutated) };
}
abstract clone(): Identity;
mutated(): boolean { return Reflect.ownKeys(this._mutated).length > 0; }
static fromJson(data: ServiceIdentity): Identity {
switch (data.type) {
case 'NA': return IdentityNone.fromJson(data);
case 'BA': return IdentityBasic.fromJson(data);
case 'TA': return IdentityToken.fromJson(data);
case 'OA': return IdentityOAuth.fromJson(data);
case 'CC': return IdentityCertificate.fromJson(data);
default: throw new Error(`Unknown identity type: ${(data as any).type}`);
}
}
}
}
/**
* No authentication
*/
export class IdentityNone extends Identity {
readonly type = 'NA' as const;
static fromJson(_data: ServiceIdentityNone): IdentityNone {
return new IdentityNone();
}
toJson(): ServiceIdentityNone {
return {
type: this.type
};
}
export class IdentityNone extends Identity<ServiceIdentityNone> {
constructor() { super({ type: 'NA' }); }
static fromJson(_data: ServiceIdentityNone): IdentityNone { return new IdentityNone(); }
clone(): IdentityNone { return IdentityNone.fromJson(this.toJson()); }
get type(): 'NA' { return this._data.type; }
}
/**
* Basic authentication (username/password)
*/
export class IdentityBasic extends Identity {
readonly type = 'BA' as const;
identity: string;
secret: string;
constructor(identity: string = '', secret: string = '') {
super();
this.identity = identity;
this.secret = secret;
}
static fromJson(data: ServiceIdentityBasic): IdentityBasic {
return new IdentityBasic(data.identity, data.secret);
}
toJson(): ServiceIdentityBasic {
return {
type: this.type,
identity: this.identity,
secret: this.secret
};
}
export class IdentityBasic extends Identity<ServiceIdentityBasic> {
constructor(identity: string = '', secret: string = '') { super({ type: 'BA', identity, secret }); }
static fromJson(data: ServiceIdentityBasic): IdentityBasic { return new IdentityBasic().load(data); }
clone(): IdentityBasic { return IdentityBasic.fromJson(this.toJson()); }
get type(): 'BA' { return this._data.type; }
get identity(): string { return this._data.identity; }
set identity(value: string) { this._data.identity = value; }
get secret(): string { return this._data.secret; }
set secret(value: string) { this._data.secret = value; }
}
/**
* Token authentication (API key, static token)
*/
export class IdentityToken extends Identity {
readonly type = 'TA' as const;
token: string;
constructor(token: string = '') {
super();
this.token = token;
}
static fromJson(data: ServiceIdentityToken): IdentityToken {
return new IdentityToken(data.token);
}
toJson(): ServiceIdentityToken {
return {
type: this.type,
token: this.token
};
}
export class IdentityToken extends Identity<ServiceIdentityToken> {
constructor(token: string = '') { super({ type: 'TA', token }); }
static fromJson(data: ServiceIdentityToken): IdentityToken { return new IdentityToken().load(data); }
clone(): IdentityToken { return IdentityToken.fromJson(this.toJson()); }
get type(): 'TA' { return this._data.type; }
get token(): string { return this._data.token; }
set token(value: string) { this._data.token = value; }
}
/**
* OAuth authentication
*/
export class IdentityOAuth extends Identity {
readonly type = 'OA' as const;
accessToken: string;
accessScope?: string[];
accessExpiry?: number;
refreshToken?: string;
refreshLocation?: string;
export class IdentityOAuth extends Identity<ServiceIdentityOAuth> {
constructor(accessToken: string = '', accessScope?: string[], accessExpiry?: number, refreshToken?: string, refreshLocation?: string) {
super({ type: 'OA', accessToken, accessScope, accessExpiry, refreshToken, refreshLocation });
}
constructor(
accessToken: string = '',
accessScope?: string[],
accessExpiry?: number,
refreshToken?: string,
refreshLocation?: string
) {
super();
this.accessToken = accessToken;
this.accessScope = accessScope;
this.accessExpiry = accessExpiry;
this.refreshToken = refreshToken;
this.refreshLocation = refreshLocation;
}
static fromJson(data: ServiceIdentityOAuth): IdentityOAuth { return new IdentityOAuth().load(data); }
clone(): IdentityOAuth { return IdentityOAuth.fromJson(this.toJson()); }
isExpired(): boolean { return this.accessExpiry ? Date.now() / 1000 >= this.accessExpiry : false; }
expiresIn(): number { return this.accessExpiry ? Math.max(0, this.accessExpiry - Date.now() / 1000) : Infinity; }
static fromJson(data: ServiceIdentityOAuth): IdentityOAuth {
return new IdentityOAuth(
data.accessToken,
data.accessScope,
data.accessExpiry,
data.refreshToken,
data.refreshLocation
);
}
toJson(): ServiceIdentityOAuth {
return {
type: this.type,
accessToken: this.accessToken,
...(this.accessScope && { accessScope: this.accessScope }),
...(this.accessExpiry && { accessExpiry: this.accessExpiry }),
...(this.refreshToken && { refreshToken: this.refreshToken }),
...(this.refreshLocation && { refreshLocation: this.refreshLocation })
};
}
isExpired(): boolean {
if (!this.accessExpiry) return false;
return Date.now() / 1000 >= this.accessExpiry;
}
expiresIn(): number {
if (!this.accessExpiry) return Infinity;
return Math.max(0, this.accessExpiry - Date.now() / 1000);
}
get type(): 'OA' { return this._data.type; }
get accessToken(): string { return this._data.accessToken; }
set accessToken(value: string) { this._data.accessToken = value; }
get accessScope(): string[] | undefined { return this._data.accessScope ? [...this._data.accessScope] : undefined; }
set accessScope(value: string[] | undefined) { this._data.accessScope = value ? [...value] : undefined; }
get accessExpiry(): number | undefined { return this._data.accessExpiry; }
set accessExpiry(value: number | undefined) { this._data.accessExpiry = value; }
get refreshToken(): string | undefined { return this._data.refreshToken; }
set refreshToken(value: string | undefined) { this._data.refreshToken = value; }
get refreshLocation(): string | undefined { return this._data.refreshLocation; }
set refreshLocation(value: string | undefined) { this._data.refreshLocation = value; }
}
/**
* Client certificate authentication (mTLS)
*/
export class IdentityCertificate extends Identity {
readonly type = 'CC' as const;
certificate: string;
privateKey: string;
passphrase?: string;
export class IdentityCertificate extends Identity<ServiceIdentityCertificate> {
constructor(certificate: string = '', privateKey: string = '', passphrase?: string) {
super({ type: 'CC', certificate, privateKey, passphrase });
}
constructor(certificate: string = '', privateKey: string = '', passphrase?: string) {
super();
this.certificate = certificate;
this.privateKey = privateKey;
this.passphrase = passphrase;
}
static fromJson(data: ServiceIdentityCertificate): IdentityCertificate {
return new IdentityCertificate(
data.certificate,
data.privateKey,
data.passphrase
);
}
toJson(): ServiceIdentityCertificate {
return {
type: this.type,
certificate: this.certificate,
privateKey: this.privateKey,
...(this.passphrase && { passphrase: this.passphrase })
};
}
static fromJson(data: ServiceIdentityCertificate): IdentityCertificate { return new IdentityCertificate().load(data); }
clone(): IdentityCertificate { return IdentityCertificate.fromJson(this.toJson()); }
get type(): 'CC' { return this._data.type; }
get certificate(): string { return this._data.certificate; }
set certificate(value: string) { this._data.certificate = value; }
get privateKey(): string { return this._data.privateKey; }
set privateKey(value: string) { this._data.privateKey = value; }
get passphrase(): string | undefined { return this._data.passphrase; }
set passphrase(value: string | undefined) { this._data.passphrase = value; }
}