octokit-load-balancer 1.0.3 → 2.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.
- package/README.md +0 -2
- package/dist/index.d.mts +1 -2
- package/dist/index.d.ts +1 -2
- package/dist/index.js +7 -22
- package/dist/index.mjs +7 -22
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -57,8 +57,6 @@ Every time you call `getApp(config)`:
|
|
|
57
57
|
| `apps` | `GitHubAppConfig[]` | Yes | Array of app configurations |
|
|
58
58
|
| `baseUrl` | `string` | Yes | GitHub API base URL |
|
|
59
59
|
|
|
60
|
-
App configs use `GitHubAppConfig` (re-exported from `@octokit/auth-app`'s `StrategyOptions`). All apps must have valid `appId` and `privateKey` — incomplete configs will throw an error.
|
|
61
|
-
|
|
62
60
|
## Scalability
|
|
63
61
|
|
|
64
62
|
This library is designed for high-throughput scenarios where a single GitHub App's rate limit (5,000 requests/hour) isn't enough. By distributing requests across multiple apps, you get N × 5,000 requests/hour.
|
package/dist/index.d.mts
CHANGED
|
@@ -34,7 +34,6 @@ interface RateLimitInfo extends RateLimitData {
|
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Get the Octokit instance with the most available rate limit.
|
|
37
|
-
* Pass your app configurations directly - incomplete configs are filtered out.
|
|
38
37
|
*
|
|
39
38
|
* @example
|
|
40
39
|
* ```typescript
|
|
@@ -59,7 +58,7 @@ interface RateLimitInfo extends RateLimitData {
|
|
|
59
58
|
* await octokit.rest.repos.get({ owner: 'org', repo: 'repo' })
|
|
60
59
|
* ```
|
|
61
60
|
*
|
|
62
|
-
* @throws {Error} When no
|
|
61
|
+
* @throws {Error} When no apps are provided or all apps have exhausted their rate limits
|
|
63
62
|
*/
|
|
64
63
|
declare function getApp(config: GitHubAppPoolConfig): Promise<Octokit>;
|
|
65
64
|
|
package/dist/index.d.ts
CHANGED
|
@@ -34,7 +34,6 @@ interface RateLimitInfo extends RateLimitData {
|
|
|
34
34
|
|
|
35
35
|
/**
|
|
36
36
|
* Get the Octokit instance with the most available rate limit.
|
|
37
|
-
* Pass your app configurations directly - incomplete configs are filtered out.
|
|
38
37
|
*
|
|
39
38
|
* @example
|
|
40
39
|
* ```typescript
|
|
@@ -59,7 +58,7 @@ interface RateLimitInfo extends RateLimitData {
|
|
|
59
58
|
* await octokit.rest.repos.get({ owner: 'org', repo: 'repo' })
|
|
60
59
|
* ```
|
|
61
60
|
*
|
|
62
|
-
* @throws {Error} When no
|
|
61
|
+
* @throws {Error} When no apps are provided or all apps have exhausted their rate limits
|
|
63
62
|
*/
|
|
64
63
|
declare function getApp(config: GitHubAppPoolConfig): Promise<Octokit>;
|
|
65
64
|
|
package/dist/index.js
CHANGED
|
@@ -29,20 +29,8 @@ var import_auth_app = require("@octokit/auth-app");
|
|
|
29
29
|
var import_octokit = require("octokit");
|
|
30
30
|
var DEBUG_KEY = "octokit-load-balancer";
|
|
31
31
|
async function getApp(config) {
|
|
32
|
-
if (!
|
|
33
|
-
throw new Error("
|
|
34
|
-
}
|
|
35
|
-
if (typeof config?.baseUrl !== "string" || !config.baseUrl) {
|
|
36
|
-
throw new Error("Invalid config: baseUrl must be a non-empty string");
|
|
37
|
-
}
|
|
38
|
-
if (config.apps.length === 0) {
|
|
39
|
-
throw new Error("Invalid config: apps array is empty");
|
|
40
|
-
}
|
|
41
|
-
const invalidApps = config.apps.filter((app) => !isCompleteConfig(app));
|
|
42
|
-
if (invalidApps.length > 0) {
|
|
43
|
-
throw new Error(
|
|
44
|
-
`Invalid config: ${invalidApps.length} app(s) missing required appId or privateKey`
|
|
45
|
-
);
|
|
32
|
+
if (!config?.apps?.length) {
|
|
33
|
+
throw new Error("No apps provided");
|
|
46
34
|
}
|
|
47
35
|
log(`Using ${config.apps.length} app configs`);
|
|
48
36
|
const octokits = config.apps.map((app) => createOctokit(app, config.baseUrl));
|
|
@@ -54,9 +42,9 @@ async function getApp(config) {
|
|
|
54
42
|
rateLimits.map((r) => `app[${r.appIndex}]: ${r.remaining}/${r.limit}`).join(", ")
|
|
55
43
|
);
|
|
56
44
|
const { bestIndex, rateLimit } = rateLimits.reduce(
|
|
57
|
-
(acc, cur
|
|
45
|
+
(acc, cur) => {
|
|
58
46
|
if (cur.remaining > acc.rateLimit.remaining) {
|
|
59
|
-
return { bestIndex:
|
|
47
|
+
return { bestIndex: cur.appIndex, rateLimit: cur };
|
|
60
48
|
}
|
|
61
49
|
return acc;
|
|
62
50
|
},
|
|
@@ -70,9 +58,6 @@ async function getApp(config) {
|
|
|
70
58
|
);
|
|
71
59
|
return octokits[bestIndex];
|
|
72
60
|
}
|
|
73
|
-
function isCompleteConfig(config) {
|
|
74
|
-
return typeof config === "object" && config !== null && "appId" in config && "privateKey" in config && !!(config.appId && config.privateKey);
|
|
75
|
-
}
|
|
76
61
|
function decodePrivateKey(key) {
|
|
77
62
|
if (key.startsWith("-----BEGIN ") && key.includes("-----END ")) {
|
|
78
63
|
return key;
|
|
@@ -84,9 +69,9 @@ function createOctokit(appConfig, baseUrl) {
|
|
|
84
69
|
authStrategy: import_auth_app.createAppAuth,
|
|
85
70
|
baseUrl,
|
|
86
71
|
auth: {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
privateKey: decodePrivateKey(appConfig.privateKey)
|
|
72
|
+
...appConfig,
|
|
73
|
+
// TODO: this type check can be removed once the issue will be fixed in @octokit/auth-app
|
|
74
|
+
privateKey: appConfig.privateKey && typeof appConfig.privateKey === "string" ? decodePrivateKey(appConfig.privateKey) : void 0
|
|
90
75
|
}
|
|
91
76
|
});
|
|
92
77
|
}
|
package/dist/index.mjs
CHANGED
|
@@ -3,20 +3,8 @@ import { createAppAuth } from "@octokit/auth-app";
|
|
|
3
3
|
import { Octokit } from "octokit";
|
|
4
4
|
var DEBUG_KEY = "octokit-load-balancer";
|
|
5
5
|
async function getApp(config) {
|
|
6
|
-
if (!
|
|
7
|
-
throw new Error("
|
|
8
|
-
}
|
|
9
|
-
if (typeof config?.baseUrl !== "string" || !config.baseUrl) {
|
|
10
|
-
throw new Error("Invalid config: baseUrl must be a non-empty string");
|
|
11
|
-
}
|
|
12
|
-
if (config.apps.length === 0) {
|
|
13
|
-
throw new Error("Invalid config: apps array is empty");
|
|
14
|
-
}
|
|
15
|
-
const invalidApps = config.apps.filter((app) => !isCompleteConfig(app));
|
|
16
|
-
if (invalidApps.length > 0) {
|
|
17
|
-
throw new Error(
|
|
18
|
-
`Invalid config: ${invalidApps.length} app(s) missing required appId or privateKey`
|
|
19
|
-
);
|
|
6
|
+
if (!config?.apps?.length) {
|
|
7
|
+
throw new Error("No apps provided");
|
|
20
8
|
}
|
|
21
9
|
log(`Using ${config.apps.length} app configs`);
|
|
22
10
|
const octokits = config.apps.map((app) => createOctokit(app, config.baseUrl));
|
|
@@ -28,9 +16,9 @@ async function getApp(config) {
|
|
|
28
16
|
rateLimits.map((r) => `app[${r.appIndex}]: ${r.remaining}/${r.limit}`).join(", ")
|
|
29
17
|
);
|
|
30
18
|
const { bestIndex, rateLimit } = rateLimits.reduce(
|
|
31
|
-
(acc, cur
|
|
19
|
+
(acc, cur) => {
|
|
32
20
|
if (cur.remaining > acc.rateLimit.remaining) {
|
|
33
|
-
return { bestIndex:
|
|
21
|
+
return { bestIndex: cur.appIndex, rateLimit: cur };
|
|
34
22
|
}
|
|
35
23
|
return acc;
|
|
36
24
|
},
|
|
@@ -44,9 +32,6 @@ async function getApp(config) {
|
|
|
44
32
|
);
|
|
45
33
|
return octokits[bestIndex];
|
|
46
34
|
}
|
|
47
|
-
function isCompleteConfig(config) {
|
|
48
|
-
return typeof config === "object" && config !== null && "appId" in config && "privateKey" in config && !!(config.appId && config.privateKey);
|
|
49
|
-
}
|
|
50
35
|
function decodePrivateKey(key) {
|
|
51
36
|
if (key.startsWith("-----BEGIN ") && key.includes("-----END ")) {
|
|
52
37
|
return key;
|
|
@@ -58,9 +43,9 @@ function createOctokit(appConfig, baseUrl) {
|
|
|
58
43
|
authStrategy: createAppAuth,
|
|
59
44
|
baseUrl,
|
|
60
45
|
auth: {
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
privateKey: decodePrivateKey(appConfig.privateKey)
|
|
46
|
+
...appConfig,
|
|
47
|
+
// TODO: this type check can be removed once the issue will be fixed in @octokit/auth-app
|
|
48
|
+
privateKey: appConfig.privateKey && typeof appConfig.privateKey === "string" ? decodePrivateKey(appConfig.privateKey) : void 0
|
|
64
49
|
}
|
|
65
50
|
});
|
|
66
51
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "octokit-load-balancer",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "Load balance across multiple GitHub App instances, always picking the one with most available rate limit",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -44,11 +44,11 @@
|
|
|
44
44
|
"url": "git+https://github.com/frankie303/octokit-load-balancer.git"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"@octokit/auth-app": "^
|
|
47
|
+
"@octokit/auth-app": "^8.0.0",
|
|
48
48
|
"octokit": "^5.0.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@octokit/auth-app": "^
|
|
51
|
+
"@octokit/auth-app": "^8.1.2",
|
|
52
52
|
"@types/node": "^20.19.28",
|
|
53
53
|
"@vitest/coverage-v8": "^4.0.17",
|
|
54
54
|
"octokit": "^5.0.5",
|