import * as interfaces from '../ts_interfaces/index.js'; import type { DcRouterApiClient } from './classes.dcrouterapiclient.js'; export class ApiToken { private clientRef: DcRouterApiClient; // Data from IApiTokenInfo public id: string; public name: string; public scopes: interfaces.data.TApiTokenScope[]; public createdAt: number; public expiresAt: number | null; public lastUsedAt: number | null; public enabled: boolean; /** Only set on creation or roll. Not persisted on server side. */ public tokenValue?: string; constructor(clientRef: DcRouterApiClient, data: interfaces.data.IApiTokenInfo, tokenValue?: string) { this.clientRef = clientRef; this.id = data.id; this.name = data.name; this.scopes = data.scopes; this.createdAt = data.createdAt; this.expiresAt = data.expiresAt; this.lastUsedAt = data.lastUsedAt; this.enabled = data.enabled; this.tokenValue = tokenValue; } public async revoke(): Promise { const response = await this.clientRef.request( 'revokeApiToken', this.clientRef.buildRequestPayload({ id: this.id }) as any, ); if (!response.success) { throw new Error(response.message || 'Failed to revoke token'); } } public async roll(): Promise { const response = await this.clientRef.request( 'rollApiToken', this.clientRef.buildRequestPayload({ id: this.id }) as any, ); if (!response.success) { throw new Error(response.message || 'Failed to roll token'); } this.tokenValue = response.tokenValue; return response.tokenValue!; } public async toggle(enabled: boolean): Promise { const response = await this.clientRef.request( 'toggleApiToken', this.clientRef.buildRequestPayload({ id: this.id, enabled }) as any, ); if (!response.success) { throw new Error(response.message || 'Failed to toggle token'); } this.enabled = enabled; } } export class ApiTokenBuilder { private clientRef: DcRouterApiClient; private tokenName: string = ''; private tokenScopes: interfaces.data.TApiTokenScope[] = []; private tokenExpiresInDays?: number | null; constructor(clientRef: DcRouterApiClient) { this.clientRef = clientRef; } public setName(name: string): this { this.tokenName = name; return this; } public setScopes(scopes: interfaces.data.TApiTokenScope[]): this { this.tokenScopes = scopes; return this; } public addScope(scope: interfaces.data.TApiTokenScope): this { if (!this.tokenScopes.includes(scope)) { this.tokenScopes.push(scope); } return this; } public setExpiresInDays(days: number | null): this { this.tokenExpiresInDays = days; return this; } public async save(): Promise { const response = await this.clientRef.request( 'createApiToken', this.clientRef.buildRequestPayload({ name: this.tokenName, scopes: this.tokenScopes, expiresInDays: this.tokenExpiresInDays, }) as any, ); if (!response.success) { throw new Error(response.message || 'Failed to create API token'); } return new ApiToken( this.clientRef, { id: response.tokenId!, name: this.tokenName, scopes: this.tokenScopes, createdAt: Date.now(), expiresAt: this.tokenExpiresInDays ? Date.now() + this.tokenExpiresInDays * 24 * 60 * 60 * 1000 : null, lastUsedAt: null, enabled: true, }, response.tokenValue, ); } } export class ApiTokenManager { private clientRef: DcRouterApiClient; constructor(clientRef: DcRouterApiClient) { this.clientRef = clientRef; } public async list(): Promise { const response = await this.clientRef.request( 'listApiTokens', this.clientRef.buildRequestPayload() as any, ); return response.tokens.map((t) => new ApiToken(this.clientRef, t)); } public async create(options: { name: string; scopes: interfaces.data.TApiTokenScope[]; expiresInDays?: number | null; }): Promise { return this.build() .setName(options.name) .setScopes(options.scopes) .setExpiresInDays(options.expiresInDays ?? null) .save(); } public build(): ApiTokenBuilder { return new ApiTokenBuilder(this.clientRef); } }