bitbucket-gemini-action 1.0.0

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.
@@ -0,0 +1,149 @@
1
+ /**
2
+ * Retry Utilities
3
+ * Handles retry logic for API operations
4
+ */
5
+
6
+ export interface RetryOptions {
7
+ maxAttempts: number;
8
+ baseDelayMs: number;
9
+ maxDelayMs: number;
10
+ shouldRetry?: (error: unknown) => boolean;
11
+ onRetry?: (attempt: number, error: unknown) => void;
12
+ }
13
+
14
+ const DEFAULT_RETRY_OPTIONS: RetryOptions = {
15
+ maxAttempts: 3,
16
+ baseDelayMs: 1000,
17
+ maxDelayMs: 10000,
18
+ shouldRetry: (error: unknown) => {
19
+ // Retry on network errors and 5xx status codes
20
+ if (error instanceof Error) {
21
+ const message = error.message.toLowerCase();
22
+ if (
23
+ message.includes("network") ||
24
+ message.includes("timeout") ||
25
+ message.includes("econnrefused") ||
26
+ message.includes("socket")
27
+ ) {
28
+ return true;
29
+ }
30
+ }
31
+
32
+ // Retry on rate limiting
33
+ if (isRateLimitError(error)) {
34
+ return true;
35
+ }
36
+
37
+ // Retry on server errors
38
+ if (isServerError(error)) {
39
+ return true;
40
+ }
41
+
42
+ return false;
43
+ },
44
+ };
45
+
46
+ /**
47
+ * Execute a function with retry logic
48
+ */
49
+ export async function withRetry<T>(
50
+ fn: () => Promise<T>,
51
+ options: Partial<RetryOptions> = {}
52
+ ): Promise<T> {
53
+ const opts = { ...DEFAULT_RETRY_OPTIONS, ...options };
54
+ let lastError: unknown;
55
+
56
+ for (let attempt = 1; attempt <= opts.maxAttempts; attempt++) {
57
+ try {
58
+ return await fn();
59
+ } catch (error) {
60
+ lastError = error;
61
+
62
+ if (attempt === opts.maxAttempts) {
63
+ break;
64
+ }
65
+
66
+ if (!opts.shouldRetry?.(error)) {
67
+ throw error;
68
+ }
69
+
70
+ opts.onRetry?.(attempt, error);
71
+
72
+ const delay = calculateDelay(attempt, opts.baseDelayMs, opts.maxDelayMs);
73
+ await sleep(delay);
74
+ }
75
+ }
76
+
77
+ throw lastError;
78
+ }
79
+
80
+ /**
81
+ * Calculate exponential backoff delay with jitter
82
+ */
83
+ function calculateDelay(
84
+ attempt: number,
85
+ baseDelayMs: number,
86
+ maxDelayMs: number
87
+ ): number {
88
+ const exponentialDelay = baseDelayMs * Math.pow(2, attempt - 1);
89
+ const jitter = Math.random() * baseDelayMs;
90
+ return Math.min(exponentialDelay + jitter, maxDelayMs);
91
+ }
92
+
93
+ /**
94
+ * Sleep for specified milliseconds
95
+ */
96
+ function sleep(ms: number): Promise<void> {
97
+ return new Promise((resolve) => setTimeout(resolve, ms));
98
+ }
99
+
100
+ /**
101
+ * Check if error is a rate limit error
102
+ */
103
+ function isRateLimitError(error: unknown): boolean {
104
+ if (error && typeof error === "object") {
105
+ const err = error as { statusCode?: number; status?: number };
106
+ return err.statusCode === 429 || err.status === 429;
107
+ }
108
+ return false;
109
+ }
110
+
111
+ /**
112
+ * Check if error is a server error (5xx)
113
+ */
114
+ function isServerError(error: unknown): boolean {
115
+ if (error && typeof error === "object") {
116
+ const err = error as { statusCode?: number; status?: number };
117
+ const status = err.statusCode || err.status;
118
+ return status !== undefined && status >= 500 && status < 600;
119
+ }
120
+ return false;
121
+ }
122
+
123
+ /**
124
+ * Retry options for Bitbucket API
125
+ */
126
+ export const BITBUCKET_RETRY_OPTIONS: Partial<RetryOptions> = {
127
+ maxAttempts: 3,
128
+ baseDelayMs: 1000,
129
+ maxDelayMs: 10000,
130
+ onRetry: (attempt, error) => {
131
+ console.warn(
132
+ `Bitbucket API retry attempt ${attempt}: ${error instanceof Error ? error.message : "Unknown error"}`
133
+ );
134
+ },
135
+ };
136
+
137
+ /**
138
+ * Retry options for Gemini API
139
+ */
140
+ export const GEMINI_RETRY_OPTIONS: Partial<RetryOptions> = {
141
+ maxAttempts: 2,
142
+ baseDelayMs: 2000,
143
+ maxDelayMs: 15000,
144
+ onRetry: (attempt, error) => {
145
+ console.warn(
146
+ `Gemini API retry attempt ${attempt}: ${error instanceof Error ? error.message : "Unknown error"}`
147
+ );
148
+ },
149
+ };
package/tsconfig.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ESNext",
5
+ "moduleResolution": "bundler",
6
+ "lib": ["ES2022"],
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true,
10
+ "forceConsistentCasingInFileNames": true,
11
+ "resolveJsonModule": true,
12
+ "declaration": true,
13
+ "declarationMap": true,
14
+ "outDir": "./dist",
15
+ "rootDir": "./src",
16
+ "noUnusedLocals": true,
17
+ "noUnusedParameters": true,
18
+ "noImplicitReturns": true,
19
+ "noFallthroughCasesInSwitch": true,
20
+ "types": ["bun-types", "node"]
21
+ },
22
+ "include": ["src/**/*"],
23
+ "exclude": ["node_modules", "dist", "test"]
24
+ }