github-archiver 1.0.2 → 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.releaserc.json +9 -1
- package/CHANGELOG.md +25 -0
- package/dist/index.js +3 -3
- package/dist/index.js.map +2 -2
- package/package.json +6 -2
- package/.claude/CLAUDE.md +0 -248
- package/.claude/settings.json +0 -15
- package/.github/dependabot.yml +0 -76
- package/.github/workflows/ci.yml +0 -64
- package/.github/workflows/release.yml +0 -55
- package/AGENTS.md +0 -248
- package/CONTRIBUTING.md +0 -343
- package/QUICKSTART.md +0 -221
- package/bun.lock +0 -1380
- package/issues.txt +0 -1105
- package/notes.md +0 -0
- package/scripts/build.ts +0 -14
- package/src/commands/archive.ts +0 -344
- package/src/commands/auth.ts +0 -184
- package/src/constants/defaults.ts +0 -6
- package/src/constants/messages.ts +0 -24
- package/src/constants/paths.ts +0 -12
- package/src/index.ts +0 -42
- package/src/services/archiver.ts +0 -192
- package/src/services/auth-manager.ts +0 -79
- package/src/services/github.ts +0 -211
- package/src/types/config.ts +0 -24
- package/src/types/error.ts +0 -35
- package/src/types/github.ts +0 -34
- package/src/types/index.ts +0 -4
- package/src/utils/colors.ts +0 -79
- package/src/utils/config.ts +0 -95
- package/src/utils/errors.ts +0 -93
- package/src/utils/formatting.ts +0 -65
- package/src/utils/input-handler.ts +0 -163
- package/src/utils/logger.ts +0 -65
- package/src/utils/parser.ts +0 -125
- package/src/utils/progress.ts +0 -87
- package/tests/unit/formatting.test.ts +0 -93
- package/tests/unit/parser.test.ts +0 -140
- package/tsconfig.json +0 -36
package/src/services/archiver.ts
DELETED
|
@@ -1,192 +0,0 @@
|
|
|
1
|
-
import PQueue from "p-queue";
|
|
2
|
-
import type {
|
|
3
|
-
ArchiveOptions,
|
|
4
|
-
ArchiveResult,
|
|
5
|
-
RepositoryIdentifier,
|
|
6
|
-
} from "../types";
|
|
7
|
-
import { ErrorCode } from "../types";
|
|
8
|
-
import { isArchiveError } from "../utils/errors";
|
|
9
|
-
import { getLogger } from "../utils/logger";
|
|
10
|
-
import type { GitHubService } from "./github";
|
|
11
|
-
|
|
12
|
-
const logger = getLogger();
|
|
13
|
-
|
|
14
|
-
export class Archiver {
|
|
15
|
-
private readonly queue: PQueue;
|
|
16
|
-
private results: ArchiveResult[] = [];
|
|
17
|
-
private readonly gitHubService: GitHubService;
|
|
18
|
-
private completed = 0;
|
|
19
|
-
private failed = 0;
|
|
20
|
-
private readonly startTime = 0;
|
|
21
|
-
|
|
22
|
-
constructor(gitHubService: GitHubService, options: ArchiveOptions) {
|
|
23
|
-
this.gitHubService = gitHubService;
|
|
24
|
-
this.queue = new PQueue({
|
|
25
|
-
concurrency: options.concurrency,
|
|
26
|
-
timeout: options.timeout * 1000,
|
|
27
|
-
interval: 1000,
|
|
28
|
-
intervalCap: options.concurrency,
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
logger.info("Archiver initialized", {
|
|
32
|
-
concurrency: options.concurrency,
|
|
33
|
-
timeout: options.timeout,
|
|
34
|
-
dryRun: options.dryRun,
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async archiveRepositories(
|
|
39
|
-
repos: RepositoryIdentifier[],
|
|
40
|
-
options: ArchiveOptions
|
|
41
|
-
): Promise<ArchiveResult[]> {
|
|
42
|
-
this.results = [];
|
|
43
|
-
this.completed = 0;
|
|
44
|
-
this.failed = 0;
|
|
45
|
-
|
|
46
|
-
logger.info(`Starting to archive ${repos.length} repositories`, {
|
|
47
|
-
dryRun: options.dryRun,
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
const tasks = repos.map((repo) =>
|
|
51
|
-
this.queue.add(() => this.archiveRepository(repo, options))
|
|
52
|
-
);
|
|
53
|
-
|
|
54
|
-
await Promise.all(tasks);
|
|
55
|
-
|
|
56
|
-
return this.results;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
private async archiveRepository(
|
|
60
|
-
repo: RepositoryIdentifier,
|
|
61
|
-
options: ArchiveOptions
|
|
62
|
-
): Promise<void> {
|
|
63
|
-
const startTime = Date.now();
|
|
64
|
-
|
|
65
|
-
try {
|
|
66
|
-
if (options.dryRun) {
|
|
67
|
-
logger.info(`[DRY-RUN] Would archive ${repo.owner}/${repo.repo}`);
|
|
68
|
-
const result: ArchiveResult = {
|
|
69
|
-
owner: repo.owner,
|
|
70
|
-
repo: repo.repo,
|
|
71
|
-
success: true,
|
|
72
|
-
archived: false,
|
|
73
|
-
duration: Date.now() - startTime,
|
|
74
|
-
message: "[DRY-RUN] Validation successful",
|
|
75
|
-
};
|
|
76
|
-
this.results.push(result);
|
|
77
|
-
this.completed++;
|
|
78
|
-
return;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const validation = await this.gitHubService.validateRepository(
|
|
82
|
-
repo.owner,
|
|
83
|
-
repo.repo
|
|
84
|
-
);
|
|
85
|
-
|
|
86
|
-
if (!validation.exists) {
|
|
87
|
-
logger.warn(`Repository not found: ${repo.owner}/${repo.repo}`);
|
|
88
|
-
const result: ArchiveResult = {
|
|
89
|
-
owner: repo.owner,
|
|
90
|
-
repo: repo.repo,
|
|
91
|
-
success: false,
|
|
92
|
-
archived: false,
|
|
93
|
-
error: "Repository not found",
|
|
94
|
-
duration: Date.now() - startTime,
|
|
95
|
-
message: "Repository does not exist on GitHub",
|
|
96
|
-
};
|
|
97
|
-
this.results.push(result);
|
|
98
|
-
this.failed++;
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
if (validation.isArchived) {
|
|
103
|
-
logger.info(`Repository already archived: ${repo.owner}/${repo.repo}`);
|
|
104
|
-
const result: ArchiveResult = {
|
|
105
|
-
owner: repo.owner,
|
|
106
|
-
repo: repo.repo,
|
|
107
|
-
success: true,
|
|
108
|
-
archived: false,
|
|
109
|
-
duration: Date.now() - startTime,
|
|
110
|
-
message: "Repository is already archived",
|
|
111
|
-
};
|
|
112
|
-
this.results.push(result);
|
|
113
|
-
this.completed++;
|
|
114
|
-
return;
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
console.log(`📦 Archiving ${repo.owner}/${repo.repo}...`);
|
|
118
|
-
await this.gitHubService.archiveRepository(repo.owner, repo.repo);
|
|
119
|
-
|
|
120
|
-
const result: ArchiveResult = {
|
|
121
|
-
owner: repo.owner,
|
|
122
|
-
repo: repo.repo,
|
|
123
|
-
success: true,
|
|
124
|
-
archived: true,
|
|
125
|
-
duration: Date.now() - startTime,
|
|
126
|
-
message: "Repository archived successfully",
|
|
127
|
-
};
|
|
128
|
-
this.results.push(result);
|
|
129
|
-
this.completed++;
|
|
130
|
-
logger.info(`✓ Archived ${repo.owner}/${repo.repo}`, {
|
|
131
|
-
duration: result.duration,
|
|
132
|
-
});
|
|
133
|
-
} catch (error) {
|
|
134
|
-
if (isArchiveError(error) && error.code === ErrorCode.ALREADY_ARCHIVED) {
|
|
135
|
-
logger.info(`Repository already archived: ${repo.owner}/${repo.repo}`);
|
|
136
|
-
const result: ArchiveResult = {
|
|
137
|
-
owner: repo.owner,
|
|
138
|
-
repo: repo.repo,
|
|
139
|
-
success: true,
|
|
140
|
-
archived: false,
|
|
141
|
-
duration: Date.now() - startTime,
|
|
142
|
-
message: "Repository is already archived",
|
|
143
|
-
};
|
|
144
|
-
this.results.push(result);
|
|
145
|
-
this.completed++;
|
|
146
|
-
return;
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
const errorMessage =
|
|
150
|
-
error instanceof Error ? error.message : String(error);
|
|
151
|
-
logger.error(
|
|
152
|
-
`✗ Failed to archive ${repo.owner}/${repo.repo}: ${errorMessage}`
|
|
153
|
-
);
|
|
154
|
-
|
|
155
|
-
const result: ArchiveResult = {
|
|
156
|
-
owner: repo.owner,
|
|
157
|
-
repo: repo.repo,
|
|
158
|
-
success: false,
|
|
159
|
-
archived: false,
|
|
160
|
-
error: errorMessage,
|
|
161
|
-
duration: Date.now() - startTime,
|
|
162
|
-
message: `Error: ${errorMessage}`,
|
|
163
|
-
};
|
|
164
|
-
this.results.push(result);
|
|
165
|
-
this.failed++;
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
getProgress(): { completed: number; failed: number; total: number } {
|
|
170
|
-
return {
|
|
171
|
-
completed: this.completed,
|
|
172
|
-
failed: this.failed,
|
|
173
|
-
total: this.results.length,
|
|
174
|
-
};
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
getSummary(): {
|
|
178
|
-
successful: number;
|
|
179
|
-
failed: number;
|
|
180
|
-
skipped: number;
|
|
181
|
-
totalDuration: number;
|
|
182
|
-
} {
|
|
183
|
-
const successful = this.results.filter(
|
|
184
|
-
(r) => r.success && r.archived
|
|
185
|
-
).length;
|
|
186
|
-
const failed = this.results.filter((r) => !r.success).length;
|
|
187
|
-
const skipped = this.results.filter((r) => r.success && !r.archived).length;
|
|
188
|
-
const totalDuration = Date.now() - this.startTime;
|
|
189
|
-
|
|
190
|
-
return { successful, failed, skipped, totalDuration };
|
|
191
|
-
}
|
|
192
|
-
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { Octokit } from "octokit";
|
|
2
|
-
import { PATHS } from "../constants/paths";
|
|
3
|
-
import type { Config, StoredCredentials } from "../types";
|
|
4
|
-
import { ConfigManager } from "../utils/config";
|
|
5
|
-
import { createAuthError } from "../utils/errors";
|
|
6
|
-
|
|
7
|
-
export class AuthManager {
|
|
8
|
-
private readonly configManager: ConfigManager;
|
|
9
|
-
|
|
10
|
-
constructor(configDir: string = PATHS.APP_DIR) {
|
|
11
|
-
this.configManager = new ConfigManager(configDir);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async saveToken(token: string): Promise<void> {
|
|
15
|
-
if (!token || typeof token !== "string") {
|
|
16
|
-
throw createAuthError("Invalid token format");
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
const octokit = new Octokit({ auth: token });
|
|
20
|
-
|
|
21
|
-
try {
|
|
22
|
-
const { data } = await octokit.rest.users.getAuthenticated();
|
|
23
|
-
|
|
24
|
-
const credentials: StoredCredentials = {
|
|
25
|
-
token,
|
|
26
|
-
savedAt: new Date().toISOString(),
|
|
27
|
-
githubUser: data.login,
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
await this.configManager.saveConfig(credentials);
|
|
31
|
-
} catch (error) {
|
|
32
|
-
throw createAuthError(
|
|
33
|
-
`Failed to validate token: ${error instanceof Error ? error.message : String(error)}`
|
|
34
|
-
);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
async getToken(): Promise<string | undefined> {
|
|
39
|
-
if (process.env.GH_TOKEN) {
|
|
40
|
-
return process.env.GH_TOKEN;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const credentials = await this.configManager.getStoredCredentials();
|
|
44
|
-
return credentials?.token;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async removeToken(): Promise<void> {
|
|
48
|
-
await this.configManager.removeStoredCredentials();
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async validateToken(
|
|
52
|
-
token: string
|
|
53
|
-
): Promise<{ valid: boolean; user?: string }> {
|
|
54
|
-
try {
|
|
55
|
-
const octokit = new Octokit({ auth: token });
|
|
56
|
-
const { data } = await octokit.rest.users.getAuthenticated();
|
|
57
|
-
return {
|
|
58
|
-
valid: true,
|
|
59
|
-
user: data.login,
|
|
60
|
-
};
|
|
61
|
-
} catch (_error) {
|
|
62
|
-
return {
|
|
63
|
-
valid: false,
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
getStoredCredentials(): Promise<StoredCredentials | null> {
|
|
69
|
-
return this.configManager.getStoredCredentials();
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
ensureConfigDir(): Promise<void> {
|
|
73
|
-
return this.configManager.ensureConfigDir();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
loadConfig(): Promise<Config> {
|
|
77
|
-
return this.configManager.loadConfig();
|
|
78
|
-
}
|
|
79
|
-
}
|
package/src/services/github.ts
DELETED
|
@@ -1,211 +0,0 @@
|
|
|
1
|
-
import { Octokit } from "octokit";
|
|
2
|
-
import { MAX_RETRIES, RETRY_DELAY_MS } from "../constants/defaults";
|
|
3
|
-
import type { RateLimitInfo } from "../types";
|
|
4
|
-
import {
|
|
5
|
-
createAlreadyArchivedError,
|
|
6
|
-
createNetworkError,
|
|
7
|
-
createPermissionError,
|
|
8
|
-
createRateLimitError,
|
|
9
|
-
createRepoNotFoundError,
|
|
10
|
-
} from "../utils/errors";
|
|
11
|
-
import { getLogger } from "../utils/logger";
|
|
12
|
-
|
|
13
|
-
const logger = getLogger();
|
|
14
|
-
|
|
15
|
-
interface OctokitError {
|
|
16
|
-
status: number;
|
|
17
|
-
response?: {
|
|
18
|
-
data?: {
|
|
19
|
-
message: string;
|
|
20
|
-
};
|
|
21
|
-
};
|
|
22
|
-
message: string;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export class GitHubService {
|
|
26
|
-
private readonly octokit: Octokit;
|
|
27
|
-
|
|
28
|
-
constructor(token: string) {
|
|
29
|
-
this.octokit = new Octokit({ auth: token });
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
async archiveRepository(owner: string, repo: string): Promise<void> {
|
|
33
|
-
const startTime = Date.now();
|
|
34
|
-
logger.debug(`Attempting to archive ${owner}/${repo}`);
|
|
35
|
-
|
|
36
|
-
await this.retryWithBackoff(async () => {
|
|
37
|
-
try {
|
|
38
|
-
await this.octokit.rest.repos.update({
|
|
39
|
-
owner,
|
|
40
|
-
repo,
|
|
41
|
-
archived: true,
|
|
42
|
-
});
|
|
43
|
-
const duration = Date.now() - startTime;
|
|
44
|
-
logger.info(`Successfully archived ${owner}/${repo} in ${duration}ms`);
|
|
45
|
-
} catch (error) {
|
|
46
|
-
this.handleArchiveError(error, owner, repo);
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
private handleArchiveError(
|
|
52
|
-
error: unknown,
|
|
53
|
-
owner: string,
|
|
54
|
-
repo: string
|
|
55
|
-
): never {
|
|
56
|
-
const err = this.parseOctokitError(error);
|
|
57
|
-
logger.error(`Failed to archive ${owner}/${repo}: ${err.message}`, {
|
|
58
|
-
status: err.status,
|
|
59
|
-
code: err.code,
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
if (err.status === 404) {
|
|
63
|
-
throw createRepoNotFoundError(owner, repo);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
if (err.status === 403 || err.message.includes("permission")) {
|
|
67
|
-
throw createPermissionError(owner, repo);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
if (err.status === 422 && err.message.includes("archived")) {
|
|
71
|
-
throw createAlreadyArchivedError(owner, repo);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
if (err.message.includes("API rate limit")) {
|
|
75
|
-
throw createRateLimitError();
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
if (
|
|
79
|
-
err.message.includes("ECONNREFUSED") ||
|
|
80
|
-
err.message.includes("ETIMEDOUT") ||
|
|
81
|
-
err.message.includes("EHOSTUNREACH") ||
|
|
82
|
-
err.message.includes("socket hang up")
|
|
83
|
-
) {
|
|
84
|
-
throw createNetworkError(err.message);
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
throw error;
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
private parseOctokitError(error: unknown): {
|
|
91
|
-
message: string;
|
|
92
|
-
status: number;
|
|
93
|
-
code: string | undefined;
|
|
94
|
-
} {
|
|
95
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
96
|
-
const err = error as unknown as OctokitError;
|
|
97
|
-
return {
|
|
98
|
-
message,
|
|
99
|
-
status: err?.status || 0,
|
|
100
|
-
code: err?.response?.data?.message,
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
async validateRepository(
|
|
105
|
-
owner: string,
|
|
106
|
-
repo: string
|
|
107
|
-
): Promise<{ exists: boolean; isArchived: boolean }> {
|
|
108
|
-
try {
|
|
109
|
-
logger.debug(`Validating repository ${owner}/${repo}`);
|
|
110
|
-
const { data } = await this.octokit.rest.repos.get({
|
|
111
|
-
owner,
|
|
112
|
-
repo,
|
|
113
|
-
});
|
|
114
|
-
|
|
115
|
-
const result = {
|
|
116
|
-
exists: true,
|
|
117
|
-
isArchived: data.archived,
|
|
118
|
-
};
|
|
119
|
-
logger.debug(`Repository ${owner}/${repo} validated`, result);
|
|
120
|
-
return result;
|
|
121
|
-
} catch (error) {
|
|
122
|
-
if (error instanceof Error && error.message.includes("404")) {
|
|
123
|
-
logger.debug(`Repository ${owner}/${repo} does not exist`);
|
|
124
|
-
return {
|
|
125
|
-
exists: false,
|
|
126
|
-
isArchived: false,
|
|
127
|
-
};
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
logger.error(`Error validating ${owner}/${repo}:`, error);
|
|
131
|
-
throw error;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
async getRateLimitStatus(): Promise<RateLimitInfo> {
|
|
136
|
-
try {
|
|
137
|
-
logger.debug("Fetching rate limit status");
|
|
138
|
-
const { data } = await this.octokit.rest.rateLimit.get();
|
|
139
|
-
|
|
140
|
-
const info: RateLimitInfo = {
|
|
141
|
-
remaining: data.rate.remaining,
|
|
142
|
-
reset: new Date(data.rate.reset * 1000),
|
|
143
|
-
limit: data.rate.limit,
|
|
144
|
-
};
|
|
145
|
-
|
|
146
|
-
logger.debug("Rate limit status retrieved", {
|
|
147
|
-
remaining: info.remaining,
|
|
148
|
-
limit: info.limit,
|
|
149
|
-
resetAt: info.reset.toISOString(),
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
return info;
|
|
153
|
-
} catch (error) {
|
|
154
|
-
logger.error("Failed to fetch rate limit status:", error);
|
|
155
|
-
throw error;
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
async validateAuth(): Promise<string> {
|
|
160
|
-
try {
|
|
161
|
-
logger.debug("Validating authentication");
|
|
162
|
-
const { data } = await this.octokit.rest.users.getAuthenticated();
|
|
163
|
-
logger.info(`Authenticated as user: ${data.login}`);
|
|
164
|
-
return data.login;
|
|
165
|
-
} catch (error) {
|
|
166
|
-
logger.error("Authentication validation failed:", error);
|
|
167
|
-
throw createNetworkError(
|
|
168
|
-
error instanceof Error ? error.message : "Authentication failed"
|
|
169
|
-
);
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
private async retryWithBackoff<T>(
|
|
174
|
-
fn: () => Promise<T>,
|
|
175
|
-
maxRetries: number = MAX_RETRIES
|
|
176
|
-
): Promise<T> {
|
|
177
|
-
let lastError: Error | undefined;
|
|
178
|
-
|
|
179
|
-
for (let attempt = 0; attempt < maxRetries; attempt++) {
|
|
180
|
-
try {
|
|
181
|
-
return await fn();
|
|
182
|
-
} catch (error) {
|
|
183
|
-
lastError = error as Error;
|
|
184
|
-
|
|
185
|
-
const message = lastError.message.toLowerCase();
|
|
186
|
-
const isRetryable =
|
|
187
|
-
message.includes("rate limit") ||
|
|
188
|
-
message.includes("timeout") ||
|
|
189
|
-
message.includes("econnrefused") ||
|
|
190
|
-
message.includes("etimedout") ||
|
|
191
|
-
message.includes("ehostunreach") ||
|
|
192
|
-
message.includes("socket hang up");
|
|
193
|
-
|
|
194
|
-
if (!isRetryable || attempt === maxRetries - 1) {
|
|
195
|
-
throw error;
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
const delay = RETRY_DELAY_MS * 2 ** attempt;
|
|
199
|
-
logger.warn(
|
|
200
|
-
`Retry attempt ${attempt + 1}/${maxRetries} after ${delay}ms`,
|
|
201
|
-
{
|
|
202
|
-
error: message,
|
|
203
|
-
}
|
|
204
|
-
);
|
|
205
|
-
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
throw lastError || new Error("Unknown error during retry");
|
|
210
|
-
}
|
|
211
|
-
}
|
package/src/types/config.ts
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
export interface Config {
|
|
2
|
-
token?: string;
|
|
3
|
-
concurrency: number;
|
|
4
|
-
timeout: number;
|
|
5
|
-
logLevel: "debug" | "info" | "warn" | "error";
|
|
6
|
-
logDir: string;
|
|
7
|
-
configDir: string;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export interface StoredCredentials {
|
|
11
|
-
token: string;
|
|
12
|
-
savedAt: string;
|
|
13
|
-
githubUser?: string;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface CommandOptions {
|
|
17
|
-
file?: string;
|
|
18
|
-
stdin?: boolean;
|
|
19
|
-
dryRun: boolean;
|
|
20
|
-
concurrency: string;
|
|
21
|
-
timeout: string;
|
|
22
|
-
verbose: boolean;
|
|
23
|
-
force: boolean;
|
|
24
|
-
}
|
package/src/types/error.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
export const ErrorCode = {
|
|
2
|
-
INVALID_AUTH: "INVALID_AUTH",
|
|
3
|
-
REPO_NOT_FOUND: "REPO_NOT_FOUND",
|
|
4
|
-
ALREADY_ARCHIVED: "ALREADY_ARCHIVED",
|
|
5
|
-
PERMISSION_DENIED: "PERMISSION_DENIED",
|
|
6
|
-
RATE_LIMITED: "RATE_LIMITED",
|
|
7
|
-
NETWORK_ERROR: "NETWORK_ERROR",
|
|
8
|
-
INVALID_URL: "INVALID_URL",
|
|
9
|
-
PARSE_ERROR: "PARSE_ERROR",
|
|
10
|
-
EDITOR_ERROR: "EDITOR_ERROR",
|
|
11
|
-
CONFIG_ERROR: "CONFIG_ERROR",
|
|
12
|
-
FILE_ERROR: "FILE_ERROR",
|
|
13
|
-
} as const;
|
|
14
|
-
|
|
15
|
-
export type ErrorCode = (typeof ErrorCode)[keyof typeof ErrorCode];
|
|
16
|
-
|
|
17
|
-
export class ArchiveError extends Error {
|
|
18
|
-
code: ErrorCode;
|
|
19
|
-
statusCode?: number;
|
|
20
|
-
retryable: boolean;
|
|
21
|
-
|
|
22
|
-
constructor(
|
|
23
|
-
code: ErrorCode,
|
|
24
|
-
message: string,
|
|
25
|
-
statusCode?: number,
|
|
26
|
-
retryable = false
|
|
27
|
-
) {
|
|
28
|
-
super(message);
|
|
29
|
-
this.name = "ArchiveError";
|
|
30
|
-
this.code = code;
|
|
31
|
-
this.statusCode = statusCode;
|
|
32
|
-
this.retryable = retryable;
|
|
33
|
-
Object.setPrototypeOf(this, ArchiveError.prototype);
|
|
34
|
-
}
|
|
35
|
-
}
|
package/src/types/github.ts
DELETED
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
export interface RepositoryIdentifier {
|
|
2
|
-
owner: string;
|
|
3
|
-
repo: string;
|
|
4
|
-
url: string;
|
|
5
|
-
}
|
|
6
|
-
|
|
7
|
-
export interface ArchiveResult {
|
|
8
|
-
owner: string;
|
|
9
|
-
repo: string;
|
|
10
|
-
success: boolean;
|
|
11
|
-
archived: boolean;
|
|
12
|
-
error?: Error | string;
|
|
13
|
-
duration: number;
|
|
14
|
-
message: string;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export interface ArchiveOptions {
|
|
18
|
-
dryRun: boolean;
|
|
19
|
-
concurrency: number;
|
|
20
|
-
timeout: number;
|
|
21
|
-
force: boolean;
|
|
22
|
-
verbose: boolean;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface RateLimitInfo {
|
|
26
|
-
remaining: number;
|
|
27
|
-
reset: Date;
|
|
28
|
-
limit: number;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface GitHubError extends Error {
|
|
32
|
-
status: number;
|
|
33
|
-
code: string;
|
|
34
|
-
}
|
package/src/types/index.ts
DELETED
package/src/utils/colors.ts
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
const RESET = "\x1b[0m";
|
|
2
|
-
const BRIGHT = "\x1b[1m";
|
|
3
|
-
const DIM = "\x1b[2m";
|
|
4
|
-
const RED = "\x1b[31m";
|
|
5
|
-
const GREEN = "\x1b[32m";
|
|
6
|
-
const YELLOW = "\x1b[33m";
|
|
7
|
-
const CYAN = "\x1b[36m";
|
|
8
|
-
|
|
9
|
-
function success(text: string): string {
|
|
10
|
-
return `${GREEN}${text}${RESET}`;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function error(text: string): string {
|
|
14
|
-
return `${RED}${text}${RESET}`;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function warning(text: string): string {
|
|
18
|
-
return `${YELLOW}${text}${RESET}`;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
function info(text: string): string {
|
|
22
|
-
return `${CYAN}${text}${RESET}`;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
function dim(text: string): string {
|
|
26
|
-
return `${DIM}${text}${RESET}`;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
function bold(text: string): string {
|
|
30
|
-
return `${BRIGHT}${text}${RESET}`;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
function successBold(text: string): string {
|
|
34
|
-
return `${GREEN}${BRIGHT}${text}${RESET}`;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function errorBold(text: string): string {
|
|
38
|
-
return `${RED}${BRIGHT}${text}${RESET}`;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function warningBold(text: string): string {
|
|
42
|
-
return `${YELLOW}${BRIGHT}${text}${RESET}`;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
function table(rows: string[]): string {
|
|
46
|
-
return rows.map((row) => `${DIM}│${RESET} ${row}`).join("\n");
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function formatStatus(
|
|
50
|
-
status: "success" | "error" | "warning" | "info"
|
|
51
|
-
): string {
|
|
52
|
-
const icons = {
|
|
53
|
-
success: "✅",
|
|
54
|
-
error: "❌",
|
|
55
|
-
warning: "⚠️ ",
|
|
56
|
-
info: "ℹ️ ",
|
|
57
|
-
};
|
|
58
|
-
const colors = {
|
|
59
|
-
success,
|
|
60
|
-
error,
|
|
61
|
-
warning,
|
|
62
|
-
info,
|
|
63
|
-
};
|
|
64
|
-
return colors[status](icons[status]);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
export const Colors = {
|
|
68
|
-
success,
|
|
69
|
-
error,
|
|
70
|
-
warning,
|
|
71
|
-
info,
|
|
72
|
-
dim,
|
|
73
|
-
bold,
|
|
74
|
-
successBold,
|
|
75
|
-
errorBold,
|
|
76
|
-
warningBold,
|
|
77
|
-
table,
|
|
78
|
-
formatStatus,
|
|
79
|
-
};
|