github-issue-tower-defence-management 1.128.0 → 1.128.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.
- package/CHANGELOG.md +7 -0
- package/bin/adapter/entry-points/console/ui-dist/assets/index-CufymFM1.js +103 -0
- package/bin/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/bin/adapter/entry-points/console/webServer.js +56 -3
- package/bin/adapter/entry-points/console/webServer.js.map +1 -1
- package/package.json +1 -1
- package/src/adapter/entry-points/console/ui/src/features/console/components/content/ConsoleMarkdownContent.stories.tsx +1 -2
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleCaches.ts +2 -4
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.test.ts +7 -7
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleOperations.ts +15 -18
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleTabData.ts +2 -5
- package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.test.ts +22 -25
- package/src/adapter/entry-points/console/ui/src/features/console/lib/consoleApi.ts +12 -23
- package/src/adapter/entry-points/console/ui/src/features/console/lib/imageProxy.test.ts +7 -10
- package/src/adapter/entry-points/console/ui/src/features/console/lib/imageProxy.ts +2 -9
- package/src/adapter/entry-points/console/ui/src/features/console/pages/ConsoleItemDetailContainer.tsx +2 -4
- package/src/adapter/entry-points/console/ui-dist/assets/index-CufymFM1.js +103 -0
- package/src/adapter/entry-points/console/ui-dist/index.html +1 -1
- package/src/adapter/entry-points/console/webServer.test.ts +283 -6
- package/src/adapter/entry-points/console/webServer.ts +64 -0
- package/types/adapter/entry-points/console/webServer.d.ts +5 -1
- package/types/adapter/entry-points/console/webServer.d.ts.map +1 -1
- package/bin/adapter/entry-points/console/ui-dist/assets/index-8H0HejYa.js +0 -103
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleToken.test.ts +0 -41
- package/src/adapter/entry-points/console/ui/src/features/console/hooks/useConsoleToken.ts +0 -64
- package/src/adapter/entry-points/console/ui-dist/assets/index-8H0HejYa.js +0 -103
|
@@ -4,9 +4,6 @@ import {
|
|
|
4
4
|
postConsoleReviewComment,
|
|
5
5
|
} from './consoleApi';
|
|
6
6
|
|
|
7
|
-
const appendToken = (url: string): string =>
|
|
8
|
-
url.includes('?') ? `${url}&k=token` : `${url}?k=token`;
|
|
9
|
-
|
|
10
7
|
const mockFetchOnce = (body: unknown, ok = true): jest.Mock => {
|
|
11
8
|
const fetchMock = jest.fn().mockResolvedValue({
|
|
12
9
|
ok,
|
|
@@ -29,19 +26,19 @@ const mockFetchFailureOnce = (status: number, rawBody: string): jest.Mock => {
|
|
|
29
26
|
};
|
|
30
27
|
|
|
31
28
|
describe('createConsoleApiClient', () => {
|
|
32
|
-
it('reads the item body
|
|
29
|
+
it('reads the item body from the api root without a token query', async () => {
|
|
33
30
|
const fetchMock = mockFetchOnce({ body: '# Title' });
|
|
34
|
-
const client = createConsoleApiClient(
|
|
31
|
+
const client = createConsoleApiClient();
|
|
35
32
|
const body = await client.fetchItemBody('https://github.com/o/r/issues/1');
|
|
36
33
|
expect(body).toBe('# Title');
|
|
37
34
|
const requested = fetchMock.mock.calls[0][0] as string;
|
|
38
35
|
expect(requested).toContain('/api/itembody?url=');
|
|
39
|
-
expect(requested).toContain('
|
|
36
|
+
expect(requested).not.toContain('k=');
|
|
40
37
|
});
|
|
41
38
|
|
|
42
39
|
it('anchors every read endpoint at the server root regardless of route', async () => {
|
|
43
40
|
const readers: ((url: string) => Promise<unknown>)[] = [];
|
|
44
|
-
const client = createConsoleApiClient(
|
|
41
|
+
const client = createConsoleApiClient();
|
|
45
42
|
readers.push((url) => client.fetchItemBody(url));
|
|
46
43
|
readers.push((url) => client.fetchComments(url));
|
|
47
44
|
readers.push((url) => client.fetchPrFiles(url));
|
|
@@ -75,7 +72,7 @@ describe('createConsoleApiClient', () => {
|
|
|
75
72
|
{ author: 'a', body: 'hello', createdAt: '2026-06-19T00:00:00.000Z' },
|
|
76
73
|
],
|
|
77
74
|
});
|
|
78
|
-
const client = createConsoleApiClient(
|
|
75
|
+
const client = createConsoleApiClient();
|
|
79
76
|
const comments = await client.fetchComments(
|
|
80
77
|
'https://github.com/o/r/issues/1',
|
|
81
78
|
);
|
|
@@ -91,14 +88,14 @@ describe('createConsoleApiClient', () => {
|
|
|
91
88
|
{ filename: 'b.ts', additions: 9, deletions: 0, status: 'added' },
|
|
92
89
|
],
|
|
93
90
|
});
|
|
94
|
-
const client = createConsoleApiClient(
|
|
91
|
+
const client = createConsoleApiClient();
|
|
95
92
|
const files = await client.fetchPrFiles('https://github.com/o/r/pull/1');
|
|
96
93
|
expect(files.map((file) => file.path)).toEqual(['a.ts', 'b.ts']);
|
|
97
94
|
});
|
|
98
95
|
|
|
99
96
|
it('returns no files when the response files array is null', async () => {
|
|
100
97
|
mockFetchOnce({ files: null });
|
|
101
|
-
const client = createConsoleApiClient(
|
|
98
|
+
const client = createConsoleApiClient();
|
|
102
99
|
expect(await client.fetchPrFiles('https://github.com/o/r/pull/1')).toEqual(
|
|
103
100
|
[],
|
|
104
101
|
);
|
|
@@ -111,7 +108,7 @@ describe('createConsoleApiClient', () => {
|
|
|
111
108
|
isPullRequest: true,
|
|
112
109
|
title: 'Decorate PR links',
|
|
113
110
|
});
|
|
114
|
-
const client = createConsoleApiClient(
|
|
111
|
+
const client = createConsoleApiClient();
|
|
115
112
|
expect(
|
|
116
113
|
await client.fetchIssueState('https://github.com/o/r/pull/1'),
|
|
117
114
|
).toEqual({
|
|
@@ -124,7 +121,7 @@ describe('createConsoleApiClient', () => {
|
|
|
124
121
|
|
|
125
122
|
it('defaults the title to an empty string when absent', async () => {
|
|
126
123
|
mockFetchOnce({ state: 'open', merged: false, isPullRequest: false });
|
|
127
|
-
const client = createConsoleApiClient(
|
|
124
|
+
const client = createConsoleApiClient();
|
|
128
125
|
expect(
|
|
129
126
|
await client.fetchIssueState('https://github.com/o/r/issues/1'),
|
|
130
127
|
).toEqual({
|
|
@@ -146,7 +143,7 @@ describe('createConsoleApiClient', () => {
|
|
|
146
143
|
},
|
|
147
144
|
],
|
|
148
145
|
});
|
|
149
|
-
const client = createConsoleApiClient(
|
|
146
|
+
const client = createConsoleApiClient();
|
|
150
147
|
const commits = await client.fetchPrCommits(
|
|
151
148
|
'https://github.com/o/r/pull/1',
|
|
152
149
|
);
|
|
@@ -177,7 +174,7 @@ describe('createConsoleApiClient', () => {
|
|
|
177
174
|
},
|
|
178
175
|
],
|
|
179
176
|
});
|
|
180
|
-
const client = createConsoleApiClient(
|
|
177
|
+
const client = createConsoleApiClient();
|
|
181
178
|
const related = await client.fetchRelatedPrs(
|
|
182
179
|
'https://github.com/o/r/issues/1',
|
|
183
180
|
);
|
|
@@ -198,7 +195,7 @@ describe('createConsoleApiClient', () => {
|
|
|
198
195
|
missingRequiredCheckNames: ['build', 'test'],
|
|
199
196
|
},
|
|
200
197
|
});
|
|
201
|
-
const client = createConsoleApiClient(
|
|
198
|
+
const client = createConsoleApiClient();
|
|
202
199
|
expect(
|
|
203
200
|
await client.fetchPullRequestStatus('https://github.com/o/r/pull/1'),
|
|
204
201
|
).toEqual({
|
|
@@ -223,7 +220,7 @@ describe('createConsoleApiClient', () => {
|
|
|
223
220
|
missingRequiredCheckNames: [],
|
|
224
221
|
},
|
|
225
222
|
});
|
|
226
|
-
const client = createConsoleApiClient(
|
|
223
|
+
const client = createConsoleApiClient();
|
|
227
224
|
const status = await client.fetchPullRequestStatus(
|
|
228
225
|
'https://github.com/o/r/pull/1',
|
|
229
226
|
);
|
|
@@ -232,7 +229,7 @@ describe('createConsoleApiClient', () => {
|
|
|
232
229
|
|
|
233
230
|
it('returns a not-found pull request status when the server reports none', async () => {
|
|
234
231
|
mockFetchOnce({ found: false, status: null });
|
|
235
|
-
const client = createConsoleApiClient(
|
|
232
|
+
const client = createConsoleApiClient();
|
|
236
233
|
expect(
|
|
237
234
|
await client.fetchPullRequestStatus('https://github.com/o/r/pull/1'),
|
|
238
235
|
).toEqual({
|
|
@@ -248,7 +245,7 @@ describe('createConsoleApiClient', () => {
|
|
|
248
245
|
|
|
249
246
|
it('throws on a non-ok response', async () => {
|
|
250
247
|
mockFetchOnce({}, false);
|
|
251
|
-
const client = createConsoleApiClient(
|
|
248
|
+
const client = createConsoleApiClient();
|
|
252
249
|
await expect(
|
|
253
250
|
client.fetchComments('https://github.com/o/r/issues/1'),
|
|
254
251
|
).rejects.toThrow('HTTP 500');
|
|
@@ -256,21 +253,21 @@ describe('createConsoleApiClient', () => {
|
|
|
256
253
|
});
|
|
257
254
|
|
|
258
255
|
describe('postConsoleOperation', () => {
|
|
259
|
-
it('posts a JSON body
|
|
256
|
+
it('posts a JSON body to the operation endpoint', async () => {
|
|
260
257
|
const fetchMock = mockFetchOnce({ ok: true });
|
|
261
|
-
await postConsoleOperation(
|
|
258
|
+
await postConsoleOperation('/api/review', {
|
|
262
259
|
pjcode: 'umino',
|
|
263
260
|
action: 'approve',
|
|
264
261
|
prUrl: 'https://github.com/o/r/pull/1',
|
|
265
262
|
projectItemId: 'PVTI_1',
|
|
266
263
|
});
|
|
267
264
|
const [url, init] = fetchMock.mock.calls[0];
|
|
268
|
-
expect(url).toBe('/api/review
|
|
265
|
+
expect(url).toBe('/api/review');
|
|
269
266
|
expect(init).toMatchObject({ method: 'POST' });
|
|
270
267
|
});
|
|
271
268
|
|
|
272
269
|
const failingReview = (): Promise<void> =>
|
|
273
|
-
postConsoleOperation(
|
|
270
|
+
postConsoleOperation('/api/review', {
|
|
274
271
|
pjcode: 'umino',
|
|
275
272
|
action: 'approve',
|
|
276
273
|
prUrl: 'https://github.com/o/r/pull/1',
|
|
@@ -301,7 +298,7 @@ describe('postConsoleOperation', () => {
|
|
|
301
298
|
describe('postConsoleReviewComment', () => {
|
|
302
299
|
it('posts the inline review comment body to the reviewcomment endpoint', async () => {
|
|
303
300
|
const fetchMock = mockFetchOnce({ ok: true });
|
|
304
|
-
await postConsoleReviewComment(
|
|
301
|
+
await postConsoleReviewComment({
|
|
305
302
|
pjcode: 'umino',
|
|
306
303
|
url: 'https://github.com/o/r/pull/1',
|
|
307
304
|
path: 'src/index.ts',
|
|
@@ -310,7 +307,7 @@ describe('postConsoleReviewComment', () => {
|
|
|
310
307
|
body: 'Consider extracting this into a helper.',
|
|
311
308
|
});
|
|
312
309
|
const [url, init] = fetchMock.mock.calls[0];
|
|
313
|
-
expect(url).toBe('/api/reviewcomment
|
|
310
|
+
expect(url).toBe('/api/reviewcomment');
|
|
314
311
|
expect(init).toMatchObject({ method: 'POST' });
|
|
315
312
|
expect(JSON.parse((init as { body: string }).body)).toEqual({
|
|
316
313
|
pjcode: 'umino',
|
|
@@ -331,7 +328,7 @@ describe('postConsoleReviewComment', () => {
|
|
|
331
328
|
}),
|
|
332
329
|
);
|
|
333
330
|
await expect(
|
|
334
|
-
postConsoleReviewComment(
|
|
331
|
+
postConsoleReviewComment({
|
|
335
332
|
pjcode: 'umino',
|
|
336
333
|
url: 'https://github.com/o/r/pull/1',
|
|
337
334
|
path: 'src/index.ts',
|
|
@@ -57,8 +57,6 @@ export type ConsoleReviewCommentRequest = {
|
|
|
57
57
|
body: string;
|
|
58
58
|
};
|
|
59
59
|
|
|
60
|
-
type AppendToken = (url: string) => string;
|
|
61
|
-
|
|
62
60
|
const isRecord = (value: unknown): value is Record<string, unknown> =>
|
|
63
61
|
value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
64
62
|
|
|
@@ -71,14 +69,12 @@ const getNumber = (value: unknown): number =>
|
|
|
71
69
|
const getBoolean = (value: unknown): boolean => value === true;
|
|
72
70
|
|
|
73
71
|
const requestJson = async (
|
|
74
|
-
appendToken: AppendToken,
|
|
75
72
|
apiPath: string,
|
|
76
73
|
resourceUrl: string,
|
|
77
74
|
): Promise<unknown> => {
|
|
78
|
-
const
|
|
75
|
+
const response = await fetch(
|
|
79
76
|
`${apiPath}?url=${encodeURIComponent(resourceUrl)}`,
|
|
80
77
|
);
|
|
81
|
-
const response = await fetch(target);
|
|
82
78
|
if (!response.ok) {
|
|
83
79
|
throw new Error(`HTTP ${response.status}`);
|
|
84
80
|
}
|
|
@@ -207,27 +203,23 @@ const parseState = (payload: unknown): ConsoleIssueState => {
|
|
|
207
203
|
};
|
|
208
204
|
};
|
|
209
205
|
|
|
210
|
-
export const createConsoleApiClient = (
|
|
211
|
-
appendToken: AppendToken,
|
|
212
|
-
): ConsoleApiClient => ({
|
|
206
|
+
export const createConsoleApiClient = (): ConsoleApiClient => ({
|
|
213
207
|
fetchItemBody: async (url) => {
|
|
214
|
-
const payload = await requestJson(
|
|
208
|
+
const payload = await requestJson('/api/itembody', url);
|
|
215
209
|
return isRecord(payload) ? getString(payload.body) : '';
|
|
216
210
|
},
|
|
217
211
|
fetchComments: async (url) =>
|
|
218
|
-
parseComments(await requestJson(
|
|
212
|
+
parseComments(await requestJson('/api/comments', url)),
|
|
219
213
|
fetchPrFiles: async (url) =>
|
|
220
|
-
parseFiles(await requestJson(
|
|
214
|
+
parseFiles(await requestJson('/api/prfiles', url)),
|
|
221
215
|
fetchPrCommits: async (url) =>
|
|
222
|
-
parseCommits(await requestJson(
|
|
216
|
+
parseCommits(await requestJson('/api/prcommits', url)),
|
|
223
217
|
fetchRelatedPrs: async (url) =>
|
|
224
|
-
parseRelatedPrs(await requestJson(
|
|
218
|
+
parseRelatedPrs(await requestJson('/api/relatedprs', url)),
|
|
225
219
|
fetchIssueState: async (url) =>
|
|
226
|
-
parseState(await requestJson(
|
|
220
|
+
parseState(await requestJson('/api/issuetitle', url)),
|
|
227
221
|
fetchPullRequestStatus: async (url) =>
|
|
228
|
-
parsePullRequestStatus(
|
|
229
|
-
await requestJson(appendToken, '/api/pullrequeststatus', url),
|
|
230
|
-
),
|
|
222
|
+
parsePullRequestStatus(await requestJson('/api/pullrequeststatus', url)),
|
|
231
223
|
});
|
|
232
224
|
|
|
233
225
|
const readOperationErrorReason = async (
|
|
@@ -249,11 +241,10 @@ const readOperationErrorReason = async (
|
|
|
249
241
|
};
|
|
250
242
|
|
|
251
243
|
export const postConsoleOperation = async (
|
|
252
|
-
appendToken: AppendToken,
|
|
253
244
|
apiPath: string,
|
|
254
245
|
body: ConsoleReviewRequest | ConsoleTriageRequest | ConsoleIntmuxRequest,
|
|
255
246
|
): Promise<void> => {
|
|
256
|
-
const response = await fetch(
|
|
247
|
+
const response = await fetch(apiPath, {
|
|
257
248
|
method: 'POST',
|
|
258
249
|
headers: { 'Content-Type': 'application/json' },
|
|
259
250
|
body: JSON.stringify(body),
|
|
@@ -283,10 +274,9 @@ const parsePostedComment = (payload: unknown): ConsoleComment => {
|
|
|
283
274
|
};
|
|
284
275
|
|
|
285
276
|
export const postConsoleComment = async (
|
|
286
|
-
appendToken: AppendToken,
|
|
287
277
|
request: ConsoleCommentRequest,
|
|
288
278
|
): Promise<ConsoleComment> => {
|
|
289
|
-
const response = await fetch(
|
|
279
|
+
const response = await fetch(COMMENT_OPERATION_PATH, {
|
|
290
280
|
method: 'POST',
|
|
291
281
|
headers: { 'Content-Type': 'application/json' },
|
|
292
282
|
body: JSON.stringify(request),
|
|
@@ -300,10 +290,9 @@ export const postConsoleComment = async (
|
|
|
300
290
|
export const REVIEW_COMMENT_OPERATION_PATH = '/api/reviewcomment';
|
|
301
291
|
|
|
302
292
|
export const postConsoleReviewComment = async (
|
|
303
|
-
appendToken: AppendToken,
|
|
304
293
|
request: ConsoleReviewCommentRequest,
|
|
305
294
|
): Promise<void> => {
|
|
306
|
-
const response = await fetch(
|
|
295
|
+
const response = await fetch(REVIEW_COMMENT_OPERATION_PATH, {
|
|
307
296
|
method: 'POST',
|
|
308
297
|
headers: { 'Content-Type': 'application/json' },
|
|
309
298
|
body: JSON.stringify(request),
|
|
@@ -27,31 +27,28 @@ describe('isProxyableImageUrl', () => {
|
|
|
27
27
|
});
|
|
28
28
|
|
|
29
29
|
describe('buildImageProxyUrl', () => {
|
|
30
|
-
it('encodes the source url
|
|
30
|
+
it('encodes the source url without appending a token', () => {
|
|
31
31
|
const src = 'https://github.com/user-attachments/assets/abc?x=1';
|
|
32
|
-
expect(buildImageProxyUrl(src
|
|
33
|
-
`/api/img?url=${encodeURIComponent(src)}
|
|
32
|
+
expect(buildImageProxyUrl(src)).toBe(
|
|
33
|
+
`/api/img?url=${encodeURIComponent(src)}`,
|
|
34
34
|
);
|
|
35
35
|
});
|
|
36
36
|
|
|
37
|
-
it('
|
|
37
|
+
it('does not include a token query parameter', () => {
|
|
38
38
|
const src = 'https://github.com/user-attachments/assets/abc';
|
|
39
|
-
expect(buildImageProxyUrl(src
|
|
40
|
-
`/api/img?url=${encodeURIComponent(src)}`,
|
|
41
|
-
);
|
|
39
|
+
expect(buildImageProxyUrl(src)).not.toContain('k=');
|
|
42
40
|
});
|
|
43
41
|
});
|
|
44
42
|
|
|
45
43
|
describe('rewriteGitHubImageSources', () => {
|
|
46
|
-
const buildProxyUrl = (src: string): string =>
|
|
47
|
-
buildImageProxyUrl(src, 'console-token');
|
|
44
|
+
const buildProxyUrl = (src: string): string => buildImageProxyUrl(src);
|
|
48
45
|
|
|
49
46
|
it('rewrites an allow-listed github image src to the proxy url', () => {
|
|
50
47
|
const githubSrc = 'https://github.com/user-attachments/assets/abc';
|
|
51
48
|
const html = `<p><img src="${githubSrc}" alt="shot" /></p>`;
|
|
52
49
|
const result = rewriteGitHubImageSources(html, buildProxyUrl);
|
|
53
50
|
expect(result).toContain(`/api/img?url=${encodeURIComponent(githubSrc)}`);
|
|
54
|
-
expect(result).toContain('k=
|
|
51
|
+
expect(result).not.toContain('k=');
|
|
55
52
|
expect(result).not.toContain(`src="${githubSrc}"`);
|
|
56
53
|
});
|
|
57
54
|
|
|
@@ -6,15 +6,8 @@ export const isProxyableImageUrl = (src: string): boolean =>
|
|
|
6
6
|
|
|
7
7
|
export type ImageProxyUrlBuilder = (src: string) => string;
|
|
8
8
|
|
|
9
|
-
export const buildImageProxyUrl = (
|
|
10
|
-
src
|
|
11
|
-
token: string | null,
|
|
12
|
-
): string => {
|
|
13
|
-
if (token === null) {
|
|
14
|
-
return `/api/img?url=${encodeURIComponent(src)}`;
|
|
15
|
-
}
|
|
16
|
-
return `/api/img?url=${encodeURIComponent(src)}&k=${encodeURIComponent(token)}`;
|
|
17
|
-
};
|
|
9
|
+
export const buildImageProxyUrl = (src: string): string =>
|
|
10
|
+
`/api/img?url=${encodeURIComponent(src)}`;
|
|
18
11
|
|
|
19
12
|
export const rewriteGitHubImageSources = (
|
|
20
13
|
html: string,
|
|
@@ -6,7 +6,6 @@ import { ConsoleOperationMenu } from '../components/operations/ConsoleOperationM
|
|
|
6
6
|
import type { ConsoleCaches } from '../hooks/useConsoleCaches';
|
|
7
7
|
import { useConsoleItemDetailData } from '../hooks/useConsoleItemDetailData';
|
|
8
8
|
import type { ConsoleOperationsApi } from '../hooks/useConsoleOperations';
|
|
9
|
-
import { useConsoleToken } from '../hooks/useConsoleToken';
|
|
10
9
|
import { buildImageProxyUrl } from '../lib/imageProxy';
|
|
11
10
|
import type { ConsoleActionKind } from '../logic/actionToast';
|
|
12
11
|
import { resolveStoryColorEnum } from '../logic/grouping';
|
|
@@ -58,10 +57,9 @@ export const ConsoleItemDetailContainer = ({
|
|
|
58
57
|
onQueueAction,
|
|
59
58
|
}: ConsoleItemDetailContainerProps) => {
|
|
60
59
|
const detail = useConsoleItemDetailData(caches, item);
|
|
61
|
-
const { token } = useConsoleToken();
|
|
62
60
|
const resolveImageProxyUrl = useCallback(
|
|
63
|
-
(src: string): string => buildImageProxyUrl(src
|
|
64
|
-
[
|
|
61
|
+
(src: string): string => buildImageProxyUrl(src),
|
|
62
|
+
[],
|
|
65
63
|
);
|
|
66
64
|
const renderReferenceLink = useCallback(
|
|
67
65
|
(href: string, fallbackText: string) => (
|