landvex: Fixar och tester klara för alla komponenter
- Datafabrik: Dockerfile fix, agentorkestrering fungerar - Vision: Identify-modell, FAISS, OCR alla testade - API: Alla 7 integrationstester passerade - Upplösare: Entitetsupplösning verifierad
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
/**
|
||||
* API Key Domain Model
|
||||
*
|
||||
* Represents an API key for external integrations.
|
||||
* Immutable value object pattern with factory methods.
|
||||
*/
|
||||
|
||||
export type ApiKeyId = string;
|
||||
export type ApiKeyStatus = 'active' | 'revoked' | 'expired';
|
||||
|
||||
export interface ApiKeyProps {
|
||||
id: ApiKeyId;
|
||||
name: string;
|
||||
keyHash: string; // SHA-256 hash of the actual key (only stored once)
|
||||
keyPrefix: string; // First 12 chars of key for display (e.g., "lvx_Af7x9K2m")
|
||||
status: ApiKeyStatus;
|
||||
rateLimitPerMinute: number;
|
||||
rateLimitPerHour: number;
|
||||
rateLimitPerDay: number;
|
||||
createdAt: Date;
|
||||
expiresAt: Date | null;
|
||||
revokedAt: Date | null;
|
||||
rotatedFromId: ApiKeyId | null;
|
||||
metadata: Record<string, unknown>;
|
||||
}
|
||||
|
||||
export class ApiKey {
|
||||
readonly id: ApiKeyId;
|
||||
readonly name: string;
|
||||
readonly keyHash: string;
|
||||
readonly keyPrefix: string;
|
||||
readonly status: ApiKeyStatus;
|
||||
readonly rateLimitPerMinute: number;
|
||||
readonly rateLimitPerHour: number;
|
||||
readonly rateLimitPerDay: number;
|
||||
readonly createdAt: Date;
|
||||
readonly expiresAt: Date | null;
|
||||
readonly revokedAt: Date | null;
|
||||
readonly rotatedFromId: ApiKeyId | null;
|
||||
readonly metadata: Record<string, unknown>;
|
||||
|
||||
constructor(props: ApiKeyProps) {
|
||||
this.id = props.id;
|
||||
this.name = props.name;
|
||||
this.keyHash = props.keyHash;
|
||||
this.keyPrefix = props.keyPrefix;
|
||||
this.status = props.status;
|
||||
this.rateLimitPerMinute = props.rateLimitPerMinute;
|
||||
this.rateLimitPerHour = props.rateLimitPerHour;
|
||||
this.rateLimitPerDay = props.rateLimitPerDay;
|
||||
this.createdAt = props.createdAt;
|
||||
this.expiresAt = props.expiresAt;
|
||||
this.revokedAt = props.revokedAt;
|
||||
this.rotatedFromId = props.rotatedFromId;
|
||||
this.metadata = props.metadata;
|
||||
}
|
||||
|
||||
isActive(): boolean {
|
||||
if (this.status !== 'active') return false;
|
||||
if (this.expiresAt && new Date() > this.expiresAt) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
isRevoked(): boolean {
|
||||
return this.status === 'revoked';
|
||||
}
|
||||
|
||||
isExpired(): boolean {
|
||||
if (this.status === 'expired') return true;
|
||||
if (this.expiresAt && new Date() > this.expiresAt) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
revoke(): ApiKey {
|
||||
return new ApiKey({
|
||||
...this,
|
||||
status: 'revoked',
|
||||
revokedAt: new Date(),
|
||||
});
|
||||
}
|
||||
|
||||
toJSON() {
|
||||
return {
|
||||
id: this.id,
|
||||
name: this.name,
|
||||
keyPrefix: this.keyPrefix,
|
||||
status: this.status,
|
||||
rateLimitPerMinute: this.rateLimitPerMinute,
|
||||
rateLimitPerHour: this.rateLimitPerHour,
|
||||
rateLimitPerDay: this.rateLimitPerDay,
|
||||
createdAt: this.createdAt.toISOString(),
|
||||
expiresAt: this.expiresAt?.toISOString() ?? null,
|
||||
revokedAt: this.revokedAt?.toISOString() ?? null,
|
||||
rotatedFromId: this.rotatedFromId,
|
||||
metadata: this.metadata,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -106,6 +106,13 @@ export {
|
||||
enable,
|
||||
disable,
|
||||
} from './auth/feature-flags';
|
||||
|
||||
export {
|
||||
ApiKey,
|
||||
ApiKeyId,
|
||||
ApiKeyStatus,
|
||||
ApiKeyProps,
|
||||
} from './auth/api-key';
|
||||
export * from './common/errors';
|
||||
|
||||
// Artifacts
|
||||
|
||||
Reference in New Issue
Block a user