Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | 1x 1x 1x 18x 8x 8x 6x 3x 5x 5x 5x 4x 4x 3x 3x 2x 2x 2x 2x 2x 3x | import * as fs from 'fs/promises';
import * as path from 'path';
export interface StoredTokens {
github?: string;
gitlab?: string;
azure?: string;
lastUpdated?: string;
}
export class TokenStorage {
private readonly tokenFilePath: string;
constructor(tokenFilePath?: string) {
this.tokenFilePath = tokenFilePath ?? path.join(process.cwd(), '.tokens.json');
}
async loadTokens(): Promise<StoredTokens> {
try {
const data = await fs.readFile(this.tokenFilePath, 'utf-8');
return JSON.parse(data) as StoredTokens;
} catch {
// File doesn't exist or is invalid, return empty tokens
return {};
}
}
async saveTokens(tokens: StoredTokens): Promise<void> {
const tokensWithTimestamp: StoredTokens = {
...tokens,
lastUpdated: new Date().toISOString(),
};
try {
await fs.writeFile(this.tokenFilePath, JSON.stringify(tokensWithTimestamp, null, 2), 'utf-8');
// Set restrictive permissions (readable only by owner)
await fs.chmod(this.tokenFilePath, 0o600);
} catch (error) {
process.stderr.write(
`Warning: Could not save tokens to ${this.tokenFilePath}: ${error instanceof Error ? error.message : String(error)}\n`,
);
}
}
async getToken(provider: 'github' | 'gitlab' | 'azure'): Promise<string | undefined> {
const tokens = await this.loadTokens();
return tokens[provider];
}
async setToken(provider: 'github' | 'gitlab' | 'azure', token: string): Promise<void> {
const tokens = await this.loadTokens();
tokens[provider] = token;
await this.saveTokens(tokens);
}
async clearTokens(): Promise<void> {
try {
await fs.unlink(this.tokenFilePath);
} catch {
// File doesn't exist, which is fine
}
}
getTokensFilePath(): string {
return this.tokenFilePath;
}
}
|