chub-dev 0.1.0 → 0.1.2-beta.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.
Files changed (139) hide show
  1. package/README.md +55 -0
  2. package/bin/chub-mcp +2 -0
  3. package/dist/airtable/docs/database/javascript/DOC.md +1437 -0
  4. package/dist/airtable/docs/database/python/DOC.md +1735 -0
  5. package/dist/amplitude/docs/analytics/javascript/DOC.md +1282 -0
  6. package/dist/amplitude/docs/analytics/python/DOC.md +1199 -0
  7. package/dist/anthropic/docs/claude-api/javascript/DOC.md +503 -0
  8. package/dist/anthropic/docs/claude-api/python/DOC.md +389 -0
  9. package/dist/asana/docs/tasks/DOC.md +1396 -0
  10. package/dist/assemblyai/docs/transcription/DOC.md +1043 -0
  11. package/dist/atlassian/docs/confluence/javascript/DOC.md +1347 -0
  12. package/dist/atlassian/docs/confluence/python/DOC.md +1604 -0
  13. package/dist/auth0/docs/identity/javascript/DOC.md +968 -0
  14. package/dist/auth0/docs/identity/python/DOC.md +1199 -0
  15. package/dist/aws/docs/s3/javascript/DOC.md +1773 -0
  16. package/dist/aws/docs/s3/python/DOC.md +1807 -0
  17. package/dist/binance/docs/trading/javascript/DOC.md +1315 -0
  18. package/dist/binance/docs/trading/python/DOC.md +1454 -0
  19. package/dist/braintree/docs/gateway/javascript/DOC.md +1278 -0
  20. package/dist/braintree/docs/gateway/python/DOC.md +1179 -0
  21. package/dist/chromadb/docs/embeddings-db/javascript/DOC.md +1263 -0
  22. package/dist/chromadb/docs/embeddings-db/python/DOC.md +1707 -0
  23. package/dist/clerk/docs/auth/javascript/DOC.md +1220 -0
  24. package/dist/clerk/docs/auth/python/DOC.md +274 -0
  25. package/dist/cloudflare/docs/workers/javascript/DOC.md +918 -0
  26. package/dist/cloudflare/docs/workers/python/DOC.md +994 -0
  27. package/dist/cockroachdb/docs/distributed-db/DOC.md +1500 -0
  28. package/dist/cohere/docs/llm/DOC.md +1335 -0
  29. package/dist/datadog/docs/monitoring/javascript/DOC.md +1740 -0
  30. package/dist/datadog/docs/monitoring/python/DOC.md +1815 -0
  31. package/dist/deepgram/docs/speech/javascript/DOC.md +885 -0
  32. package/dist/deepgram/docs/speech/python/DOC.md +685 -0
  33. package/dist/deepl/docs/translation/javascript/DOC.md +887 -0
  34. package/dist/deepl/docs/translation/python/DOC.md +944 -0
  35. package/dist/deepseek/docs/llm/DOC.md +1220 -0
  36. package/dist/directus/docs/headless-cms/javascript/DOC.md +1128 -0
  37. package/dist/directus/docs/headless-cms/python/DOC.md +1276 -0
  38. package/dist/discord/docs/bot/javascript/DOC.md +1090 -0
  39. package/dist/discord/docs/bot/python/DOC.md +1130 -0
  40. package/dist/elasticsearch/docs/search/DOC.md +1634 -0
  41. package/dist/elevenlabs/docs/text-to-speech/javascript/DOC.md +336 -0
  42. package/dist/elevenlabs/docs/text-to-speech/python/DOC.md +552 -0
  43. package/dist/firebase/docs/auth/DOC.md +1015 -0
  44. package/dist/gemini/docs/genai/javascript/DOC.md +691 -0
  45. package/dist/gemini/docs/genai/python/DOC.md +555 -0
  46. package/dist/github/docs/octokit/DOC.md +1560 -0
  47. package/dist/google/docs/bigquery/javascript/DOC.md +1688 -0
  48. package/dist/google/docs/bigquery/python/DOC.md +1503 -0
  49. package/dist/hubspot/docs/crm/javascript/DOC.md +1805 -0
  50. package/dist/hubspot/docs/crm/python/DOC.md +2033 -0
  51. package/dist/huggingface/docs/transformers/DOC.md +948 -0
  52. package/dist/intercom/docs/messaging/javascript/DOC.md +1844 -0
  53. package/dist/intercom/docs/messaging/python/DOC.md +1797 -0
  54. package/dist/jira/docs/issues/javascript/DOC.md +1420 -0
  55. package/dist/jira/docs/issues/python/DOC.md +1492 -0
  56. package/dist/kafka/docs/streaming/javascript/DOC.md +1671 -0
  57. package/dist/kafka/docs/streaming/python/DOC.md +1464 -0
  58. package/dist/landingai-ade/docs/api/DOC.md +620 -0
  59. package/dist/landingai-ade/docs/sdk/python/DOC.md +489 -0
  60. package/dist/landingai-ade/docs/sdk/typescript/DOC.md +542 -0
  61. package/dist/landingai-ade/skills/SKILL.md +489 -0
  62. package/dist/launchdarkly/docs/feature-flags/javascript/DOC.md +1191 -0
  63. package/dist/launchdarkly/docs/feature-flags/python/DOC.md +1671 -0
  64. package/dist/linear/docs/tracker/DOC.md +1554 -0
  65. package/dist/livekit/docs/realtime/javascript/DOC.md +303 -0
  66. package/dist/livekit/docs/realtime/python/DOC.md +163 -0
  67. package/dist/mailchimp/docs/marketing/DOC.md +1420 -0
  68. package/dist/meilisearch/docs/search/DOC.md +1241 -0
  69. package/dist/microsoft/docs/onedrive/javascript/DOC.md +1421 -0
  70. package/dist/microsoft/docs/onedrive/python/DOC.md +1549 -0
  71. package/dist/mongodb/docs/atlas/DOC.md +2041 -0
  72. package/dist/notion/docs/workspace-api/javascript/DOC.md +1435 -0
  73. package/dist/notion/docs/workspace-api/python/DOC.md +1400 -0
  74. package/dist/okta/docs/identity/javascript/DOC.md +1171 -0
  75. package/dist/okta/docs/identity/python/DOC.md +1401 -0
  76. package/dist/openai/docs/chat/javascript/DOC.md +407 -0
  77. package/dist/openai/docs/chat/python/DOC.md +568 -0
  78. package/dist/paypal/docs/checkout/DOC.md +278 -0
  79. package/dist/pinecone/docs/sdk/javascript/DOC.md +984 -0
  80. package/dist/pinecone/docs/sdk/python/DOC.md +1395 -0
  81. package/dist/plaid/docs/banking/javascript/DOC.md +1163 -0
  82. package/dist/plaid/docs/banking/python/DOC.md +1203 -0
  83. package/dist/playwright-community/skills/login-flows/SKILL.md +108 -0
  84. package/dist/postmark/docs/transactional-email/DOC.md +1168 -0
  85. package/dist/prisma/docs/orm/javascript/DOC.md +1419 -0
  86. package/dist/prisma/docs/orm/python/DOC.md +1317 -0
  87. package/dist/qdrant/docs/vector-search/javascript/DOC.md +1221 -0
  88. package/dist/qdrant/docs/vector-search/python/DOC.md +1653 -0
  89. package/dist/rabbitmq/docs/message-queue/javascript/DOC.md +1193 -0
  90. package/dist/rabbitmq/docs/message-queue/python/DOC.md +1243 -0
  91. package/dist/razorpay/docs/payments/javascript/DOC.md +1219 -0
  92. package/dist/razorpay/docs/payments/python/DOC.md +1330 -0
  93. package/dist/redis/docs/key-value/javascript/DOC.md +1851 -0
  94. package/dist/redis/docs/key-value/python/DOC.md +2054 -0
  95. package/dist/registry.json +2817 -0
  96. package/dist/replicate/docs/model-hosting/DOC.md +1318 -0
  97. package/dist/resend/docs/email/DOC.md +1271 -0
  98. package/dist/salesforce/docs/crm/javascript/DOC.md +1241 -0
  99. package/dist/salesforce/docs/crm/python/DOC.md +1183 -0
  100. package/dist/search-index.json +1 -0
  101. package/dist/sendgrid/docs/email-api/javascript/DOC.md +371 -0
  102. package/dist/sendgrid/docs/email-api/python/DOC.md +656 -0
  103. package/dist/sentry/docs/error-tracking/javascript/DOC.md +1073 -0
  104. package/dist/sentry/docs/error-tracking/python/DOC.md +1309 -0
  105. package/dist/shopify/docs/storefront/DOC.md +457 -0
  106. package/dist/slack/docs/workspace/javascript/DOC.md +933 -0
  107. package/dist/slack/docs/workspace/python/DOC.md +271 -0
  108. package/dist/square/docs/payments/javascript/DOC.md +1855 -0
  109. package/dist/square/docs/payments/python/DOC.md +1728 -0
  110. package/dist/stripe/docs/api/DOC.md +1727 -0
  111. package/dist/stripe/docs/payments/DOC.md +1726 -0
  112. package/dist/stytch/docs/auth/javascript/DOC.md +1813 -0
  113. package/dist/stytch/docs/auth/python/DOC.md +1962 -0
  114. package/dist/supabase/docs/client/DOC.md +1606 -0
  115. package/dist/twilio/docs/messaging/python/DOC.md +469 -0
  116. package/dist/twilio/docs/messaging/typescript/DOC.md +946 -0
  117. package/dist/vercel/docs/platform/DOC.md +1940 -0
  118. package/dist/weaviate/docs/vector-db/javascript/DOC.md +1268 -0
  119. package/dist/weaviate/docs/vector-db/python/DOC.md +1388 -0
  120. package/dist/zendesk/docs/support/javascript/DOC.md +2150 -0
  121. package/dist/zendesk/docs/support/python/DOC.md +2297 -0
  122. package/package.json +22 -6
  123. package/skills/get-api-docs/SKILL.md +84 -0
  124. package/src/commands/annotate.js +83 -0
  125. package/src/commands/build.js +12 -1
  126. package/src/commands/feedback.js +150 -0
  127. package/src/commands/get.js +83 -42
  128. package/src/commands/search.js +7 -0
  129. package/src/index.js +43 -17
  130. package/src/lib/analytics.js +90 -0
  131. package/src/lib/annotations.js +57 -0
  132. package/src/lib/bm25.js +170 -0
  133. package/src/lib/cache.js +69 -6
  134. package/src/lib/config.js +8 -3
  135. package/src/lib/identity.js +99 -0
  136. package/src/lib/registry.js +103 -20
  137. package/src/lib/telemetry.js +86 -0
  138. package/src/mcp/server.js +177 -0
  139. package/src/mcp/tools.js +251 -0
@@ -0,0 +1,1560 @@
1
+ ---
2
+ name: octokit
3
+ description: "Official GitHub SDK for JavaScript providing REST API, GraphQL API, authentication, and App support via Octokit packages."
4
+ metadata:
5
+ languages: "javascript"
6
+ versions: "5.0.5"
7
+ updated-on: "2026-03-01"
8
+ source: maintainer
9
+ tags: "github,octokit,rest,graphql,api"
10
+ ---
11
+
12
+ # GitHub Octokit.js SDK Coding Guide
13
+
14
+ ## 1. Golden Rule
15
+
16
+ **Always use the official Octokit packages from GitHub.** The main `octokit` package is recommended for most use cases as it includes REST API, GraphQL API, authentication, App support, and recommended plugins out of the box.
17
+
18
+ **Never use deprecated or unofficial GitHub API libraries.**
19
+
20
+ To view available Octokit packages and their details:
21
+ ```bash
22
+ npm view octokit
23
+ npm view @octokit/core
24
+ npm view @octokit/rest
25
+ npm view @octokit/graphql
26
+ ```
27
+
28
+ ## 2. Installation
29
+
30
+ ```bash
31
+ npm install octokit
32
+ # Or: yarn add octokit
33
+ # Or: pnpm add octokit
34
+ ```
35
+
36
+ For specific components, use `@octokit/rest`, `@octokit/graphql`, or `@octokit/core`.
37
+
38
+ **Environment Variables:**
39
+ ```bash
40
+ # Personal Access Token (classic or fine-grained)
41
+ GITHUB_TOKEN=ghp_xxxxxxxxxxxxxxxxxxxx
42
+
43
+ # For GitHub Apps
44
+ GITHUB_APP_ID=123456
45
+ GITHUB_PRIVATE_KEY="-----BEGIN RSA PRIVATE KEY-----\n..."
46
+ GITHUB_INSTALLATION_ID=789012
47
+
48
+ # For OAuth Apps
49
+ GITHUB_CLIENT_ID=Iv1.xxxxxxxxxxxx
50
+ GITHUB_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxx
51
+
52
+ # GitHub Enterprise Server (optional)
53
+ GITHUB_API_URL=https://github.mycompany.com/api/v3
54
+ ```
55
+
56
+ ## 3. Initialization
57
+
58
+ ### Basic Authentication with Personal Access Token
59
+ ```javascript
60
+ import { Octokit } from "octokit";
61
+
62
+ // Using environment variable
63
+ const octokit = new Octokit({
64
+ auth: process.env.GITHUB_TOKEN
65
+ });
66
+
67
+ // Or explicit token
68
+ const octokit = new Octokit({
69
+ auth: "ghp_xxxxxxxxxxxxxxxxxxxx"
70
+ });
71
+ ```
72
+
73
+ ### Unauthenticated Requests
74
+ ```javascript
75
+ import { Octokit } from "octokit";
76
+
77
+ // Lower rate limits (60 requests/hour)
78
+ const octokit = new Octokit();
79
+ ```
80
+
81
+ ### GitHub App Authentication
82
+ ```javascript
83
+ import { Octokit } from "octokit";
84
+ import { createAppAuth } from "@octokit/auth-app";
85
+
86
+ const octokit = new Octokit({
87
+ authStrategy: createAppAuth,
88
+ auth: {
89
+ appId: process.env.GITHUB_APP_ID,
90
+ privateKey: process.env.GITHUB_PRIVATE_KEY,
91
+ installationId: process.env.GITHUB_INSTALLATION_ID
92
+ }
93
+ });
94
+ ```
95
+
96
+ ### OAuth App Authentication
97
+ ```javascript
98
+ import { Octokit } from "octokit";
99
+ import { createOAuthAppAuth } from "@octokit/auth-oauth-app";
100
+
101
+ const octokit = new Octokit({
102
+ authStrategy: createOAuthAppAuth,
103
+ auth: {
104
+ clientId: process.env.GITHUB_CLIENT_ID,
105
+ clientSecret: process.env.GITHUB_CLIENT_SECRET
106
+ }
107
+ });
108
+ ```
109
+
110
+ ### GitHub Actions Authentication
111
+ ```javascript
112
+ import { Octokit } from "octokit";
113
+
114
+ // In GitHub Actions, use the built-in token
115
+ const octokit = new Octokit({
116
+ auth: process.env.GITHUB_TOKEN // Available in all workflows
117
+ });
118
+ ```
119
+
120
+ ### GitHub Enterprise Server
121
+ ```javascript
122
+ import { Octokit } from "octokit";
123
+
124
+ const octokit = new Octokit({
125
+ auth: process.env.GITHUB_TOKEN,
126
+ baseUrl: "https://github.mycompany.com/api/v3"
127
+ });
128
+ ```
129
+
130
+ ## 4. Core API Surfaces
131
+
132
+ ### Repositories
133
+
134
+ **Minimal Example - Get Repository:**
135
+ ```javascript
136
+ const { data: repo } = await octokit.rest.repos.get({
137
+ owner: "octokit",
138
+ repo: "rest.js"
139
+ });
140
+ ```
141
+
142
+ **Advanced Example - Create Repository:**
143
+ ```javascript
144
+ const { data: newRepo } = await octokit.rest.repos.createForAuthenticatedUser({
145
+ name: "my-new-repo",
146
+ description: "Created via Octokit",
147
+ private: false,
148
+ auto_init: true,
149
+ gitignore_template: "Node",
150
+ license_template: "mit",
151
+ homepage: "https://example.com",
152
+ has_issues: true,
153
+ has_projects: true,
154
+ has_wiki: true
155
+ });
156
+ ```
157
+
158
+ **List User Repositories:**
159
+
160
+ To view available methods and parameters:
161
+ ```bash
162
+ npm view @octokit/plugin-rest-endpoint-methods
163
+ ```
164
+
165
+ ```javascript
166
+ const { data: repos } = await octokit.rest.repos.listForAuthenticatedUser({
167
+ sort: "updated",
168
+ direction: "desc",
169
+ per_page: 100
170
+ });
171
+ ```
172
+
173
+ **Update Repository:**
174
+ ```javascript
175
+ const { data: updated } = await octokit.rest.repos.update({
176
+ owner: "username",
177
+ repo: "repo-name",
178
+ description: "New description",
179
+ homepage: "https://newsite.com",
180
+ has_issues: false
181
+ });
182
+ ```
183
+
184
+ ### Issues
185
+
186
+ **Minimal Example - List Issues:**
187
+
188
+ For CLI alternative: `gh issue list --repo owner/repo`
189
+
190
+ ```javascript
191
+ const { data: issues } = await octokit.rest.issues.listForRepo({
192
+ owner: "facebook",
193
+ repo: "react"
194
+ });
195
+ ```
196
+
197
+ **Advanced Example - Create Issue with Labels:**
198
+ ```javascript
199
+ const { data: issue } = await octokit.rest.issues.create({
200
+ owner: "owner",
201
+ repo: "repo",
202
+ title: "Bug: Application crashes on startup",
203
+ body: `## Description
204
+ Detailed description of the issue...
205
+
206
+ ## Steps to Reproduce
207
+ 1. Step 1
208
+ 2. Step 2
209
+
210
+ ## Expected Behavior
211
+ What should happen
212
+
213
+ ## Actual Behavior
214
+ What actually happens`,
215
+ labels: ["bug", "high-priority"],
216
+ assignees: ["username1", "username2"],
217
+ milestone: 1
218
+ });
219
+ ```
220
+
221
+ **Update Issue:**
222
+ ```javascript
223
+ const { data: updated } = await octokit.rest.issues.update({
224
+ owner: "owner",
225
+ repo: "repo",
226
+ issue_number: 123,
227
+ state: "closed",
228
+ state_reason: "completed",
229
+ labels: ["resolved"]
230
+ });
231
+ ```
232
+
233
+ **Add Comment:**
234
+ ```javascript
235
+ const { data: comment } = await octokit.rest.issues.createComment({
236
+ owner: "owner",
237
+ repo: "repo",
238
+ issue_number: 123,
239
+ body: "Thanks for reporting! This has been fixed in v2.0.0"
240
+ });
241
+ ```
242
+
243
+ ### Pull Requests
244
+
245
+ **Minimal Example - List Pull Requests:**
246
+
247
+ For CLI alternative: `gh pr list --repo owner/repo --state open`
248
+
249
+ ```javascript
250
+ const { data: pulls } = await octokit.rest.pulls.list({
251
+ owner: "microsoft",
252
+ repo: "vscode",
253
+ state: "open"
254
+ });
255
+ ```
256
+
257
+ **Advanced Example - Create Pull Request:**
258
+ ```javascript
259
+ const { data: pr } = await octokit.rest.pulls.create({
260
+ owner: "owner",
261
+ repo: "repo",
262
+ title: "Add new feature",
263
+ head: "feature-branch",
264
+ base: "main",
265
+ body: "Detailed description of changes in this pull request.",
266
+ maintainer_can_modify: true,
267
+ draft: false
268
+ });
269
+ ```
270
+
271
+ **Get Pull Request Files:**
272
+ ```javascript
273
+ const { data: files } = await octokit.rest.pulls.listFiles({
274
+ owner: "owner",
275
+ repo: "repo",
276
+ pull_number: 123
277
+ });
278
+ ```
279
+
280
+ **Merge Pull Request:**
281
+ ```javascript
282
+ const { data: merge } = await octokit.rest.pulls.merge({
283
+ owner: "owner",
284
+ repo: "repo",
285
+ pull_number: 123,
286
+ commit_title: "Merge PR #123: Add new feature",
287
+ commit_message: "Additional details about the merge",
288
+ merge_method: "squash" // or "merge" or "rebase"
289
+ });
290
+ ```
291
+
292
+ **Request Reviewers:**
293
+ ```javascript
294
+ await octokit.rest.pulls.requestReviewers({
295
+ owner: "owner",
296
+ repo: "repo",
297
+ pull_number: 123,
298
+ reviewers: ["reviewer1", "reviewer2"],
299
+ team_reviewers: ["team-slug"]
300
+ });
301
+ ```
302
+
303
+ ### Commits
304
+
305
+ **Minimal Example - Get Commit:**
306
+ ```javascript
307
+ const { data: commit } = await octokit.rest.repos.getCommit({
308
+ owner: "owner",
309
+ repo: "repo",
310
+ ref: "abc123"
311
+ });
312
+ ```
313
+
314
+ **Advanced Example - List Commits with Filtering:**
315
+ ```javascript
316
+ const { data: commits } = await octokit.rest.repos.listCommits({
317
+ owner: "owner",
318
+ repo: "repo",
319
+ sha: "main",
320
+ path: "src/index.js",
321
+ author: "username",
322
+ since: "2025-01-01T00:00:00Z",
323
+ until: "2025-12-31T23:59:59Z",
324
+ per_page: 100
325
+ });
326
+ ```
327
+
328
+ **Compare Commits:**
329
+ ```javascript
330
+ const { data: comparison } = await octokit.rest.repos.compareCommits({
331
+ owner: "owner",
332
+ repo: "repo",
333
+ base: "main",
334
+ head: "feature-branch"
335
+ });
336
+ ```
337
+
338
+ ### Branches
339
+
340
+ **List Branches:**
341
+
342
+ For CLI alternative: `gh api repos/owner/repo/branches` or `git branch -r`
343
+
344
+ ```javascript
345
+ const { data: branches } = await octokit.rest.repos.listBranches({
346
+ owner: "owner",
347
+ repo: "repo"
348
+ });
349
+ ```
350
+
351
+ **Get Branch:**
352
+ ```javascript
353
+ const { data: branch } = await octokit.rest.repos.getBranch({
354
+ owner: "owner",
355
+ repo: "repo",
356
+ branch: "main"
357
+ });
358
+ ```
359
+
360
+ **Create Branch (via Git References):**
361
+ ```javascript
362
+ // First, get the SHA of the source branch
363
+ const { data: refData } = await octokit.rest.git.getRef({
364
+ owner: "owner",
365
+ repo: "repo",
366
+ ref: "heads/main"
367
+ });
368
+
369
+ // Create new branch from that SHA
370
+ await octokit.rest.git.createRef({
371
+ owner: "owner",
372
+ repo: "repo",
373
+ ref: "refs/heads/new-feature",
374
+ sha: refData.object.sha
375
+ });
376
+ ```
377
+
378
+ ### Files and Content
379
+
380
+ **Minimal Example - Get File Content:**
381
+ ```javascript
382
+ const { data: file } = await octokit.rest.repos.getContent({
383
+ owner: "owner",
384
+ repo: "repo",
385
+ path: "README.md"
386
+ });
387
+
388
+ // Decode base64 content
389
+ const content = Buffer.from(file.content, "base64").toString("utf8");
390
+ console.log(content);
391
+ ```
392
+
393
+ **Advanced Example - Create or Update File:**
394
+ ```javascript
395
+ // Get current file to retrieve SHA (required for updates)
396
+ let sha;
397
+ try {
398
+ const { data: existing } = await octokit.rest.repos.getContent({
399
+ owner: "owner",
400
+ repo: "repo",
401
+ path: "config.json"
402
+ });
403
+ sha = existing.sha;
404
+ } catch (error) {
405
+ // File doesn't exist, will create new
406
+ }
407
+
408
+ const content = JSON.stringify({ version: "2.0.0" }, null, 2);
409
+ const { data: result } = await octokit.rest.repos.createOrUpdateFileContents({
410
+ owner: "owner",
411
+ repo: "repo",
412
+ path: "config.json",
413
+ message: "Update config version to 2.0.0",
414
+ content: Buffer.from(content).toString("base64"),
415
+ sha: sha, // Required for updates, omit for new files
416
+ branch: "main",
417
+ committer: {
418
+ name: "Bot Name",
419
+ email: "bot@example.com"
420
+ },
421
+ author: {
422
+ name: "Author Name",
423
+ email: "author@example.com"
424
+ }
425
+ });
426
+
427
+ console.log(`File updated: ${result.content.html_url}`);
428
+ ```
429
+
430
+ **Delete File:**
431
+ ```javascript
432
+ // Get file SHA first
433
+ const { data: file } = await octokit.rest.repos.getContent({
434
+ owner: "owner",
435
+ repo: "repo",
436
+ path: "file-to-delete.txt"
437
+ });
438
+
439
+ await octokit.rest.repos.deleteFile({
440
+ owner: "owner",
441
+ repo: "repo",
442
+ path: "file-to-delete.txt",
443
+ message: "Remove obsolete file",
444
+ sha: file.sha,
445
+ branch: "main"
446
+ });
447
+ ```
448
+
449
+ ### Releases
450
+
451
+ **Minimal Example - List Releases:**
452
+
453
+ For CLI alternative: `gh release list --repo owner/repo`
454
+
455
+ ```javascript
456
+ const { data: releases } = await octokit.rest.repos.listReleases({
457
+ owner: "owner",
458
+ repo: "repo"
459
+ });
460
+ ```
461
+
462
+ **Advanced Example - Create Release:**
463
+ ```javascript
464
+ const { data: release } = await octokit.rest.repos.createRelease({
465
+ owner: "owner",
466
+ repo: "repo",
467
+ tag_name: "v2.0.0",
468
+ name: "Version 2.0.0",
469
+ body: "Release notes and changelog content here.",
470
+ draft: false,
471
+ prerelease: false,
472
+ generate_release_notes: false,
473
+ target_commitish: "main"
474
+ });
475
+
476
+ ```
477
+
478
+ **Get Latest Release:**
479
+
480
+ For CLI alternative: `gh release view --repo owner/repo`
481
+
482
+ ```javascript
483
+ const { data: latest } = await octokit.rest.repos.getLatestRelease({
484
+ owner: "owner",
485
+ repo: "repo"
486
+ });
487
+ ```
488
+
489
+ ### Gists
490
+
491
+ **Minimal Example - Create Gist:**
492
+ ```javascript
493
+ const { data: gist } = await octokit.rest.gists.create({
494
+ files: {
495
+ "hello.js": {
496
+ content: "console.log('Hello World');"
497
+ }
498
+ },
499
+ description: "Hello World example",
500
+ public: true
501
+ });
502
+
503
+ ```
504
+
505
+ **Advanced Example - Multi-file Gist:**
506
+ ```javascript
507
+ const { data: gist } = await octokit.rest.gists.create({
508
+ files: {
509
+ "package.json": {
510
+ content: JSON.stringify({
511
+ name: "example",
512
+ version: "1.0.0"
513
+ }, null, 2)
514
+ },
515
+ "index.js": {
516
+ content: "const express = require('express');\n// App code here"
517
+ },
518
+ "README.md": {
519
+ content: "# Example Project\n\nDescription here"
520
+ }
521
+ },
522
+ description: "Full project example",
523
+ public: false
524
+ });
525
+ ```
526
+
527
+ ### Search
528
+
529
+ **Search Repositories:**
530
+ ```javascript
531
+ const { data: results } = await octokit.rest.search.repos({
532
+ q: "language:javascript stars:>1000 created:>2024-01-01",
533
+ sort: "stars",
534
+ order: "desc",
535
+ per_page: 30
536
+ });
537
+ ```
538
+
539
+ **Search Issues and Pull Requests:**
540
+ ```javascript
541
+ const { data: results } = await octokit.rest.search.issuesAndPullRequests({
542
+ q: "type:pr repo:facebook/react is:open label:bug",
543
+ sort: "created",
544
+ order: "desc"
545
+ });
546
+ ```
547
+
548
+ **Search Code:**
549
+ ```javascript
550
+ const { data: results } = await octokit.rest.search.code({
551
+ q: "import Octokit from octokit language:javascript",
552
+ per_page: 50
553
+ });
554
+ ```
555
+
556
+ **Search Users:**
557
+ ```javascript
558
+ const { data: results } = await octokit.rest.search.users({
559
+ q: "followers:>1000 location:London",
560
+ per_page: 20
561
+ });
562
+ ```
563
+
564
+ ### Users and Organizations
565
+
566
+ **Get Authenticated User:**
567
+
568
+ For CLI alternative: `gh api user`
569
+
570
+ ```javascript
571
+ const { data: user } = await octokit.rest.users.getAuthenticated();
572
+ ```
573
+
574
+ **Get User by Username:**
575
+
576
+ For CLI alternative: `gh api users/username`
577
+
578
+ ```javascript
579
+ const { data: user } = await octokit.rest.users.getByUsername({
580
+ username: "torvalds"
581
+ });
582
+ ```
583
+
584
+ **List Organization Repositories:**
585
+
586
+ For CLI alternative: `gh repo list org-name`
587
+
588
+ ```javascript
589
+ const { data: repos } = await octokit.rest.repos.listForOrg({
590
+ org: "github",
591
+ type: "public",
592
+ sort: "updated",
593
+ per_page: 100
594
+ });
595
+ ```
596
+
597
+ **List Organization Members:**
598
+
599
+ For CLI alternative: `gh api orgs/org-name/members`
600
+
601
+ ```javascript
602
+ const { data: members } = await octokit.rest.orgs.listMembers({
603
+ org: "github",
604
+ per_page: 100
605
+ });
606
+ ```
607
+
608
+ ### Webhooks
609
+
610
+ **List Repository Webhooks:**
611
+
612
+ For CLI alternative: `gh api repos/owner/repo/hooks`
613
+
614
+ ```javascript
615
+ const { data: hooks } = await octokit.rest.repos.listWebhooks({
616
+ owner: "owner",
617
+ repo: "repo"
618
+ });
619
+ ```
620
+
621
+ **Create Webhook:**
622
+ ```javascript
623
+ const { data: hook } = await octokit.rest.repos.createWebhook({
624
+ owner: "owner",
625
+ repo: "repo",
626
+ name: "web",
627
+ active: true,
628
+ events: ["push", "pull_request", "issues"],
629
+ config: {
630
+ url: "https://example.com/webhook",
631
+ content_type: "json",
632
+ secret: process.env.WEBHOOK_SECRET,
633
+ insecure_ssl: "0"
634
+ }
635
+ });
636
+ ```
637
+
638
+ ### GraphQL API
639
+
640
+ **Minimal Example - Simple Query:**
641
+ ```javascript
642
+ const { repository } = await octokit.graphql(`
643
+ query {
644
+ repository(owner: "octokit", name: "graphql.js") {
645
+ name
646
+ description
647
+ stargazerCount
648
+ }
649
+ }
650
+ `);
651
+ ```
652
+
653
+ **Advanced Example - Query with Variables:**
654
+ ```javascript
655
+ const query = `
656
+ query($owner: String!, $repo: String!, $issueCount: Int!) {
657
+ repository(owner: $owner, name: $repo) {
658
+ name
659
+ issues(last: $issueCount, states: OPEN) {
660
+ edges {
661
+ node {
662
+ number
663
+ title
664
+ author {
665
+ login
666
+ }
667
+ createdAt
668
+ labels(first: 5) {
669
+ nodes {
670
+ name
671
+ }
672
+ }
673
+ }
674
+ }
675
+ }
676
+ }
677
+ }
678
+ `;
679
+
680
+ const { repository } = await octokit.graphql(query, {
681
+ owner: "facebook",
682
+ repo: "react",
683
+ issueCount: 10
684
+ });
685
+ ```
686
+
687
+ **GraphQL Mutation Example:**
688
+ ```javascript
689
+ const mutation = `
690
+ mutation($repositoryId: ID!, $issueTitle: String!, $issueBody: String!) {
691
+ createIssue(input: {
692
+ repositoryId: $repositoryId,
693
+ title: $issueTitle,
694
+ body: $issueBody
695
+ }) {
696
+ issue {
697
+ number
698
+ url
699
+ }
700
+ }
701
+ }
702
+ `;
703
+
704
+ // First get repository ID
705
+ const { repository } = await octokit.graphql(`
706
+ query($owner: String!, $name: String!) {
707
+ repository(owner: $owner, name: $name) {
708
+ id
709
+ }
710
+ }
711
+ `, {
712
+ owner: "owner",
713
+ name: "repo"
714
+ });
715
+
716
+ // Create issue
717
+ const result = await octokit.graphql(mutation, {
718
+ repositoryId: repository.id,
719
+ issueTitle: "New issue via GraphQL",
720
+ issueBody: "Issue body content"
721
+ });
722
+ ```
723
+
724
+ ## 5. Advanced Features
725
+
726
+ ### Pagination
727
+
728
+ **Automatic Pagination - Get All Results:**
729
+ ```javascript
730
+ // Get all issues (auto-handles pagination)
731
+ const allIssues = await octokit.paginate(
732
+ octokit.rest.issues.listForRepo,
733
+ {
734
+ owner: "facebook",
735
+ repo: "react",
736
+ state: "all",
737
+ per_page: 100
738
+ }
739
+ );
740
+ ```
741
+
742
+ **Iterator-based Pagination:**
743
+ ```javascript
744
+ // Process results as they come
745
+ for await (const response of octokit.paginate.iterator(
746
+ octokit.rest.repos.listForOrg,
747
+ {
748
+ org: "github",
749
+ per_page: 100
750
+ }
751
+ )) {
752
+ // response.data contains up to 100 items
753
+ // Process each batch here
754
+ }
755
+ ```
756
+
757
+ **Custom Page Limit:**
758
+ ```javascript
759
+ // Get only first 500 items across pages
760
+ const limitedResults = await octokit.paginate(
761
+ octokit.rest.issues.listForRepo,
762
+ {
763
+ owner: "owner",
764
+ repo: "repo",
765
+ per_page: 100
766
+ },
767
+ (response, done) => {
768
+ if (response.data.length >= 500) {
769
+ done();
770
+ }
771
+ return response.data;
772
+ }
773
+ );
774
+ ```
775
+
776
+ ### Error Handling
777
+
778
+ **Comprehensive Error Handling:**
779
+ ```javascript
780
+ import { RequestError } from "@octokit/request-error";
781
+
782
+ try {
783
+ const { data } = await octokit.rest.repos.get({
784
+ owner: "owner",
785
+ repo: "nonexistent"
786
+ });
787
+ } catch (error) {
788
+ if (error instanceof RequestError) {
789
+ console.error(`Error ${error.status}: ${error.message}`);
790
+
791
+ // Check specific error codes
792
+ if (error.status === 404) {
793
+ console.error("Repository not found");
794
+ } else if (error.status === 403) {
795
+ if (error.response.headers["x-ratelimit-remaining"] === "0") {
796
+ console.error("Rate limit exceeded");
797
+ const resetTime = new Date(
798
+ error.response.headers["x-ratelimit-reset"] * 1000
799
+ );
800
+ console.error(`Rate limit resets at ${resetTime}`);
801
+ } else {
802
+ console.error("Forbidden - check permissions");
803
+ }
804
+ } else if (error.status === 401) {
805
+ console.error("Unauthorized - check authentication token");
806
+ } else if (error.status >= 500) {
807
+ console.error("GitHub server error - retry later");
808
+ }
809
+
810
+ // Log additional error details
811
+ console.error("Request ID:", error.response.headers["x-github-request-id"]);
812
+ } else {
813
+ console.error("Unexpected error:", error);
814
+ }
815
+ }
816
+ ```
817
+
818
+ ### Rate Limiting with Throttle Plugin
819
+
820
+ **Setup:**
821
+ ```bash
822
+ npm install @octokit/plugin-throttling
823
+ ```
824
+
825
+ **Implementation:**
826
+ ```javascript
827
+ import { Octokit } from "@octokit/core";
828
+ import { throttling } from "@octokit/plugin-throttling";
829
+
830
+ const MyOctokit = Octokit.plugin(throttling);
831
+
832
+ const octokit = new MyOctokit({
833
+ auth: process.env.GITHUB_TOKEN,
834
+ throttle: {
835
+ onRateLimit: (retryAfter, options, octokit, retryCount) => {
836
+ octokit.log.warn(
837
+ `Request quota exhausted for request ${options.method} ${options.url}`
838
+ );
839
+
840
+ // Retry first 3 times
841
+ if (retryCount < 3) {
842
+ octokit.log.info(`Retrying after ${retryAfter} seconds!`);
843
+ return true;
844
+ }
845
+ },
846
+ onSecondaryRateLimit: (retryAfter, options, octokit, retryCount) => {
847
+ octokit.log.warn(
848
+ `SecondaryRateLimit detected for request ${options.method} ${options.url}`
849
+ );
850
+
851
+ // Always retry on secondary rate limit
852
+ if (retryCount < 5) {
853
+ octokit.log.info(`Retrying after ${retryAfter} seconds!`);
854
+ return true;
855
+ }
856
+ }
857
+ }
858
+ });
859
+ ```
860
+
861
+ ### Retry Plugin
862
+
863
+ **Setup:**
864
+ ```bash
865
+ npm install @octokit/plugin-retry
866
+ ```
867
+
868
+ **Implementation:**
869
+ ```javascript
870
+ import { Octokit } from "@octokit/core";
871
+ import { retry } from "@octokit/plugin-retry";
872
+
873
+ const MyOctokit = Octokit.plugin(retry);
874
+
875
+ const octokit = new MyOctokit({
876
+ auth: process.env.GITHUB_TOKEN
877
+ });
878
+
879
+ // Automatic retries on 500 errors (up to 3 times)
880
+ const { data } = await octokit.rest.repos.get({
881
+ owner: "owner",
882
+ repo: "repo"
883
+ });
884
+
885
+ // Manual retry configuration
886
+ const { data: issues } = await octokit.rest.issues.listForRepo({
887
+ owner: "owner",
888
+ repo: "repo",
889
+ request: {
890
+ retries: 5,
891
+ retryAfter: 3 // seconds
892
+ }
893
+ });
894
+ ```
895
+
896
+ ### Custom Request Options
897
+
898
+ **Timeouts:**
899
+ ```javascript
900
+ const { data } = await octokit.rest.repos.get({
901
+ owner: "owner",
902
+ repo: "repo",
903
+ request: {
904
+ timeout: 10000 // 10 seconds
905
+ }
906
+ });
907
+ ```
908
+
909
+ **Custom Headers:**
910
+ ```javascript
911
+ const { data } = await octokit.rest.repos.get({
912
+ owner: "owner",
913
+ repo: "repo",
914
+ headers: {
915
+ "X-GitHub-Api-Version": "2022-11-28"
916
+ }
917
+ });
918
+ ```
919
+
920
+ **Signal for Abort:**
921
+ ```javascript
922
+ const controller = new AbortController();
923
+
924
+ setTimeout(() => controller.abort(), 5000); // Abort after 5s
925
+
926
+ try {
927
+ const { data } = await octokit.rest.repos.get({
928
+ owner: "owner",
929
+ repo: "repo",
930
+ request: {
931
+ signal: controller.signal
932
+ }
933
+ });
934
+ } catch (error) {
935
+ if (error.name === "AbortError") {
936
+ console.log("Request was aborted");
937
+ }
938
+ }
939
+ ```
940
+
941
+ ## 6. TypeScript Usage
942
+
943
+ ### Basic TypeScript Setup
944
+
945
+ **tsconfig.json Configuration:**
946
+ ```json
947
+ {
948
+ "compilerOptions": {
949
+ "moduleResolution": "node16",
950
+ "module": "node16",
951
+ "target": "ES2022",
952
+ "lib": ["ES2022"]
953
+ }
954
+ }
955
+ ```
956
+
957
+ ### Type-Safe API Calls
958
+
959
+ **Import Types:**
960
+ ```typescript
961
+ import { Octokit } from "octokit";
962
+ import type { RestEndpointMethodTypes } from "@octokit/plugin-rest-endpoint-methods";
963
+
964
+ // Type for a specific endpoint
965
+ type GetRepoResponse = RestEndpointMethodTypes["repos"]["get"]["response"];
966
+ type GetRepoParams = RestEndpointMethodTypes["repos"]["get"]["parameters"];
967
+
968
+ const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
969
+
970
+ const params: GetRepoParams = {
971
+ owner: "octokit",
972
+ repo: "rest.js"
973
+ };
974
+
975
+ const response: GetRepoResponse = await octokit.rest.repos.get(params);
976
+ const repo = response.data;
977
+ ```
978
+
979
+ **Generic Response Types:**
980
+ ```typescript
981
+ import type { Endpoints } from "@octokit/types";
982
+
983
+ type IssuesListResponse = Endpoints["GET /repos/{owner}/{repo}/issues"]["response"];
984
+ type Issue = Endpoints["GET /repos/{owner}/{repo}/issues"]["response"]["data"][number];
985
+
986
+ const issues: IssuesListResponse = await octokit.rest.issues.listForRepo({
987
+ owner: "facebook",
988
+ repo: "react"
989
+ });
990
+
991
+ const firstIssue: Issue = issues.data[0];
992
+ ```
993
+
994
+ **Custom Type-Safe Wrapper:**
995
+ ```typescript
996
+ interface GitHubService {
997
+ getRepository(owner: string, repo: string): Promise<Repository>;
998
+ createIssue(params: CreateIssueParams): Promise<Issue>;
999
+ }
1000
+
1001
+ interface Repository {
1002
+ name: string;
1003
+ description: string;
1004
+ stars: number;
1005
+ url: string;
1006
+ }
1007
+
1008
+ interface CreateIssueParams {
1009
+ owner: string;
1010
+ repo: string;
1011
+ title: string;
1012
+ body: string;
1013
+ labels?: string[];
1014
+ }
1015
+
1016
+ interface Issue {
1017
+ number: number;
1018
+ title: string;
1019
+ url: string;
1020
+ }
1021
+
1022
+ class GitHubClient implements GitHubService {
1023
+ constructor(private octokit: Octokit) {}
1024
+
1025
+ async getRepository(owner: string, repo: string): Promise<Repository> {
1026
+ const { data } = await this.octokit.rest.repos.get({ owner, repo });
1027
+
1028
+ return {
1029
+ name: data.name,
1030
+ description: data.description || "",
1031
+ stars: data.stargazers_count,
1032
+ url: data.html_url
1033
+ };
1034
+ }
1035
+
1036
+ async createIssue(params: CreateIssueParams): Promise<Issue> {
1037
+ const { data } = await this.octokit.rest.issues.create({
1038
+ owner: params.owner,
1039
+ repo: params.repo,
1040
+ title: params.title,
1041
+ body: params.body,
1042
+ labels: params.labels
1043
+ });
1044
+
1045
+ return {
1046
+ number: data.number,
1047
+ title: data.title,
1048
+ url: data.html_url
1049
+ };
1050
+ }
1051
+ }
1052
+
1053
+ // Usage
1054
+ const client = new GitHubClient(octokit);
1055
+ const repo = await client.getRepository("facebook", "react");
1056
+ ```
1057
+
1058
+ ### GraphQL TypeScript
1059
+
1060
+ ```typescript
1061
+ import { Octokit } from "octokit";
1062
+
1063
+ interface RepositoryQuery {
1064
+ repository: {
1065
+ name: string;
1066
+ stargazerCount: number;
1067
+ issues: {
1068
+ totalCount: number;
1069
+ nodes: Array<{
1070
+ number: number;
1071
+ title: string;
1072
+ author: {
1073
+ login: string;
1074
+ } | null;
1075
+ }>;
1076
+ };
1077
+ };
1078
+ }
1079
+
1080
+ const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
1081
+
1082
+ const result: RepositoryQuery = await octokit.graphql(`
1083
+ query($owner: String!, $repo: String!) {
1084
+ repository(owner: $owner, name: $repo) {
1085
+ name
1086
+ stargazerCount
1087
+ issues(last: 5, states: OPEN) {
1088
+ totalCount
1089
+ nodes {
1090
+ number
1091
+ title
1092
+ author {
1093
+ login
1094
+ }
1095
+ }
1096
+ }
1097
+ }
1098
+ }
1099
+ `, {
1100
+ owner: "facebook",
1101
+ repo: "react"
1102
+ });
1103
+ ```
1104
+
1105
+ ## 7. Best Practices
1106
+
1107
+ ### Authentication and Security
1108
+
1109
+ **Never Hardcode Tokens:**
1110
+ ```javascript
1111
+ // BAD - Never do this
1112
+ const octokit = new Octokit({ auth: "ghp_actualtoken123" });
1113
+
1114
+ // GOOD - Use environment variables
1115
+ const octokit = new Octokit({ auth: process.env.GITHUB_TOKEN });
1116
+ ```
1117
+
1118
+ **Use Fine-Grained Tokens:**
1119
+ Fine-grained personal access tokens provide more granular permissions and are repository-scoped. Use them instead of classic tokens when possible.
1120
+
1121
+ **Rotate Tokens Regularly:**
1122
+ Implement a token rotation strategy, especially for long-running applications.
1123
+
1124
+ **Use GitHub Apps for Production:**
1125
+ GitHub Apps provide better security, higher rate limits, and better audit trails than personal access tokens.
1126
+
1127
+ ### Rate Limiting Strategy
1128
+
1129
+ **Check Rate Limit Status:**
1130
+ ```javascript
1131
+ const { data: rateLimit } = await octokit.rest.rateLimit.get();
1132
+
1133
+ console.log(`Remaining: ${rateLimit.rate.remaining}/${rateLimit.rate.limit}`);
1134
+ console.log(`Resets at: ${new Date(rateLimit.rate.reset * 1000)}`);
1135
+
1136
+ // Check specific resource limits
1137
+ console.log(`Search limit: ${rateLimit.resources.search.remaining}`);
1138
+ console.log(`GraphQL limit: ${rateLimit.resources.graphql.remaining}`);
1139
+ ```
1140
+
1141
+ **Implement Backoff Strategy:**
1142
+ ```javascript
1143
+ async function makeRequestWithBackoff(fn, maxRetries = 3) {
1144
+ for (let i = 0; i < maxRetries; i++) {
1145
+ try {
1146
+ return await fn();
1147
+ } catch (error) {
1148
+ if (error.status === 403 && error.response.headers["x-ratelimit-remaining"] === "0") {
1149
+ const resetTime = parseInt(error.response.headers["x-ratelimit-reset"]) * 1000;
1150
+ const waitTime = resetTime - Date.now();
1151
+
1152
+ if (i < maxRetries - 1) {
1153
+ console.log(`Rate limited. Waiting ${waitTime}ms...`);
1154
+ await new Promise(resolve => setTimeout(resolve, waitTime));
1155
+ continue;
1156
+ }
1157
+ }
1158
+ throw error;
1159
+ }
1160
+ }
1161
+ }
1162
+ ```
1163
+
1164
+ **Use Conditional Requests:**
1165
+ ```javascript
1166
+ // First request
1167
+ const { data, headers } = await octokit.rest.repos.get({
1168
+ owner: "owner",
1169
+ repo: "repo"
1170
+ });
1171
+
1172
+ const etag = headers.etag;
1173
+
1174
+ // Later request - only downloads if changed
1175
+ const { status, data: newData } = await octokit.rest.repos.get({
1176
+ owner: "owner",
1177
+ repo: "repo",
1178
+ headers: {
1179
+ "If-None-Match": etag
1180
+ }
1181
+ });
1182
+
1183
+ if (status === 304) {
1184
+ console.log("No changes - use cached data");
1185
+ } else {
1186
+ console.log("Data changed - use new data");
1187
+ }
1188
+ ```
1189
+
1190
+ ### Error Recovery
1191
+
1192
+ **Implement Retry Logic:**
1193
+ ```javascript
1194
+ async function retryRequest(fn, maxRetries = 3, delay = 1000) {
1195
+ for (let i = 0; i < maxRetries; i++) {
1196
+ try {
1197
+ return await fn();
1198
+ } catch (error) {
1199
+ const isLastRetry = i === maxRetries - 1;
1200
+ const shouldRetry = error.status >= 500 || error.status === 429;
1201
+
1202
+ if (!shouldRetry || isLastRetry) {
1203
+ throw error;
1204
+ }
1205
+
1206
+ const backoffDelay = delay * Math.pow(2, i);
1207
+ console.log(`Retry ${i + 1}/${maxRetries} after ${backoffDelay}ms`);
1208
+ await new Promise(resolve => setTimeout(resolve, backoffDelay));
1209
+ }
1210
+ }
1211
+ }
1212
+
1213
+ // Usage
1214
+ const data = await retryRequest(
1215
+ () => octokit.rest.repos.get({ owner: "owner", repo: "repo" })
1216
+ );
1217
+ ```
1218
+
1219
+ ### Performance Optimization
1220
+
1221
+ **Use GraphQL for Complex Queries:**
1222
+ ```javascript
1223
+ // BAD - Multiple REST requests
1224
+ const { data: repo } = await octokit.rest.repos.get({ owner, repo });
1225
+ const { data: issues } = await octokit.rest.issues.listForRepo({ owner, repo });
1226
+ const { data: pulls } = await octokit.rest.pulls.list({ owner, repo });
1227
+
1228
+ // GOOD - Single GraphQL request
1229
+ const result = await octokit.graphql(`
1230
+ query($owner: String!, $repo: String!) {
1231
+ repository(owner: $owner, name: $repo) {
1232
+ name
1233
+ description
1234
+ issues(last: 10, states: OPEN) {
1235
+ totalCount
1236
+ nodes { number title }
1237
+ }
1238
+ pullRequests(last: 10, states: OPEN) {
1239
+ totalCount
1240
+ nodes { number title }
1241
+ }
1242
+ }
1243
+ }
1244
+ `, { owner, repo });
1245
+ ```
1246
+
1247
+ **Batch Operations:**
1248
+ ```javascript
1249
+ // Process items in batches to avoid overwhelming the API
1250
+ async function processBatch(items, batchSize, handler) {
1251
+ for (let i = 0; i < items.length; i += batchSize) {
1252
+ const batch = items.slice(i, i + batchSize);
1253
+ await Promise.all(batch.map(handler));
1254
+
1255
+ // Brief pause between batches
1256
+ if (i + batchSize < items.length) {
1257
+ await new Promise(resolve => setTimeout(resolve, 1000));
1258
+ }
1259
+ }
1260
+ }
1261
+
1262
+ // Usage
1263
+ await processBatch(
1264
+ repositories,
1265
+ 10,
1266
+ async (repo) => {
1267
+ const { data } = await octokit.rest.repos.get({
1268
+ owner: repo.owner,
1269
+ repo: repo.name
1270
+ });
1271
+ // Process repo data
1272
+ }
1273
+ );
1274
+ ```
1275
+
1276
+ ### Data Validation
1277
+
1278
+ **Validate Input:**
1279
+ ```javascript
1280
+ function validateRepoParams(owner, repo) {
1281
+ if (!owner || typeof owner !== "string" || owner.trim() === "") {
1282
+ throw new Error("Invalid owner parameter");
1283
+ }
1284
+ if (!repo || typeof repo !== "string" || repo.trim() === "") {
1285
+ throw new Error("Invalid repo parameter");
1286
+ }
1287
+ if (!/^[a-zA-Z0-9-_.]+$/.test(owner)) {
1288
+ throw new Error("Owner contains invalid characters");
1289
+ }
1290
+ if (!/^[a-zA-Z0-9-_.]+$/.test(repo)) {
1291
+ throw new Error("Repo contains invalid characters");
1292
+ }
1293
+ }
1294
+
1295
+ // Usage
1296
+ validateRepoParams(userInput.owner, userInput.repo);
1297
+ const { data } = await octokit.rest.repos.get({
1298
+ owner: userInput.owner,
1299
+ repo: userInput.repo
1300
+ });
1301
+ ```
1302
+
1303
+ **Sanitize Output:**
1304
+ ```javascript
1305
+ function sanitizeIssue(issue) {
1306
+ return {
1307
+ number: issue.number,
1308
+ title: issue.title.trim(),
1309
+ body: issue.body?.trim() || "",
1310
+ state: issue.state,
1311
+ createdAt: new Date(issue.created_at),
1312
+ author: issue.user?.login || "unknown"
1313
+ };
1314
+ }
1315
+ ```
1316
+
1317
+ ## 8. Production Checklist
1318
+
1319
+ ### Version Pinning
1320
+ ```json
1321
+ {
1322
+ "dependencies": {
1323
+ "octokit": "3.1.2"
1324
+ }
1325
+ }
1326
+ ```
1327
+
1328
+ Pin exact versions (no `^` or `~`) to prevent unexpected breaking changes.
1329
+
1330
+ ### Robust Error Handling
1331
+ ```javascript
1332
+ // Production-ready request wrapper
1333
+ async function safeRequest(requestFn) {
1334
+ try {
1335
+ const { data } = await requestFn();
1336
+ return { success: true, data, error: null };
1337
+ } catch (error) {
1338
+ console.error("GitHub API Error:", {
1339
+ status: error.status,
1340
+ message: error.message,
1341
+ requestId: error.response?.headers?.["x-github-request-id"],
1342
+ timestamp: new Date().toISOString()
1343
+ });
1344
+
1345
+ return {
1346
+ success: false,
1347
+ data: null,
1348
+ error: {
1349
+ code: error.status,
1350
+ message: error.message,
1351
+ retryable: error.status >= 500 || error.status === 429
1352
+ }
1353
+ };
1354
+ }
1355
+ }
1356
+
1357
+ // Usage
1358
+ const result = await safeRequest(
1359
+ () => octokit.rest.repos.get({ owner: "owner", repo: "repo" })
1360
+ );
1361
+
1362
+ if (result.success) {
1363
+ console.log(result.data);
1364
+ } else {
1365
+ console.error("Request failed:", result.error);
1366
+ if (result.error.retryable) {
1367
+ // Implement retry logic
1368
+ }
1369
+ }
1370
+ ```
1371
+
1372
+ ### Environment Configuration
1373
+ ```javascript
1374
+ // config.js
1375
+ export const config = {
1376
+ github: {
1377
+ token: process.env.GITHUB_TOKEN,
1378
+ baseUrl: process.env.GITHUB_API_URL || "https://api.github.com",
1379
+ timeout: parseInt(process.env.GITHUB_TIMEOUT || "30000"),
1380
+ userAgent: `${process.env.APP_NAME}/${process.env.APP_VERSION}`
1381
+ }
1382
+ };
1383
+
1384
+ // Validate configuration on startup
1385
+ function validateConfig() {
1386
+ if (!config.github.token) {
1387
+ throw new Error("GITHUB_TOKEN environment variable is required");
1388
+ }
1389
+ if (config.github.timeout < 1000 || config.github.timeout > 60000) {
1390
+ throw new Error("GITHUB_TIMEOUT must be between 1000 and 60000");
1391
+ }
1392
+ }
1393
+
1394
+ validateConfig();
1395
+
1396
+ export const octokit = new Octokit({
1397
+ auth: config.github.token,
1398
+ baseUrl: config.github.baseUrl,
1399
+ userAgent: config.github.userAgent,
1400
+ request: {
1401
+ timeout: config.github.timeout
1402
+ }
1403
+ });
1404
+ ```
1405
+
1406
+ ### Logging and Monitoring
1407
+ ```javascript
1408
+ import { Octokit } from "@octokit/core";
1409
+
1410
+ class LoggingOctokit extends Octokit {
1411
+ constructor(options) {
1412
+ super(options);
1413
+
1414
+ this.hook.before("request", async (options) => {
1415
+ console.log(`[GitHub API] ${options.method} ${options.url}`, {
1416
+ timestamp: new Date().toISOString()
1417
+ });
1418
+ });
1419
+
1420
+ this.hook.after("request", async (response, options) => {
1421
+ console.log(`[GitHub API] ${options.method} ${options.url} - ${response.status}`, {
1422
+ rateLimit: response.headers["x-ratelimit-remaining"],
1423
+ timestamp: new Date().toISOString()
1424
+ });
1425
+ });
1426
+
1427
+ this.hook.error("request", async (error, options) => {
1428
+ console.error(`[GitHub API] ${options.method} ${options.url} - ERROR`, {
1429
+ status: error.status,
1430
+ message: error.message,
1431
+ requestId: error.response?.headers?.["x-github-request-id"],
1432
+ timestamp: new Date().toISOString()
1433
+ });
1434
+ throw error;
1435
+ });
1436
+ }
1437
+ }
1438
+
1439
+ const octokit = new LoggingOctokit({ auth: process.env.GITHUB_TOKEN });
1440
+ ```
1441
+
1442
+ ### Validate Structured Output
1443
+ ```javascript
1444
+ function validateRepository(data) {
1445
+ const required = ["id", "name", "full_name", "owner", "html_url"];
1446
+ for (const field of required) {
1447
+ if (!(field in data)) {
1448
+ throw new Error(`Missing required field: ${field}`);
1449
+ }
1450
+ }
1451
+ return data;
1452
+ }
1453
+
1454
+ const { data } = await octokit.rest.repos.get({ owner, repo });
1455
+ const validatedRepo = validateRepository(data);
1456
+ ```
1457
+
1458
+ ### Avoid Preview/Unstable APIs
1459
+ ```javascript
1460
+ // BAD - Using preview API
1461
+ const { data } = await octokit.rest.repos.get({
1462
+ owner: "owner",
1463
+ repo: "repo",
1464
+ mediaType: {
1465
+ previews: ["mercy"] // Preview API
1466
+ }
1467
+ });
1468
+
1469
+ // GOOD - Use stable APIs only
1470
+ const { data } = await octokit.rest.repos.get({
1471
+ owner: "owner",
1472
+ repo: "repo"
1473
+ });
1474
+ ```
1475
+
1476
+ ### Health Checks
1477
+ ```javascript
1478
+ async function healthCheck() {
1479
+ try {
1480
+ const { data: rateLimit } = await octokit.rest.rateLimit.get();
1481
+ const remaining = rateLimit.rate.remaining;
1482
+
1483
+ return {
1484
+ healthy: remaining > 100,
1485
+ rateLimit: {
1486
+ remaining,
1487
+ limit: rateLimit.rate.limit,
1488
+ reset: new Date(rateLimit.rate.reset * 1000)
1489
+ }
1490
+ };
1491
+ } catch (error) {
1492
+ return {
1493
+ healthy: false,
1494
+ error: error.message
1495
+ };
1496
+ }
1497
+ }
1498
+
1499
+ // Run periodically
1500
+ setInterval(async () => {
1501
+ const health = await healthCheck();
1502
+ if (!health.healthy) {
1503
+ console.warn("GitHub API health check failed", health);
1504
+ }
1505
+ }, 60000); // Every minute
1506
+ ```
1507
+
1508
+ ### Testing Strategy
1509
+ ```javascript
1510
+ // Mock Octokit for tests
1511
+ import { jest } from "@jest/globals";
1512
+
1513
+ const mockOctokit = {
1514
+ rest: {
1515
+ repos: {
1516
+ get: jest.fn().mockResolvedValue({
1517
+ data: {
1518
+ id: 1,
1519
+ name: "test-repo",
1520
+ full_name: "owner/test-repo",
1521
+ owner: { login: "owner" },
1522
+ html_url: "https://github.com/owner/test-repo"
1523
+ }
1524
+ })
1525
+ }
1526
+ }
1527
+ };
1528
+
1529
+ // Test
1530
+ test("getRepository returns formatted data", async () => {
1531
+ const client = new GitHubClient(mockOctokit);
1532
+ const repo = await client.getRepository("owner", "test-repo");
1533
+
1534
+ expect(repo.name).toBe("test-repo");
1535
+ expect(mockOctokit.rest.repos.get).toHaveBeenCalledWith({
1536
+ owner: "owner",
1537
+ repo: "test-repo"
1538
+ });
1539
+ });
1540
+ ```
1541
+
1542
+ ### Graceful Degradation
1543
+ ```javascript
1544
+ async function getRepoWithFallback(owner, repo) {
1545
+ try {
1546
+ const { data } = await octokit.rest.repos.get({ owner, repo });
1547
+ return data;
1548
+ } catch (error) {
1549
+ if (error.status === 404) {
1550
+ console.warn(`Repository ${owner}/${repo} not found`);
1551
+ return null;
1552
+ }
1553
+ if (error.status === 403) {
1554
+ console.warn("Rate limited - using cached data");
1555
+ return getCachedRepo(owner, repo);
1556
+ }
1557
+ throw error; // Re-throw unexpected errors
1558
+ }
1559
+ }
1560
+ ```