@duyquangnvx/webnovel-downloader 0.1.0 → 0.2.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/README.md +29 -2
- package/dist/{chunk-D5G3S2VW.js → chunk-DFJ7E7IG.js} +12 -10
- package/dist/chunk-DFJ7E7IG.js.map +1 -0
- package/dist/{chunk-7IERJRIL.js → chunk-V2JVYKS3.js} +25 -2
- package/dist/chunk-V2JVYKS3.js.map +1 -0
- package/dist/{client-OCC6BJIO.js → client-UKPAYL5D.js} +3 -3
- package/dist/{errors-UKZDQ6Y3.js → errors-GRDU3PLX.js} +8 -4
- package/dist/index.cjs +3075 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +884 -0
- package/dist/index.d.ts +46 -24
- package/dist/index.js +719 -537
- package/dist/index.js.map +1 -1
- package/package.json +12 -4
- package/dist/chunk-7IERJRIL.js.map +0 -1
- package/dist/chunk-D5G3S2VW.js.map +0 -1
- /package/dist/{client-OCC6BJIO.js.map → client-UKPAYL5D.js.map} +0 -0
- /package/dist/{errors-UKZDQ6Y3.js.map → errors-GRDU3PLX.js.map} +0 -0
package/README.md
CHANGED
|
@@ -72,6 +72,8 @@ pnpm add patchright
|
|
|
72
72
|
|
|
73
73
|
Published to npm under public access (`@duyquangnvx/webnovel-downloader`).
|
|
74
74
|
|
|
75
|
+
Ships both ESM and CommonJS builds, so `import` and `require` both work.
|
|
76
|
+
|
|
75
77
|
## Quick example
|
|
76
78
|
|
|
77
79
|
```ts
|
|
@@ -90,12 +92,18 @@ if (result.status === "success") {
|
|
|
90
92
|
|
|
91
93
|
## Resume & partial downloads
|
|
92
94
|
|
|
93
|
-
`download()`
|
|
95
|
+
`download()` returns a result envelope rather than throwing for download
|
|
96
|
+
failures. It only throws on abort (`CancelledError`), or when a browser-tier
|
|
97
|
+
site (e.g. wikicv) can't start its browser — no `patchright`/`playwright`
|
|
98
|
+
installed (`BrowserModuleNotInstalledError`) or `transport: "http-only"`
|
|
99
|
+
(`ParseError`).
|
|
94
100
|
|
|
95
101
|
```ts
|
|
96
102
|
const result = await downloader.download(url, { resume: true });
|
|
97
103
|
|
|
98
|
-
|
|
104
|
+
// `partial` is a union on `resumable`; the resume token only exists on the
|
|
105
|
+
// resumable arm, so narrow on it before reading the token.
|
|
106
|
+
if (result.status === "partial" && result.resumable) {
|
|
99
107
|
// Some chapters failed; retry just those with the issued token.
|
|
100
108
|
const retry = await downloader.download(url, {
|
|
101
109
|
resume: { token: result.resumeToken },
|
|
@@ -116,6 +124,25 @@ downloader.canHandle("https://truyenfull.vn/x/"); // boolean
|
|
|
116
124
|
downloader.supportedSites(); // [{ id, displayName, hostnames }, ...]
|
|
117
125
|
```
|
|
118
126
|
|
|
127
|
+
Errors carry a stable `code`; the error channel is a discriminated union, so a
|
|
128
|
+
`switch` narrows to the concrete error and its typed fields:
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
const result = await downloader.download(url);
|
|
132
|
+
if (result.status === "error") {
|
|
133
|
+
switch (result.error.code) {
|
|
134
|
+
case "HTTP_ERROR":
|
|
135
|
+
console.error(`HTTP ${result.error.status} for ${result.error.url}`);
|
|
136
|
+
break;
|
|
137
|
+
case "RATE_LIMITED":
|
|
138
|
+
console.error(`rate limited; retry after ${result.error.retryAfterMs}ms`);
|
|
139
|
+
break;
|
|
140
|
+
default:
|
|
141
|
+
console.error(result.error.message);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
```
|
|
145
|
+
|
|
119
146
|
For browser-tier sites (e.g. wikicv) in a long-lived process, build your own
|
|
120
147
|
instance and dispose it; the shared `downloader` singleton is fine for short
|
|
121
148
|
scripts:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CancelledError,
|
|
3
3
|
ChallengeUnresolvedError
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-V2JVYKS3.js";
|
|
5
5
|
|
|
6
6
|
// src/data-model/primitives.ts
|
|
7
7
|
import { z } from "zod";
|
|
@@ -13,9 +13,6 @@ var ChapterIndexSchema = z.number().int().nonnegative().brand();
|
|
|
13
13
|
function unsafeBrandChapterIndex(input) {
|
|
14
14
|
return input;
|
|
15
15
|
}
|
|
16
|
-
function chapterIndex(input) {
|
|
17
|
-
return ChapterIndexSchema.parse(input);
|
|
18
|
-
}
|
|
19
16
|
var AdapterIdSchema = z.string().min(1).brand();
|
|
20
17
|
function unsafeBrandAdapterId(input) {
|
|
21
18
|
return input;
|
|
@@ -81,7 +78,7 @@ function isCloudflareChallenge(res) {
|
|
|
81
78
|
}
|
|
82
79
|
|
|
83
80
|
// src/http/browser/client.ts
|
|
84
|
-
var RESPONSE_BUFFER_LIMIT =
|
|
81
|
+
var RESPONSE_BUFFER_LIMIT = 20;
|
|
85
82
|
var CHALLENGE_TITLE = new RegExp(`^(?:${CF_TITLE_PHRASES})`, "i");
|
|
86
83
|
var BrowserHttpClient = class {
|
|
87
84
|
#pool;
|
|
@@ -105,7 +102,7 @@ var BrowserHttpClient = class {
|
|
|
105
102
|
throw new ChallengeUnresolvedError(url, "manual-solve");
|
|
106
103
|
}
|
|
107
104
|
const body = await page.content();
|
|
108
|
-
const status = response?.status() ??
|
|
105
|
+
const status = response?.status() ?? 0;
|
|
109
106
|
const headers = response?.headers() ?? {};
|
|
110
107
|
return { status, headers, body, url };
|
|
111
108
|
} finally {
|
|
@@ -113,7 +110,7 @@ var BrowserHttpClient = class {
|
|
|
113
110
|
}
|
|
114
111
|
} catch (err) {
|
|
115
112
|
if (opts?.signal?.aborted) {
|
|
116
|
-
throw new CancelledError({ cause: opts.signal.reason });
|
|
113
|
+
throw new CancelledError({ cause: err ?? opts.signal.reason });
|
|
117
114
|
}
|
|
118
115
|
throw err;
|
|
119
116
|
} finally {
|
|
@@ -137,7 +134,13 @@ var BrowserClientImpl = class {
|
|
|
137
134
|
};
|
|
138
135
|
page.on("response", onResponse);
|
|
139
136
|
if (opts.initScript !== void 0) {
|
|
140
|
-
|
|
137
|
+
try {
|
|
138
|
+
await page.addInitScript(opts.initScript);
|
|
139
|
+
} catch (err) {
|
|
140
|
+
page.off("response", onResponse);
|
|
141
|
+
await safeClosePage(page);
|
|
142
|
+
throw err;
|
|
143
|
+
}
|
|
141
144
|
}
|
|
142
145
|
let navError;
|
|
143
146
|
try {
|
|
@@ -233,7 +236,6 @@ export {
|
|
|
233
236
|
unsafeBrandUrl,
|
|
234
237
|
ChapterIndexSchema,
|
|
235
238
|
unsafeBrandChapterIndex,
|
|
236
|
-
chapterIndex,
|
|
237
239
|
AdapterIdSchema,
|
|
238
240
|
unsafeBrandAdapterId,
|
|
239
241
|
IsoDateSchema,
|
|
@@ -247,4 +249,4 @@ export {
|
|
|
247
249
|
BrowserClientImpl,
|
|
248
250
|
captureCfCookies
|
|
249
251
|
};
|
|
250
|
-
//# sourceMappingURL=chunk-
|
|
252
|
+
//# sourceMappingURL=chunk-DFJ7E7IG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/data-model/primitives.ts","../src/http/browser/safe-close.ts","../src/http/cookie-jar.ts","../src/http/cf-challenge.ts","../src/http/browser/client.ts"],"sourcesContent":["import { z } from \"zod\";\n\nexport const UrlSchema = z.string().url().brand<\"Url\">();\n/**\n * An absolute URL string, branded after validation so an unchecked string\n * cannot be passed where a real URL is required. Library output is already\n * branded; to brand untrusted input, use `parseUrl` from `data-model/parse.ts`.\n */\nexport type Url = z.infer<typeof UrlSchema>;\n/**\n * Brand a string as Url WITHOUT runtime validation. Use only when the caller\n * has already proved the value is a valid absolute URL (e.g. it came from\n * `new URL().toString()` or from a Zod-validated source). For untrusted input,\n * use `parseUrl` from `data-model/parse.ts` instead.\n */\nexport function unsafeBrandUrl(input: string): Url {\n return input as Url;\n}\n\nexport const ChapterIndexSchema = z.number().int().nonnegative().brand<\"ChapterIndex\">();\n/**\n * A chapter's position in the table of contents, branded as a non-negative\n * integer. Indices are **0-based**: chapter 1 is index 0. Build one with\n * {@link chapterIndex}.\n */\nexport type ChapterIndex = z.infer<typeof ChapterIndexSchema>;\n/** Brand a number as ChapterIndex without validation. See `unsafeBrandUrl`. */\nexport function unsafeBrandChapterIndex(input: number): ChapterIndex {\n return input as ChapterIndex;\n}\n/**\n * Build a validated ChapterIndex from a plain number. Throws if `input` is not\n * a non-negative integer. Used internally and by custom adapters when hand-\n * building a {@link ChapterRef}; `DownloadOptions.chapterRange` takes plain\n * numbers, so callers do not need this for ranges. Indices are 0-based.\n */\nexport function chapterIndex(input: number): ChapterIndex {\n return ChapterIndexSchema.parse(input);\n}\n\nexport const AdapterIdSchema = z.string().min(1).brand<\"AdapterId\">();\n/** Stable identifier for a site adapter (e.g. `\"truyenfull\"`), branded as a non-empty string. */\nexport type AdapterId = z.infer<typeof AdapterIdSchema>;\n/** Brand a string as AdapterId without validation. See `unsafeBrandUrl`. */\nexport function unsafeBrandAdapterId(input: string): AdapterId {\n return input as AdapterId;\n}\n\nexport const IsoDateSchema = z.string().datetime().brand<\"IsoDate\">();\n/** An ISO-8601 datetime string (e.g. `\"2026-06-17T09:30:00.000Z\"`), branded after validation. */\nexport type IsoDate = z.infer<typeof IsoDateSchema>;\n/** Brand a string as IsoDate without validation. See `unsafeBrandUrl`. */\nexport function unsafeBrandIsoDate(input: string): IsoDate {\n return input as IsoDate;\n}\n\nexport const ResumeTokenSchema = z.string().min(1).brand<\"ResumeToken\">();\n/**\n * Opaque token returned on a partial download (see {@link DownloadPartial}).\n * Pass it back via `DownloadOptions.resume` to continue where the run left off.\n * Branded as a non-empty string.\n */\nexport type ResumeToken = z.infer<typeof ResumeTokenSchema>;\n/** Brand a string as ResumeToken without validation. See `unsafeBrandUrl`. */\nexport function unsafeBrandResumeToken(input: string): ResumeToken {\n return input as ResumeToken;\n}\n","import type { Logger } from \"../../data-model/ports.js\";\n\ninterface Closeable {\n close(): Promise<void>;\n}\n\nexport async function safeClosePage(page: Closeable, logger?: Logger): Promise<void> {\n try {\n await page.close();\n } catch (err) {\n logger?.debug({ err }, \"page close failed (non-fatal)\");\n }\n}\n\nexport async function safeCloseContext(ctx: Closeable, logger?: Logger): Promise<void> {\n try {\n await ctx.close();\n } catch (err) {\n logger?.debug({ err }, \"context close failed (non-fatal)\");\n }\n}\n","export interface Cookie {\n readonly name: string;\n readonly value: string;\n}\n\nexport interface CookieJarReadResult {\n readonly cookieHeader: string | null;\n readonly ua: string | null;\n}\n\ninterface Entry {\n readonly cookies: readonly Cookie[];\n readonly ua: string;\n}\n\nconst CF_NAME_PATTERN = /^(cf_clearance|__cf_bm|cf_chl)/;\n\nexport function isCfCookie(name: string): boolean {\n return CF_NAME_PATTERN.test(name);\n}\n\nexport class CookieJar {\n readonly #byHost = new Map<string, Entry>();\n\n put(host: string, cookies: readonly Cookie[], ua: string): void {\n // The UA pin is needed for HTTP-branch session continuity even when CF\n // hasn't issued cookies yet — dropping the entry on `filtered.length === 0`\n // would let the rotating UA client churn UAs until the first challenge.\n const filtered = cookies.filter((c) => isCfCookie(c.name));\n const key = host.toLowerCase();\n const existing = this.#byHost.get(key);\n const nextCookies = filtered.length > 0 ? filtered : (existing?.cookies ?? []);\n this.#byHost.set(key, { cookies: nextCookies, ua });\n }\n\n read(host: string): CookieJarReadResult {\n const entry = this.#byHost.get(host.toLowerCase());\n if (!entry) return { cookieHeader: null, ua: null };\n const cookieHeader =\n entry.cookies.length > 0\n ? entry.cookies.map((c) => `${c.name}=${c.value}`).join(\"; \")\n : null;\n return { cookieHeader, ua: entry.ua };\n }\n}\n","import type { HttpResponse } from \"./types.js\";\n\n// Raw regex-alternation fragment, not a plain string: callers splice it into a\n// `new RegExp()`. Phrases must stay metacharacter-free or the built regex shifts.\nexport const CF_TITLE_PHRASES = \"Just a moment|Chờ một chút\";\nconst CF_TITLE_REGEX = new RegExp(`<title>(?:${CF_TITLE_PHRASES})\\\\b`, \"i\");\nconst CF_BODY_MARKER = /cf-browser-verification|cdn-cgi\\/challenge-platform/;\n// Cloudflare serves challenge pages on 403 (block), 503 (\"Under Attack\"),\n// 429 (rate-gate), and occasionally 200 (Turnstile interstitial). The body /\n// header markers below still gate the decision; status alone is not enough.\nconst CF_CANDIDATE_STATUSES = new Set([200, 403, 429, 503]);\n\nexport function isCloudflareChallenge(res: HttpResponse): boolean {\n if (!CF_CANDIDATE_STATUSES.has(res.status)) return false;\n if (res.headers[\"cf-mitigated\"] === \"challenge\") return true;\n if (CF_TITLE_REGEX.test(res.body)) return true;\n if (CF_BODY_MARKER.test(res.body)) return true;\n return false;\n}\n","// src/http/browser/client.ts\nimport type { ZodType } from \"zod\";\nimport type { Url } from \"../../data-model/primitives.js\";\nimport { unsafeBrandUrl } from \"../../data-model/primitives.js\";\nimport type { HttpClient, HttpRequestOptions, HttpResponse } from \"../types.js\";\nimport type {\n BrowserClient,\n BrowserPage,\n NavigateOptions,\n RuntimeContext,\n RuntimePage,\n RuntimeResponse,\n WaitForResponseJsonOpts,\n WaitForResponseTextOpts,\n} from \"./types.js\";\nimport type { BrowserPool } from \"./pool.js\";\nimport { safeClosePage } from \"./safe-close.js\";\nimport { ChallengeUnresolvedError, CancelledError } from \"../../core/errors.js\";\nimport { isCfCookie } from \"../cookie-jar.js\";\nimport { CF_TITLE_PHRASES } from \"../cf-challenge.js\";\n\ntype WaitOpts =\n | {\n readonly timeoutMs?: number;\n readonly signal?: AbortSignal;\n readonly parse: \"text\";\n readonly skipBuffer?: boolean;\n }\n | {\n readonly timeoutMs?: number;\n readonly signal?: AbortSignal;\n readonly parse: \"json\";\n readonly schema: ZodType<unknown>;\n readonly skipBuffer?: boolean;\n };\n\ninterface BufferedResponse {\n url: string;\n status: number;\n headers: Record<string, string>;\n raw: RuntimeResponse;\n}\n\n// Cap how many responses we retain between `navigate()` and `waitForResponse()`.\n// Each entry holds a strong ref to a Playwright Response (with its body buffer),\n// so an uncapped buffer leaks memory for the page's lifetime. 20 is ample for the\n// fast-path case (target XHR fired during goto/before listener attach).\nconst RESPONSE_BUFFER_LIMIT = 20;\n\nconst CHALLENGE_TITLE = new RegExp(`^(?:${CF_TITLE_PHRASES})`, \"i\");\n\nexport class BrowserHttpClient implements HttpClient {\n readonly #pool: BrowserPool;\n readonly #navTimeoutMs: number;\n\n constructor(opts: { pool: BrowserPool; navigationTimeoutMs?: number }) {\n this.#pool = opts.pool;\n this.#navTimeoutMs = opts.navigationTimeoutMs ?? 30_000;\n }\n\n async get(url: Url, opts?: HttpRequestOptions): Promise<HttpResponse> {\n const handle = await this.#pool.acquireContext();\n try {\n const page = await handle.context.newPage();\n try {\n const response = await page.goto(String(url), {\n timeout: this.#navTimeoutMs,\n waitUntil: \"domcontentloaded\",\n ...(opts?.signal ? { signal: opts.signal } : {}),\n });\n const title = await page.title();\n if (CHALLENGE_TITLE.test(title)) {\n throw new ChallengeUnresolvedError(url, \"manual-solve\");\n }\n const body = await page.content();\n const status = response?.status() ?? 0;\n const headers = response?.headers() ?? {};\n return { status, headers, body, url };\n } finally {\n await safeClosePage(page);\n }\n } catch (err) {\n if (opts?.signal?.aborted) {\n throw new CancelledError({ cause: err ?? opts.signal.reason });\n }\n throw err;\n } finally {\n await handle.release();\n }\n }\n}\n\nexport class BrowserClientImpl implements BrowserClient {\n readonly #context: RuntimeContext;\n readonly #navTimeoutMs: number;\n\n constructor(opts: { context: RuntimeContext; navigationTimeoutMs?: number }) {\n this.#context = opts.context;\n this.#navTimeoutMs = opts.navigationTimeoutMs ?? 30_000;\n }\n\n async navigate(\n url: Url,\n signal: AbortSignal,\n opts: NavigateOptions = {},\n ): Promise<BrowserPage> {\n const page: RuntimePage = await this.#context.newPage();\n const buffer: BufferedResponse[] = [];\n const onResponse = (r: RuntimeResponse): void => {\n buffer.push({ url: r.url(), status: r.status(), headers: r.headers(), raw: r });\n if (buffer.length > RESPONSE_BUFFER_LIMIT) buffer.shift();\n };\n page.on(\"response\", onResponse);\n\n if (opts.initScript !== undefined) {\n try {\n await page.addInitScript(opts.initScript);\n } catch (err) {\n page.off(\"response\", onResponse);\n await safeClosePage(page);\n throw err;\n }\n }\n\n let navError: unknown;\n try {\n await page.goto(String(url), {\n timeout: this.#navTimeoutMs,\n waitUntil: \"domcontentloaded\",\n ...(signal ? { signal } : {}),\n });\n } catch (err) {\n navError = err;\n }\n\n function waitForResponse(\n pattern: RegExp,\n waitOpts: WaitForResponseTextOpts,\n ): Promise<{ url: Url; status: number; body: string }>;\n function waitForResponse<T>(\n pattern: RegExp,\n waitOpts: WaitForResponseJsonOpts<T>,\n ): Promise<{ url: Url; status: number; body: T }>;\n async function waitForResponse(\n pattern: RegExp,\n waitOpts: WaitOpts,\n ): Promise<{ url: Url; status: number; body: unknown }> {\n if (navError !== undefined) throw navError;\n const timeoutMs = waitOpts.timeoutMs ?? 30_000;\n const innerSignal = waitOpts.signal;\n const validate = async (raw: RuntimeResponse): Promise<unknown> => {\n if (waitOpts.parse === \"text\") return raw.text();\n const json = await raw.json();\n return waitOpts.schema.parse(json);\n };\n\n const existing = waitOpts.skipBuffer\n ? undefined\n : buffer.find((r) => pattern.test(r.url));\n if (existing) {\n return {\n // Playwright Response.url() always returns an absolute URL\n url: unsafeBrandUrl(existing.url),\n status: existing.status,\n body: await validate(existing.raw),\n };\n }\n\n return new Promise<{ url: Url; status: number; body: unknown }>((resolve, reject) => {\n function listener(r: RuntimeResponse): void {\n if (!pattern.test(r.url())) return;\n cleanup();\n validate(r)\n .then((body) =>\n // Playwright Response.url() always returns an absolute URL\n resolve({ url: unsafeBrandUrl(r.url()), status: r.status(), body }),\n )\n .catch(reject);\n }\n\n function onAbort(): void {\n cleanup();\n reject(new CancelledError({ cause: innerSignal?.reason ?? signal.reason }));\n }\n\n function cleanup(): void {\n clearTimeout(timer);\n page.off(\"response\", listener);\n innerSignal?.removeEventListener(\"abort\", onAbort);\n signal.removeEventListener(\"abort\", onAbort);\n }\n\n const timer = setTimeout(() => {\n cleanup();\n reject(new Error(`Timeout waiting for response matching ${pattern}`));\n }, timeoutMs);\n\n if (innerSignal?.aborted) { onAbort(); return; }\n if (signal.aborted) { onAbort(); return; }\n innerSignal?.addEventListener(\"abort\", onAbort, { once: true });\n signal.addEventListener(\"abort\", onAbort, { once: true });\n page.on(\"response\", listener);\n });\n }\n\n return {\n waitForResponse,\n\n async content(): Promise<string> {\n if (navError !== undefined) throw navError;\n return page.content();\n },\n\n async evaluate(script: string): Promise<unknown> {\n if (navError !== undefined) throw navError;\n return page.evaluate(script);\n },\n\n async close(): Promise<void> {\n page.off(\"response\", onResponse);\n await safeClosePage(page);\n },\n };\n }\n}\n\n/** Snapshot a context's CF cookies for jar replay. */\nexport async function captureCfCookies(\n context: RuntimeContext,\n origin: string,\n): Promise<{ cookies: ReadonlyArray<{ name: string; value: string }>; ua: string | null }> {\n const all = await context.cookies([origin]);\n const cookies = all\n .filter((c) => isCfCookie(c.name))\n .map((c) => ({ name: c.name, value: c.value }));\n // UA is set per-context at newContext({userAgent}) time; the pool callsite\n // owns this. captureCfCookies returns ua: null and the orchestrator pins the UA elsewhere.\n return { cookies, ua: null };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -39,10 +39,12 @@ var ParseError = class extends DownloadError {
|
|
|
39
39
|
code = "PARSE_ERROR";
|
|
40
40
|
url;
|
|
41
41
|
snippet;
|
|
42
|
+
path;
|
|
42
43
|
constructor(message, options) {
|
|
43
44
|
super(message, options);
|
|
44
45
|
this.url = options?.url;
|
|
45
46
|
this.snippet = options?.snippet;
|
|
47
|
+
this.path = options?.path;
|
|
46
48
|
}
|
|
47
49
|
};
|
|
48
50
|
var ChapterFetchError = class extends DownloadError {
|
|
@@ -87,6 +89,25 @@ var ChallengeUnresolvedError = class extends DownloadError {
|
|
|
87
89
|
hint;
|
|
88
90
|
code = "CHALLENGE_UNRESOLVED";
|
|
89
91
|
};
|
|
92
|
+
function normalizeToKnownError(err) {
|
|
93
|
+
if (err instanceof AdapterNotFoundError) return err;
|
|
94
|
+
if (err instanceof HttpError) return err;
|
|
95
|
+
if (err instanceof RateLimitedError) return err;
|
|
96
|
+
if (err instanceof ParseError) return err;
|
|
97
|
+
if (err instanceof ChapterFetchError) return err;
|
|
98
|
+
if (err instanceof TimeoutError) return err;
|
|
99
|
+
if (err instanceof CancelledError) return err;
|
|
100
|
+
if (err instanceof BrowserModuleNotInstalledError) return err;
|
|
101
|
+
if (err instanceof ChallengeUnresolvedError) return err;
|
|
102
|
+
if (err instanceof DownloadError) return new ParseError(err.message, { cause: err });
|
|
103
|
+
return new ParseError(String(err), { cause: err });
|
|
104
|
+
}
|
|
105
|
+
function normalizeToEnvelopeError(err) {
|
|
106
|
+
if (err instanceof CancelledError) throw err;
|
|
107
|
+
const known = normalizeToKnownError(err);
|
|
108
|
+
if (known instanceof CancelledError) throw known;
|
|
109
|
+
return known;
|
|
110
|
+
}
|
|
90
111
|
|
|
91
112
|
export {
|
|
92
113
|
DownloadError,
|
|
@@ -98,6 +119,8 @@ export {
|
|
|
98
119
|
TimeoutError,
|
|
99
120
|
CancelledError,
|
|
100
121
|
BrowserModuleNotInstalledError,
|
|
101
|
-
ChallengeUnresolvedError
|
|
122
|
+
ChallengeUnresolvedError,
|
|
123
|
+
normalizeToKnownError,
|
|
124
|
+
normalizeToEnvelopeError
|
|
102
125
|
};
|
|
103
|
-
//# sourceMappingURL=chunk-
|
|
126
|
+
//# sourceMappingURL=chunk-V2JVYKS3.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/core/errors.ts"],"sourcesContent":["import type { Url } from \"../data-model/primitives.js\";\nimport type { ChapterRef } from \"../data-model/novel.js\";\n\n/**\n * Base class for every error this library raises or returns. Each subclass\n * carries a stable, machine-readable `code` (see {@link DownloadErrorCode}).\n * The result/event error channels are typed as {@link KnownDownloadError}, so\n * `switch (error.code)` narrows to the concrete subclass and exposes its typed\n * fields. Custom subclasses (open extension point) use `instanceof DownloadError`.\n */\nexport abstract class DownloadError extends Error {\n abstract readonly code: string;\n override readonly cause?: unknown;\n constructor(message: string, options?: { cause?: unknown }) {\n super(message);\n this.cause = options?.cause;\n this.name = this.constructor.name;\n }\n}\n\n/**\n * No registered adapter can handle the given URL (`code: \"ADAPTER_NOT_FOUND\"`).\n * `download()` returns this in its `{ status: \"error\" }` envelope;\n * `fetchMetadata()` throws it.\n */\nexport class AdapterNotFoundError extends DownloadError {\n readonly code = \"ADAPTER_NOT_FOUND\" as const;\n constructor(\n public readonly url: string,\n options?: { cause?: unknown },\n ) {\n super(`No adapter for URL: ${url}`, options);\n }\n}\n\n/** A non-retryable HTTP error response (`code: \"HTTP_ERROR\"`); carries `status` and `url`. */\nexport class HttpError extends DownloadError {\n readonly code = \"HTTP_ERROR\" as const;\n constructor(\n public readonly status: number,\n public readonly url: Url,\n message?: string,\n options?: { cause?: unknown },\n ) {\n super(message ?? `HTTP ${status} for ${url}`, options);\n }\n}\n\n/** The host signalled rate limiting, e.g. HTTP 429 (`code: \"RATE_LIMITED\"`); `retryAfterMs` if known. */\nexport class RateLimitedError extends DownloadError {\n readonly code = \"RATE_LIMITED\" as const;\n constructor(\n public readonly url: Url,\n public readonly retryAfterMs?: number,\n options?: { cause?: unknown },\n ) {\n super(`Rate limited at ${url}`, options);\n }\n}\n\n/**\n * Malformed input or an unparseable/invalid response (`code: \"PARSE_ERROR\"`) —\n * e.g. a bad URL, an out-of-range `chapterRange` bound, or adapter output that\n * fails schema validation. Carries optional `url` and `snippet` for debugging.\n */\nexport class ParseError extends DownloadError {\n readonly code = \"PARSE_ERROR\" as const;\n readonly url: Url | undefined;\n readonly snippet: string | undefined;\n readonly path: string | undefined;\n constructor(message: string, options?: { cause?: unknown; url?: Url; snippet?: string; path?: string }) {\n super(message, options);\n this.url = options?.url;\n this.snippet = options?.snippet;\n this.path = options?.path;\n }\n}\n\n/**\n * A single chapter could not be fetched (`code: \"CHAPTER_FETCH_FAILED\"`);\n * carries the failing `ref`. Surfaces in {@link DownloadPartial}'s `failures`.\n */\nexport class ChapterFetchError extends DownloadError {\n readonly code = \"CHAPTER_FETCH_FAILED\" as const;\n constructor(\n public readonly ref: ChapterRef,\n options?: { cause?: unknown },\n ) {\n super(`Chapter ${ref.index} failed: ${ref.url}`, options);\n }\n}\n\n/** A request exceeded its timeout (`code: \"TIMEOUT\"`). */\nexport class TimeoutError extends DownloadError {\n readonly code = \"TIMEOUT\" as const;\n constructor(\n public readonly url: Url,\n options?: { cause?: unknown },\n ) {\n super(`Timeout for ${url}`, options);\n }\n}\n\n/**\n * The operation was aborted via an `AbortSignal` (`code: \"CANCELLED\"`).\n * `download()` **throws** this rather than returning an error envelope.\n */\nexport class CancelledError extends DownloadError {\n readonly code = \"CANCELLED\" as const;\n constructor(options?: { cause?: unknown }) {\n super(\"Cancelled\", options);\n }\n}\n\n/**\n * A browser-tier request was required but neither `patchright` nor `playwright`\n * is installed (`code: \"BROWSER_MODULE_NOT_INSTALLED\"`). The message lists the\n * install commands and the `http-only` opt-out.\n */\nexport class BrowserModuleNotInstalledError extends DownloadError {\n readonly code = \"BROWSER_MODULE_NOT_INSTALLED\" as const;\n constructor(options?: { cause?: unknown }) {\n super(\n \"No headless browser module installed. Install one of:\\n\" +\n \" pnpm add patchright (recommended for Cloudflare-fronted sites)\\n\" +\n \" pnpm add playwright (works for non-protected pages)\\n\" +\n 'Or pass transport: \"http-only\" to disable the browser tier.',\n options,\n );\n }\n}\n\n/**\n * Suggested remedy on a {@link ChallengeUnresolvedError}:\n * `\"manual-solve\"` (launch a headed browser and solve once) or\n * `\"transport-config\"` (raise the navigation timeout / use a stronger transport).\n */\nexport type ChallengeUnresolvedHint = \"manual-solve\" | \"transport-config\";\n\n/**\n * A Cloudflare challenge could not be cleared within the navigation timeout\n * (`code: \"CHALLENGE_UNRESOLVED\"`). `hint` indicates how to recover; the message\n * spells out the concrete fix.\n */\nexport class ChallengeUnresolvedError extends DownloadError {\n readonly code = \"CHALLENGE_UNRESOLVED\" as const;\n constructor(\n public readonly url: Url,\n public readonly hint: ChallengeUnresolvedHint,\n options?: { cause?: unknown },\n ) {\n const tail =\n hint === \"manual-solve\"\n ? 'Try transport: { mode: \"auto\", browserOptions: { headed: true } } and solve the checkbox in the launched window once.'\n : \"Increase transport.browserOptions.navigationTimeoutMs or switch to a stronger transport (e.g. a Browserless/ZenRows custom HttpClient).\";\n super(`Cloudflare challenge could not be resolved within the navigation timeout for ${url}. ${tail}`, options);\n }\n}\n\n/** Stable, machine-readable code for every built-in {@link DownloadError}. */\nexport type DownloadErrorCode = KnownDownloadError[\"code\"];\n\n/**\n * Discriminated union of every built-in error. The result/event error channels\n * use this so `switch (error.code)` narrows to the concrete class (e.g. reaching\n * {@link HttpError.status}). A custom-adapter error that is not one of these is\n * normalized to {@link ParseError} in the returned envelope (its original is on\n * `.cause`); use `instanceof DownloadError` as the catch-all.\n */\nexport type KnownDownloadError =\n | AdapterNotFoundError\n | HttpError\n | RateLimitedError\n | ParseError\n | ChapterFetchError\n | TimeoutError\n | CancelledError\n | BrowserModuleNotInstalledError\n | ChallengeUnresolvedError;\n\n/**\n * Coerce any thrown value into a {@link KnownDownloadError} without a cast.\n * Built-in errors pass through with full type; everything else (including an\n * exotic custom `DownloadError` subclass) is wrapped in a {@link ParseError}\n * with the original preserved on `cause`.\n */\nexport function normalizeToKnownError(err: unknown): KnownDownloadError {\n if (err instanceof AdapterNotFoundError) return err;\n if (err instanceof HttpError) return err;\n if (err instanceof RateLimitedError) return err;\n if (err instanceof ParseError) return err;\n if (err instanceof ChapterFetchError) return err;\n if (err instanceof TimeoutError) return err;\n if (err instanceof CancelledError) return err;\n if (err instanceof BrowserModuleNotInstalledError) return err;\n if (err instanceof ChallengeUnresolvedError) return err;\n if (err instanceof DownloadError) return new ParseError(err.message, { cause: err });\n return new ParseError(String(err), { cause: err });\n}\n\n/**\n * Like {@link normalizeToKnownError} but re-throws {@link CancelledError}\n * instead of returning it. Use at `download()` return sites where `CancelledError`\n * is always thrown, never placed in the error envelope.\n */\nexport function normalizeToEnvelopeError(err: unknown): Exclude<KnownDownloadError, CancelledError> {\n if (err instanceof CancelledError) throw err;\n const known = normalizeToKnownError(err);\n if (known instanceof CancelledError) throw known;\n return known;\n}\n"],"mappings":";AAUO,IAAe,gBAAf,cAAqC,MAAM;AAAA,EAE9B;AAAA,EAClB,YAAY,SAAiB,SAA+B;AAC1D,UAAM,OAAO;AACb,SAAK,QAAQ,SAAS;AACtB,SAAK,OAAO,KAAK,YAAY;AAAA,EAC/B;AACF;AAOO,IAAM,uBAAN,cAAmC,cAAc;AAAA,EAEtD,YACkB,KAChB,SACA;AACA,UAAM,uBAAuB,GAAG,IAAI,OAAO;AAH3B;AAAA,EAIlB;AAAA,EAJkB;AAAA,EAFT,OAAO;AAOlB;AAGO,IAAM,YAAN,cAAwB,cAAc;AAAA,EAE3C,YACkB,QACA,KAChB,SACA,SACA;AACA,UAAM,WAAW,QAAQ,MAAM,QAAQ,GAAG,IAAI,OAAO;AALrC;AACA;AAAA,EAKlB;AAAA,EANkB;AAAA,EACA;AAAA,EAHT,OAAO;AASlB;AAGO,IAAM,mBAAN,cAA+B,cAAc;AAAA,EAElD,YACkB,KACA,cAChB,SACA;AACA,UAAM,mBAAmB,GAAG,IAAI,OAAO;AAJvB;AACA;AAAA,EAIlB;AAAA,EALkB;AAAA,EACA;AAAA,EAHT,OAAO;AAQlB;AAOO,IAAM,aAAN,cAAyB,cAAc;AAAA,EACnC,OAAO;AAAA,EACP;AAAA,EACA;AAAA,EACA;AAAA,EACT,YAAY,SAAiB,SAA2E;AACtG,UAAM,SAAS,OAAO;AACtB,SAAK,MAAM,SAAS;AACpB,SAAK,UAAU,SAAS;AACxB,SAAK,OAAO,SAAS;AAAA,EACvB;AACF;AAMO,IAAM,oBAAN,cAAgC,cAAc;AAAA,EAEnD,YACkB,KAChB,SACA;AACA,UAAM,WAAW,IAAI,KAAK,YAAY,IAAI,GAAG,IAAI,OAAO;AAHxC;AAAA,EAIlB;AAAA,EAJkB;AAAA,EAFT,OAAO;AAOlB;AAGO,IAAM,eAAN,cAA2B,cAAc;AAAA,EAE9C,YACkB,KAChB,SACA;AACA,UAAM,eAAe,GAAG,IAAI,OAAO;AAHnB;AAAA,EAIlB;AAAA,EAJkB;AAAA,EAFT,OAAO;AAOlB;AAMO,IAAM,iBAAN,cAA6B,cAAc;AAAA,EACvC,OAAO;AAAA,EAChB,YAAY,SAA+B;AACzC,UAAM,aAAa,OAAO;AAAA,EAC5B;AACF;AAOO,IAAM,iCAAN,cAA6C,cAAc;AAAA,EACvD,OAAO;AAAA,EAChB,YAAY,SAA+B;AACzC;AAAA,MACE;AAAA,MAIA;AAAA,IACF;AAAA,EACF;AACF;AAcO,IAAM,2BAAN,cAAuC,cAAc;AAAA,EAE1D,YACkB,KACA,MAChB,SACA;AACA,UAAM,OACJ,SAAS,iBACL,0HACA;AACN,UAAM,gFAAgF,GAAG,KAAK,IAAI,IAAI,OAAO;AAR7F;AACA;AAAA,EAQlB;AAAA,EATkB;AAAA,EACA;AAAA,EAHT,OAAO;AAYlB;AA6BO,SAAS,sBAAsB,KAAkC;AACtE,MAAI,eAAe,qBAAsB,QAAO;AAChD,MAAI,eAAe,UAAW,QAAO;AACrC,MAAI,eAAe,iBAAkB,QAAO;AAC5C,MAAI,eAAe,WAAY,QAAO;AACtC,MAAI,eAAe,kBAAmB,QAAO;AAC7C,MAAI,eAAe,aAAc,QAAO;AACxC,MAAI,eAAe,eAAgB,QAAO;AAC1C,MAAI,eAAe,+BAAgC,QAAO;AAC1D,MAAI,eAAe,yBAA0B,QAAO;AACpD,MAAI,eAAe,cAAe,QAAO,IAAI,WAAW,IAAI,SAAS,EAAE,OAAO,IAAI,CAAC;AACnF,SAAO,IAAI,WAAW,OAAO,GAAG,GAAG,EAAE,OAAO,IAAI,CAAC;AACnD;AAOO,SAAS,yBAAyB,KAA2D;AAClG,MAAI,eAAe,eAAgB,OAAM;AACzC,QAAM,QAAQ,sBAAsB,GAAG;AACvC,MAAI,iBAAiB,eAAgB,OAAM;AAC3C,SAAO;AACT;","names":[]}
|
|
@@ -2,11 +2,11 @@ import {
|
|
|
2
2
|
BrowserClientImpl,
|
|
3
3
|
BrowserHttpClient,
|
|
4
4
|
captureCfCookies
|
|
5
|
-
} from "./chunk-
|
|
6
|
-
import "./chunk-
|
|
5
|
+
} from "./chunk-DFJ7E7IG.js";
|
|
6
|
+
import "./chunk-V2JVYKS3.js";
|
|
7
7
|
export {
|
|
8
8
|
BrowserClientImpl,
|
|
9
9
|
BrowserHttpClient,
|
|
10
10
|
captureCfCookies
|
|
11
11
|
};
|
|
12
|
-
//# sourceMappingURL=client-
|
|
12
|
+
//# sourceMappingURL=client-UKPAYL5D.js.map
|
|
@@ -8,8 +8,10 @@ import {
|
|
|
8
8
|
HttpError,
|
|
9
9
|
ParseError,
|
|
10
10
|
RateLimitedError,
|
|
11
|
-
TimeoutError
|
|
12
|
-
|
|
11
|
+
TimeoutError,
|
|
12
|
+
normalizeToEnvelopeError,
|
|
13
|
+
normalizeToKnownError
|
|
14
|
+
} from "./chunk-V2JVYKS3.js";
|
|
13
15
|
export {
|
|
14
16
|
AdapterNotFoundError,
|
|
15
17
|
BrowserModuleNotInstalledError,
|
|
@@ -20,6 +22,8 @@ export {
|
|
|
20
22
|
HttpError,
|
|
21
23
|
ParseError,
|
|
22
24
|
RateLimitedError,
|
|
23
|
-
TimeoutError
|
|
25
|
+
TimeoutError,
|
|
26
|
+
normalizeToEnvelopeError,
|
|
27
|
+
normalizeToKnownError
|
|
24
28
|
};
|
|
25
|
-
//# sourceMappingURL=errors-
|
|
29
|
+
//# sourceMappingURL=errors-GRDU3PLX.js.map
|