gh-api-client 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.
- package/LICENSE +21 -0
- package/README.md +371 -0
- package/dist/index.d.mts +1726 -0
- package/dist/index.d.ts +1726 -0
- package/dist/index.js +971 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +948 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +53 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,971 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
CommitResource: () => CommitResource,
|
|
24
|
+
GitHubApiError: () => GitHubApiError,
|
|
25
|
+
GitHubClient: () => GitHubClient,
|
|
26
|
+
OrganizationResource: () => OrganizationResource,
|
|
27
|
+
PullRequestResource: () => PullRequestResource,
|
|
28
|
+
RepositoryResource: () => RepositoryResource,
|
|
29
|
+
Security: () => Security,
|
|
30
|
+
UserResource: () => UserResource
|
|
31
|
+
});
|
|
32
|
+
module.exports = __toCommonJS(index_exports);
|
|
33
|
+
|
|
34
|
+
// src/security/Security.ts
|
|
35
|
+
var Security = class {
|
|
36
|
+
/**
|
|
37
|
+
* Creates a new Security instance with a GitHub personal access token.
|
|
38
|
+
*
|
|
39
|
+
* @param token - A GitHub personal access token (e.g., `ghp_...`) or OAuth token
|
|
40
|
+
* @param apiUrl - The base URL of the GitHub API. Defaults to `'https://api.github.com'`.
|
|
41
|
+
* Must be a valid URL; throws if it cannot be parsed.
|
|
42
|
+
*
|
|
43
|
+
* @throws {TypeError} If `apiUrl` is not a valid URL
|
|
44
|
+
*/
|
|
45
|
+
constructor(token, apiUrl = "https://api.github.com") {
|
|
46
|
+
if (!URL.canParse(apiUrl)) {
|
|
47
|
+
throw new TypeError(`Invalid apiUrl: "${apiUrl}" is not a valid URL`);
|
|
48
|
+
}
|
|
49
|
+
this.apiUrl = apiUrl.replace(/\/$/, "");
|
|
50
|
+
this.token = token;
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Returns the base URL of the GitHub API, without a trailing slash.
|
|
54
|
+
*
|
|
55
|
+
* @returns The API base URL
|
|
56
|
+
*/
|
|
57
|
+
getApiUrl() {
|
|
58
|
+
return this.apiUrl;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Returns the value of the `Authorization` header for Bearer authentication.
|
|
62
|
+
*
|
|
63
|
+
* @returns The Authorization header value in the format `Bearer <token>`
|
|
64
|
+
*/
|
|
65
|
+
getAuthorizationHeader() {
|
|
66
|
+
return `Bearer ${this.token}`;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Returns the full set of HTTP headers required for authenticated GitHub API requests.
|
|
70
|
+
*
|
|
71
|
+
* @returns An object containing `Authorization`, `Accept`, `Content-Type`, and `X-GitHub-Api-Version` headers
|
|
72
|
+
*/
|
|
73
|
+
getHeaders() {
|
|
74
|
+
return {
|
|
75
|
+
Authorization: `Bearer ${this.token}`,
|
|
76
|
+
Accept: "application/vnd.github+json",
|
|
77
|
+
"Content-Type": "application/json",
|
|
78
|
+
"X-GitHub-Api-Version": "2022-11-28"
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Returns headers for raw file content requests.
|
|
83
|
+
*
|
|
84
|
+
* @returns Headers with `Accept: application/vnd.github.raw+json`
|
|
85
|
+
*/
|
|
86
|
+
getRawHeaders() {
|
|
87
|
+
return {
|
|
88
|
+
...this.getHeaders(),
|
|
89
|
+
Accept: "application/vnd.github.raw+json"
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
// src/errors/GitHubApiError.ts
|
|
95
|
+
var GitHubApiError = class extends Error {
|
|
96
|
+
constructor(status, statusText) {
|
|
97
|
+
super(`GitHub API error: ${status} ${statusText}`);
|
|
98
|
+
this.name = "GitHubApiError";
|
|
99
|
+
this.status = status;
|
|
100
|
+
this.statusText = statusText;
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// src/resources/PullRequestResource.ts
|
|
105
|
+
var PullRequestResource = class {
|
|
106
|
+
/** @internal */
|
|
107
|
+
constructor(request, requestList, owner, repo, pullNumber) {
|
|
108
|
+
this.request = request;
|
|
109
|
+
this.requestList = requestList;
|
|
110
|
+
this.basePath = `/repos/${owner}/${repo}/pulls/${pullNumber}`;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Allows the resource to be awaited directly, resolving with the pull request info.
|
|
114
|
+
* Delegates to {@link PullRequestResource.get}.
|
|
115
|
+
*/
|
|
116
|
+
then(onfulfilled, onrejected) {
|
|
117
|
+
return this.get().then(onfulfilled, onrejected);
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Fetches the pull request details.
|
|
121
|
+
*
|
|
122
|
+
* `GET /repos/{owner}/{repo}/pulls/{pull_number}`
|
|
123
|
+
*
|
|
124
|
+
* @returns The pull request object
|
|
125
|
+
*/
|
|
126
|
+
async get() {
|
|
127
|
+
return this.request(this.basePath);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Fetches the commits included in this pull request.
|
|
131
|
+
*
|
|
132
|
+
* `GET /repos/{owner}/{repo}/pulls/{pull_number}/commits`
|
|
133
|
+
*
|
|
134
|
+
* @param params - Optional pagination: `per_page`, `page`
|
|
135
|
+
* @returns A paged response of commits
|
|
136
|
+
*/
|
|
137
|
+
async commits(params) {
|
|
138
|
+
return this.requestList(
|
|
139
|
+
`${this.basePath}/commits`,
|
|
140
|
+
params
|
|
141
|
+
);
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Fetches the files changed by this pull request.
|
|
145
|
+
*
|
|
146
|
+
* `GET /repos/{owner}/{repo}/pulls/{pull_number}/files`
|
|
147
|
+
*
|
|
148
|
+
* @param params - Optional pagination: `per_page`, `page`
|
|
149
|
+
* @returns A paged response of changed files
|
|
150
|
+
*/
|
|
151
|
+
async files(params) {
|
|
152
|
+
return this.requestList(
|
|
153
|
+
`${this.basePath}/files`,
|
|
154
|
+
params
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Fetches the reviews submitted on this pull request.
|
|
159
|
+
*
|
|
160
|
+
* `GET /repos/{owner}/{repo}/pulls/{pull_number}/reviews`
|
|
161
|
+
*
|
|
162
|
+
* @param params - Optional pagination: `per_page`, `page`
|
|
163
|
+
* @returns A paged response of reviews
|
|
164
|
+
*/
|
|
165
|
+
async reviews(params) {
|
|
166
|
+
return this.requestList(
|
|
167
|
+
`${this.basePath}/reviews`,
|
|
168
|
+
params
|
|
169
|
+
);
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Fetches the inline review comments on this pull request's diff.
|
|
173
|
+
*
|
|
174
|
+
* `GET /repos/{owner}/{repo}/pulls/{pull_number}/comments`
|
|
175
|
+
*
|
|
176
|
+
* @param params - Optional filters: `sort`, `direction`, `since`, `per_page`, `page`
|
|
177
|
+
* @returns A paged response of review comments
|
|
178
|
+
*/
|
|
179
|
+
async reviewComments(params) {
|
|
180
|
+
return this.requestList(
|
|
181
|
+
`${this.basePath}/comments`,
|
|
182
|
+
params
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Checks whether the pull request has been merged.
|
|
187
|
+
*
|
|
188
|
+
* `GET /repos/{owner}/{repo}/pulls/{pull_number}/merge`
|
|
189
|
+
*
|
|
190
|
+
* @returns `true` if merged (HTTP 204), `false` if not merged (HTTP 404)
|
|
191
|
+
*/
|
|
192
|
+
async isMerged() {
|
|
193
|
+
try {
|
|
194
|
+
await this.request(`${this.basePath}/merge`);
|
|
195
|
+
return true;
|
|
196
|
+
} catch {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
// src/resources/CommitResource.ts
|
|
203
|
+
var CommitResource = class {
|
|
204
|
+
/** @internal */
|
|
205
|
+
constructor(request, requestList, owner, repo, ref) {
|
|
206
|
+
this.request = request;
|
|
207
|
+
this.requestList = requestList;
|
|
208
|
+
this.basePath = `/repos/${owner}/${repo}/commits/${ref}`;
|
|
209
|
+
this.ref = ref;
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Allows the resource to be awaited directly, resolving with the commit info.
|
|
213
|
+
* Delegates to {@link CommitResource.get}.
|
|
214
|
+
*/
|
|
215
|
+
then(onfulfilled, onrejected) {
|
|
216
|
+
return this.get().then(onfulfilled, onrejected);
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* Fetches the commit details, including stats and changed files.
|
|
220
|
+
*
|
|
221
|
+
* `GET /repos/{owner}/{repo}/commits/{ref}`
|
|
222
|
+
*
|
|
223
|
+
* @returns The commit object with stats and files
|
|
224
|
+
*/
|
|
225
|
+
async get() {
|
|
226
|
+
return this.request(this.basePath);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Fetches the individual commit statuses (from CI/CD systems via the Statuses API).
|
|
230
|
+
*
|
|
231
|
+
* `GET /repos/{owner}/{repo}/statuses/{sha}`
|
|
232
|
+
*
|
|
233
|
+
* @param params - Optional pagination: `per_page`, `page`
|
|
234
|
+
* @returns A paged response of commit statuses
|
|
235
|
+
*/
|
|
236
|
+
async statuses(params) {
|
|
237
|
+
const repoPath = this.basePath.replace(`/commits/${this.ref}`, "");
|
|
238
|
+
return this.requestList(
|
|
239
|
+
`${repoPath}/statuses/${this.ref}`,
|
|
240
|
+
params
|
|
241
|
+
);
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Fetches the combined commit status — an aggregation of all statuses for this ref.
|
|
245
|
+
*
|
|
246
|
+
* `GET /repos/{owner}/{repo}/commits/{ref}/status`
|
|
247
|
+
*
|
|
248
|
+
* @returns The combined status object
|
|
249
|
+
*/
|
|
250
|
+
async combinedStatus() {
|
|
251
|
+
return this.request(`${this.basePath}/status`);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Fetches GitHub Actions check runs for this commit.
|
|
255
|
+
*
|
|
256
|
+
* `GET /repos/{owner}/{repo}/commits/{ref}/check-runs`
|
|
257
|
+
*
|
|
258
|
+
* @param params - Optional filters: `check_name`, `status`, `app_id`, `per_page`, `page`
|
|
259
|
+
* @returns A paged response of check runs
|
|
260
|
+
*/
|
|
261
|
+
async checkRuns(params) {
|
|
262
|
+
const raw = await this.request(
|
|
263
|
+
`${this.basePath}/check-runs`,
|
|
264
|
+
params
|
|
265
|
+
);
|
|
266
|
+
return {
|
|
267
|
+
values: raw.check_runs,
|
|
268
|
+
hasNextPage: false
|
|
269
|
+
};
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
// src/resources/RepositoryResource.ts
|
|
274
|
+
var RepositoryResource = class {
|
|
275
|
+
/** @internal */
|
|
276
|
+
constructor(request, requestList, requestText, owner, repo) {
|
|
277
|
+
this.request = request;
|
|
278
|
+
this.requestList = requestList;
|
|
279
|
+
this.requestText = requestText;
|
|
280
|
+
this.owner = owner;
|
|
281
|
+
this.repo = repo;
|
|
282
|
+
this.basePath = `/repos/${owner}/${repo}`;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Allows the resource to be awaited directly, resolving with the repository info.
|
|
286
|
+
* Delegates to {@link RepositoryResource.get}.
|
|
287
|
+
*/
|
|
288
|
+
then(onfulfilled, onrejected) {
|
|
289
|
+
return this.get().then(onfulfilled, onrejected);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Fetches the repository details.
|
|
293
|
+
*
|
|
294
|
+
* `GET /repos/{owner}/{repo}`
|
|
295
|
+
*
|
|
296
|
+
* @returns The repository object
|
|
297
|
+
*/
|
|
298
|
+
async get() {
|
|
299
|
+
return this.request(this.basePath);
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Fetches pull requests for this repository.
|
|
303
|
+
*
|
|
304
|
+
* `GET /repos/{owner}/{repo}/pulls`
|
|
305
|
+
*
|
|
306
|
+
* @param params - Optional filters: `state`, `head`, `base`, `sort`, `direction`, `per_page`, `page`
|
|
307
|
+
* @returns A paged response of pull requests
|
|
308
|
+
*/
|
|
309
|
+
async pullRequests(params) {
|
|
310
|
+
return this.requestList(
|
|
311
|
+
`${this.basePath}/pulls`,
|
|
312
|
+
params
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Returns a {@link PullRequestResource} for a given pull request number.
|
|
317
|
+
*
|
|
318
|
+
* The returned resource can be awaited directly to fetch pull request info,
|
|
319
|
+
* or chained to access nested resources.
|
|
320
|
+
*
|
|
321
|
+
* @param pullNumber - The pull request number (not the ID)
|
|
322
|
+
* @returns A chainable pull request resource
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```typescript
|
|
326
|
+
* const pr = await gh.org('github').repo('linguist').pullRequest(42);
|
|
327
|
+
* const files = await gh.org('github').repo('linguist').pullRequest(42).files();
|
|
328
|
+
* const reviews = await gh.org('github').repo('linguist').pullRequest(42).reviews();
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
pullRequest(pullNumber) {
|
|
332
|
+
return new PullRequestResource(
|
|
333
|
+
this.request,
|
|
334
|
+
this.requestList,
|
|
335
|
+
this.owner,
|
|
336
|
+
this.repo,
|
|
337
|
+
pullNumber
|
|
338
|
+
);
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Fetches commits for this repository.
|
|
342
|
+
*
|
|
343
|
+
* `GET /repos/{owner}/{repo}/commits`
|
|
344
|
+
*
|
|
345
|
+
* @param params - Optional filters: `sha`, `path`, `author`, `since`, `until`, `per_page`, `page`
|
|
346
|
+
* @returns A paged response of commits
|
|
347
|
+
*/
|
|
348
|
+
async commits(params) {
|
|
349
|
+
return this.requestList(
|
|
350
|
+
`${this.basePath}/commits`,
|
|
351
|
+
params
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Returns a {@link CommitResource} for a given commit ref (SHA, branch, or tag).
|
|
356
|
+
*
|
|
357
|
+
* The returned resource can be awaited directly to fetch commit info,
|
|
358
|
+
* or chained to access nested resources.
|
|
359
|
+
*
|
|
360
|
+
* @param ref - Commit SHA, branch name, or tag name
|
|
361
|
+
* @returns A chainable commit resource
|
|
362
|
+
*
|
|
363
|
+
* @example
|
|
364
|
+
* ```typescript
|
|
365
|
+
* const commit = await gh.org('github').repo('linguist').commit('abc123');
|
|
366
|
+
* const statuses = await gh.org('github').repo('linguist').commit('abc123').statuses();
|
|
367
|
+
* ```
|
|
368
|
+
*/
|
|
369
|
+
commit(ref) {
|
|
370
|
+
return new CommitResource(
|
|
371
|
+
this.request,
|
|
372
|
+
this.requestList,
|
|
373
|
+
this.owner,
|
|
374
|
+
this.repo,
|
|
375
|
+
ref
|
|
376
|
+
);
|
|
377
|
+
}
|
|
378
|
+
/**
|
|
379
|
+
* Fetches branches for this repository.
|
|
380
|
+
*
|
|
381
|
+
* `GET /repos/{owner}/{repo}/branches`
|
|
382
|
+
*
|
|
383
|
+
* @param params - Optional filters: `protected`, `per_page`, `page`
|
|
384
|
+
* @returns A paged response of branches
|
|
385
|
+
*/
|
|
386
|
+
async branches(params) {
|
|
387
|
+
return this.requestList(
|
|
388
|
+
`${this.basePath}/branches`,
|
|
389
|
+
params
|
|
390
|
+
);
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Fetches a specific branch by name.
|
|
394
|
+
*
|
|
395
|
+
* `GET /repos/{owner}/{repo}/branches/{branch}`
|
|
396
|
+
*
|
|
397
|
+
* @param name - The branch name (e.g., `'main'`)
|
|
398
|
+
* @returns The branch object
|
|
399
|
+
*/
|
|
400
|
+
async branch(name) {
|
|
401
|
+
return this.request(`${this.basePath}/branches/${encodeURIComponent(name)}`);
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Fetches tags for this repository.
|
|
405
|
+
*
|
|
406
|
+
* `GET /repos/{owner}/{repo}/tags`
|
|
407
|
+
*
|
|
408
|
+
* @param params - Optional pagination: `per_page`, `page`
|
|
409
|
+
* @returns A paged response of tags
|
|
410
|
+
*/
|
|
411
|
+
async tags(params) {
|
|
412
|
+
return this.requestList(
|
|
413
|
+
`${this.basePath}/tags`,
|
|
414
|
+
params
|
|
415
|
+
);
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Fetches releases for this repository.
|
|
419
|
+
*
|
|
420
|
+
* `GET /repos/{owner}/{repo}/releases`
|
|
421
|
+
*
|
|
422
|
+
* @param params - Optional pagination: `per_page`, `page`
|
|
423
|
+
* @returns A paged response of releases
|
|
424
|
+
*/
|
|
425
|
+
async releases(params) {
|
|
426
|
+
return this.requestList(
|
|
427
|
+
`${this.basePath}/releases`,
|
|
428
|
+
params
|
|
429
|
+
);
|
|
430
|
+
}
|
|
431
|
+
/**
|
|
432
|
+
* Fetches the latest published release for this repository.
|
|
433
|
+
*
|
|
434
|
+
* `GET /repos/{owner}/{repo}/releases/latest`
|
|
435
|
+
*
|
|
436
|
+
* @returns The latest release object
|
|
437
|
+
*/
|
|
438
|
+
async latestRelease() {
|
|
439
|
+
return this.request(`${this.basePath}/releases/latest`);
|
|
440
|
+
}
|
|
441
|
+
/**
|
|
442
|
+
* Fetches the forks of this repository.
|
|
443
|
+
*
|
|
444
|
+
* `GET /repos/{owner}/{repo}/forks`
|
|
445
|
+
*
|
|
446
|
+
* @param params - Optional filters: `sort`, `per_page`, `page`
|
|
447
|
+
* @returns A paged response of forked repositories
|
|
448
|
+
*/
|
|
449
|
+
async forks(params) {
|
|
450
|
+
return this.requestList(
|
|
451
|
+
`${this.basePath}/forks`,
|
|
452
|
+
params
|
|
453
|
+
);
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* Fetches webhooks configured on this repository.
|
|
457
|
+
*
|
|
458
|
+
* `GET /repos/{owner}/{repo}/hooks`
|
|
459
|
+
*
|
|
460
|
+
* @param params - Optional pagination: `per_page`, `page`
|
|
461
|
+
* @returns A paged response of webhooks
|
|
462
|
+
*/
|
|
463
|
+
async webhooks(params) {
|
|
464
|
+
return this.requestList(
|
|
465
|
+
`${this.basePath}/hooks`,
|
|
466
|
+
params
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Fetches the contents of a file or directory in this repository.
|
|
471
|
+
*
|
|
472
|
+
* `GET /repos/{owner}/{repo}/contents/{path}`
|
|
473
|
+
*
|
|
474
|
+
* Returns a single {@link GitHubContent} for files, or an array for directories.
|
|
475
|
+
*
|
|
476
|
+
* @param path - Path to the file or directory (e.g., `'src/index.ts'` or `'src'`). Omit for root.
|
|
477
|
+
* @param params - Optional: `ref` (branch, tag, or commit SHA)
|
|
478
|
+
* @returns File content object or array of directory entries
|
|
479
|
+
*/
|
|
480
|
+
async contents(path, params) {
|
|
481
|
+
const contentPath = path ? `${this.basePath}/contents/${path}` : `${this.basePath}/contents`;
|
|
482
|
+
return this.request(
|
|
483
|
+
contentPath,
|
|
484
|
+
params
|
|
485
|
+
);
|
|
486
|
+
}
|
|
487
|
+
/**
|
|
488
|
+
* Fetches the raw text content of a file in this repository.
|
|
489
|
+
*
|
|
490
|
+
* Uses `Accept: application/vnd.github.raw+json` to retrieve the file directly
|
|
491
|
+
* without base64 encoding.
|
|
492
|
+
*
|
|
493
|
+
* `GET /repos/{owner}/{repo}/contents/{filePath}`
|
|
494
|
+
*
|
|
495
|
+
* @param filePath - Path to the file (e.g., `'src/index.ts'`)
|
|
496
|
+
* @param params - Optional: `ref` (branch, tag, or commit SHA)
|
|
497
|
+
* @returns The raw file content as a string
|
|
498
|
+
*/
|
|
499
|
+
async raw(filePath, params) {
|
|
500
|
+
return this.requestText(
|
|
501
|
+
`${this.basePath}/contents/${filePath}`,
|
|
502
|
+
params
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Fetches the repository topics.
|
|
507
|
+
*
|
|
508
|
+
* `GET /repos/{owner}/{repo}/topics`
|
|
509
|
+
*
|
|
510
|
+
* @returns An array of topic strings
|
|
511
|
+
*/
|
|
512
|
+
async topics() {
|
|
513
|
+
const data = await this.request(`${this.basePath}/topics`);
|
|
514
|
+
return data.names;
|
|
515
|
+
}
|
|
516
|
+
/**
|
|
517
|
+
* Fetches contributors to this repository.
|
|
518
|
+
*
|
|
519
|
+
* `GET /repos/{owner}/{repo}/contributors`
|
|
520
|
+
*
|
|
521
|
+
* @param params - Optional filters: `anon` (include anonymous contributors), `per_page`, `page`
|
|
522
|
+
* @returns A paged response of contributors
|
|
523
|
+
*/
|
|
524
|
+
async contributors(params) {
|
|
525
|
+
return this.requestList(
|
|
526
|
+
`${this.basePath}/contributors`,
|
|
527
|
+
params
|
|
528
|
+
);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
// src/resources/OrganizationResource.ts
|
|
533
|
+
var OrganizationResource = class {
|
|
534
|
+
/** @internal */
|
|
535
|
+
constructor(request, requestList, requestText, org) {
|
|
536
|
+
this.request = request;
|
|
537
|
+
this.requestList = requestList;
|
|
538
|
+
this.requestText = requestText;
|
|
539
|
+
this.org = org;
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Allows the resource to be awaited directly, resolving with the organization info.
|
|
543
|
+
* Delegates to {@link OrganizationResource.get}.
|
|
544
|
+
*/
|
|
545
|
+
then(onfulfilled, onrejected) {
|
|
546
|
+
return this.get().then(onfulfilled, onrejected);
|
|
547
|
+
}
|
|
548
|
+
/**
|
|
549
|
+
* Fetches the organization details.
|
|
550
|
+
*
|
|
551
|
+
* `GET /orgs/{org}`
|
|
552
|
+
*
|
|
553
|
+
* @returns The organization object
|
|
554
|
+
*/
|
|
555
|
+
async get() {
|
|
556
|
+
return this.request(`/orgs/${this.org}`);
|
|
557
|
+
}
|
|
558
|
+
/**
|
|
559
|
+
* Fetches repositories belonging to this organization.
|
|
560
|
+
*
|
|
561
|
+
* `GET /orgs/{org}/repos`
|
|
562
|
+
*
|
|
563
|
+
* @param params - Optional filters: `type`, `sort`, `direction`, `per_page`, `page`
|
|
564
|
+
* @returns A paged response of repositories
|
|
565
|
+
*/
|
|
566
|
+
async repos(params) {
|
|
567
|
+
return this.requestList(
|
|
568
|
+
`/orgs/${this.org}/repos`,
|
|
569
|
+
params
|
|
570
|
+
);
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Returns a {@link RepositoryResource} for a given repository name within this organization.
|
|
574
|
+
*
|
|
575
|
+
* The returned resource can be awaited directly to fetch repository info,
|
|
576
|
+
* or chained to access nested resources.
|
|
577
|
+
*
|
|
578
|
+
* @param name - The repository name (e.g., `'linguist'`)
|
|
579
|
+
* @returns A chainable repository resource
|
|
580
|
+
*
|
|
581
|
+
* @example
|
|
582
|
+
* ```typescript
|
|
583
|
+
* const repo = await gh.org('github').repo('linguist');
|
|
584
|
+
* const prs = await gh.org('github').repo('linguist').pullRequests({ state: 'open' });
|
|
585
|
+
* const commits = await gh.org('github').repo('linguist').commits({ per_page: 10 });
|
|
586
|
+
* ```
|
|
587
|
+
*/
|
|
588
|
+
repo(name) {
|
|
589
|
+
return new RepositoryResource(
|
|
590
|
+
this.request,
|
|
591
|
+
this.requestList,
|
|
592
|
+
this.requestText,
|
|
593
|
+
this.org,
|
|
594
|
+
name
|
|
595
|
+
);
|
|
596
|
+
}
|
|
597
|
+
/**
|
|
598
|
+
* Fetches members of this organization.
|
|
599
|
+
*
|
|
600
|
+
* `GET /orgs/{org}/members`
|
|
601
|
+
*
|
|
602
|
+
* @param params - Optional filters: `role`, `filter`, `per_page`, `page`
|
|
603
|
+
* @returns A paged response of users
|
|
604
|
+
*/
|
|
605
|
+
async members(params) {
|
|
606
|
+
return this.requestList(
|
|
607
|
+
`/orgs/${this.org}/members`,
|
|
608
|
+
params
|
|
609
|
+
);
|
|
610
|
+
}
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
// src/resources/UserResource.ts
|
|
614
|
+
var UserResource = class {
|
|
615
|
+
/** @internal */
|
|
616
|
+
constructor(request, requestList, requestText, login) {
|
|
617
|
+
this.request = request;
|
|
618
|
+
this.requestList = requestList;
|
|
619
|
+
this.requestText = requestText;
|
|
620
|
+
this.login = login;
|
|
621
|
+
this.basePath = `/users/${login}`;
|
|
622
|
+
}
|
|
623
|
+
/**
|
|
624
|
+
* Allows the resource to be awaited directly, resolving with the user info.
|
|
625
|
+
* Delegates to {@link UserResource.get}.
|
|
626
|
+
*/
|
|
627
|
+
then(onfulfilled, onrejected) {
|
|
628
|
+
return this.get().then(onfulfilled, onrejected);
|
|
629
|
+
}
|
|
630
|
+
/**
|
|
631
|
+
* Fetches the user details.
|
|
632
|
+
*
|
|
633
|
+
* `GET /users/{username}`
|
|
634
|
+
*
|
|
635
|
+
* @returns The user object
|
|
636
|
+
*/
|
|
637
|
+
async get() {
|
|
638
|
+
return this.request(this.basePath);
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* Fetches public repositories for this user.
|
|
642
|
+
*
|
|
643
|
+
* `GET /users/{username}/repos`
|
|
644
|
+
*
|
|
645
|
+
* @param params - Optional filters: `type`, `sort`, `direction`, `per_page`, `page`
|
|
646
|
+
* @returns A paged response of repositories
|
|
647
|
+
*/
|
|
648
|
+
async repos(params) {
|
|
649
|
+
return this.requestList(
|
|
650
|
+
`${this.basePath}/repos`,
|
|
651
|
+
params
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
/**
|
|
655
|
+
* Returns a {@link RepositoryResource} for a given repository under this user,
|
|
656
|
+
* providing access to all repository sub-resources.
|
|
657
|
+
*
|
|
658
|
+
* @param name - The repository name
|
|
659
|
+
* @returns A chainable repository resource
|
|
660
|
+
*
|
|
661
|
+
* @example
|
|
662
|
+
* ```typescript
|
|
663
|
+
* const repo = await gh.user('octocat').repo('Hello-World');
|
|
664
|
+
* const content = await gh.user('octocat').repo('Hello-World').raw('README.md');
|
|
665
|
+
* ```
|
|
666
|
+
*/
|
|
667
|
+
repo(name) {
|
|
668
|
+
return new RepositoryResource(
|
|
669
|
+
this.request,
|
|
670
|
+
this.requestList,
|
|
671
|
+
this.requestText,
|
|
672
|
+
this.login,
|
|
673
|
+
name
|
|
674
|
+
);
|
|
675
|
+
}
|
|
676
|
+
/**
|
|
677
|
+
* Fetches the users this user is following.
|
|
678
|
+
*
|
|
679
|
+
* `GET /users/{username}/following`
|
|
680
|
+
*
|
|
681
|
+
* @returns A paged response of users
|
|
682
|
+
*/
|
|
683
|
+
async following(params) {
|
|
684
|
+
return this.requestList(
|
|
685
|
+
`${this.basePath}/following`,
|
|
686
|
+
params
|
|
687
|
+
);
|
|
688
|
+
}
|
|
689
|
+
/**
|
|
690
|
+
* Fetches the users following this user.
|
|
691
|
+
*
|
|
692
|
+
* `GET /users/{username}/followers`
|
|
693
|
+
*
|
|
694
|
+
* @returns A paged response of users
|
|
695
|
+
*/
|
|
696
|
+
async followers(params) {
|
|
697
|
+
return this.requestList(
|
|
698
|
+
`${this.basePath}/followers`,
|
|
699
|
+
params
|
|
700
|
+
);
|
|
701
|
+
}
|
|
702
|
+
};
|
|
703
|
+
|
|
704
|
+
// src/GitHubClient.ts
|
|
705
|
+
var GitHubClient = class {
|
|
706
|
+
/**
|
|
707
|
+
* @param options - Authentication and connection options
|
|
708
|
+
* @throws {TypeError} If `apiUrl` is not a valid URL
|
|
709
|
+
*/
|
|
710
|
+
constructor({ token, apiUrl }) {
|
|
711
|
+
this.listeners = /* @__PURE__ */ new Map();
|
|
712
|
+
this.security = new Security(token, apiUrl);
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Subscribes to a client event.
|
|
716
|
+
*
|
|
717
|
+
* @example
|
|
718
|
+
* ```typescript
|
|
719
|
+
* gh.on('request', (event) => {
|
|
720
|
+
* console.log(`${event.method} ${event.url} — ${event.durationMs}ms`);
|
|
721
|
+
* if (event.error) console.error('Request failed:', event.error);
|
|
722
|
+
* });
|
|
723
|
+
* ```
|
|
724
|
+
*/
|
|
725
|
+
on(event, callback) {
|
|
726
|
+
const callbacks = this.listeners.get(event) ?? [];
|
|
727
|
+
callbacks.push(callback);
|
|
728
|
+
this.listeners.set(event, callbacks);
|
|
729
|
+
return this;
|
|
730
|
+
}
|
|
731
|
+
emit(event, payload) {
|
|
732
|
+
const callbacks = this.listeners.get(event) ?? [];
|
|
733
|
+
for (const cb of callbacks) {
|
|
734
|
+
cb(payload);
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
/**
|
|
738
|
+
* Performs an authenticated GET request returning a single JSON object.
|
|
739
|
+
* @internal
|
|
740
|
+
*/
|
|
741
|
+
async request(path, params, options) {
|
|
742
|
+
const base = `${this.security.getApiUrl()}${path}`;
|
|
743
|
+
const url = buildUrl(base, params);
|
|
744
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
745
|
+
let statusCode;
|
|
746
|
+
try {
|
|
747
|
+
const headers = options?.headers ?? this.security.getHeaders();
|
|
748
|
+
const response = await fetch(url, { headers });
|
|
749
|
+
statusCode = response.status;
|
|
750
|
+
if (!response.ok) {
|
|
751
|
+
throw new GitHubApiError(response.status, response.statusText);
|
|
752
|
+
}
|
|
753
|
+
const data = await response.json();
|
|
754
|
+
this.emit("request", { url, method: "GET", startedAt, finishedAt: /* @__PURE__ */ new Date(), durationMs: Date.now() - startedAt.getTime(), statusCode });
|
|
755
|
+
return data;
|
|
756
|
+
} catch (err) {
|
|
757
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
758
|
+
this.emit("request", { url, method: "GET", startedAt, finishedAt, durationMs: finishedAt.getTime() - startedAt.getTime(), statusCode, error: err instanceof Error ? err : new Error(String(err)) });
|
|
759
|
+
throw err;
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Performs an authenticated GET request returning a paginated list.
|
|
764
|
+
* Parses the `Link` response header to determine if more pages exist.
|
|
765
|
+
* @internal
|
|
766
|
+
*/
|
|
767
|
+
async requestList(path, params) {
|
|
768
|
+
const base = `${this.security.getApiUrl()}${path}`;
|
|
769
|
+
const url = buildUrl(base, params);
|
|
770
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
771
|
+
let statusCode;
|
|
772
|
+
try {
|
|
773
|
+
const response = await fetch(url, { headers: this.security.getHeaders() });
|
|
774
|
+
statusCode = response.status;
|
|
775
|
+
if (!response.ok) {
|
|
776
|
+
throw new GitHubApiError(response.status, response.statusText);
|
|
777
|
+
}
|
|
778
|
+
const data = await response.json();
|
|
779
|
+
const linkHeader = response.headers.get("Link");
|
|
780
|
+
const nextPage = parseNextPage(linkHeader);
|
|
781
|
+
this.emit("request", { url, method: "GET", startedAt, finishedAt: /* @__PURE__ */ new Date(), durationMs: Date.now() - startedAt.getTime(), statusCode });
|
|
782
|
+
return {
|
|
783
|
+
values: data,
|
|
784
|
+
hasNextPage: nextPage !== void 0,
|
|
785
|
+
nextPage
|
|
786
|
+
};
|
|
787
|
+
} catch (err) {
|
|
788
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
789
|
+
this.emit("request", { url, method: "GET", startedAt, finishedAt, durationMs: finishedAt.getTime() - startedAt.getTime(), statusCode, error: err instanceof Error ? err : new Error(String(err)) });
|
|
790
|
+
throw err;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
/**
|
|
794
|
+
* Performs a GET request returning raw text content.
|
|
795
|
+
* Uses `Accept: application/vnd.github.raw+json` to retrieve file content directly.
|
|
796
|
+
* @internal
|
|
797
|
+
*/
|
|
798
|
+
async requestText(path, params) {
|
|
799
|
+
const base = `${this.security.getApiUrl()}${path}`;
|
|
800
|
+
const url = buildUrl(base, params);
|
|
801
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
802
|
+
let statusCode;
|
|
803
|
+
try {
|
|
804
|
+
const response = await fetch(url, { headers: this.security.getRawHeaders() });
|
|
805
|
+
statusCode = response.status;
|
|
806
|
+
if (!response.ok) {
|
|
807
|
+
throw new GitHubApiError(response.status, response.statusText);
|
|
808
|
+
}
|
|
809
|
+
const text = await response.text();
|
|
810
|
+
this.emit("request", { url, method: "GET", startedAt, finishedAt: /* @__PURE__ */ new Date(), durationMs: Date.now() - startedAt.getTime(), statusCode });
|
|
811
|
+
return text;
|
|
812
|
+
} catch (err) {
|
|
813
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
814
|
+
this.emit("request", { url, method: "GET", startedAt, finishedAt, durationMs: finishedAt.getTime() - startedAt.getTime(), statusCode, error: err instanceof Error ? err : new Error(String(err)) });
|
|
815
|
+
throw err;
|
|
816
|
+
}
|
|
817
|
+
}
|
|
818
|
+
makeRequestFn() {
|
|
819
|
+
return (path, params) => this.request(path, params);
|
|
820
|
+
}
|
|
821
|
+
makeRequestListFn() {
|
|
822
|
+
return (path, params) => this.requestList(path, params);
|
|
823
|
+
}
|
|
824
|
+
makeRequestTextFn() {
|
|
825
|
+
return (path, params) => this.requestText(path, params);
|
|
826
|
+
}
|
|
827
|
+
/**
|
|
828
|
+
* Fetches the authenticated user's profile.
|
|
829
|
+
*
|
|
830
|
+
* `GET /user`
|
|
831
|
+
*
|
|
832
|
+
* @returns The authenticated user object
|
|
833
|
+
*
|
|
834
|
+
* @example
|
|
835
|
+
* ```typescript
|
|
836
|
+
* const me = await gh.currentUser();
|
|
837
|
+
* console.log(me.login); // 'octocat'
|
|
838
|
+
* ```
|
|
839
|
+
*/
|
|
840
|
+
async currentUser() {
|
|
841
|
+
return this.request("/user");
|
|
842
|
+
}
|
|
843
|
+
/**
|
|
844
|
+
* Returns a {@link UserResource} for a given GitHub login, providing access
|
|
845
|
+
* to user data and their repositories.
|
|
846
|
+
*
|
|
847
|
+
* The returned resource can be awaited directly to fetch user info,
|
|
848
|
+
* or chained to access nested resources.
|
|
849
|
+
*
|
|
850
|
+
* @param login - The user's login name (e.g., `'octocat'`)
|
|
851
|
+
* @returns A chainable user resource
|
|
852
|
+
*
|
|
853
|
+
* @example
|
|
854
|
+
* ```typescript
|
|
855
|
+
* const user = await gh.user('octocat');
|
|
856
|
+
* const repos = await gh.user('octocat').repos({ sort: 'updated' });
|
|
857
|
+
* const pr = await gh.user('octocat').repo('Hello-World').pullRequest(1).files();
|
|
858
|
+
* ```
|
|
859
|
+
*/
|
|
860
|
+
user(login) {
|
|
861
|
+
return new UserResource(
|
|
862
|
+
this.makeRequestFn(),
|
|
863
|
+
this.makeRequestListFn(),
|
|
864
|
+
this.makeRequestTextFn(),
|
|
865
|
+
login
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
/**
|
|
869
|
+
* Returns an {@link OrganizationResource} for a given GitHub organization, providing
|
|
870
|
+
* access to organization data and its repositories.
|
|
871
|
+
*
|
|
872
|
+
* The returned resource can be awaited directly to fetch organization info,
|
|
873
|
+
* or chained to access nested resources.
|
|
874
|
+
*
|
|
875
|
+
* @param name - The organization's login name (e.g., `'github'`)
|
|
876
|
+
* @returns A chainable organization resource
|
|
877
|
+
*
|
|
878
|
+
* @example
|
|
879
|
+
* ```typescript
|
|
880
|
+
* const org = await gh.org('github');
|
|
881
|
+
* const repos = await gh.org('github').repos({ type: 'public' });
|
|
882
|
+
* const prs = await gh.org('github').repo('linguist').pullRequests({ state: 'open' });
|
|
883
|
+
* ```
|
|
884
|
+
*/
|
|
885
|
+
org(name) {
|
|
886
|
+
return new OrganizationResource(
|
|
887
|
+
this.makeRequestFn(),
|
|
888
|
+
this.makeRequestListFn(),
|
|
889
|
+
this.makeRequestTextFn(),
|
|
890
|
+
name
|
|
891
|
+
);
|
|
892
|
+
}
|
|
893
|
+
/**
|
|
894
|
+
* Returns a {@link RepositoryResource} for a given owner and repository name.
|
|
895
|
+
*
|
|
896
|
+
* Shortcut that works for both user repositories and organization repositories.
|
|
897
|
+
*
|
|
898
|
+
* @param owner - The owner login (user or organization)
|
|
899
|
+
* @param name - The repository name
|
|
900
|
+
* @returns A chainable repository resource
|
|
901
|
+
*
|
|
902
|
+
* @example
|
|
903
|
+
* ```typescript
|
|
904
|
+
* const repo = await gh.repo('octocat', 'Hello-World');
|
|
905
|
+
* const prs = await gh.repo('octocat', 'Hello-World').pullRequests();
|
|
906
|
+
* ```
|
|
907
|
+
*/
|
|
908
|
+
repo(owner, name) {
|
|
909
|
+
return new RepositoryResource(
|
|
910
|
+
this.makeRequestFn(),
|
|
911
|
+
this.makeRequestListFn(),
|
|
912
|
+
this.makeRequestTextFn(),
|
|
913
|
+
owner,
|
|
914
|
+
name
|
|
915
|
+
);
|
|
916
|
+
}
|
|
917
|
+
/**
|
|
918
|
+
* Searches for repositories using GitHub's search syntax.
|
|
919
|
+
*
|
|
920
|
+
* `GET /search/repositories`
|
|
921
|
+
*
|
|
922
|
+
* @param params - Search query and optional filters. `q` is required.
|
|
923
|
+
* @returns A paged response of repositories with `totalCount`
|
|
924
|
+
*
|
|
925
|
+
* @example
|
|
926
|
+
* ```typescript
|
|
927
|
+
* const results = await gh.searchRepos({ q: 'language:typescript stars:>1000', sort: 'stars' });
|
|
928
|
+
* console.log(`Found ${results.totalCount} repositories`);
|
|
929
|
+
* ```
|
|
930
|
+
*/
|
|
931
|
+
async searchRepos(params) {
|
|
932
|
+
const base = `${this.security.getApiUrl()}/search/repositories`;
|
|
933
|
+
const url = buildUrl(base, params);
|
|
934
|
+
const startedAt = /* @__PURE__ */ new Date();
|
|
935
|
+
let statusCode;
|
|
936
|
+
try {
|
|
937
|
+
const response = await fetch(url, { headers: this.security.getHeaders() });
|
|
938
|
+
statusCode = response.status;
|
|
939
|
+
if (!response.ok) {
|
|
940
|
+
throw new GitHubApiError(response.status, response.statusText);
|
|
941
|
+
}
|
|
942
|
+
const data = await response.json();
|
|
943
|
+
const linkHeader = response.headers.get("Link");
|
|
944
|
+
const nextPage = parseNextPage(linkHeader);
|
|
945
|
+
this.emit("request", { url, method: "GET", startedAt, finishedAt: /* @__PURE__ */ new Date(), durationMs: Date.now() - startedAt.getTime(), statusCode });
|
|
946
|
+
return {
|
|
947
|
+
values: data.items,
|
|
948
|
+
hasNextPage: nextPage !== void 0,
|
|
949
|
+
nextPage,
|
|
950
|
+
totalCount: data.total_count
|
|
951
|
+
};
|
|
952
|
+
} catch (err) {
|
|
953
|
+
const finishedAt = /* @__PURE__ */ new Date();
|
|
954
|
+
this.emit("request", { url, method: "GET", startedAt, finishedAt, durationMs: finishedAt.getTime() - startedAt.getTime(), statusCode, error: err instanceof Error ? err : new Error(String(err)) });
|
|
955
|
+
throw err;
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
};
|
|
959
|
+
function buildUrl(base, params) {
|
|
960
|
+
if (!params) return base;
|
|
961
|
+
const entries = Object.entries(params).filter(([, v]) => v !== void 0);
|
|
962
|
+
if (entries.length === 0) return base;
|
|
963
|
+
const search = new URLSearchParams(entries.map(([k, v]) => [k, String(v)]));
|
|
964
|
+
return `${base}?${search.toString()}`;
|
|
965
|
+
}
|
|
966
|
+
function parseNextPage(linkHeader) {
|
|
967
|
+
if (!linkHeader) return void 0;
|
|
968
|
+
const match = linkHeader.match(/<[^>]*[?&]page=(\d+)[^>]*>;\s*rel="next"/);
|
|
969
|
+
return match ? parseInt(match[1], 10) : void 0;
|
|
970
|
+
}
|
|
971
|
+
//# sourceMappingURL=index.js.map
|