pixivflow 2.15.0 → 2.16.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/dist/auth/PixivAuth.d.ts +18 -0
- package/dist/auth/PixivAuth.d.ts.map +1 -0
- package/dist/auth/PixivAuth.js +200 -0
- package/dist/auth/PixivAuth.js.map +1 -0
- package/dist/commands/DoctorCommand.d.ts.map +1 -1
- package/dist/commands/DoctorCommand.js +23 -0
- package/dist/commands/DoctorCommand.js.map +1 -1
- package/dist/commands/DownloadCommand.js +4 -4
- package/dist/commands/DownloadCommand.js.map +1 -1
- package/dist/commands/HealthCommand.d.ts.map +1 -1
- package/dist/commands/HealthCommand.js +14 -1
- package/dist/commands/HealthCommand.js.map +1 -1
- package/dist/commands/RandomDownloadCommand.js +4 -4
- package/dist/commands/RandomDownloadCommand.js.map +1 -1
- package/dist/commands/TagsCommand.js +4 -4
- package/dist/commands/TagsCommand.js.map +1 -1
- package/dist/commands/TopicCommand.d.ts.map +1 -1
- package/dist/commands/TopicCommand.js +4 -4
- package/dist/commands/TopicCommand.js.map +1 -1
- package/dist/commands/scheduler-runtime.d.ts +2 -2
- package/dist/commands/scheduler-runtime.d.ts.map +1 -1
- package/dist/commands/scheduler-runtime.js +4 -4
- package/dist/commands/scheduler-runtime.js.map +1 -1
- package/dist/config/types.d.ts +7 -0
- package/dist/config/types.d.ts.map +1 -1
- package/dist/download/IllustrationDownloader.d.ts +1 -1
- package/dist/download/IllustrationDownloader.d.ts.map +1 -1
- package/dist/download/NovelDownloader.d.ts +1 -1
- package/dist/download/NovelDownloader.d.ts.map +1 -1
- package/dist/download/RankingService.d.ts +1 -1
- package/dist/download/RankingService.d.ts.map +1 -1
- package/dist/download/handlers/IllustrationTargetHandler.d.ts.map +1 -1
- package/dist/download/handlers/IllustrationTargetHandler.js +12 -5
- package/dist/download/handlers/IllustrationTargetHandler.js.map +1 -1
- package/dist/download/handlers/NovelTargetHandler.d.ts.map +1 -1
- package/dist/download/handlers/NovelTargetHandler.js +12 -5
- package/dist/download/handlers/NovelTargetHandler.js.map +1 -1
- package/dist/download/pipeline/DownloadPipeline.d.ts +1 -1
- package/dist/download/pipeline/DownloadPipeline.d.ts.map +1 -1
- package/dist/download/plan/DownloadPlanner.d.ts +1 -1
- package/dist/download/plan/DownloadPlanner.d.ts.map +1 -1
- package/dist/download/recovery/ErrorRecovery.d.ts.map +1 -1
- package/dist/download/recovery/ErrorRecovery.js +8 -2
- package/dist/download/recovery/ErrorRecovery.js.map +1 -1
- package/dist/interfaces/IPixivClient.d.ts +1 -5
- package/dist/interfaces/IPixivClient.d.ts.map +1 -1
- package/dist/package.json +1 -1
- package/dist/pixiv/AuthClient.d.ts +6 -12
- package/dist/pixiv/AuthClient.d.ts.map +1 -1
- package/dist/pixiv/AuthClient.js +7 -188
- package/dist/pixiv/AuthClient.js.map +1 -1
- package/dist/pixiv/PixivClient.d.ts +14 -156
- package/dist/pixiv/PixivClient.d.ts.map +1 -1
- package/dist/pixiv/PixivClient.js +15 -292
- package/dist/pixiv/PixivClient.js.map +1 -1
- package/dist/pixiv-client/PixivAuthTokenProvider.d.ts +16 -0
- package/dist/pixiv-client/PixivAuthTokenProvider.d.ts.map +1 -0
- package/dist/pixiv-client/PixivAuthTokenProvider.js +27 -0
- package/dist/pixiv-client/PixivAuthTokenProvider.js.map +1 -0
- package/dist/pixiv-client/PixivFlowPixivClient.d.ts +77 -0
- package/dist/pixiv-client/PixivFlowPixivClient.d.ts.map +1 -0
- package/dist/pixiv-client/PixivFlowPixivClient.js +146 -0
- package/dist/pixiv-client/PixivFlowPixivClient.js.map +1 -0
- package/dist/pixiv-client/TargetSearchRunner.d.ts +29 -0
- package/dist/pixiv-client/TargetSearchRunner.d.ts.map +1 -0
- package/dist/pixiv-client/TargetSearchRunner.js +182 -0
- package/dist/pixiv-client/TargetSearchRunner.js.map +1 -0
- package/dist/pixiv-client/createPixivFlowClient.d.ts +11 -0
- package/dist/pixiv-client/createPixivFlowClient.d.ts.map +1 -0
- package/dist/pixiv-client/createPixivFlowClient.js +29 -0
- package/dist/pixiv-client/createPixivFlowClient.js.map +1 -0
- package/dist/pixiv-client/query-mapper.d.ts +14 -0
- package/dist/pixiv-client/query-mapper.d.ts.map +1 -0
- package/dist/pixiv-client/query-mapper.js +63 -0
- package/dist/pixiv-client/query-mapper.js.map +1 -0
- package/dist/random-download.js +4 -4
- package/dist/random-download.js.map +1 -1
- package/dist/storage/Database.d.ts +4 -0
- package/dist/storage/Database.d.ts.map +1 -1
- package/dist/storage/Database.js +7 -0
- package/dist/storage/Database.js.map +1 -1
- package/dist/storage/DatabaseMigration.d.ts.map +1 -1
- package/dist/storage/DatabaseMigration.js +8 -0
- package/dist/storage/DatabaseMigration.js.map +1 -1
- package/dist/storage/repositories/RateLimitStateRepository.d.ts +17 -0
- package/dist/storage/repositories/RateLimitStateRepository.d.ts.map +1 -0
- package/dist/storage/repositories/RateLimitStateRepository.js +46 -0
- package/dist/storage/repositories/RateLimitStateRepository.js.map +1 -0
- package/dist/tags/types.d.ts +1 -1
- package/dist/tags/types.d.ts.map +1 -1
- package/dist/utils/concurrency.d.ts.map +1 -1
- package/dist/utils/concurrency.js +2 -1
- package/dist/utils/concurrency.js.map +1 -1
- package/dist/utils/errors.d.ts +20 -0
- package/dist/utils/errors.d.ts.map +1 -1
- package/dist/utils/errors.js +56 -1
- package/dist/utils/errors.js.map +1 -1
- package/dist/utils/pixiv-sort.d.ts +1 -1
- package/dist/utils/pixiv-sort.d.ts.map +1 -1
- package/dist/utils/pixiv-utils.d.ts +1 -1
- package/dist/utils/pixiv-utils.d.ts.map +1 -1
- package/dist/utils/token-maintenance.d.ts +1 -1
- package/dist/utils/token-maintenance.d.ts.map +1 -1
- package/dist/version.js +1 -1
- package/dist/webui/package.json +1 -1
- package/dist/webui/services/DownloadTaskManager.js +4 -4
- package/dist/webui/services/DownloadTaskManager.js.map +1 -1
- package/package.json +11 -4
- package/dist/pixiv/IPixivRequestHandler.d.ts +0 -26
- package/dist/pixiv/IPixivRequestHandler.d.ts.map +0 -1
- package/dist/pixiv/IPixivRequestHandler.js +0 -3
- package/dist/pixiv/IPixivRequestHandler.js.map +0 -1
- package/dist/pixiv/RateLimitCoordinator.d.ts +0 -30
- package/dist/pixiv/RateLimitCoordinator.d.ts.map +0 -1
- package/dist/pixiv/RateLimitCoordinator.js +0 -66
- package/dist/pixiv/RateLimitCoordinator.js.map +0 -1
- package/dist/pixiv/client/IllustService.d.ts +0 -24
- package/dist/pixiv/client/IllustService.d.ts.map +0 -1
- package/dist/pixiv/client/IllustService.js +0 -70
- package/dist/pixiv/client/IllustService.js.map +0 -1
- package/dist/pixiv/client/MediaDownloadService.d.ts +0 -11
- package/dist/pixiv/client/MediaDownloadService.d.ts.map +0 -1
- package/dist/pixiv/client/MediaDownloadService.js +0 -22
- package/dist/pixiv/client/MediaDownloadService.js.map +0 -1
- package/dist/pixiv/client/NovelService.d.ts +0 -30
- package/dist/pixiv/client/NovelService.d.ts.map +0 -1
- package/dist/pixiv/client/NovelService.js +0 -203
- package/dist/pixiv/client/NovelService.js.map +0 -1
- package/dist/pixiv/client/PixivApiCore.d.ts +0 -52
- package/dist/pixiv/client/PixivApiCore.d.ts.map +0 -1
- package/dist/pixiv/client/PixivApiCore.js +0 -412
- package/dist/pixiv/client/PixivApiCore.js.map +0 -1
- package/dist/pixiv/client/SearchService.d.ts +0 -21
- package/dist/pixiv/client/SearchService.d.ts.map +0 -1
- package/dist/pixiv/client/SearchService.js +0 -207
- package/dist/pixiv/client/SearchService.js.map +0 -1
- package/dist/pixiv/client/search/SearchFilters.d.ts +0 -31
- package/dist/pixiv/client/search/SearchFilters.d.ts.map +0 -1
- package/dist/pixiv/client/search/SearchFilters.js +0 -102
- package/dist/pixiv/client/search/SearchFilters.js.map +0 -1
- package/dist/pixiv/types.d.ts +0 -72
- package/dist/pixiv/types.d.ts.map +0 -1
- package/dist/pixiv/types.js +0 -6
- package/dist/pixiv/types.js.map +0 -1
|
@@ -1,412 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.PixivApiCore = void 0;
|
|
7
|
-
const node_url_1 = require("node:url");
|
|
8
|
-
const promises_1 = require("node:timers/promises");
|
|
9
|
-
const undici_1 = require("undici");
|
|
10
|
-
const socks_proxy_agent_1 = require("socks-proxy-agent");
|
|
11
|
-
const axios_1 = __importDefault(require("axios"));
|
|
12
|
-
const logger_1 = require("../../logger");
|
|
13
|
-
const errors_1 = require("../../utils/errors");
|
|
14
|
-
class PixivApiCore {
|
|
15
|
-
baseUrl;
|
|
16
|
-
userAgent;
|
|
17
|
-
defaultTimeoutMs;
|
|
18
|
-
maxRetries;
|
|
19
|
-
rateLimitPerSecond;
|
|
20
|
-
proxyUrl;
|
|
21
|
-
getAccessToken;
|
|
22
|
-
proxyAgent;
|
|
23
|
-
socksAgent;
|
|
24
|
-
useAxiosForProxy;
|
|
25
|
-
axiosInstance;
|
|
26
|
-
rateLimiter;
|
|
27
|
-
constructor(options = {}) {
|
|
28
|
-
this.baseUrl = options.baseUrl ?? 'https://app-api.pixiv.net';
|
|
29
|
-
this.userAgent = options.userAgent;
|
|
30
|
-
this.defaultTimeoutMs = options.defaultTimeoutMs ?? 30_000;
|
|
31
|
-
this.maxRetries = options.maxRetries ?? 2;
|
|
32
|
-
this.rateLimitPerSecond = options.rateLimitPerSecond;
|
|
33
|
-
this.proxyUrl = options.proxyUrl ? new node_url_1.URL(options.proxyUrl) : undefined;
|
|
34
|
-
this.getAccessToken = options.getAccessToken;
|
|
35
|
-
this.rateLimiter = options.rateLimiter;
|
|
36
|
-
// Determine if we need to use axios for SOCKS proxy
|
|
37
|
-
let useAxios = false;
|
|
38
|
-
if (this.proxyUrl) {
|
|
39
|
-
const protocol = this.proxyUrl.protocol.replace(':', '').toLowerCase();
|
|
40
|
-
// Check if it's a SOCKS protocol
|
|
41
|
-
if (protocol === 'socks4' || protocol === 'socks5' || protocol === 'socks') {
|
|
42
|
-
// Use socks-proxy-agent for SOCKS protocols
|
|
43
|
-
this.socksAgent = new socks_proxy_agent_1.SocksProxyAgent(this.proxyUrl.toString());
|
|
44
|
-
useAxios = true;
|
|
45
|
-
logger_1.logger.info('SOCKS proxy enabled', {
|
|
46
|
-
protocol,
|
|
47
|
-
host: this.proxyUrl.hostname,
|
|
48
|
-
port: this.proxyUrl.port,
|
|
49
|
-
});
|
|
50
|
-
}
|
|
51
|
-
else if (protocol === 'http' || protocol === 'https') {
|
|
52
|
-
// Use undici ProxyAgent for HTTP/HTTPS protocols
|
|
53
|
-
this.proxyAgent = new undici_1.ProxyAgent(this.proxyUrl.toString());
|
|
54
|
-
logger_1.logger.info('HTTP/HTTPS proxy enabled', {
|
|
55
|
-
protocol,
|
|
56
|
-
host: this.proxyUrl.hostname,
|
|
57
|
-
port: this.proxyUrl.port,
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
else {
|
|
61
|
-
logger_1.logger.warn('Unknown proxy protocol, attempting to use with undici ProxyAgent', {
|
|
62
|
-
protocol,
|
|
63
|
-
proxyUrl: this.proxyUrl.toString(),
|
|
64
|
-
});
|
|
65
|
-
try {
|
|
66
|
-
this.proxyAgent = new undici_1.ProxyAgent(this.proxyUrl.toString());
|
|
67
|
-
}
|
|
68
|
-
catch (error) {
|
|
69
|
-
const errorMessage = `Failed to create ProxyAgent with protocol '${protocol}'. ` +
|
|
70
|
-
`Supported protocols: 'http', 'https', 'socks4', 'socks5'.`;
|
|
71
|
-
logger_1.logger.error(errorMessage, {
|
|
72
|
-
protocol,
|
|
73
|
-
proxyUrl: this.proxyUrl.toString(),
|
|
74
|
-
error: error instanceof Error ? error.message : String(error),
|
|
75
|
-
});
|
|
76
|
-
throw new Error(errorMessage);
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
this.useAxiosForProxy = useAxios;
|
|
81
|
-
// Create axios instance for SOCKS proxy support
|
|
82
|
-
if (useAxios && this.socksAgent) {
|
|
83
|
-
this.axiosInstance = axios_1.default.create({
|
|
84
|
-
httpAgent: this.socksAgent,
|
|
85
|
-
httpsAgent: this.socksAgent,
|
|
86
|
-
timeout: this.defaultTimeoutMs,
|
|
87
|
-
});
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
// Minimal request method signature; implementation will be added during wiring.
|
|
91
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
92
|
-
async request(path, init) {
|
|
93
|
-
const url = this.resolveUrl(path);
|
|
94
|
-
let lastError;
|
|
95
|
-
// maxRetries is the number of retries, so total attempts = maxRetries + 1 (initial attempt)
|
|
96
|
-
const maxAttempts = Math.max(1, this.maxRetries + 1);
|
|
97
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
98
|
-
try {
|
|
99
|
-
const controller = new AbortController();
|
|
100
|
-
const timeout = setTimeout(() => controller.abort(), this.defaultTimeoutMs);
|
|
101
|
-
try {
|
|
102
|
-
const headers = {
|
|
103
|
-
...(this.userAgent ? { 'User-Agent': this.userAgent } : {}),
|
|
104
|
-
Referer: 'https://app-api.pixiv.net/',
|
|
105
|
-
...init?.headers,
|
|
106
|
-
};
|
|
107
|
-
// Authorization header
|
|
108
|
-
// skipAuth: web endpoints (www.pixiv.net/ajax/*) reject the App
|
|
109
|
-
// Bearer token, so callers may opt out for those requests.
|
|
110
|
-
if (this.getAccessToken && !init?.skipAuth) {
|
|
111
|
-
const token = await Promise.resolve(this.getAccessToken());
|
|
112
|
-
if (token) {
|
|
113
|
-
headers.Authorization = `Bearer ${token}`;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
// Shared global rate-limit gate (429 cooldown + pacing).
|
|
117
|
-
if (this.rateLimiter) {
|
|
118
|
-
await this.rateLimiter.acquire(controller.signal);
|
|
119
|
-
}
|
|
120
|
-
else {
|
|
121
|
-
const waitMs = this.calculateRateLimitWaitTime();
|
|
122
|
-
if (waitMs > 0)
|
|
123
|
-
await (0, promises_1.setTimeout)(waitMs);
|
|
124
|
-
}
|
|
125
|
-
let res;
|
|
126
|
-
if (this.useAxiosForProxy && this.axiosInstance) {
|
|
127
|
-
// Use axios for SOCKS proxy
|
|
128
|
-
const axiosResponse = await this.axiosInstance.request({
|
|
129
|
-
url,
|
|
130
|
-
method: init?.method || 'GET',
|
|
131
|
-
headers,
|
|
132
|
-
data: init?.body,
|
|
133
|
-
signal: controller.signal,
|
|
134
|
-
responseType: 'json',
|
|
135
|
-
});
|
|
136
|
-
// Convert axios response to fetch-like Response
|
|
137
|
-
res = new Response(JSON.stringify(axiosResponse.data), {
|
|
138
|
-
status: axiosResponse.status,
|
|
139
|
-
statusText: axiosResponse.statusText,
|
|
140
|
-
headers: axiosResponse.headers,
|
|
141
|
-
});
|
|
142
|
-
}
|
|
143
|
-
else {
|
|
144
|
-
// Use undici fetch for HTTP/HTTPS proxy or no proxy
|
|
145
|
-
const fetchOptions = {
|
|
146
|
-
...init,
|
|
147
|
-
headers,
|
|
148
|
-
signal: controller.signal,
|
|
149
|
-
};
|
|
150
|
-
if (this.proxyAgent) {
|
|
151
|
-
fetchOptions.dispatcher = this.proxyAgent;
|
|
152
|
-
}
|
|
153
|
-
res = await fetch(url, fetchOptions);
|
|
154
|
-
}
|
|
155
|
-
return await this.processResponse(res, url, attempt, init?.responseType);
|
|
156
|
-
}
|
|
157
|
-
finally {
|
|
158
|
-
clearTimeout(timeout);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
catch (error) {
|
|
162
|
-
lastError = error;
|
|
163
|
-
// Do not retry 404
|
|
164
|
-
if ((0, errors_1.is404Error)(error)) {
|
|
165
|
-
throw error;
|
|
166
|
-
}
|
|
167
|
-
// If last attempt, throw
|
|
168
|
-
if (attempt >= maxAttempts - 1) {
|
|
169
|
-
throw error;
|
|
170
|
-
}
|
|
171
|
-
const wait = this.backoffWaitMs(error, attempt);
|
|
172
|
-
// Extract detailed error information
|
|
173
|
-
const errorInfo = {
|
|
174
|
-
url,
|
|
175
|
-
attempt: attempt + 1,
|
|
176
|
-
maxAttempts,
|
|
177
|
-
waitSec: Math.round(wait / 1000),
|
|
178
|
-
};
|
|
179
|
-
if (error instanceof Error) {
|
|
180
|
-
errorInfo.error = error.message;
|
|
181
|
-
errorInfo.errorType = error.name;
|
|
182
|
-
errorInfo.errorCode = error.code;
|
|
183
|
-
// Include cause if available
|
|
184
|
-
if (error.cause instanceof Error) {
|
|
185
|
-
errorInfo.cause = error.cause.message;
|
|
186
|
-
errorInfo.causeType = error.cause.name;
|
|
187
|
-
errorInfo.causeCode = error.cause.code;
|
|
188
|
-
}
|
|
189
|
-
// For AbortError (timeout), add timeout info
|
|
190
|
-
if (error.name === 'AbortError') {
|
|
191
|
-
errorInfo.reason = 'Request timeout';
|
|
192
|
-
errorInfo.timeoutMs = this.defaultTimeoutMs;
|
|
193
|
-
}
|
|
194
|
-
}
|
|
195
|
-
else {
|
|
196
|
-
errorInfo.error = String(error);
|
|
197
|
-
}
|
|
198
|
-
logger_1.logger.warn('PixivApiCore request failed, will retry', errorInfo);
|
|
199
|
-
await (0, promises_1.setTimeout)(wait);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
|
-
// Should not reach here
|
|
203
|
-
const message = lastError instanceof Error ? lastError.message : String(lastError);
|
|
204
|
-
throw new errors_1.NetworkError(`Request to ${url} failed: ${message}`, url, lastError instanceof Error ? lastError : undefined);
|
|
205
|
-
}
|
|
206
|
-
async downloadBinary(pathOrUrl, init) {
|
|
207
|
-
const url = this.resolveUrl(pathOrUrl);
|
|
208
|
-
let lastError;
|
|
209
|
-
// Large binaries (e.g. ugoira zips) may need longer than the API default
|
|
210
|
-
const attemptTimeoutMs = init?.timeoutMs ?? this.defaultTimeoutMs;
|
|
211
|
-
// maxRetries is the number of retries, so total attempts = maxRetries + 1 (initial attempt)
|
|
212
|
-
const maxAttempts = Math.max(1, this.maxRetries + 1);
|
|
213
|
-
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
214
|
-
try {
|
|
215
|
-
const controller = new AbortController();
|
|
216
|
-
const timeout = setTimeout(() => controller.abort(), attemptTimeoutMs);
|
|
217
|
-
try {
|
|
218
|
-
const headers = {
|
|
219
|
-
...(this.userAgent ? { 'User-Agent': this.userAgent } : {}),
|
|
220
|
-
Referer: 'https://app-api.pixiv.net/',
|
|
221
|
-
...init?.headers,
|
|
222
|
-
};
|
|
223
|
-
if (this.getAccessToken) {
|
|
224
|
-
const token = await Promise.resolve(this.getAccessToken());
|
|
225
|
-
if (token) {
|
|
226
|
-
headers.Authorization = `Bearer ${token}`;
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
if (this.rateLimiter) {
|
|
230
|
-
await this.rateLimiter.acquire(controller.signal);
|
|
231
|
-
}
|
|
232
|
-
else {
|
|
233
|
-
const waitMs = this.calculateRateLimitWaitTime();
|
|
234
|
-
if (waitMs > 0)
|
|
235
|
-
await (0, promises_1.setTimeout)(waitMs);
|
|
236
|
-
}
|
|
237
|
-
if (this.useAxiosForProxy && this.axiosInstance) {
|
|
238
|
-
// Use axios for SOCKS proxy
|
|
239
|
-
const axiosResponse = await this.axiosInstance.request({
|
|
240
|
-
url,
|
|
241
|
-
method: init?.method || 'GET',
|
|
242
|
-
headers,
|
|
243
|
-
data: init?.body,
|
|
244
|
-
signal: controller.signal,
|
|
245
|
-
responseType: 'arraybuffer',
|
|
246
|
-
});
|
|
247
|
-
if (axiosResponse.status < 200 || axiosResponse.status >= 300) {
|
|
248
|
-
const body = typeof axiosResponse.data === 'string'
|
|
249
|
-
? axiosResponse.data
|
|
250
|
-
: Buffer.from(axiosResponse.data).toString('utf-8');
|
|
251
|
-
throw new errors_1.NetworkError(`Pixiv API binary error: ${axiosResponse.status} ${axiosResponse.statusText}${body ? ` - ${body}` : ''}`, url);
|
|
252
|
-
}
|
|
253
|
-
return axiosResponse.data;
|
|
254
|
-
}
|
|
255
|
-
else {
|
|
256
|
-
// Use undici fetch for HTTP/HTTPS proxy or no proxy
|
|
257
|
-
const fetchOptions = {
|
|
258
|
-
method: 'GET',
|
|
259
|
-
...init,
|
|
260
|
-
headers,
|
|
261
|
-
signal: controller.signal,
|
|
262
|
-
};
|
|
263
|
-
if (this.proxyAgent) {
|
|
264
|
-
fetchOptions.dispatcher = this.proxyAgent;
|
|
265
|
-
}
|
|
266
|
-
const res = await fetch(url, fetchOptions);
|
|
267
|
-
if (!res.ok) {
|
|
268
|
-
const body = await this.tryReadText(res);
|
|
269
|
-
throw new errors_1.NetworkError(`Pixiv API binary error: ${res.status} ${res.statusText}${body ? ` - ${body}` : ''}`, url);
|
|
270
|
-
}
|
|
271
|
-
return await res.arrayBuffer();
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
finally {
|
|
275
|
-
clearTimeout(timeout);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
catch (error) {
|
|
279
|
-
lastError = error;
|
|
280
|
-
if ((0, errors_1.is404Error)(error)) {
|
|
281
|
-
throw error;
|
|
282
|
-
}
|
|
283
|
-
if (attempt >= maxAttempts - 1) {
|
|
284
|
-
throw error;
|
|
285
|
-
}
|
|
286
|
-
const wait = this.backoffWaitMs(error, attempt);
|
|
287
|
-
// Extract detailed error information
|
|
288
|
-
const errorInfo = {
|
|
289
|
-
url,
|
|
290
|
-
attempt: attempt + 1,
|
|
291
|
-
maxAttempts,
|
|
292
|
-
waitSec: Math.round(wait / 1000),
|
|
293
|
-
};
|
|
294
|
-
if (error instanceof Error) {
|
|
295
|
-
errorInfo.error = error.message;
|
|
296
|
-
errorInfo.errorType = error.name;
|
|
297
|
-
errorInfo.errorCode = error.code;
|
|
298
|
-
// Include cause if available
|
|
299
|
-
if (error.cause instanceof Error) {
|
|
300
|
-
errorInfo.cause = error.cause.message;
|
|
301
|
-
errorInfo.causeType = error.cause.name;
|
|
302
|
-
errorInfo.causeCode = error.cause.code;
|
|
303
|
-
}
|
|
304
|
-
// For AbortError (timeout), add timeout info
|
|
305
|
-
if (error.name === 'AbortError') {
|
|
306
|
-
errorInfo.reason = 'Request timeout';
|
|
307
|
-
errorInfo.timeoutMs = this.defaultTimeoutMs;
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
else {
|
|
311
|
-
errorInfo.error = String(error);
|
|
312
|
-
}
|
|
313
|
-
logger_1.logger.warn('PixivApiCore binary download failed, will retry', errorInfo);
|
|
314
|
-
await (0, promises_1.setTimeout)(wait);
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
// Provide detailed error message for final failure
|
|
318
|
-
let errorMessage = `Binary download from ${url} failed after ${maxAttempts} attempts`;
|
|
319
|
-
if (lastError instanceof Error) {
|
|
320
|
-
errorMessage += `: ${lastError.message}`;
|
|
321
|
-
if (lastError.name === 'AbortError') {
|
|
322
|
-
errorMessage += ` (timeout after ${this.defaultTimeoutMs}ms)`;
|
|
323
|
-
}
|
|
324
|
-
const errorCode = lastError.code;
|
|
325
|
-
if (errorCode) {
|
|
326
|
-
errorMessage += ` [${errorCode}]`;
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
else {
|
|
330
|
-
errorMessage += `: ${String(lastError)}`;
|
|
331
|
-
}
|
|
332
|
-
throw new errors_1.NetworkError(errorMessage, url, lastError instanceof Error ? lastError : undefined);
|
|
333
|
-
}
|
|
334
|
-
calculateRateLimitWaitTime() {
|
|
335
|
-
if (!this.rateLimitPerSecond || this.rateLimitPerSecond <= 0)
|
|
336
|
-
return 0;
|
|
337
|
-
return Math.ceil(1000 / this.rateLimitPerSecond);
|
|
338
|
-
}
|
|
339
|
-
async processResponse(response, url, attempt, responseType) {
|
|
340
|
-
// 401: likely token issue
|
|
341
|
-
if (response.status === 401) {
|
|
342
|
-
const body = await this.tryReadText(response);
|
|
343
|
-
throw new errors_1.NetworkError(`Pixiv API error: 401 Unauthorized${body ? ` - ${body}` : ''}`, url);
|
|
344
|
-
}
|
|
345
|
-
// 404: not found, do not retry
|
|
346
|
-
if (response.status === 404) {
|
|
347
|
-
const body = await this.tryReadText(response);
|
|
348
|
-
throw new errors_1.NetworkError(`Pixiv API error: 404 Not Found${body ? ` - ${body}` : ''}`, url);
|
|
349
|
-
}
|
|
350
|
-
// 429: rate limited
|
|
351
|
-
if (response.status === 429) {
|
|
352
|
-
const body = await this.tryReadText(response);
|
|
353
|
-
const retryAfter = response.headers.get('Retry-After');
|
|
354
|
-
const waitMs = this.rateLimiter
|
|
355
|
-
? this.rateLimiter.reportRateLimited(retryAfter)
|
|
356
|
-
: this.parseRetryAfterHeader(retryAfter) ?? this.exponentialBackoffMs(attempt);
|
|
357
|
-
throw new errors_1.NetworkError(`Pixiv API error: 429 Rate Limit${body ? ` - ${body.slice(0, 120)}` : ''}`, url, undefined, { isRateLimit: true, waitTime: waitMs });
|
|
358
|
-
}
|
|
359
|
-
if (!response.ok) {
|
|
360
|
-
const body = await this.tryReadText(response);
|
|
361
|
-
throw new errors_1.NetworkError(`Pixiv API error: ${response.status} ${response.statusText}${body ? ` - ${body}` : ''}`, url);
|
|
362
|
-
}
|
|
363
|
-
this.rateLimiter?.reportSuccess();
|
|
364
|
-
if (responseType === 'text') {
|
|
365
|
-
return (await response.text());
|
|
366
|
-
}
|
|
367
|
-
return (await response.json());
|
|
368
|
-
}
|
|
369
|
-
parseRetryAfterHeader(value) {
|
|
370
|
-
if (!value)
|
|
371
|
-
return undefined;
|
|
372
|
-
const seconds = Number(value);
|
|
373
|
-
if (Number.isFinite(seconds))
|
|
374
|
-
return seconds * 1000;
|
|
375
|
-
const date = Date.parse(value);
|
|
376
|
-
return Number.isFinite(date) ? Math.max(0, date - Date.now()) : undefined;
|
|
377
|
-
}
|
|
378
|
-
resolveUrl(pathOrUrl) {
|
|
379
|
-
try {
|
|
380
|
-
// If it's already an absolute URL, return as is
|
|
381
|
-
const maybeUrl = new node_url_1.URL(pathOrUrl);
|
|
382
|
-
return maybeUrl.toString();
|
|
383
|
-
}
|
|
384
|
-
catch {
|
|
385
|
-
// Not a full URL, resolve against base
|
|
386
|
-
const withLeadingSlash = pathOrUrl.startsWith('/') ? pathOrUrl : `/${pathOrUrl}`;
|
|
387
|
-
return new node_url_1.URL(withLeadingSlash, this.baseUrl).toString();
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
exponentialBackoffMs(attempt) {
|
|
391
|
-
// 1s, 2s, 4s, 8s ... capped at 10 minutes
|
|
392
|
-
return Math.min(1000 * Math.pow(2, attempt), 600_000);
|
|
393
|
-
}
|
|
394
|
-
backoffWaitMs(error, attempt) {
|
|
395
|
-
const isRateLimit = error instanceof errors_1.NetworkError && error.isRateLimit === true;
|
|
396
|
-
if (isRateLimit) {
|
|
397
|
-
const wait = error.waitTime ?? this.exponentialBackoffMs(attempt);
|
|
398
|
-
return wait;
|
|
399
|
-
}
|
|
400
|
-
return Math.min(1000 * (attempt + 1), 5000);
|
|
401
|
-
}
|
|
402
|
-
async tryReadText(response) {
|
|
403
|
-
try {
|
|
404
|
-
return await response.text();
|
|
405
|
-
}
|
|
406
|
-
catch {
|
|
407
|
-
return '';
|
|
408
|
-
}
|
|
409
|
-
}
|
|
410
|
-
}
|
|
411
|
-
exports.PixivApiCore = PixivApiCore;
|
|
412
|
-
//# sourceMappingURL=PixivApiCore.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"PixivApiCore.js","sourceRoot":"","sources":["../../../src/pixiv/client/PixivApiCore.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { PixivApiCore } from './PixivApiCore';
|
|
2
|
-
import type { PixivIllust, PixivNovel, PixivTag } from '../types';
|
|
3
|
-
import type { TargetConfig } from '../../config';
|
|
4
|
-
/**
|
|
5
|
-
* Search service for illustrations and novels with pagination, filtering and sorting.
|
|
6
|
-
* Depends on PixivApiCore for HTTP concerns.
|
|
7
|
-
*/
|
|
8
|
-
export declare class SearchService {
|
|
9
|
-
private readonly api;
|
|
10
|
-
constructor(api: PixivApiCore);
|
|
11
|
-
getTagAutocomplete(seed: string): Promise<PixivTag[]>;
|
|
12
|
-
searchIllustrations(target: TargetConfig, requestDelayMs: number): Promise<PixivIllust[]>;
|
|
13
|
-
searchNovels(target: TargetConfig, requestDelayMs: number): Promise<PixivNovel[]>;
|
|
14
|
-
private searchIllustrationsSingleTag;
|
|
15
|
-
private searchNovelsSingleTag;
|
|
16
|
-
/**
|
|
17
|
-
* Generic pagination search method that works for both illustrations and novels.
|
|
18
|
-
*/
|
|
19
|
-
private searchWithPagination;
|
|
20
|
-
}
|
|
21
|
-
//# sourceMappingURL=SearchService.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"SearchService.d.ts","sourceRoot":"","sources":["../../../src/pixiv/client/SearchService.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,UAAU,CAAC;AAGlE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAGjD;;;GAGG;AACH,qBAAa,aAAa;IACZ,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,EAAE,YAAY;IAExC,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAcrD,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA6CzF,YAAY,CAAC,MAAM,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,CAAC;YA6CzE,4BAA4B;YA+C5B,qBAAqB;IA2CnC;;OAEG;YACW,oBAAoB;CAsEnC"}
|
|
@@ -1,207 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.SearchService = void 0;
|
|
4
|
-
const promises_1 = require("node:timers/promises");
|
|
5
|
-
const logger_1 = require("../../logger");
|
|
6
|
-
const pixiv_sort_1 = require("../../utils/pixiv-sort");
|
|
7
|
-
const SearchFilters_1 = require("./search/SearchFilters");
|
|
8
|
-
/**
|
|
9
|
-
* Search service for illustrations and novels with pagination, filtering and sorting.
|
|
10
|
-
* Depends on PixivApiCore for HTTP concerns.
|
|
11
|
-
*/
|
|
12
|
-
class SearchService {
|
|
13
|
-
api;
|
|
14
|
-
constructor(api) {
|
|
15
|
-
this.api = api;
|
|
16
|
-
}
|
|
17
|
-
async getTagAutocomplete(seed) {
|
|
18
|
-
const params = new URLSearchParams({
|
|
19
|
-
word: seed,
|
|
20
|
-
merge_plain_keyword_results: 'true',
|
|
21
|
-
});
|
|
22
|
-
const response = await this.api.request(`/v2/search/autocomplete?${params.toString()}`, { method: 'GET' });
|
|
23
|
-
if (Array.isArray(response.tags))
|
|
24
|
-
return response.tags;
|
|
25
|
-
return (response.search_auto_complete_keywords ?? []).map((name) => ({ name }));
|
|
26
|
-
}
|
|
27
|
-
async searchIllustrations(target, requestDelayMs) {
|
|
28
|
-
if (!target.tag) {
|
|
29
|
-
throw new Error('tag is required for illustration search');
|
|
30
|
-
}
|
|
31
|
-
// Support tagRelation === 'or': split space-separated tags, query sequentially, merge & dedupe
|
|
32
|
-
if (target.tagRelation === 'or') {
|
|
33
|
-
const tags = target.tag.split(/\s+/).map((t) => t.trim()).filter(Boolean);
|
|
34
|
-
if (tags.length <= 1) {
|
|
35
|
-
return this.searchIllustrationsSingleTag(target, target.tag, requestDelayMs);
|
|
36
|
-
}
|
|
37
|
-
const seen = new Set();
|
|
38
|
-
const merged = [];
|
|
39
|
-
for (let i = 0; i < tags.length; i++) {
|
|
40
|
-
const tag = tags[i];
|
|
41
|
-
const part = await this.searchIllustrationsSingleTag(target, tag, requestDelayMs);
|
|
42
|
-
for (const item of part) {
|
|
43
|
-
const key = String(item.id);
|
|
44
|
-
if (!seen.has(key)) {
|
|
45
|
-
seen.add(key);
|
|
46
|
-
merged.push(item);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// Respect global limit early if possible
|
|
50
|
-
if (target.limit && merged.length >= target.limit) {
|
|
51
|
-
break;
|
|
52
|
-
}
|
|
53
|
-
// Add delay between tag requests to reduce rate limiting
|
|
54
|
-
if (i < tags.length - 1 && requestDelayMs > 0) {
|
|
55
|
-
await (0, promises_1.setTimeout)(requestDelayMs);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
const sorted = (0, pixiv_sort_1.sortPixivItems)(merged, target.sort);
|
|
59
|
-
if (target.limit && sorted.length > target.limit) {
|
|
60
|
-
return sorted.slice(0, target.limit);
|
|
61
|
-
}
|
|
62
|
-
return sorted;
|
|
63
|
-
}
|
|
64
|
-
return this.searchIllustrationsSingleTag(target, target.tag, requestDelayMs);
|
|
65
|
-
}
|
|
66
|
-
async searchNovels(target, requestDelayMs) {
|
|
67
|
-
if (!target.tag) {
|
|
68
|
-
throw new Error('tag is required for novel search');
|
|
69
|
-
}
|
|
70
|
-
// Support tagRelation === 'or': split space-separated tags, query sequentially, merge & dedupe
|
|
71
|
-
if (target.tagRelation === 'or') {
|
|
72
|
-
const tags = target.tag.split(/\s+/).map((t) => t.trim()).filter(Boolean);
|
|
73
|
-
if (tags.length <= 1) {
|
|
74
|
-
return this.searchNovelsSingleTag(target, target.tag, requestDelayMs);
|
|
75
|
-
}
|
|
76
|
-
const seen = new Set();
|
|
77
|
-
const merged = [];
|
|
78
|
-
for (let i = 0; i < tags.length; i++) {
|
|
79
|
-
const tag = tags[i];
|
|
80
|
-
const part = await this.searchNovelsSingleTag(target, tag, requestDelayMs);
|
|
81
|
-
for (const item of part) {
|
|
82
|
-
const key = String(item.id);
|
|
83
|
-
if (!seen.has(key)) {
|
|
84
|
-
seen.add(key);
|
|
85
|
-
merged.push(item);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
// Respect global limit early if possible
|
|
89
|
-
if (target.limit && merged.length >= target.limit) {
|
|
90
|
-
break;
|
|
91
|
-
}
|
|
92
|
-
// Add delay between tag requests to reduce rate limiting
|
|
93
|
-
if (i < tags.length - 1 && requestDelayMs > 0) {
|
|
94
|
-
await (0, promises_1.setTimeout)(requestDelayMs);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
const sorted = (0, pixiv_sort_1.sortPixivItems)(merged, target.sort);
|
|
98
|
-
if (target.limit && sorted.length > target.limit) {
|
|
99
|
-
return sorted.slice(0, target.limit);
|
|
100
|
-
}
|
|
101
|
-
return sorted;
|
|
102
|
-
}
|
|
103
|
-
return this.searchNovelsSingleTag(target, target.tag, requestDelayMs);
|
|
104
|
-
}
|
|
105
|
-
async searchIllustrationsSingleTag(target, tag, requestDelayMs) {
|
|
106
|
-
logger_1.logger.debug('Searching illustrations', {
|
|
107
|
-
tag,
|
|
108
|
-
sort: target.sort,
|
|
109
|
-
searchTarget: target.searchTarget,
|
|
110
|
-
startDate: target.startDate,
|
|
111
|
-
endDate: target.endDate,
|
|
112
|
-
});
|
|
113
|
-
const dateRange = SearchFilters_1.SearchFilters.parseDateRangeFromTarget(target);
|
|
114
|
-
if (dateRange === null) {
|
|
115
|
-
return [];
|
|
116
|
-
}
|
|
117
|
-
const { startDate, endDate } = dateRange;
|
|
118
|
-
// filter=for_ios excludes R-18 works; omit it when the target opts in.
|
|
119
|
-
const paramsObj = {
|
|
120
|
-
word: tag,
|
|
121
|
-
search_target: target.searchTarget ?? 'partial_match_for_tags',
|
|
122
|
-
include_translated_tag_results: 'true',
|
|
123
|
-
};
|
|
124
|
-
if (!target.r18)
|
|
125
|
-
paramsObj.filter = 'for_ios';
|
|
126
|
-
const params = new URLSearchParams(paramsObj);
|
|
127
|
-
if (target.sort)
|
|
128
|
-
params.set('sort', target.sort);
|
|
129
|
-
const sortMode = target.sort || 'date_desc';
|
|
130
|
-
const hasDateFilter = !!(startDate || endDate);
|
|
131
|
-
const fetchLimit = SearchFilters_1.SearchFilters.calculateFetchLimit(target, sortMode, hasDateFilter);
|
|
132
|
-
return this.searchWithPagination(`/v1/search/illust?${params.toString()}`, 'illusts', target, tag, requestDelayMs, sortMode, startDate, endDate, hasDateFilter, fetchLimit);
|
|
133
|
-
}
|
|
134
|
-
async searchNovelsSingleTag(target, tag, requestDelayMs) {
|
|
135
|
-
logger_1.logger.debug('Searching novels', {
|
|
136
|
-
tag,
|
|
137
|
-
sort: target.sort,
|
|
138
|
-
searchTarget: target.searchTarget,
|
|
139
|
-
startDate: target.startDate,
|
|
140
|
-
endDate: target.endDate,
|
|
141
|
-
});
|
|
142
|
-
const dateRange = SearchFilters_1.SearchFilters.parseDateRangeFromTarget(target);
|
|
143
|
-
if (dateRange === null) {
|
|
144
|
-
return [];
|
|
145
|
-
}
|
|
146
|
-
const { startDate, endDate } = dateRange;
|
|
147
|
-
const params = new URLSearchParams({
|
|
148
|
-
word: tag,
|
|
149
|
-
search_target: target.searchTarget ?? 'partial_match_for_tags',
|
|
150
|
-
});
|
|
151
|
-
if (target.sort)
|
|
152
|
-
params.set('sort', target.sort);
|
|
153
|
-
const sortMode = target.sort || 'date_desc';
|
|
154
|
-
const hasDateFilter = !!(startDate || endDate);
|
|
155
|
-
const fetchLimit = SearchFilters_1.SearchFilters.calculateFetchLimit(target, sortMode, hasDateFilter);
|
|
156
|
-
return this.searchWithPagination(`/v1/search/novel?${params.toString()}`, 'novels', target, tag, requestDelayMs, sortMode, startDate, endDate, hasDateFilter, fetchLimit);
|
|
157
|
-
}
|
|
158
|
-
/**
|
|
159
|
-
* Generic pagination search method that works for both illustrations and novels.
|
|
160
|
-
*/
|
|
161
|
-
async searchWithPagination(initialUrl, itemsKey, target, tag, requestDelayMs, sortMode, startDate, endDate, hasDateFilter, fetchLimit) {
|
|
162
|
-
const results = [];
|
|
163
|
-
let nextUrl = initialUrl;
|
|
164
|
-
let pageCount = 0;
|
|
165
|
-
let shouldStop = false;
|
|
166
|
-
while (nextUrl && (!fetchLimit || results.length < fetchLimit) && !shouldStop) {
|
|
167
|
-
pageCount++;
|
|
168
|
-
const response = await this.api.request(nextUrl, { method: 'GET' });
|
|
169
|
-
const items = response[itemsKey] || [];
|
|
170
|
-
const responseNextUrl = response.next_url;
|
|
171
|
-
for (const item of items) {
|
|
172
|
-
const filterResult = SearchFilters_1.SearchFilters.filterItemByDate(item, target, startDate, endDate, sortMode);
|
|
173
|
-
if (filterResult.shouldStop) {
|
|
174
|
-
shouldStop = true;
|
|
175
|
-
break;
|
|
176
|
-
}
|
|
177
|
-
if (filterResult.shouldInclude) {
|
|
178
|
-
results.push(item);
|
|
179
|
-
if (fetchLimit && results.length >= fetchLimit) {
|
|
180
|
-
break;
|
|
181
|
-
}
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
nextUrl = responseNextUrl;
|
|
185
|
-
if (nextUrl && requestDelayMs > 0 && !shouldStop) {
|
|
186
|
-
logger_1.logger.debug(`Tag "${tag}" page ${pageCount}: found ${items.length} ${itemsKey}, total collected: ${results.length}, waiting ${requestDelayMs}ms before next page...`);
|
|
187
|
-
await (0, promises_1.setTimeout)(requestDelayMs);
|
|
188
|
-
}
|
|
189
|
-
}
|
|
190
|
-
// Post-process for popular_desc mode with date filter
|
|
191
|
-
let finalResults = results;
|
|
192
|
-
if (sortMode === 'popular_desc' && hasDateFilter && results.length > 0) {
|
|
193
|
-
const validResults = SearchFilters_1.SearchFilters.filterResultsByDateRange(results, startDate, endDate);
|
|
194
|
-
if (validResults.length < results.length) {
|
|
195
|
-
logger_1.logger.debug(`Date filtering in popular_desc mode: ${results.length} total results, ${validResults.length} within date range`);
|
|
196
|
-
}
|
|
197
|
-
finalResults = validResults;
|
|
198
|
-
}
|
|
199
|
-
const sortedResults = (0, pixiv_sort_1.sortPixivItems)(finalResults, target.sort);
|
|
200
|
-
if (target.limit && sortedResults.length > target.limit) {
|
|
201
|
-
return sortedResults.slice(0, target.limit);
|
|
202
|
-
}
|
|
203
|
-
return sortedResults;
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
exports.SearchService = SearchService;
|
|
207
|
-
//# sourceMappingURL=SearchService.js.map
|