github-issue-tower-defence-management 1.123.3 → 1.125.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/bin/adapter/entry-points/cli/projectConfig.js +6 -11
- package/bin/adapter/entry-points/cli/projectConfig.js.map +1 -1
- package/bin/adapter/repositories/GraphqlProjectRepository.js +21 -36
- package/bin/adapter/repositories/GraphqlProjectRepository.js.map +1 -1
- package/bin/adapter/repositories/githubGraphqlClient.js +99 -0
- package/bin/adapter/repositories/githubGraphqlClient.js.map +1 -0
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js +278 -304
- package/bin/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.js.map +1 -1
- package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js +79 -142
- package/bin/adapter/repositories/issue/GraphqlProjectItemRepository.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/cli/projectConfig.ts +6 -11
- package/src/adapter/repositories/GraphqlProjectRepository.ts +81 -77
- package/src/adapter/repositories/githubGraphqlClient.test.ts +251 -0
- package/src/adapter/repositories/githubGraphqlClient.ts +122 -0
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.test.ts +663 -328
- package/src/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.ts +465 -449
- package/src/adapter/repositories/issue/GraphqlProjectItemRepository.test.ts +62 -0
- package/src/adapter/repositories/issue/GraphqlProjectItemRepository.ts +208 -237
- package/types/adapter/entry-points/cli/projectConfig.d.ts.map +1 -1
- package/types/adapter/repositories/GraphqlProjectRepository.d.ts.map +1 -1
- package/types/adapter/repositories/githubGraphqlClient.d.ts +21 -0
- package/types/adapter/repositories/githubGraphqlClient.d.ts.map +1 -0
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts +6 -0
- package/types/adapter/repositories/issue/ApiV3CheerioRestIssueRepository.d.ts.map +1 -1
- package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts +2 -0
- package/types/adapter/repositories/issue/GraphqlProjectItemRepository.d.ts.map +1 -1
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import ky from 'ky';
|
|
2
|
+
|
|
3
|
+
export const GITHUB_GRAPHQL_ENDPOINT = 'https://api.github.com/graphql';
|
|
4
|
+
|
|
5
|
+
export const RATE_LIMIT_SELECTION = 'rateLimit { cost remaining }';
|
|
6
|
+
|
|
7
|
+
export type GithubGraphqlRateLimit = {
|
|
8
|
+
cost: number;
|
|
9
|
+
remaining: number;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export const isMutationOperation = (query: string): boolean =>
|
|
13
|
+
query.trimStart().startsWith('mutation');
|
|
14
|
+
|
|
15
|
+
export const extractGraphqlOperationName = (query: string): string => {
|
|
16
|
+
const match = query.match(
|
|
17
|
+
/^\s*(?:query|mutation)\s+([A-Za-z_][A-Za-z0-9_]*)/,
|
|
18
|
+
);
|
|
19
|
+
return match ? match[1] : 'anonymous';
|
|
20
|
+
};
|
|
21
|
+
|
|
22
|
+
export const injectRateLimitSelection = (query: string): string => {
|
|
23
|
+
if (isMutationOperation(query)) {
|
|
24
|
+
return query;
|
|
25
|
+
}
|
|
26
|
+
const lastBraceIndex = query.lastIndexOf('}');
|
|
27
|
+
if (lastBraceIndex === -1) {
|
|
28
|
+
return query;
|
|
29
|
+
}
|
|
30
|
+
return `${query.slice(0, lastBraceIndex)} ${RATE_LIMIT_SELECTION}\n${query.slice(lastBraceIndex)}`;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
const extractRateLimit = (
|
|
34
|
+
responseBody: unknown,
|
|
35
|
+
): GithubGraphqlRateLimit | null => {
|
|
36
|
+
if (
|
|
37
|
+
typeof responseBody !== 'object' ||
|
|
38
|
+
responseBody === null ||
|
|
39
|
+
!('data' in responseBody)
|
|
40
|
+
) {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
const data: unknown = responseBody.data;
|
|
44
|
+
if (typeof data !== 'object' || data === null || !('rateLimit' in data)) {
|
|
45
|
+
return null;
|
|
46
|
+
}
|
|
47
|
+
const rateLimit: unknown = data.rateLimit;
|
|
48
|
+
if (
|
|
49
|
+
typeof rateLimit !== 'object' ||
|
|
50
|
+
rateLimit === null ||
|
|
51
|
+
!('cost' in rateLimit) ||
|
|
52
|
+
!('remaining' in rateLimit)
|
|
53
|
+
) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
const { cost, remaining } = rateLimit;
|
|
57
|
+
if (typeof cost !== 'number' || typeof remaining !== 'number') {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return { cost, remaining };
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export const logGithubGraphqlCost = (
|
|
64
|
+
query: string,
|
|
65
|
+
responseBody: unknown,
|
|
66
|
+
): void => {
|
|
67
|
+
const rateLimit = extractRateLimit(responseBody);
|
|
68
|
+
if (!rateLimit) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
console.log(
|
|
72
|
+
`githubGraphqlClient: query=${extractGraphqlOperationName(query)} cost=${rateLimit.cost} remaining=${rateLimit.remaining}`,
|
|
73
|
+
);
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
export const postGithubGraphqlJson = async <T>(params: {
|
|
77
|
+
ghToken: string;
|
|
78
|
+
query: string;
|
|
79
|
+
variables?: Record<string, unknown>;
|
|
80
|
+
}): Promise<T> => {
|
|
81
|
+
const response = await ky
|
|
82
|
+
.post(GITHUB_GRAPHQL_ENDPOINT, {
|
|
83
|
+
json: {
|
|
84
|
+
query: injectRateLimitSelection(params.query),
|
|
85
|
+
...(params.variables !== undefined
|
|
86
|
+
? { variables: params.variables }
|
|
87
|
+
: {}),
|
|
88
|
+
},
|
|
89
|
+
headers: {
|
|
90
|
+
Authorization: `Bearer ${params.ghToken}`,
|
|
91
|
+
},
|
|
92
|
+
})
|
|
93
|
+
.json<T>();
|
|
94
|
+
logGithubGraphqlCost(params.query, response);
|
|
95
|
+
return response;
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
export const fetchGithubGraphql = async (params: {
|
|
99
|
+
ghToken: string;
|
|
100
|
+
query: string;
|
|
101
|
+
variables?: Record<string, unknown>;
|
|
102
|
+
}): Promise<Response> => {
|
|
103
|
+
const response = await fetch(GITHUB_GRAPHQL_ENDPOINT, {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
headers: {
|
|
106
|
+
Authorization: `Bearer ${params.ghToken}`,
|
|
107
|
+
'Content-Type': 'application/json',
|
|
108
|
+
},
|
|
109
|
+
body: JSON.stringify({
|
|
110
|
+
query: injectRateLimitSelection(params.query),
|
|
111
|
+
variables: params.variables,
|
|
112
|
+
}),
|
|
113
|
+
});
|
|
114
|
+
if (response.ok) {
|
|
115
|
+
const responseBody: unknown = await response
|
|
116
|
+
.clone()
|
|
117
|
+
.json()
|
|
118
|
+
.catch((): null => null);
|
|
119
|
+
logGithubGraphqlCost(params.query, responseBody);
|
|
120
|
+
}
|
|
121
|
+
return response;
|
|
122
|
+
};
|