@stats-forge/github-stats-forge-core 0.0.1

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 (211) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +148 -0
  3. package/build/api/api-result.d.ts +44 -0
  4. package/build/api/api-result.d.ts.map +1 -0
  5. package/build/api/api-result.js +33 -0
  6. package/build/api/gist.d.ts +29 -0
  7. package/build/api/gist.d.ts.map +1 -0
  8. package/build/api/gist.js +52 -0
  9. package/build/api/index.d.ts +13 -0
  10. package/build/api/index.d.ts.map +1 -0
  11. package/build/api/index.js +8 -0
  12. package/build/api/params.d.ts +93 -0
  13. package/build/api/params.d.ts.map +1 -0
  14. package/build/api/params.js +145 -0
  15. package/build/api/pin.d.ts +47 -0
  16. package/build/api/pin.d.ts.map +1 -0
  17. package/build/api/pin.js +87 -0
  18. package/build/api/stats.d.ts +42 -0
  19. package/build/api/stats.d.ts.map +1 -0
  20. package/build/api/stats.js +132 -0
  21. package/build/api/top-langs.d.ts +37 -0
  22. package/build/api/top-langs.d.ts.map +1 -0
  23. package/build/api/top-langs.js +101 -0
  24. package/build/api/wakatime.d.ts +34 -0
  25. package/build/api/wakatime.d.ts.map +1 -0
  26. package/build/api/wakatime.js +91 -0
  27. package/build/calculateRank.d.ts +29 -0
  28. package/build/calculateRank.d.ts.map +1 -0
  29. package/build/calculateRank.js +58 -0
  30. package/build/cards/gist.d.ts +16 -0
  31. package/build/cards/gist.d.ts.map +1 -0
  32. package/build/cards/gist.js +119 -0
  33. package/build/cards/index.d.ts +11 -0
  34. package/build/cards/index.d.ts.map +1 -0
  35. package/build/cards/index.js +7 -0
  36. package/build/cards/options.d.ts +19 -0
  37. package/build/cards/options.d.ts.map +1 -0
  38. package/build/cards/options.js +1 -0
  39. package/build/cards/repo.d.ts +25 -0
  40. package/build/cards/repo.d.ts.map +1 -0
  41. package/build/cards/repo.js +276 -0
  42. package/build/cards/stats.d.ts +37 -0
  43. package/build/cards/stats.d.ts.map +1 -0
  44. package/build/cards/stats.js +457 -0
  45. package/build/cards/top-languages.d.ts +153 -0
  46. package/build/cards/top-languages.d.ts.map +1 -0
  47. package/build/cards/top-languages.js +805 -0
  48. package/build/cards/wakatime.d.ts +31 -0
  49. package/build/cards/wakatime.d.ts.map +1 -0
  50. package/build/cards/wakatime.js +376 -0
  51. package/build/common/Card.d.ts +121 -0
  52. package/build/common/Card.d.ts.map +1 -0
  53. package/build/common/Card.js +305 -0
  54. package/build/common/I18n.d.ts +27 -0
  55. package/build/common/I18n.d.ts.map +1 -0
  56. package/build/common/I18n.js +35 -0
  57. package/build/common/color.d.ts +112 -0
  58. package/build/common/color.d.ts.map +1 -0
  59. package/build/common/color.js +188 -0
  60. package/build/common/config.d.ts +53 -0
  61. package/build/common/config.d.ts.map +1 -0
  62. package/build/common/config.js +87 -0
  63. package/build/common/constants.d.ts +7 -0
  64. package/build/common/constants.d.ts.map +1 -0
  65. package/build/common/constants.js +9 -0
  66. package/build/common/date.d.ts +29 -0
  67. package/build/common/date.d.ts.map +1 -0
  68. package/build/common/date.js +23 -0
  69. package/build/common/error.d.ts +87 -0
  70. package/build/common/error.d.ts.map +1 -0
  71. package/build/common/error.js +108 -0
  72. package/build/common/fmt.d.ts +28 -0
  73. package/build/common/fmt.d.ts.map +1 -0
  74. package/build/common/fmt.js +68 -0
  75. package/build/common/html.d.ts +8 -0
  76. package/build/common/html.d.ts.map +1 -0
  77. package/build/common/html.js +14 -0
  78. package/build/common/http.d.ts +53 -0
  79. package/build/common/http.d.ts.map +1 -0
  80. package/build/common/http.js +47 -0
  81. package/build/common/icons.d.ts +28 -0
  82. package/build/common/icons.d.ts.map +1 -0
  83. package/build/common/icons.js +77 -0
  84. package/build/common/languageColors.d.ts +11 -0
  85. package/build/common/languageColors.d.ts.map +1 -0
  86. package/build/common/languageColors.js +15 -0
  87. package/build/common/languageColors.json +678 -0
  88. package/build/common/log.d.ts +9 -0
  89. package/build/common/log.d.ts.map +1 -0
  90. package/build/common/log.js +8 -0
  91. package/build/common/ops.d.ts +59 -0
  92. package/build/common/ops.d.ts.map +1 -0
  93. package/build/common/ops.js +115 -0
  94. package/build/common/render.d.ts +196 -0
  95. package/build/common/render.d.ts.map +1 -0
  96. package/build/common/render.js +474 -0
  97. package/build/common/retryer.d.ts +36 -0
  98. package/build/common/retryer.d.ts.map +1 -0
  99. package/build/common/retryer.js +67 -0
  100. package/build/fetchers/gist.d.ts +15 -0
  101. package/build/fetchers/gist.d.ts.map +1 -0
  102. package/build/fetchers/gist.js +68 -0
  103. package/build/fetchers/index.d.ts +13 -0
  104. package/build/fetchers/index.d.ts.map +1 -0
  105. package/build/fetchers/index.js +10 -0
  106. package/build/fetchers/repo.d.ts +27 -0
  107. package/build/fetchers/repo.d.ts.map +1 -0
  108. package/build/fetchers/repo.js +100 -0
  109. package/build/fetchers/stats.d.ts +74 -0
  110. package/build/fetchers/stats.d.ts.map +1 -0
  111. package/build/fetchers/stats.js +498 -0
  112. package/build/fetchers/top-languages.d.ts +23 -0
  113. package/build/fetchers/top-languages.d.ts.map +1 -0
  114. package/build/fetchers/top-languages.js +89 -0
  115. package/build/fetchers/types.d.ts +130 -0
  116. package/build/fetchers/types.d.ts.map +1 -0
  117. package/build/fetchers/types.js +1 -0
  118. package/build/fetchers/wakatime.d.ts +19 -0
  119. package/build/fetchers/wakatime.d.ts.map +1 -0
  120. package/build/fetchers/wakatime.js +36 -0
  121. package/build/graphql/contributionsDocument.d.ts +18 -0
  122. package/build/graphql/contributionsDocument.d.ts.map +1 -0
  123. package/build/graphql/contributionsDocument.js +30 -0
  124. package/build/graphql/generated/common.d.ts +42 -0
  125. package/build/graphql/generated/common.d.ts.map +1 -0
  126. package/build/graphql/generated/common.js +2 -0
  127. package/build/graphql/generated/gist.d.ts +44 -0
  128. package/build/graphql/generated/gist.d.ts.map +1 -0
  129. package/build/graphql/generated/gist.js +27 -0
  130. package/build/graphql/generated/repo.d.ts +67 -0
  131. package/build/graphql/generated/repo.d.ts.map +1 -0
  132. package/build/graphql/generated/repo.js +30 -0
  133. package/build/graphql/generated/stats.d.ts +150 -0
  134. package/build/graphql/generated/stats.d.ts.map +1 -0
  135. package/build/graphql/generated/stats.js +95 -0
  136. package/build/graphql/generated/top-languages.d.ts +54 -0
  137. package/build/graphql/generated/top-languages.d.ts.map +1 -0
  138. package/build/graphql/generated/top-languages.js +27 -0
  139. package/build/graphql/graphqlDocument.d.ts +22 -0
  140. package/build/graphql/graphqlDocument.d.ts.map +1 -0
  141. package/build/graphql/graphqlDocument.js +8 -0
  142. package/build/graphql/reposContributedToDocument.d.ts +27 -0
  143. package/build/graphql/reposContributedToDocument.d.ts.map +1 -0
  144. package/build/graphql/reposContributedToDocument.js +59 -0
  145. package/build/index.d.ts +15 -0
  146. package/build/index.d.ts.map +1 -0
  147. package/build/index.js +10 -0
  148. package/build/themes/index.d.ts +505 -0
  149. package/build/themes/index.d.ts.map +1 -0
  150. package/build/themes/index.js +505 -0
  151. package/build/translations.d.ts +1153 -0
  152. package/build/translations.d.ts.map +1 -0
  153. package/build/translations.js +1156 -0
  154. package/package.json +114 -0
  155. package/src/_emoji-name-map.d.ts +10 -0
  156. package/src/_github-username-regex.d.ts +4 -0
  157. package/src/api/api-result.ts +69 -0
  158. package/src/api/gist.ts +66 -0
  159. package/src/api/index.ts +16 -0
  160. package/src/api/params.ts +221 -0
  161. package/src/api/pin.ts +126 -0
  162. package/src/api/stats.ts +195 -0
  163. package/src/api/top-langs.ts +150 -0
  164. package/src/api/wakatime.ts +130 -0
  165. package/src/calculateRank.ts +91 -0
  166. package/src/cards/gist.ts +169 -0
  167. package/src/cards/index.ts +21 -0
  168. package/src/cards/options.ts +18 -0
  169. package/src/cards/repo.ts +376 -0
  170. package/src/cards/stats.ts +615 -0
  171. package/src/cards/top-languages.ts +1077 -0
  172. package/src/cards/wakatime.ts +501 -0
  173. package/src/common/Card.ts +364 -0
  174. package/src/common/I18n.ts +51 -0
  175. package/src/common/color.ts +296 -0
  176. package/src/common/config.ts +118 -0
  177. package/src/common/constants.ts +12 -0
  178. package/src/common/date.ts +34 -0
  179. package/src/common/error.ts +163 -0
  180. package/src/common/fmt.ts +86 -0
  181. package/src/common/html.ts +17 -0
  182. package/src/common/http.ts +98 -0
  183. package/src/common/icons.ts +80 -0
  184. package/src/common/languageColors.json +678 -0
  185. package/src/common/languageColors.ts +19 -0
  186. package/src/common/log.ts +12 -0
  187. package/src/common/ops.ts +145 -0
  188. package/src/common/render.ts +641 -0
  189. package/src/common/retryer.ts +111 -0
  190. package/src/fetchers/gist.ts +82 -0
  191. package/src/fetchers/index.ts +25 -0
  192. package/src/fetchers/repo.ts +140 -0
  193. package/src/fetchers/stats.ts +742 -0
  194. package/src/fetchers/top-languages.ts +134 -0
  195. package/src/fetchers/types.ts +136 -0
  196. package/src/fetchers/wakatime.ts +56 -0
  197. package/src/graphql/contributionsDocument.ts +44 -0
  198. package/src/graphql/generated/common.ts +26 -0
  199. package/src/graphql/generated/gist.ts +56 -0
  200. package/src/graphql/generated/repo.ts +79 -0
  201. package/src/graphql/generated/stats.ts +180 -0
  202. package/src/graphql/generated/top-languages.ts +66 -0
  203. package/src/graphql/graphqlDocument.ts +25 -0
  204. package/src/graphql/queries/gist.graphql +25 -0
  205. package/src/graphql/queries/repo.graphql +28 -0
  206. package/src/graphql/queries/stats.graphql +113 -0
  207. package/src/graphql/queries/top-languages.graphql +27 -0
  208. package/src/graphql/reposContributedToDocument.ts +83 -0
  209. package/src/index.ts +18 -0
  210. package/src/themes/index.ts +519 -0
  211. package/src/translations.ts +1169 -0
@@ -0,0 +1,111 @@
1
+ import type { CardConfig } from './config.js';
2
+ import { CardError } from './error.js';
3
+ import type { FetcherContext, HttpResponse } from './http.js';
4
+ import { logger } from './log.js';
5
+
6
+ /**
7
+ * Error-detection fields the retryer inspects to detect rate-limiting and credential failures.
8
+ * Every fetcher's payload is intersected with
9
+ * this, so the retryer can read `errors`/`message` regardless of the payload's own shape.
10
+ */
11
+ interface ResponseErrors {
12
+ errors?: Array<{ type?: string; message?: string }>;
13
+ message?: string;
14
+ }
15
+
16
+ /**
17
+ * Returns a random integer from 0 (inclusive) to `max` (exclusive).
18
+ *
19
+ * The value is generated using `Math.random()` and uniformly distributed
20
+ * across the range.
21
+ *
22
+ * @param max The upper bound (exclusive). Must be a positive number.
23
+ *
24
+ * @returns A random integer `n` such that `0 <= n < max`.
25
+ */
26
+ function getRandomInt(max: number): number {
27
+ return Math.floor(Math.random() * max);
28
+ }
29
+
30
+ /**
31
+ * A fetcher's response. `TData` is the shape of `response.data`,
32
+ * which is intersected with {@link ResponseErrors} so the retryer can inspect
33
+ * `errors`/`message`.
34
+ * Defaults to `unknown` (error fields only) for callers that don't care about the payload.
35
+ */
36
+ type FetcherResponse<TData = unknown> = HttpResponse<TData & ResponseErrors>;
37
+
38
+ type FetcherFunction<TData = unknown, TVariables = Record<string, unknown>> = (
39
+ variables: TVariables,
40
+ token: string,
41
+ context: FetcherContext,
42
+ ) => Promise<FetcherResponse<TData>>;
43
+
44
+ /**
45
+ * Try to execute the fetcher function until it succeeds or the max number of retries is reached.
46
+ *
47
+ * @template TData Shape of `response.data` returned by the fetcher.
48
+ * @template TVariables Variables the fetcher accepts.
49
+ * @param fetcher The fetcher function.
50
+ * @param variables Object with arguments to pass to the fetcher function.
51
+ * @param config Deployment config supplying the PAT pool and the transport.
52
+ * @returns The response from the fetcher function.
53
+ */
54
+ const retryer = async <TData = unknown, TVariables = Record<string, unknown>>(
55
+ fetcher: FetcherFunction<TData, TVariables>,
56
+ variables: TVariables,
57
+ config: CardConfig,
58
+ ): Promise<FetcherResponse<TData>> => {
59
+ const PATs = config.pats;
60
+
61
+ if (!PATs.length) {
62
+ throw new CardError('No GitHub API tokens found', { code: 'no_tokens' });
63
+ }
64
+ const startPAT = getRandomInt(PATs.length);
65
+
66
+ for (let retries = 0; retries < PATs.length; retries++) {
67
+ const currentPAT = PATs[(startPAT + retries) % PATs.length];
68
+ if (!currentPAT) {
69
+ continue;
70
+ }
71
+
72
+ // a non-2xx comes back as a response, so only a transport failure throws — and that is fatal
73
+ const response = await fetcher(variables, currentPAT.value, {
74
+ fetch: config.fetch,
75
+ retries,
76
+ });
77
+
78
+ // react on both type and message-based rate-limit signals.
79
+ // https://github.com/anuraghazra/github-readme-stats/issues/4425
80
+ const errors = response.data.errors;
81
+ const errorType = errors?.[0]?.type;
82
+ const errorMsg = errors?.[0]?.message ?? '';
83
+ const isRateLimited =
84
+ (!!errors && errorType === 'RATE_LIMITED') || /rate limit/i.test(errorMsg);
85
+
86
+ if (isRateLimited) {
87
+ logger.log(`${currentPAT.name} Failed due to rate limiting`);
88
+ continue;
89
+ }
90
+
91
+ // also checking for bad credentials if any tokens gets invalidated
92
+ const message = response.data.message;
93
+ const isBadCredential = message === 'Bad credentials';
94
+ const isAccountSuspended = message === 'Sorry. Your account was suspended.';
95
+
96
+ if (isBadCredential || isAccountSuspended) {
97
+ logger.log(`${currentPAT.name} Failed due to bad credentials`);
98
+ continue;
99
+ }
100
+
101
+ // anything else — including an HTTP error — is the caller's to interpret
102
+ return response;
103
+ }
104
+
105
+ throw new CardError('Downtime due to GitHub API rate limiting', {
106
+ code: 'rate_limited',
107
+ });
108
+ };
109
+
110
+ export { retryer };
111
+ export type { FetcherResponse };
@@ -0,0 +1,82 @@
1
+ import type { CardConfig } from '../common/config.js';
2
+ import { CardError, GIST_NOT_FOUND } from '../common/error.js';
3
+ import { createGraphQLFetcher } from '../common/http.js';
4
+ import { retryer } from '../common/retryer.js';
5
+ import { GistInfoDocument } from '../graphql/generated/gist.js';
6
+ import type { GistFileInfoFragment } from '../graphql/generated/gist.js';
7
+
8
+ import type { GistData } from './types.js';
9
+
10
+ const fetcher = createGraphQLFetcher(GistInfoDocument, 'token');
11
+
12
+ /**
13
+ * This function calculates the primary language of a gist by files size.
14
+ *
15
+ * @param files Files.
16
+ * @returns Primary language, or `null` when no file has a language.
17
+ */
18
+ const calculatePrimaryLanguage = (files: Array<GistFileInfoFragment>): string | null => {
19
+ const languages: Record<string, number> = {};
20
+
21
+ for (const file of files) {
22
+ if (file.language) {
23
+ languages[file.language.name] = (languages[file.language.name] ?? 0) + (file.size ?? 0);
24
+ }
25
+ }
26
+
27
+ let primaryLanguage: string | null = null;
28
+ let maxSize = -1;
29
+ for (const [language, size] of Object.entries(languages)) {
30
+ if (size > maxSize) {
31
+ maxSize = size;
32
+ primaryLanguage = language;
33
+ }
34
+ }
35
+
36
+ return primaryLanguage;
37
+ };
38
+
39
+ /**
40
+ * Fetch GitHub gist information by given username and ID.
41
+ *
42
+ * @param props Fetcher props.
43
+ * @param props.id GitHub gist ID.
44
+ * @param config Deployment config supplying the PAT pool.
45
+ * @returns Gist data.
46
+ */
47
+ const fetchGist = async (
48
+ { id }: { id: string | undefined },
49
+ config: CardConfig,
50
+ ): Promise<GistData> => {
51
+ if (!id) {
52
+ throw CardError.missingParam(['id'], '/api/gist?id=GIST_ID');
53
+ }
54
+ const res = await retryer(fetcher, { gistName: id }, config);
55
+ if (res.data.errors) {
56
+ throw new CardError(res.data.errors[0]?.message ?? 'Could not fetch gist.', {
57
+ code: 'upstream',
58
+ });
59
+ }
60
+ const gist = res.data.data.viewer.gist;
61
+ if (!gist) {
62
+ throw new CardError('Gist not found', {
63
+ code: 'not_found',
64
+ secondaryMessage: GIST_NOT_FOUND,
65
+ });
66
+ }
67
+ const firstFile = gist.files?.[0];
68
+ if (!firstFile?.name) {
69
+ // A gist with nothing to render will not gain a file on a retry.
70
+ throw new CardError('Gist has no files', { code: 'not_found' });
71
+ }
72
+ return {
73
+ name: firstFile.name,
74
+ nameWithOwner: `${gist.owner?.login ?? ''}/${firstFile.name}`,
75
+ description: gist.description,
76
+ language: calculatePrimaryLanguage(gist.files?.filter((file) => !!file) ?? []),
77
+ starsCount: gist.stargazerCount,
78
+ forksCount: gist.forks.totalCount,
79
+ };
80
+ };
81
+
82
+ export { fetchGist };
@@ -0,0 +1,25 @@
1
+ export { fetchGist } from './gist.js';
2
+ export { fetchRepo } from './repo.js';
3
+ export { fetchRepoUserStats, fetchStats } from './stats.js';
4
+ export { fetchTopLanguages } from './top-languages.js';
5
+ export { fetchWakatimeStats } from './wakatime.js';
6
+
7
+ export type {
8
+ GistData,
9
+ Lang,
10
+ RepoUserStats,
11
+ RepositoryData,
12
+ StatsData,
13
+ TopLangData,
14
+ WakaTimeData,
15
+ WakaTimeLang,
16
+ } from './types.js';
17
+
18
+ // every fetcher takes a config, so this entry carries it rather than sending a
19
+ // consumer back to the package root for it.
20
+ export { CardConfig } from '../common/config.js';
21
+ export type { CardConfigInit, PersonalAccessToken } from '../common/config.js';
22
+ export type { FetchLike } from '../common/http.js';
23
+ export { retryer } from '../common/retryer.js';
24
+ export { CardError } from '../common/error.js';
25
+ export type { ErrorCode } from '../common/error.js';
@@ -0,0 +1,140 @@
1
+ import type { CardConfig } from '../common/config.js';
2
+ import { CardError, REPO_NOT_FOUND } from '../common/error.js';
3
+ import { createGraphQLFetcher } from '../common/http.js';
4
+ import { retryer } from '../common/retryer.js';
5
+ import { GetRepoDocument } from '../graphql/generated/repo.js';
6
+
7
+ import { fetchRepoUserStats } from './stats.js';
8
+ import type { RepositoryData } from './types.js';
9
+
10
+ const fetcher = createGraphQLFetcher(GetRepoDocument, 'token');
11
+
12
+ const urlExample = '/api/pin?username=USERNAME&repo=REPO_NAME';
13
+
14
+ /**
15
+ * Fetch repository data.
16
+ *
17
+ * @param props Fetcher props.
18
+ * @param props.username GitHub username.
19
+ * @param props.reponame GitHub repository name.
20
+ * @param props.include_prs_authored Include count of PRs authored.
21
+ * @param props.include_prs_commented Include count of PRs commented.
22
+ * @param props.include_prs_reviewed Include count of PRs reviewed.
23
+ * @param props.include_issues_authored Include count of issues authored.
24
+ * @param props.include_issues_commented Include count of issues commented.
25
+ * @param config Deployment config supplying the PAT pool.
26
+ * @returns Repository data.
27
+ */
28
+ const fetchRepo = async (
29
+ {
30
+ username,
31
+ reponame,
32
+ include_prs_authored = false,
33
+ include_prs_commented = false,
34
+ include_prs_reviewed = false,
35
+ include_issues_authored = false,
36
+ include_issues_commented = false,
37
+ }: {
38
+ username: string | undefined;
39
+ reponame: string | undefined;
40
+ include_prs_authored?: boolean | undefined;
41
+ include_prs_commented?: boolean | undefined;
42
+ include_prs_reviewed?: boolean | undefined;
43
+ include_issues_authored?: boolean | undefined;
44
+ include_issues_commented?: boolean | undefined;
45
+ },
46
+ config: CardConfig,
47
+ ): Promise<RepositoryData> => {
48
+ let owner = username;
49
+ if (reponame && reponame.includes('/')) {
50
+ const [parsedOwner, parsedRepo] = reponame.split('/');
51
+ owner = parsedOwner ?? '';
52
+ reponame = parsedRepo ?? '';
53
+ }
54
+
55
+ if (owner && !username) {
56
+ username = owner;
57
+ }
58
+ if (username && !owner) {
59
+ owner = username;
60
+ }
61
+ if (!username && !reponame) {
62
+ throw CardError.missingParam(['username', 'repo'], urlExample);
63
+ }
64
+ if (!username) {
65
+ throw CardError.missingParam(['username'], urlExample);
66
+ }
67
+ if (!reponame) {
68
+ throw CardError.missingParam(['repo'], urlExample);
69
+ }
70
+
71
+ // the guards above leave `username` set, and `owner` mirrors it when `repo` carried none
72
+ const repoOwner = owner ?? username;
73
+
74
+ const res = await retryer(fetcher, { login: repoOwner, repo: reponame }, config);
75
+
76
+ const data = res.data.data;
77
+
78
+ if (!data.user && !data.organization) {
79
+ throw new CardError('Not found', {
80
+ code: 'not_found',
81
+ secondaryMessage: REPO_NOT_FOUND,
82
+ });
83
+ }
84
+
85
+ if (data.organization === null && data.user) {
86
+ const repository = data.user.repository;
87
+ if (!repository || repository.isPrivate) {
88
+ throw new CardError('User Repository Not found', {
89
+ code: 'not_found',
90
+ secondaryMessage: REPO_NOT_FOUND,
91
+ });
92
+ }
93
+ const repoUserStats = await fetchRepoUserStats(
94
+ {
95
+ username,
96
+ repo: [`${repoOwner}/${reponame}`],
97
+ include_prs_authored,
98
+ include_prs_commented,
99
+ include_prs_reviewed,
100
+ include_issues_authored,
101
+ include_issues_commented,
102
+ },
103
+ config,
104
+ );
105
+ return {
106
+ ...repoUserStats,
107
+ ...repository,
108
+ };
109
+ }
110
+
111
+ if (data.user === null && data.organization) {
112
+ const repository = data.organization.repository;
113
+ if (!repository || repository.isPrivate) {
114
+ throw new CardError('Organization Repository Not found', {
115
+ code: 'not_found',
116
+ secondaryMessage: REPO_NOT_FOUND,
117
+ });
118
+ }
119
+ const repoUserStats = await fetchRepoUserStats(
120
+ {
121
+ username,
122
+ repo: [`${repoOwner}/${reponame}`],
123
+ include_prs_authored,
124
+ include_prs_commented,
125
+ include_prs_reviewed,
126
+ include_issues_authored,
127
+ include_issues_commented,
128
+ },
129
+ config,
130
+ );
131
+ return {
132
+ ...repoUserStats,
133
+ ...repository,
134
+ };
135
+ }
136
+
137
+ throw new CardError('Unexpected behavior', { code: 'upstream' });
138
+ };
139
+
140
+ export { fetchRepo };