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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 el_jijuna
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,371 @@
1
+ # gh-api-client
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
4
+
5
+ TypeScript client for the [GitHub REST API](https://docs.github.com/en/rest).
6
+ Works in **Node.js** and the **browser** (isomorphic). Fully typed, zero runtime dependencies.
7
+
8
+ ---
9
+
10
+ ## Installation
11
+
12
+ ```bash
13
+ npm install gh-api-client
14
+ ```
15
+
16
+ ---
17
+
18
+ ## Quick start
19
+
20
+ ```typescript
21
+ import { GitHubClient } from 'gh-api-client';
22
+
23
+ const gh = new GitHubClient({
24
+ token: 'ghp_yourPersonalAccessToken',
25
+ });
26
+ ```
27
+
28
+ For **GitHub Enterprise Server**, pass a custom `apiUrl`:
29
+
30
+ ```typescript
31
+ const gh = new GitHubClient({
32
+ token: 'ghp_yourPersonalAccessToken',
33
+ apiUrl: 'https://github.mycompany.com/api/v3',
34
+ });
35
+ ```
36
+
37
+ ---
38
+
39
+ ## API reference
40
+
41
+ ### Current user
42
+
43
+ ```typescript
44
+ const me = await gh.currentUser();
45
+ // { login: 'octocat', name: 'The Octocat', ... }
46
+ ```
47
+
48
+ ### Users
49
+
50
+ ```typescript
51
+ // Get a user's profile
52
+ const user = await gh.user('octocat');
53
+
54
+ // List a user's public repositories
55
+ const repos = await gh.user('octocat').repos();
56
+ const repos = await gh.user('octocat').repos({ sort: 'updated', per_page: 50 });
57
+
58
+ // Navigate into a user repository
59
+ const repo = await gh.user('octocat').repo('Hello-World');
60
+ const content = await gh.user('octocat').repo('Hello-World').raw('README.md');
61
+
62
+ // Followers and following
63
+ const followers = await gh.user('octocat').followers();
64
+ const following = await gh.user('octocat').following();
65
+ ```
66
+
67
+ ### Organizations
68
+
69
+ ```typescript
70
+ // Get an organization
71
+ const org = await gh.org('github');
72
+
73
+ // List an organization's repositories
74
+ const repos = await gh.org('github').repos();
75
+ const repos = await gh.org('github').repos({ type: 'public', per_page: 100 });
76
+
77
+ // List members
78
+ const members = await gh.org('github').members();
79
+ const members = await gh.org('github').members({ role: 'admin' });
80
+
81
+ // Navigate into an org repository
82
+ const repo = await gh.org('github').repo('linguist');
83
+ const prs = await gh.org('github').repo('linguist').pullRequests({ state: 'open' });
84
+ ```
85
+
86
+ ### Repositories
87
+
88
+ ```typescript
89
+ // Shortcut: access any repo by owner + name
90
+ const repo = await gh.repo('octocat', 'Hello-World');
91
+
92
+ // Repository info
93
+ const repo = await gh.repo('octocat', 'Hello-World');
94
+ // { id, name, full_name, owner, private, default_branch, ... }
95
+
96
+ // Forks
97
+ const forks = await gh.repo('octocat', 'Hello-World').forks();
98
+ const forks = await gh.repo('octocat', 'Hello-World').forks({ sort: 'newest' });
99
+
100
+ // Webhooks
101
+ const hooks = await gh.repo('octocat', 'Hello-World').webhooks();
102
+
103
+ // Topics
104
+ const topics = await gh.repo('octocat', 'Hello-World').topics();
105
+ // ['typescript', 'api-client']
106
+
107
+ // Contributors
108
+ const contributors = await gh.repo('octocat', 'Hello-World').contributors();
109
+
110
+ // Raw file content (returns string)
111
+ const content = await gh.repo('octocat', 'Hello-World').raw('README.md');
112
+ const content = await gh.repo('octocat', 'Hello-World').raw('src/index.ts', { ref: 'main' });
113
+
114
+ // File/directory contents (returns GitHubContent or GitHubContent[])
115
+ const file = await gh.repo('octocat', 'Hello-World').contents('README.md');
116
+ const dir = await gh.repo('octocat', 'Hello-World').contents('src');
117
+ const root = await gh.repo('octocat', 'Hello-World').contents();
118
+ ```
119
+
120
+ ### Branches
121
+
122
+ ```typescript
123
+ // List branches
124
+ const branches = await gh.repo('octocat', 'Hello-World').branches();
125
+ const branches = await gh.repo('octocat', 'Hello-World').branches({ protected: true });
126
+
127
+ // Get a single branch
128
+ const branch = await gh.repo('octocat', 'Hello-World').branch('main');
129
+ ```
130
+
131
+ ### Tags
132
+
133
+ ```typescript
134
+ const tags = await gh.repo('octocat', 'Hello-World').tags();
135
+ const tags = await gh.repo('octocat', 'Hello-World').tags({ per_page: 50 });
136
+ ```
137
+
138
+ ### Releases
139
+
140
+ ```typescript
141
+ // List releases
142
+ const releases = await gh.repo('octocat', 'Hello-World').releases();
143
+
144
+ // Get the latest published release
145
+ const latest = await gh.repo('octocat', 'Hello-World').latestRelease();
146
+ ```
147
+
148
+ ### Commits
149
+
150
+ ```typescript
151
+ // List commits
152
+ const commits = await gh.repo('octocat', 'Hello-World').commits();
153
+ const commits = await gh.repo('octocat', 'Hello-World').commits({
154
+ sha: 'main',
155
+ path: 'src/index.ts',
156
+ author: 'octocat',
157
+ since: '2024-01-01T00:00:00Z',
158
+ until: '2024-12-31T23:59:59Z',
159
+ });
160
+
161
+ // Get a single commit (includes stats and files)
162
+ const commit = await gh.repo('octocat', 'Hello-World').commit('abc123def456');
163
+
164
+ // Commit statuses (from external CI/CD via Statuses API)
165
+ const statuses = await gh.repo('octocat', 'Hello-World').commit('abc123').statuses();
166
+
167
+ // Combined status (aggregate of all statuses)
168
+ const combined = await gh.repo('octocat', 'Hello-World').commit('abc123').combinedStatus();
169
+ // { state: 'success', total_count: 3, statuses: [...] }
170
+
171
+ // GitHub Actions check runs
172
+ const checks = await gh.repo('octocat', 'Hello-World').commit('abc123').checkRuns();
173
+ const checks = await gh.repo('octocat', 'Hello-World').commit('abc123').checkRuns({ status: 'completed' });
174
+ ```
175
+
176
+ ### Pull requests
177
+
178
+ ```typescript
179
+ // List pull requests
180
+ const prs = await gh.repo('octocat', 'Hello-World').pullRequests();
181
+ const prs = await gh.repo('octocat', 'Hello-World').pullRequests({
182
+ state: 'open',
183
+ base: 'main',
184
+ sort: 'updated',
185
+ direction: 'desc',
186
+ per_page: 50,
187
+ });
188
+
189
+ // Get a single pull request
190
+ const pr = await gh.repo('octocat', 'Hello-World').pullRequest(42);
191
+
192
+ // Commits in the PR
193
+ const commits = await gh.repo('octocat', 'Hello-World').pullRequest(42).commits();
194
+
195
+ // Changed files
196
+ const files = await gh.repo('octocat', 'Hello-World').pullRequest(42).files();
197
+
198
+ // Reviews
199
+ const reviews = await gh.repo('octocat', 'Hello-World').pullRequest(42).reviews();
200
+
201
+ // Inline review comments (diff comments)
202
+ const comments = await gh.repo('octocat', 'Hello-World').pullRequest(42).reviewComments();
203
+
204
+ // Check if merged
205
+ const merged = await gh.repo('octocat', 'Hello-World').pullRequest(42).isMerged();
206
+ // true | false
207
+ ```
208
+
209
+ ### Repository search
210
+
211
+ ```typescript
212
+ // Search repositories using GitHub's search syntax
213
+ const results = await gh.searchRepos({ q: 'language:typescript stars:>1000' });
214
+ const results = await gh.searchRepos({ q: 'user:octocat', sort: 'stars', order: 'desc' });
215
+
216
+ console.log(`Found ${results.totalCount} repositories`);
217
+ results.values; // GitHubRepository[]
218
+ ```
219
+
220
+ ---
221
+
222
+ ## Pagination
223
+
224
+ Every list method returns a `GitHubPagedResponse<T>`:
225
+
226
+ ```typescript
227
+ const page = await gh.repo('octocat', 'Hello-World').commits({ per_page: 30 });
228
+
229
+ page.values // GitHubCommit[] — the items on this page
230
+ page.hasNextPage // boolean
231
+ page.nextPage // number | undefined — pass as `page` to get the next page
232
+ page.totalCount // number | undefined — only available on search endpoints
233
+ ```
234
+
235
+ Iterate all pages:
236
+
237
+ ```typescript
238
+ let page = 1;
239
+ let hasMore = true;
240
+
241
+ while (hasMore) {
242
+ const res = await gh.repo('octocat', 'Hello-World').commits({ per_page: 100, page });
243
+ process(res.values);
244
+ hasMore = res.hasNextPage;
245
+ page = res.nextPage ?? page + 1;
246
+ }
247
+ ```
248
+
249
+ ---
250
+
251
+ ## Request events
252
+
253
+ Subscribe to every HTTP request made by the client for logging, monitoring, or debugging:
254
+
255
+ ```typescript
256
+ gh.on('request', (event) => {
257
+ console.log(`[${event.method}] ${event.url} → ${event.statusCode} (${event.durationMs}ms)`);
258
+ if (event.error) {
259
+ console.error('Request failed:', event.error.message);
260
+ }
261
+ });
262
+ ```
263
+
264
+ The `event` object contains:
265
+
266
+ | Field | Type | Description |
267
+ |---|---|---|
268
+ | `url` | `string` | Full URL that was requested |
269
+ | `method` | `'GET'` | HTTP method used |
270
+ | `startedAt` | `Date` | When the request started |
271
+ | `finishedAt` | `Date` | When the request finished |
272
+ | `durationMs` | `number` | Duration in milliseconds |
273
+ | `statusCode` | `number \| undefined` | HTTP status code, if a response was received |
274
+ | `error` | `Error \| undefined` | Present only if the request failed |
275
+
276
+ Multiple listeners can be registered. `on()` returns `this` for chaining.
277
+
278
+ ---
279
+
280
+ ## Error handling
281
+
282
+ Non-2xx responses throw a `GitHubApiError` with the HTTP status code and status text:
283
+
284
+ ```typescript
285
+ import { GitHubApiError } from 'gh-api-client';
286
+
287
+ try {
288
+ await gh.repo('octocat', 'nonexistent-repo');
289
+ } catch (err) {
290
+ if (err instanceof GitHubApiError) {
291
+ console.log(err.status); // 404
292
+ console.log(err.statusText); // 'Not Found'
293
+ console.log(err.message); // 'GitHub API error: 404 Not Found'
294
+ console.log(err.stack); // full stack trace
295
+ }
296
+ }
297
+ ```
298
+
299
+ ---
300
+
301
+ ## Chainable resource pattern
302
+
303
+ Every resource that maps to a single entity implements `PromiseLike`, so you can **await it directly** or **chain methods** to access sub-resources:
304
+
305
+ ```typescript
306
+ // Await directly → fetches the resource
307
+ const user = await gh.user('octocat');
308
+ const repo = await gh.repo('octocat', 'Hello-World');
309
+ const pr = await gh.repo('octocat', 'Hello-World').pullRequest(42);
310
+
311
+ // Chain → access sub-resources without awaiting intermediate objects
312
+ const repos = await gh.user('octocat').repos({ sort: 'updated' });
313
+ const commits = await gh.repo('octocat', 'Hello-World').pullRequest(42).commits();
314
+ const statuses = await gh.org('github').repo('linguist').commit('abc123').statuses();
315
+ ```
316
+
317
+ ---
318
+
319
+ ## Authentication
320
+
321
+ The client uses **Bearer token authentication**. Supported token types:
322
+
323
+ - **Personal Access Token (PAT)** — generate at GitHub → Settings → Developer settings → Personal access tokens
324
+ - **Fine-grained PAT** — recommended for scoped access
325
+ - **OAuth token** — from an OAuth App
326
+ - **GitHub App installation token** — for GitHub App integrations
327
+
328
+ ```typescript
329
+ const gh = new GitHubClient({ token: 'ghp_yourToken' });
330
+ ```
331
+
332
+ ---
333
+
334
+ ## TypeScript types
335
+
336
+ All domain types are exported:
337
+
338
+ ```typescript
339
+ import type {
340
+ // Pagination
341
+ GitHubPagedResponse, PaginationParams,
342
+ // Client
343
+ GitHubClientOptions, RequestEvent, GitHubClientEvents,
344
+ // Users & Orgs
345
+ GitHubUser, UsersParams, SearchUsersParams,
346
+ GitHubOrganization, OrgMembersParams,
347
+ // Repositories
348
+ GitHubRepository, ReposParams, ForksParams, SearchReposParams,
349
+ // Pull Requests
350
+ GitHubPullRequest, GitHubRef, GitHubLabel, GitHubMilestone, PullRequestsParams,
351
+ GitHubReview, GitHubReviewComment, ReviewsParams, ReviewCommentsParams,
352
+ GitHubPullRequestFile, PullRequestFilesParams,
353
+ // Commits
354
+ GitHubCommit, GitHubCommitFile, CommitsParams,
355
+ GitHubCommitStatus, GitHubCombinedStatus, GitHubCheckRun,
356
+ CommitStatusesParams, CheckRunsParams,
357
+ // Branches, Tags, Releases
358
+ GitHubBranch, BranchesParams,
359
+ GitHubTag, TagsParams,
360
+ GitHubRelease, GitHubReleaseAsset, ReleasesParams,
361
+ // Webhooks & Content
362
+ GitHubWebhook, WebhooksParams,
363
+ GitHubContent, ContentParams,
364
+ } from 'gh-api-client';
365
+ ```
366
+
367
+ ---
368
+
369
+ ## License
370
+
371
+ [MIT](LICENSE)