Skip to content

Conversation

@deflis
Copy link
Owner

@deflis deflis commented Dec 10, 2025

Summary

  • remove the browser example note about fetch options that cannot be used

Testing

  • pnpm run check:lint

Codex Task

Copilot AI review requested due to automatic review settings December 10, 2025 04:46
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds support for passing custom fetch options (like headers) to all API methods in the library. The changes enable users to configure fetch behavior when making API calls, such as adding custom user-agent headers or other RequestInit options. This functionality works in Node.js (fetch implementation) while being gracefully ignored in browser environments (JSONP implementation).

Key Changes:

  • Added optional RequestInit fetchOptions parameter to all builder execute() methods
  • Implemented complex overload resolution for RankingBuilder.executeWithFields() to support backwards-compatible API with new fetchOptions parameter
  • Added test coverage for basic fetchOptions functionality in ranking and low-level fetch implementation

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/narou.ts Added fetchOptions parameter to all internal execute methods (executeNovel, executeRanking, executeUserSearch, etc.)
src/narou-fetch.ts Updated fetch implementation to pass fetchOptions to the underlying fetch call
src/narou-jsonp.ts Added fetchOptions parameter (intentionally ignored with void pattern for browser compatibility)
src/search-builder.ts Added fetchOptions parameter to NovelSearchBuilderBase.execute() method
src/search-builder-r18.ts Added fetchOptions parameter to SearchBuilderR18.execute() method
src/user-search.ts Added fetchOptions parameter to UserSearchBuilder.execute() method
src/ranking.ts Added fetchOptions parameter with complex overload resolution for executeWithFields, including runtime type guard
test/ranking.test.ts Added tests for passing fetchOptions to execute() and executeWithFields() methods
test/narou-fetch.test.ts Added test verifying fetchOptions are passed to the underlying fetch function
README.md Updated examples to demonstrate fetchOptions usage with custom headers

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +478 to 480
execute(fetchOptions?: RequestInit): Promise<NarouSearchResults<NarouSearchResult, T>> {
return this.api.executeNovel(this.params, fetchOptions);
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for the new fetchOptions parameter added to the execute() method. Consider adding a test similar to the one in test/ranking.test.ts:32-54 that verifies fetchOptions (e.g., custom headers) are properly passed through to the underlying API call.

Copilot uses AI. Check for mistakes.
Comment on lines +34 to +37
execute(
fetchOptions?: RequestInit
): Promise<NarouSearchResults<NarouSearchResult, T | TOpt>> {
return this.api.executeNovel18(this.params, fetchOptions);
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for the new fetchOptions parameter added to the execute() method. Consider adding a test similar to the one in test/ranking.test.ts:32-54 that verifies fetchOptions (e.g., custom headers) are properly passed through to the underlying API call.

Copilot uses AI. Check for mistakes.
Comment on lines +108 to 115
execute(
fetchOptions?: RequestInit
): Promise<NarouSearchResults<UserSearchResult, TField>> {
return this.api.executeUserSearch(
this.params as UserSearchParams,
fetchOptions
);
}
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for the new fetchOptions parameter added to the execute() method. Consider adding a test similar to the one in test/ranking.test.ts:32-54 that verifies fetchOptions (e.g., custom headers) are properly passed through to the underlying API call.

Copilot uses AI. Check for mistakes.
import { addDays, formatDate } from "./util/date.js";

function isRequestInit(value: unknown): value is RequestInit {
return typeof value == "object" && value !== null && !Array.isArray(value);
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use strict equality (===) instead of loose equality (==) for type checking. While this works correctly in this case, using === is a best practice in TypeScript/JavaScript to avoid unexpected type coercion.

Suggested change
return typeof value == "object" && value !== null && !Array.isArray(value);
return typeof value === "object" && value !== null && !Array.isArray(value);

Copilot uses AI. Check for mistakes.
Comment on lines +173 to +175
* @param fetchOptions fetch のオプション
* @returns {Promise<RankingResult<SearchResultFields<TFields>>[]>} 詳細情報を含むランキング結果の配列
*/
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Inconsistent JSDoc indentation. The @param fetchOptions and @returns tags should be aligned with the other JSDoc tags (no leading spaces). The extra leading spaces before these lines break the standard JSDoc formatting convention.

Suggested change
* @param fetchOptions fetch のオプション
* @returns {Promise<RankingResult<SearchResultFields<TFields>>[]>} 詳細情報を含むランキング結果の配列
*/
* @param fetchOptions fetch のオプション
* @returns {Promise<RankingResult<SearchResultFields<TFields>>[]>} 詳細情報を含むランキング結果の配列
*/

Copilot uses AI. Check for mistakes.
Comment on lines +56 to +118
test("fetchOptions を executeWithFields の両 API に渡せる", async () => {
const rankingHeaderMock = vi.fn();
const detailHeaderMock = vi.fn();

server.use(
http.get("https://api.syosetu.com/rank/rankget/", ({ request }) => {
const url = new URL(request.url);
rankingHeaderMock(request.headers.get("x-test-header"));
const response: NarouRankingResult[] = [
{ ncode: "N0000AA", rank: 1, pt: 1000 },
];
return responseGzipOrJson(response, url);
}),
http.get("https://api.syosetu.com/novelapi/api/", ({ request }) => {
const url = new URL(request.url);
detailHeaderMock(request.headers.get("x-test-header"));
const response = [
{ allcount: 1 },
{
ncode: "N0000AA",
title: "タイトル",
writer: "作者",
story: "あらすじ",
biggenre: 1,
genre: 101,
keyword: ["キーワード"],
general_firstup: "2021-01-01 00:00:00",
general_lastup: "2021-01-01 00:00:00",
novel_type: 1,
end: 0,
general_all_no: 100,
length: 100,
time: 100,
isstop: 0,
isr15: 0,
isbl: 0,
isgl: 0,
iszankoku: 0,
istensei: 0,
istenni: 0,
global_point: 100,
fav_novel_cnt: 100,
review_cnt: 100,
all_point: 100,
all_hyoka_cnt: 100,
sasie_cnt: 100,
kaiwaritu: 100,
novelupdated_at: "2021-01-01 00:00:00",
updated_at: "2021-01-01 00:00:00",
},
];
return responseGzipOrJson(response, url);
})
);

const result = await ranking().executeWithFields({
headers: { "x-test-header": "ranking-detail-header" },
});

expect(result).toHaveLength(1);
expect(rankingHeaderMock).toHaveBeenCalledWith("ranking-detail-header");
expect(detailHeaderMock).toHaveBeenCalledWith("ranking-detail-header");
});
Copy link

Copilot AI Dec 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing test coverage for executeWithFields overloads that pass both fields and fetchOptions. The current tests only cover:

  1. executeWithFields() - no parameters
  2. executeWithFields(fetchOptions) - only fetchOptions
  3. executeWithFields([Fields.title]) - only fields

Consider adding tests for:

  • executeWithFields([Fields.title], fetchOptions) - fields + fetchOptions
  • executeWithFields([], OptionalFields.weekly, fetchOptions) - fields + opt + fetchOptions
  • executeWithFields([Fields.title], OptionalFields.weekly, fetchOptions) - all parameters

This will ensure the parameter detection logic in lines 187-194 works correctly for all overload combinations.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants