feat(apiclient): add TypeScript API client (ts_apiclient) with resource managers and package exports

This commit is contained in:
2026-03-06 07:52:10 +00:00
parent ca2d2b09ad
commit abde872ab2
18 changed files with 1850 additions and 236 deletions

View File

@@ -0,0 +1,157 @@
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<void> {
const response = await this.clientRef.request<interfaces.requests.IReq_RevokeApiToken>(
'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<string> {
const response = await this.clientRef.request<interfaces.requests.IReq_RollApiToken>(
'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<void> {
const response = await this.clientRef.request<interfaces.requests.IReq_ToggleApiToken>(
'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<ApiToken> {
const response = await this.clientRef.request<interfaces.requests.IReq_CreateApiToken>(
'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<ApiToken[]> {
const response = await this.clientRef.request<interfaces.requests.IReq_ListApiTokens>(
'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<ApiToken> {
return this.build()
.setName(options.name)
.setScopes(options.scopes)
.setExpiresInDays(options.expiresInDays ?? null)
.save();
}
public build(): ApiTokenBuilder {
return new ApiTokenBuilder(this.clientRef);
}
}