Files
chrono_manager/src/models/identity.ts
T
2026-06-28 12:21:09 -04:00

125 lines
5.8 KiB
TypeScript

/**
* Identity models for Chrono Manager services
*/
import type {
ServiceIdentity,
ServiceIdentityBasic,
ServiceIdentityCertificate,
ServiceIdentityNone,
ServiceIdentityOAuth,
ServiceIdentityToken
} from '@/types/service';
import { clonePlain } from './clone-plain';
import { MutationProxy } from './mutation-proxy';
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}`);
}
}
}
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; }
}
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; }
}
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; }
}
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 });
}
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; }
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; }
}
export class IdentityCertificate extends Identity<ServiceIdentityCertificate> {
constructor(certificate: string = '', privateKey: string = '', passphrase?: string) {
super({ type: 'CC', certificate, privateKey, 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; }
}