@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,53 @@
1
+ import type { FetchLike } from './http.js';
2
+ type Env = Record<string, string | undefined>;
3
+ interface PersonalAccessToken {
4
+ /** Env variable the token came from — the retryer logs this name, never the value. */
5
+ name: string;
6
+ value: string;
7
+ }
8
+ /** Overrides for a {@link CardConfig}; the constructor defaults anything omitted. */
9
+ interface CardConfigInit {
10
+ pats?: ReadonlyArray<PersonalAccessToken>;
11
+ usernameAllowlist?: ReadonlyArray<string> | undefined;
12
+ gistAllowlist?: ReadonlyArray<string> | undefined;
13
+ excludeRepositories?: ReadonlyArray<string>;
14
+ fetchMultiPageStars?: number;
15
+ fetch?: FetchLike;
16
+ }
17
+ /**
18
+ * Deployment-wide configuration for the card renderers.
19
+ *
20
+ * Immutable, and built by the host rather than read from the environment, so the
21
+ * library behaves identically under Node, in the browser and under vitest.
22
+ */
23
+ export declare class CardConfig {
24
+ readonly pats: ReadonlyArray<PersonalAccessToken>;
25
+ /** Allowed usernames; `undefined` means no allowlist configured. */
26
+ readonly usernameAllowlist: ReadonlyArray<string> | undefined;
27
+ /** Allowed gist ids; `undefined` means no allowlist configured. */
28
+ readonly gistAllowlist: ReadonlyArray<string> | undefined;
29
+ readonly excludeRepositories: ReadonlyArray<string>;
30
+ /** Max pages of starred repos; `Infinity` means every page, `1` only the first. */
31
+ readonly fetchMultiPageStars: number;
32
+ /** Transport every fetcher sends through; defaults to `globalThis.fetch`. */
33
+ readonly fetch: FetchLike;
34
+ constructor(init?: CardConfigInit);
35
+ /**
36
+ * @param env Environment variables to read — the host passes `process.env` or an equivalent.
37
+ * @returns Config for this deployment.
38
+ */
39
+ static fromEnv(env: Env): CardConfig;
40
+ /**
41
+ * @param id Username or gist id being requested.
42
+ * @param kind Which allowlist applies.
43
+ * @returns Whether this deployment serves the id.
44
+ */
45
+ isAllowed(id: string, kind: 'username' | 'gist'): boolean;
46
+ /**
47
+ * @param overrides Fields to replace.
48
+ * @returns A copy with `overrides` applied — how a host swaps in a user's PAT per request.
49
+ */
50
+ with(overrides: CardConfigInit): CardConfig;
51
+ }
52
+ export type { PersonalAccessToken, CardConfigInit };
53
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/common/config.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAE3C,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC;AAE9C,UAAU,mBAAmB;IAC3B,sFAAsF;IACtF,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED,qFAAqF;AACrF,UAAU,cAAc;IACtB,IAAI,CAAC,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IAC1C,iBAAiB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IACtD,aAAa,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IAClD,mBAAmB,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IAC5C,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,KAAK,CAAC,EAAE,SAAS,CAAC;CACnB;AA8BD;;;;;GAKG;AACH,qBAAa,UAAU;IACrB,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAC;IAClD,oEAAoE;IACpE,QAAQ,CAAC,iBAAiB,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IAC9D,mEAAmE;IACnE,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,SAAS,CAAC;IAC1D,QAAQ,CAAC,mBAAmB,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;IACpD,mFAAmF;IACnF,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAC;IACrC,6EAA6E;IAC7E,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;gBAEd,IAAI,GAAE,cAAmB;IASrC;;;OAGG;IACH,MAAM,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,GAAG,UAAU;IAUpC;;;;OAIG;IACH,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,MAAM,GAAG,OAAO;IAKzD;;;OAGG;IACH,IAAI,CAAC,SAAS,EAAE,cAAc,GAAG,UAAU;CAW5C;AAED,YAAY,EAAE,mBAAmB,EAAE,cAAc,EAAE,CAAC"}
@@ -0,0 +1,87 @@
1
+ import { defaultFetch } from './http.js';
2
+ /**
3
+ * @param value Comma-separated string.
4
+ * @returns Parsed string values.
5
+ */
6
+ const parseCsv = (value) => value ? value.split(',') : undefined;
7
+ /**
8
+ * @param value Raw `FETCH_MULTI_PAGE_STARS` value.
9
+ * @returns Page limit: `"true"` means every page, a positive number caps the pages, anything else means one.
10
+ */
11
+ const parseFetchMultiPageStars = (value) => {
12
+ if (value === 'true') {
13
+ return Infinity;
14
+ }
15
+ const limit = Number(value);
16
+ return limit > 0 ? limit : 1;
17
+ };
18
+ /**
19
+ * @param env Environment variables to inspect.
20
+ * @returns Personal access tokens found in the environment.
21
+ */
22
+ const parsePATsFromEnv = (env) => Object.keys(env)
23
+ .filter((key) => /PAT_\d*$/.exec(key))
24
+ .map((name) => ({ name, value: env[name] ?? '' }));
25
+ /**
26
+ * Deployment-wide configuration for the card renderers.
27
+ *
28
+ * Immutable, and built by the host rather than read from the environment, so the
29
+ * library behaves identically under Node, in the browser and under vitest.
30
+ */
31
+ export class CardConfig {
32
+ pats;
33
+ /** Allowed usernames; `undefined` means no allowlist configured. */
34
+ usernameAllowlist;
35
+ /** Allowed gist ids; `undefined` means no allowlist configured. */
36
+ gistAllowlist;
37
+ excludeRepositories;
38
+ /** Max pages of starred repos; `Infinity` means every page, `1` only the first. */
39
+ fetchMultiPageStars;
40
+ /** Transport every fetcher sends through; defaults to `globalThis.fetch`. */
41
+ fetch;
42
+ constructor(init = {}) {
43
+ this.pats = init.pats ?? [];
44
+ this.usernameAllowlist = init.usernameAllowlist;
45
+ this.gistAllowlist = init.gistAllowlist;
46
+ this.excludeRepositories = init.excludeRepositories ?? [];
47
+ this.fetchMultiPageStars = init.fetchMultiPageStars ?? 1;
48
+ this.fetch = init.fetch ?? defaultFetch;
49
+ }
50
+ /**
51
+ * @param env Environment variables to read — the host passes `process.env` or an equivalent.
52
+ * @returns Config for this deployment.
53
+ */
54
+ static fromEnv(env) {
55
+ return new CardConfig({
56
+ pats: parsePATsFromEnv(env),
57
+ usernameAllowlist: parseCsv(env['WHITELIST']),
58
+ gistAllowlist: parseCsv(env['GIST_WHITELIST']),
59
+ excludeRepositories: parseCsv(env['EXCLUDE_REPO']) ?? [],
60
+ fetchMultiPageStars: parseFetchMultiPageStars(env['FETCH_MULTI_PAGE_STARS']),
61
+ });
62
+ }
63
+ /**
64
+ * @param id Username or gist id being requested.
65
+ * @param kind Which allowlist applies.
66
+ * @returns Whether this deployment serves the id.
67
+ */
68
+ isAllowed(id, kind) {
69
+ const list = kind === 'gist' ? this.gistAllowlist : this.usernameAllowlist;
70
+ return list === undefined || list.includes(id);
71
+ }
72
+ /**
73
+ * @param overrides Fields to replace.
74
+ * @returns A copy with `overrides` applied — how a host swaps in a user's PAT per request.
75
+ */
76
+ with(overrides) {
77
+ return new CardConfig({
78
+ pats: this.pats,
79
+ usernameAllowlist: this.usernameAllowlist,
80
+ gistAllowlist: this.gistAllowlist,
81
+ excludeRepositories: this.excludeRepositories,
82
+ fetchMultiPageStars: this.fetchMultiPageStars,
83
+ fetch: this.fetch,
84
+ ...overrides,
85
+ });
86
+ }
87
+ }
@@ -0,0 +1,7 @@
1
+ import type { RepositoryAffiliation } from '../graphql/generated/common.js';
2
+ /**
3
+ * Valid owner affiliations for GitHub API queries.
4
+ */
5
+ declare const OWNER_AFFILIATIONS: Array<RepositoryAffiliation>;
6
+ export { OWNER_AFFILIATIONS };
7
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/common/constants.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gCAAgC,CAAC;AAE5E;;GAEG;AACH,QAAA,MAAM,kBAAkB,EAAE,KAAK,CAAC,qBAAqB,CAIpD,CAAC;AAEF,OAAO,EAAE,kBAAkB,EAAE,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Valid owner affiliations for GitHub API queries.
3
+ */
4
+ const OWNER_AFFILIATIONS = [
5
+ 'OWNER',
6
+ 'COLLABORATOR',
7
+ 'ORGANIZATION_MEMBER',
8
+ ];
9
+ export { OWNER_AFFILIATIONS };
@@ -0,0 +1,29 @@
1
+ /** A span between two dates, as GitHub's range arguments take it. */
2
+ interface GitHubDateRange {
3
+ /** Start of the range, inclusive. */
4
+ from: Date;
5
+ /** End of the range, inclusive. */
6
+ to: Date;
7
+ }
8
+ /**
9
+ * Format a date as a GitHub `DateTime` scalar.
10
+ * Seconds precision, no milliseconds.
11
+ *
12
+ * @param date Date to format.
13
+ * @returns e.g. `2024-01-01T00:00:00Z`.
14
+ */
15
+ declare const toGitHubDateTime: (date: Date) => string;
16
+ /**
17
+ * The full UTC span of a calendar year, both ends inclusive.
18
+ *
19
+ * The end matters to callers that would otherwise leave a range open:
20
+ * GitHub's `contributionsCollection` defaults `to` to one year after `from`,
21
+ * which pulls the next 1st of January into the year.
22
+ *
23
+ * @param year Four-digit year.
24
+ * @returns The range covering it.
25
+ */
26
+ declare const getGitHubYearRange: (year: number) => GitHubDateRange;
27
+ export { getGitHubYearRange, toGitHubDateTime };
28
+ export type { GitHubDateRange };
29
+ //# sourceMappingURL=date.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"date.d.ts","sourceRoot":"","sources":["../../src/common/date.ts"],"names":[],"mappings":"AAAA,qEAAqE;AACrE,UAAU,eAAe;IACvB,qCAAqC;IACrC,IAAI,EAAE,IAAI,CAAC;IACX,mCAAmC;IACnC,EAAE,EAAE,IAAI,CAAC;CACV;AAED;;;;;;GAMG;AACH,QAAA,MAAM,gBAAgB,GAAI,MAAM,IAAI,KAAG,MAA+C,CAAC;AAEvF;;;;;;;;;GASG;AACH,QAAA,MAAM,kBAAkB,GAAI,MAAM,MAAM,KAAG,eAGzC,CAAC;AAEH,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,CAAC;AAChD,YAAY,EAAE,eAAe,EAAE,CAAC"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Format a date as a GitHub `DateTime` scalar.
3
+ * Seconds precision, no milliseconds.
4
+ *
5
+ * @param date Date to format.
6
+ * @returns e.g. `2024-01-01T00:00:00Z`.
7
+ */
8
+ const toGitHubDateTime = (date) => `${date.toISOString().slice(0, 19)}Z`;
9
+ /**
10
+ * The full UTC span of a calendar year, both ends inclusive.
11
+ *
12
+ * The end matters to callers that would otherwise leave a range open:
13
+ * GitHub's `contributionsCollection` defaults `to` to one year after `from`,
14
+ * which pulls the next 1st of January into the year.
15
+ *
16
+ * @param year Four-digit year.
17
+ * @returns The range covering it.
18
+ */
19
+ const getGitHubYearRange = (year) => ({
20
+ from: new Date(Date.UTC(year, 0, 1)),
21
+ to: new Date(Date.UTC(year, 11, 31, 23, 59, 59)),
22
+ });
23
+ export { getGitHubYearRange, toGitHubDateTime };
@@ -0,0 +1,87 @@
1
+ /**
2
+ * @file One error type for everything a card render can fail on.
3
+ *
4
+ * A failure carries a `code` a host can branch on, the two lines the error card
5
+ * draws, and — through the code — whether repeating the request could help.
6
+ * The fetchers throw this rather than a bare `Error`, so a host is told what failed.
7
+ * Anything else that escapes is wrapped as `upstream` by `from`, which is retryable —
8
+ * so a permanent failure has to throw a `CardError` to be reported as one.
9
+ */
10
+ /** A general message to ask user to try again later. */
11
+ declare const TRY_AGAIN_LATER = "Please try again later";
12
+ /** Why a request failed. */
13
+ type ErrorCode =
14
+ /** The query is wrong: a param is malformed, unsafe, or not renderable. */
15
+ 'invalid_param'
16
+ /** The query is missing a param the endpoint cannot render without. */
17
+ | 'missing_param'
18
+ /** The user, repository or gist does not exist. */
19
+ | 'not_found'
20
+ /** The deployment has no usable GitHub token. */
21
+ | 'no_tokens'
22
+ /** Every token is rate limited. */
23
+ | 'rate_limited'
24
+ /** GitHub or WakaTime answered with something unusable. */
25
+ | 'upstream';
26
+ /** The second line the error card draws, per code. */
27
+ declare const SECONDARY_ERROR_MESSAGES: Partial<Record<ErrorCode, string>>;
28
+ /** What a failure is, once it reaches the api layer. */
29
+ interface CardErrorInit {
30
+ /** Why it failed. */
31
+ code: ErrorCode;
32
+ /** Second line of the error card; the code's own message when omitted. */
33
+ secondaryMessage?: string | undefined;
34
+ /** The first param at fault, when the failure names one. */
35
+ param?: string | undefined;
36
+ }
37
+ /** Everything this package throws. */
38
+ declare class CardError extends Error {
39
+ readonly code: ErrorCode;
40
+ readonly secondaryMessage: string | undefined;
41
+ readonly param: string | undefined;
42
+ /**
43
+ * @param message First line of the error card.
44
+ * @param init Why it failed, and what to draw under the message.
45
+ */
46
+ constructor(message: string, init: CardErrorInit);
47
+ /** Whether repeating the request could produce a different answer. */
48
+ get retryable(): boolean;
49
+ /**
50
+ * A param the endpoint cannot render with.
51
+ *
52
+ * @param param Name of the param.
53
+ * @param secondaryMessage What is wrong with it.
54
+ * @returns The error.
55
+ */
56
+ static invalidParam(param: string, secondaryMessage: string): CardError;
57
+ /**
58
+ * A param the endpoint cannot render without.
59
+ *
60
+ * @param params Names of the missing params.
61
+ * `param` carries the first; the message names them all.
62
+ * @param secondaryMessage Where to pass them, when the endpoint can say.
63
+ * @returns The error.
64
+ */
65
+ static missingParam(params: Array<string>, secondaryMessage?: string): CardError;
66
+ /**
67
+ * Anything thrown that is not already a `CardError`:
68
+ * an upstream failure, since the query itself got this far.
69
+ *
70
+ * @param err Whatever was thrown.
71
+ * @returns The error, unchanged when it already was one.
72
+ */
73
+ static from(err: unknown): CardError;
74
+ }
75
+ /** The affiliation values `role` accepts, named in the rejection. */
76
+ declare const INVALID_AFFILIATION: string;
77
+ /** The user exists but has no public WakaTime profile. */
78
+ declare const WAKATIME_USER_NOT_FOUND = "Make sure you have a public WakaTime profile";
79
+ /** A GitHub username that resolves to nothing, or to an organization. */
80
+ declare const USER_NOT_FOUND = "Make sure the provided username is not an organization";
81
+ /** A repository the token cannot see, because it is missing or private. */
82
+ declare const REPO_NOT_FOUND = "Make sure the provided username and repository are correct";
83
+ /** A gist id that resolves to nothing. */
84
+ declare const GIST_NOT_FOUND = "Make sure the provided gist ID is correct";
85
+ export type { ErrorCode };
86
+ export { CardError, GIST_NOT_FOUND, INVALID_AFFILIATION, REPO_NOT_FOUND, SECONDARY_ERROR_MESSAGES, TRY_AGAIN_LATER, USER_NOT_FOUND, WAKATIME_USER_NOT_FOUND, };
87
+ //# sourceMappingURL=error.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"error.d.ts","sourceRoot":"","sources":["../../src/common/error.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AAEH,wDAAwD;AACxD,QAAA,MAAM,eAAe,2BAA2B,CAAC;AAEjD,4BAA4B;AAC5B,KAAK,SAAS;AACZ,2EAA2E;AACzE,eAAe;AACjB,uEAAuE;GACrE,eAAe;AACjB,mDAAmD;GACjD,WAAW;AACb,iDAAiD;GAC/C,WAAW;AACb,mCAAmC;GACjC,cAAc;AAChB,2DAA2D;GACzD,UAAU,CAAC;AAef,sDAAsD;AACtD,QAAA,MAAM,wBAAwB,EAAE,OAAO,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAKhE,CAAC;AAEF,wDAAwD;AACxD,UAAU,aAAa;IACrB,qBAAqB;IACrB,IAAI,EAAE,SAAS,CAAC;IAChB,0EAA0E;IAC1E,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,4DAA4D;IAC5D,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B;AAED,sCAAsC;AACtC,cAAM,SAAU,SAAQ,KAAK;IAC3B,QAAQ,CAAC,IAAI,EAAE,SAAS,CAAC;IACzB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,GAAG,SAAS,CAAC;IAC9C,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAEnC;;;OAGG;gBACS,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,aAAa;IAQhD,sEAAsE;IACtE,IAAI,SAAS,IAAI,OAAO,CAEvB;IAED;;;;;;OAMG;IACH,MAAM,CAAC,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,GAAG,SAAS;IAQvE;;;;;;;OAOG;IACH,MAAM,CAAC,YAAY,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS;IAShF;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,CAAC,GAAG,EAAE,OAAO,GAAG,SAAS;CASrC;AAED,qEAAqE;AACrE,QAAA,MAAM,mBAAmB,QAEtB,CAAC;AAEJ,0DAA0D;AAC1D,QAAA,MAAM,uBAAuB,iDAAiD,CAAC;AAE/E,yEAAyE;AACzE,QAAA,MAAM,cAAc,2DAA2D,CAAC;AAEhF,2EAA2E;AAC3E,QAAA,MAAM,cAAc,+DAA+D,CAAC;AAEpF,0CAA0C;AAC1C,QAAA,MAAM,cAAc,8CAA8C,CAAC;AAEnE,YAAY,EAAE,SAAS,EAAE,CAAC;AAE1B,OAAO,EACL,SAAS,EACT,cAAc,EACd,mBAAmB,EACnB,cAAc,EACd,wBAAwB,EACxB,eAAe,EACf,cAAc,EACd,uBAAuB,GACxB,CAAC"}
@@ -0,0 +1,108 @@
1
+ import { OWNER_AFFILIATIONS } from './constants.js';
2
+ /**
3
+ * @file One error type for everything a card render can fail on.
4
+ *
5
+ * A failure carries a `code` a host can branch on, the two lines the error card
6
+ * draws, and — through the code — whether repeating the request could help.
7
+ * The fetchers throw this rather than a bare `Error`, so a host is told what failed.
8
+ * Anything else that escapes is wrapped as `upstream` by `from`, which is retryable —
9
+ * so a permanent failure has to throw a `CardError` to be reported as one.
10
+ */
11
+ /** A general message to ask user to try again later. */
12
+ const TRY_AGAIN_LATER = 'Please try again later';
13
+ /**
14
+ * Whether repeating the request could produce a different answer.
15
+ * A host reads this to decide between caching the failure and retrying it.
16
+ */
17
+ const RETRYABLE = {
18
+ invalid_param: false,
19
+ missing_param: false,
20
+ not_found: false,
21
+ no_tokens: false,
22
+ rate_limited: true,
23
+ upstream: true,
24
+ };
25
+ /** The second line the error card draws, per code. */
26
+ const SECONDARY_ERROR_MESSAGES = {
27
+ rate_limited: 'You can deploy own instance or wait until public will be no longer limited',
28
+ no_tokens: 'Please add an env variable called PAT_1 with your GitHub API token in your deployment environment',
29
+ upstream: TRY_AGAIN_LATER,
30
+ };
31
+ /** Everything this package throws. */
32
+ class CardError extends Error {
33
+ code;
34
+ secondaryMessage;
35
+ param;
36
+ /**
37
+ * @param message First line of the error card.
38
+ * @param init Why it failed, and what to draw under the message.
39
+ */
40
+ constructor(message, init) {
41
+ super(message);
42
+ this.name = 'CardError';
43
+ this.code = init.code;
44
+ this.param = init.param;
45
+ this.secondaryMessage = init.secondaryMessage ?? SECONDARY_ERROR_MESSAGES[init.code];
46
+ }
47
+ /** Whether repeating the request could produce a different answer. */
48
+ get retryable() {
49
+ return RETRYABLE[this.code];
50
+ }
51
+ /**
52
+ * A param the endpoint cannot render with.
53
+ *
54
+ * @param param Name of the param.
55
+ * @param secondaryMessage What is wrong with it.
56
+ * @returns The error.
57
+ */
58
+ static invalidParam(param, secondaryMessage) {
59
+ return new CardError('Something went wrong', {
60
+ code: 'invalid_param',
61
+ secondaryMessage,
62
+ param,
63
+ });
64
+ }
65
+ /**
66
+ * A param the endpoint cannot render without.
67
+ *
68
+ * @param params Names of the missing params.
69
+ * `param` carries the first; the message names them all.
70
+ * @param secondaryMessage Where to pass them, when the endpoint can say.
71
+ * @returns The error.
72
+ */
73
+ static missingParam(params, secondaryMessage) {
74
+ const named = params.map((param) => `"${param}"`).join(', ');
75
+ return new CardError(`Missing params ${named} make sure you pass the parameters in URL`, {
76
+ code: 'missing_param',
77
+ secondaryMessage,
78
+ param: params[0],
79
+ });
80
+ }
81
+ /**
82
+ * Anything thrown that is not already a `CardError`:
83
+ * an upstream failure, since the query itself got this far.
84
+ *
85
+ * @param err Whatever was thrown.
86
+ * @returns The error, unchanged when it already was one.
87
+ */
88
+ static from(err) {
89
+ if (err instanceof CardError) {
90
+ return err;
91
+ }
92
+ if (err instanceof Error) {
93
+ return new CardError(err.message, { code: 'upstream' });
94
+ }
95
+ return new CardError('An unknown error occurred', { code: 'upstream' });
96
+ }
97
+ }
98
+ /** The affiliation values `role` accepts, named in the rejection. */
99
+ const INVALID_AFFILIATION = `Invalid owner affiliations. Valid values are: ${OWNER_AFFILIATIONS.join(', ')}`;
100
+ /** The user exists but has no public WakaTime profile. */
101
+ const WAKATIME_USER_NOT_FOUND = 'Make sure you have a public WakaTime profile';
102
+ /** A GitHub username that resolves to nothing, or to an organization. */
103
+ const USER_NOT_FOUND = 'Make sure the provided username is not an organization';
104
+ /** A repository the token cannot see, because it is missing or private. */
105
+ const REPO_NOT_FOUND = 'Make sure the provided username and repository are correct';
106
+ /** A gist id that resolves to nothing. */
107
+ const GIST_NOT_FOUND = 'Make sure the provided gist ID is correct';
108
+ export { CardError, GIST_NOT_FOUND, INVALID_AFFILIATION, REPO_NOT_FOUND, SECONDARY_ERROR_MESSAGES, TRY_AGAIN_LATER, USER_NOT_FOUND, WAKATIME_USER_NOT_FOUND, };
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Retrieves num with suffix k(thousands) precise to given decimal places.
3
+ *
4
+ * @param num The number to format.
5
+ * @param precision The number of decimal places to include.
6
+ * @returns The formatted number.
7
+ */
8
+ declare const kFormatter: (num: number, precision?: number) => string | number;
9
+ /**
10
+ * Convert bytes to a human-readable string representation.
11
+ *
12
+ * @param bytes The number of bytes to convert.
13
+ * @returns The human-readable representation of bytes.
14
+ * @throws {Error} If bytes is negative or too large.
15
+ */
16
+ declare const formatBytes: (bytes: number) => string;
17
+ /**
18
+ * Split text over multiple lines based on the card width.
19
+ *
20
+ * @param text Text to split.
21
+ * @param width Available wrap width in px.
22
+ * @param fontSize Font size in px.
23
+ * @param maxLines Maximum number of lines.
24
+ * @returns Array of lines.
25
+ */
26
+ declare const wrapTextMultiline: (text: string, width: number, fontSize: number, maxLines?: number) => Array<string>;
27
+ export { kFormatter, formatBytes, wrapTextMultiline };
28
+ //# sourceMappingURL=fmt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fmt.d.ts","sourceRoot":"","sources":["../../src/common/fmt.ts"],"names":[],"mappings":"AAGA;;;;;;GAMG;AACH,QAAA,MAAM,UAAU,GAAI,KAAK,MAAM,EAAE,YAAY,MAAM,KAAG,MAAM,GAAG,MAa9D,CAAC;AAEF;;;;;;GAMG;AACH,QAAA,MAAM,WAAW,GAAI,OAAO,MAAM,KAAG,MAmBpC,CAAC;AAEF;;;;;;;;GAQG;AACH,QAAA,MAAM,iBAAiB,GACrB,MAAM,MAAM,EACZ,OAAO,MAAM,EACb,UAAU,MAAM,EAChB,iBAAY,KACX,KAAK,CAAC,MAAM,CAgBd,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,iBAAiB,EAAE,CAAC"}
@@ -0,0 +1,68 @@
1
+ import { encodeHTML } from './html.js';
2
+ import { splitWrappedText } from './render.js';
3
+ /**
4
+ * Retrieves num with suffix k(thousands) precise to given decimal places.
5
+ *
6
+ * @param num The number to format.
7
+ * @param precision The number of decimal places to include.
8
+ * @returns The formatted number.
9
+ */
10
+ const kFormatter = (num, precision) => {
11
+ const abs = Math.abs(num);
12
+ const sign = Math.sign(num);
13
+ if (typeof precision === 'number' && !isNaN(precision)) {
14
+ return (sign * (abs / 1000)).toFixed(precision) + 'k';
15
+ }
16
+ if (abs < 1000) {
17
+ return sign * abs;
18
+ }
19
+ return `${sign * parseFloat((abs / 1000).toFixed(1))}k`;
20
+ };
21
+ /**
22
+ * Convert bytes to a human-readable string representation.
23
+ *
24
+ * @param bytes The number of bytes to convert.
25
+ * @returns The human-readable representation of bytes.
26
+ * @throws {Error} If bytes is negative or too large.
27
+ */
28
+ const formatBytes = (bytes) => {
29
+ if (bytes < 0) {
30
+ throw new Error('Bytes must be a non-negative number');
31
+ }
32
+ if (bytes === 0) {
33
+ return '0 B';
34
+ }
35
+ const sizes = ['B', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB'];
36
+ const base = 1024;
37
+ const i = Math.floor(Math.log(bytes) / Math.log(base));
38
+ const unit = sizes[i];
39
+ if (unit === undefined) {
40
+ throw new Error('Bytes is too large to convert to a human-readable string');
41
+ }
42
+ return `${(bytes / Math.pow(base, i)).toFixed(1)} ${unit}`;
43
+ };
44
+ /**
45
+ * Split text over multiple lines based on the card width.
46
+ *
47
+ * @param text Text to split.
48
+ * @param width Available wrap width in px.
49
+ * @param fontSize Font size in px.
50
+ * @param maxLines Maximum number of lines.
51
+ * @returns Array of lines.
52
+ */
53
+ const wrapTextMultiline = (text, width, fontSize, maxLines = 3) => {
54
+ const wrapped = splitWrappedText(text, fontSize, width);
55
+ const lines = wrapped.map((line) => encodeHTML(line.trim())).slice(0, maxLines); // Only consider maxLines lines
56
+ // Add "..." to the last line if the text exceeds maxLines
57
+ if (wrapped.length > maxLines) {
58
+ const lastIndex = maxLines - 1;
59
+ const lastLine = lines[lastIndex];
60
+ if (lastLine !== undefined) {
61
+ lines[lastIndex] = `${lastLine}...`;
62
+ }
63
+ }
64
+ // Remove empty lines if text fits in less than maxLines lines
65
+ const multiLineText = lines.filter(Boolean);
66
+ return multiLineText;
67
+ };
68
+ export { kFormatter, formatBytes, wrapTextMultiline };
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Encode string as HTML.
3
+ *
4
+ * @see https://stackoverflow.com/a/48073476/10629172
5
+ */
6
+ declare const encodeHTML: (str: string) => string;
7
+ export { encodeHTML };
8
+ //# sourceMappingURL=html.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"html.d.ts","sourceRoot":"","sources":["../../src/common/html.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,QAAA,MAAM,UAAU,GAAI,KAAK,MAAM,KAAG,MASjC,CAAC;AAEF,OAAO,EAAE,UAAU,EAAE,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Encode string as HTML.
3
+ *
4
+ * @see https://stackoverflow.com/a/48073476/10629172
5
+ */
6
+ const encodeHTML = (str) => {
7
+ return (str
8
+ .replace(/[\u00A0-\u9999<>&"'](?!#)/gim, (i) => {
9
+ return `&#${i.charCodeAt(0)};`;
10
+ })
11
+ // eslint-disable-next-line no-control-regex
12
+ .replace(/\u0008/gim, ''));
13
+ };
14
+ export { encodeHTML };
@@ -0,0 +1,53 @@
1
+ import type { GraphQLDocument } from '../graphql/graphqlDocument.js';
2
+ /**
3
+ * The slice of `fetch` this library calls.
4
+ * A host substitutes it through `CardConfig` to mock, cache or proxy every request core makes.
5
+ */
6
+ type FetchLike = (input: string, init?: RequestInit) => Promise<Response>;
7
+ /**
8
+ * Resolves the global `fetch` at call time rather than capturing it on import,
9
+ * so a host that patches the global afterwards is still picked up.
10
+ */
11
+ declare const defaultFetch: FetchLike;
12
+ /**
13
+ * A response, parsed.
14
+ * A non-2xx is a value here rather than a throw:
15
+ * the retryer reads the body of a rejected request to tell a spent token from a rate limit.
16
+ */
17
+ interface HttpResponse<TData> {
18
+ status: number;
19
+ /** Reason phrase, which HTTP/2 omits — only ever used to annotate an error. */
20
+ statusText: string;
21
+ data: TData;
22
+ }
23
+ /** What the retryer hands a fetcher on each attempt. */
24
+ interface FetcherContext {
25
+ /** Transport to send the request with. */
26
+ fetch: FetchLike;
27
+ /** Attempt index, from 0. Tests read it to fake a rate limit on the first token. */
28
+ retries: number;
29
+ }
30
+ /**
31
+ * @param fetchImpl Transport to send the request with.
32
+ * @param url Absolute URL to request.
33
+ * @param init Request init forwarded to the transport.
34
+ * @returns The response; a JSON body parsed, anything else left as text.
35
+ */
36
+ declare const httpRequest: <TData>(fetchImpl: FetchLike, url: string, init?: RequestInit) => Promise<HttpResponse<TData>>;
37
+ /** Response of a GraphQL call: the envelope the GitHub API wraps results in. */
38
+ type GraphQLResponse<TResult> = HttpResponse<{
39
+ data: TResult;
40
+ errors?: Array<{
41
+ type?: string;
42
+ message?: string;
43
+ }>;
44
+ }>;
45
+ /**
46
+ * @param document Generated query document.
47
+ * @param scheme `Authorization` scheme for the token.
48
+ * @returns A fetcher `retryer` can drive.
49
+ */
50
+ declare const createGraphQLFetcher: <TResult, TVariables>(document: GraphQLDocument<TResult, TVariables>, scheme: "bearer" | "token") => (variables: TVariables, token: string, { fetch }: FetcherContext) => Promise<GraphQLResponse<TResult>>;
51
+ export { createGraphQLFetcher, defaultFetch, httpRequest };
52
+ export type { FetcherContext, FetchLike, GraphQLResponse, HttpResponse };
53
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../../src/common/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAIrE;;;GAGG;AACH,KAAK,SAAS,GAAG,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;AAE1E;;;GAGG;AACH,QAAA,MAAM,YAAY,EAAE,SAA+C,CAAC;AAEpE;;;;GAIG;AACH,UAAU,YAAY,CAAC,KAAK;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,+EAA+E;IAC/E,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,KAAK,CAAC;CACb;AAED,wDAAwD;AACxD,UAAU,cAAc;IACtB,0CAA0C;IAC1C,KAAK,EAAE,SAAS,CAAC;IACjB,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;;;;GAKG;AACH,QAAA,MAAM,WAAW,GAAU,KAAK,EAC9B,WAAW,SAAS,EACpB,KAAK,MAAM,EACX,OAAO,WAAW,KACjB,OAAO,CAAC,YAAY,CAAC,KAAK,CAAC,CAiB7B,CAAC;AAEF,gFAAgF;AAChF,KAAK,eAAe,CAAC,OAAO,IAAI,YAAY,CAAC;IAC3C,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,OAAO,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACrD,CAAC,CAAC;AAEH;;;;GAIG;AACH,QAAA,MAAM,oBAAoB,GAAI,OAAO,EAAE,UAAU,EAC/C,UAAU,eAAe,CAAC,OAAO,EAAE,UAAU,CAAC,EAC9C,QAAQ,QAAQ,GAAG,OAAO,MAGxB,WAAW,UAAU,EACrB,OAAO,MAAM,EACb,WAAW,cAAc,KACxB,OAAO,CAAC,eAAe,CAAC,OAAO,CAAC,CAUpC,CAAC;AAEF,OAAO,EAAE,oBAAoB,EAAE,YAAY,EAAE,WAAW,EAAE,CAAC;AAC3D,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,eAAe,EAAE,YAAY,EAAE,CAAC"}
@@ -0,0 +1,47 @@
1
+ const GITHUB_GRAPHQL_API = 'https://api.github.com/graphql';
2
+ /**
3
+ * Resolves the global `fetch` at call time rather than capturing it on import,
4
+ * so a host that patches the global afterwards is still picked up.
5
+ */
6
+ const defaultFetch = (input, init) => fetch(input, init);
7
+ /**
8
+ * @param fetchImpl Transport to send the request with.
9
+ * @param url Absolute URL to request.
10
+ * @param init Request init forwarded to the transport.
11
+ * @returns The response; a JSON body parsed, anything else left as text.
12
+ */
13
+ const httpRequest = async (fetchImpl, url, init) => {
14
+ const response = await fetchImpl(url, init);
15
+ const body = await response.text();
16
+ let data;
17
+ try {
18
+ data = JSON.parse(body);
19
+ }
20
+ catch {
21
+ // an empty or non-JSON body reads as text, so callers still get a defined `data`
22
+ data = body;
23
+ }
24
+ return {
25
+ status: response.status,
26
+ statusText: response.statusText,
27
+ data: data,
28
+ };
29
+ };
30
+ /**
31
+ * @param document Generated query document.
32
+ * @param scheme `Authorization` scheme for the token.
33
+ * @returns A fetcher `retryer` can drive.
34
+ */
35
+ const createGraphQLFetcher = (document, scheme) => {
36
+ return (variables, token, { fetch }) => {
37
+ return httpRequest(fetch, GITHUB_GRAPHQL_API, {
38
+ method: 'POST',
39
+ headers: {
40
+ Authorization: `${scheme} ${token}`,
41
+ 'Content-Type': 'application/json',
42
+ },
43
+ body: JSON.stringify({ query: document.text, variables }),
44
+ });
45
+ };
46
+ };
47
+ export { createGraphQLFetcher, defaultFetch, httpRequest };