sfiledl 2.2.4 → 2.2.6

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/build/lib.cjs CHANGED
@@ -1,970 +1,3 @@
1
- 'use strict';
2
-
3
- Object.defineProperty(exports, '__esModule', { value: true });
4
-
5
- const path = require('path');
6
- const fs$1 = require('fs');
7
- const crypto = require('crypto');
8
- const playwright = require('playwright');
9
- const fs = require('fs/promises');
10
- const os = require('os');
11
-
12
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
13
-
14
- function _interopNamespace(e) {
15
- if (e && e.__esModule) return e;
16
- const n = Object.create(null);
17
- if (e) {
18
- for (const k in e) {
19
- if (k !== 'default') {
20
- const d = Object.getOwnPropertyDescriptor(e, k);
21
- Object.defineProperty(n, k, d.get ? d : {
22
- enumerable: true,
23
- get: function () { return e[k]; }
24
- });
25
- }
26
- }
27
- }
28
- n.default = e;
29
- return n;
30
- }
31
-
32
- const path__namespace = /*#__PURE__*/_interopNamespace(path);
33
- const fs__namespace = /*#__PURE__*/_interopNamespace(fs);
34
- const os__default = /*#__PURE__*/_interopDefault(os);
35
-
36
- class AppError extends Error {
37
- timestamp;
38
- context;
39
- code;
40
- retryable;
41
- constructor(message, code, retryable = false, context) {
42
- super(message);
43
- this.name = this.constructor.name;
44
- this.code = code;
45
- this.retryable = retryable;
46
- this.timestamp = new Date().toISOString();
47
- this.context = context ? Object.freeze({ ...context }) : Object.freeze({});
48
- if (Error.captureStackTrace) {
49
- Error.captureStackTrace(this, this.constructor);
50
- }
51
- Object.freeze(this);
52
- }
53
- toJSON() {
54
- return {
55
- name: this.name,
56
- code: this.code,
57
- message: this.message,
58
- retryable: this.retryable,
59
- timestamp: this.timestamp,
60
- context: this.context,
61
- stack: process.env['NODE_ENV'] === 'development' ? this.stack : undefined,
62
- };
63
- }
64
- toString() {
65
- return `${this.name} [${this.code}]: ${this.message}`;
66
- }
67
- isCode(code) {
68
- return this.code === code;
69
- }
70
- isRetryable() {
71
- return this.retryable;
72
- }
73
- }
74
-
75
- class ValidationError extends AppError {
76
- constructor(message, context) {
77
- super(message, 'VALIDATION_ERROR', false, context);
78
- Object.freeze(this);
79
- }
80
- }
81
- class NetworkError extends AppError {
82
- constructor(message, context) {
83
- super(message, 'NETWORK_ERROR', true, context);
84
- Object.freeze(this);
85
- }
86
- }
87
- class FileError extends AppError {
88
- constructor(message, context) {
89
- super(message, 'FILE_ERROR', false, context);
90
- Object.freeze(this);
91
- }
92
- }
93
- class BrowserError extends AppError {
94
- constructor(message, context) {
95
- super(message, 'BROWSER_ERROR', true, context);
96
- Object.freeze(this);
97
- }
98
- }
99
- function isAppError(err) {
100
- return err instanceof AppError;
101
- }
102
- function isRetryableError(err) {
103
- return isAppError(err) && err.retryable;
104
- }
105
- function isErrorWithCode(err, code) {
106
- return isAppError(err) && err.code === code;
107
- }
108
-
109
- const DEFAULTS = {
110
- userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
111
- headless: true,
112
- timeout: 60000,
113
- downloadButtonTimeout: 30000,
114
- fallbackWaitMs: 3000,
115
- retries: 3,
116
- retryDelay: 1000,
117
- maxRetryDelay: 30000,
118
- saveDebugArtifacts: true,
119
- maxFilenameLength: 255,
120
- sanitizeReplacement: '_',
121
- };
122
-
123
- class SfilePageInteractions {
124
- page;
125
- logger;
126
- constructor(page, logger) {
127
- this.page = page;
128
- this.logger = logger;
129
- }
130
- async waitForDownloadButton(timeout) {
131
- this.logger.debug('Waiting for #download button', { timeout });
132
- const button = this.page.locator('#download');
133
- await button.waitFor({ state: 'visible', timeout });
134
- this.logger.debug('Button is visible, checking if active');
135
- await this.page.waitForFunction(() => {
136
- const btn = document.querySelector('#download');
137
- if (!btn)
138
- return false;
139
- const href = btn.getAttribute('href');
140
- const style = window.getComputedStyle(btn);
141
- const isDisabled = btn.hasAttribute('disabled') ||
142
- btn.getAttribute('aria-disabled') === 'true' ||
143
- btn.classList.contains('disabled');
144
- return !!(href &&
145
- href !== '#' &&
146
- href.trim() !== '' &&
147
- style.pointerEvents !== 'none' &&
148
- !isDisabled);
149
- }, { timeout });
150
- this.logger.debug('Download button is active and ready');
151
- }
152
- async extractIntermediateUrl() {
153
- this.logger.debug('Extracting href from #download button');
154
- try {
155
- const href = await this.page.$eval('#download', (el) => {
156
- const anchor = el;
157
- return anchor.href;
158
- });
159
- if (!href || href === '#' || href.trim() === '') {
160
- throw new NetworkError('Download button href is empty or invalid', { href });
161
- }
162
- return href;
163
- }
164
- catch (err) {
165
- if (err instanceof Error && err.message?.includes('Element not found')) {
166
- throw new NetworkError('Download button (#download) not found in page', {
167
- selector: '#download',
168
- originalError: err.message,
169
- });
170
- }
171
- throw err;
172
- }
173
- }
174
- }
175
-
176
- function sanitizeFilename(name, replacement = '_') {
177
- const safeName = name.replace(/\.\.[\\/]/g, '');
178
- const sanitized = safeName
179
- .replace(/[<>:"/\\|?*\x00-\x1F]/g, replacement)
180
- .replace(new RegExp(`${replacement}+`, 'g'), replacement)
181
- .trim();
182
- const maxLength = 255;
183
- const trimmed = sanitized.slice(0, maxLength);
184
- return trimmed || `file${replacement}bin`;
185
- }
186
- const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
187
- function safeStringify(value, indent = 0) {
188
- try {
189
- const seen = new WeakSet();
190
- return JSON.stringify(value, (_key, val) => {
191
- if (typeof val === 'object' && val !== null) {
192
- if (seen.has(val))
193
- return '[Circular]';
194
- seen.add(val);
195
- }
196
- if (typeof val === 'bigint')
197
- return val.toString() + 'n';
198
- if (val instanceof Error) {
199
- return { name: val.name, message: val.message, stack: val.stack };
200
- }
201
- return val;
202
- }, indent);
203
- }
204
- catch {
205
- return '[unserializable]';
206
- }
207
- }
208
- function extractFilenameFromContentDisposition(header) {
209
- if (!header)
210
- return null;
211
- const encodedMatch = header.match(/filename\*=UTF-8''([^;\n"]+)/i);
212
- if (encodedMatch?.[1]) {
213
- try {
214
- return decodeURIComponent(encodedMatch[1]);
215
- }
216
- catch { }
217
- }
218
- const quotedMatch = header.match(/filename\s*=\s*"([^"]+)"/i);
219
- if (quotedMatch?.[1])
220
- return quotedMatch[1];
221
- const plainMatch = header.match(/filename\s*=\s*([^;,\n"]+)/i);
222
- if (plainMatch?.[1])
223
- return plainMatch[1].trim();
224
- return null;
225
- }
226
- function calculateRetryDelay(attempt, baseDelayMs, maxDelayMs = 30000) {
227
- const exponential = baseDelayMs * Math.pow(2, attempt - 1);
228
- const jitter = Math.random() * 0.3 * exponential;
229
- return Math.min(exponential + jitter, maxDelayMs);
230
- }
231
- function isError(value) {
232
- return (value instanceof Error ||
233
- (typeof value === 'object' && value !== null && 'message' in value));
234
- }
235
-
236
- class BrowserManager {
237
- logger;
238
- opts;
239
- browser = null;
240
- context = null;
241
- page = null;
242
- interactions = null;
243
- debugDir = null;
244
- stageHistory = [];
245
- constructor(logger, opts) {
246
- this.logger = logger;
247
- this.opts = opts;
248
- }
249
- trackStage(stage) {
250
- this.stageHistory.push({ stage, ts: Date.now() });
251
- }
252
- async launch() {
253
- const stage = 'launch';
254
- this.trackStage(stage);
255
- try {
256
- this.logger.info('Launching browser', { headless: this.opts.headless });
257
- this.browser = await playwright.chromium.launch({
258
- headless: this.opts.headless,
259
- args: [
260
- '--no-sandbox',
261
- '--disable-setuid-sandbox',
262
- '--disable-dev-shm-usage',
263
- '--disable-accelerated-2d-canvas',
264
- '--no-first-run',
265
- '--no-zygote',
266
- ],
267
- });
268
- this.context = await this.browser.newContext({
269
- userAgent: this.opts.userAgent,
270
- acceptDownloads: true,
271
- locale: 'en-US',
272
- timezoneId: 'UTC',
273
- viewport: { width: 1280, height: 720 },
274
- });
275
- await this.context.addCookies([
276
- {
277
- name: 'safe_link_counter',
278
- value: '1',
279
- domain: '.sfile.co',
280
- path: '/',
281
- expires: Math.floor(Date.now() / 1000) + 3600,
282
- },
283
- ]);
284
- this.page = await this.context.newPage();
285
- this.interactions = new SfilePageInteractions(this.page, this.logger);
286
- if (this.opts.debug) {
287
- this.setupDebugListeners();
288
- }
289
- this.logger.info('Browser ready');
290
- }
291
- catch (err) {
292
- await this.handleStageError(stage, err);
293
- throw new BrowserError(`Failed to launch browser: ${err.message}`, {
294
- stage,
295
- originalError: err.message,
296
- userAgent: this.opts.userAgent,
297
- });
298
- }
299
- }
300
- setupDebugListeners() {
301
- if (!this.page)
302
- return;
303
- this.page.on('console', (msg) => {
304
- const type = msg.type();
305
- const text = msg.text();
306
- if (type === 'error') {
307
- this.logger.error(`[console] ${text}`, { location: msg.location() });
308
- }
309
- else if (type === 'warning') {
310
- this.logger.warn(`[console] ${text}`);
311
- }
312
- else if (type === 'debug') {
313
- this.logger.debug(`[console] ${text}`);
314
- }
315
- });
316
- this.page.on('pageerror', (err) => {
317
- this.logger.error('[pageerror]', undefined, err);
318
- });
319
- this.page.on('requestfailed', (req) => {
320
- const failure = req.failure();
321
- this.logger.warn('[requestfailed]', {
322
- url: req.url(),
323
- method: req.method(),
324
- error: failure?.errorText,
325
- });
326
- });
327
- }
328
- async goto(url, waitUntil = 'networkidle') {
329
- const stage = 'navigation';
330
- this.trackStage(stage);
331
- if (!this.page) {
332
- throw new BrowserError('Page not initialized', { stage });
333
- }
334
- try {
335
- this.logger.debug(`Navigating to ${url}`, { waitUntil, timeout: this.opts.timeout });
336
- await this.page.goto(url, { waitUntil, timeout: this.opts.timeout });
337
- }
338
- catch (err) {
339
- await this.handleStageError(stage, err);
340
- throw new NetworkError(`Navigation failed: ${err.message}`, {
341
- url,
342
- stage,
343
- waitUntil,
344
- timeout: this.opts.timeout,
345
- originalError: err.message,
346
- });
347
- }
348
- }
349
- async waitForDownloadButton() {
350
- const stage = 'waitForButton';
351
- this.trackStage(stage);
352
- if (!this.interactions) {
353
- throw new BrowserError('Interactions not ready', { stage });
354
- }
355
- const timeout = this.opts.downloadButtonTimeout ?? DEFAULTS.downloadButtonTimeout;
356
- try {
357
- await this.interactions.waitForDownloadButton(timeout);
358
- }
359
- catch (err) {
360
- await this.handleStageError(stage, err);
361
- throw new NetworkError(`Failed to wait for download button: ${err.message}`, {
362
- stage,
363
- timeout,
364
- originalError: err.message,
365
- });
366
- }
367
- }
368
- async getIntermediateUrl() {
369
- const stage = 'extractUrl';
370
- this.trackStage(stage);
371
- if (!this.interactions) {
372
- throw new BrowserError('Interactions not ready', { stage });
373
- }
374
- try {
375
- const url = await this.interactions.extractIntermediateUrl();
376
- this.logger.debug('Intermediate URL extracted', { url });
377
- return url;
378
- }
379
- catch (err) {
380
- await this.handleStageError(stage, err);
381
- throw new NetworkError(`Failed to extract intermediate URL: ${err.message}`, {
382
- stage,
383
- originalError: err.message,
384
- });
385
- }
386
- }
387
- async startDownloadAndWait(autoUrl) {
388
- const stage = 'downloadWait';
389
- this.trackStage(stage);
390
- if (!this.page) {
391
- throw new BrowserError('Page not initialized', { stage });
392
- }
393
- const downloadPromise = this.page
394
- .waitForEvent('download', { timeout: this.opts.timeout })
395
- .catch((err) => {
396
- this.logger.debug('Download event timeout', {
397
- timeout: this.opts.timeout,
398
- error: err.message,
399
- });
400
- return null;
401
- });
402
- this.logger.debug('Navigating to auto download URL', { url: autoUrl });
403
- await this.page
404
- .goto(autoUrl, { waitUntil: 'commit', timeout: this.opts.timeout })
405
- .catch((err) => {
406
- this.logger.warn('Navigation to auto URL failed, continuing anyway', {
407
- error: err.message,
408
- });
409
- });
410
- const download = await downloadPromise;
411
- if (download) {
412
- this.logger.info('Download event captured');
413
- return download;
414
- }
415
- this.logger.debug('No download event captured within timeout');
416
- return null;
417
- }
418
- async fallbackCollectFileResponse() {
419
- const stage = 'fallbackIntercept';
420
- this.trackStage(stage);
421
- if (!this.page) {
422
- throw new BrowserError('Page not initialized', { stage });
423
- }
424
- this.logger.info('Falling back to response interception');
425
- const responses = [];
426
- const handler = (res) => responses.push(res);
427
- this.page.on('response', handler);
428
- await sleep(DEFAULTS.fallbackWaitMs);
429
- this.page.off('response', handler);
430
- const fileResponse = [...responses].reverse().find((r) => {
431
- const headers = r.headers();
432
- const disposition = headers['content-disposition'];
433
- const contentType = headers['content-type'];
434
- const url = r.url();
435
- return ((disposition && disposition.includes('attachment')) ||
436
- url.includes('/downloadfile/') ||
437
- (contentType &&
438
- !contentType.startsWith('text/html') &&
439
- !contentType.startsWith('application/json')));
440
- });
441
- if (!fileResponse) {
442
- this.logger.debug('No suitable file response found in fallback', {
443
- responseCount: responses.length,
444
- sampleUrls: responses.slice(0, 3).map((r) => r.url()),
445
- });
446
- return null;
447
- }
448
- try {
449
- const buffer = await fileResponse.body();
450
- let filename = extractFilenameFromContentDisposition(fileResponse.headers()['content-disposition']);
451
- if (!filename) {
452
- const urlParts = fileResponse.url().split('/');
453
- filename = urlParts[urlParts.length - 1]?.split('?')[0] || 'file.bin';
454
- }
455
- filename = filename.replace(/[<>:"/\\|?*]/g, '_');
456
- this.logger.info('Fallback response captured', {
457
- filename,
458
- size: buffer.length,
459
- contentType: fileResponse.headers()['content-type'],
460
- });
461
- return { buffer, filename };
462
- }
463
- catch (err) {
464
- this.logger.error('Failed to read fallback response body', { error: err.message });
465
- return null;
466
- }
467
- }
468
- async saveDebugArtifacts(errorMessage) {
469
- if (!this.opts.debug || !this.page)
470
- return null;
471
- try {
472
- this.debugDir = path__namespace.default.join(os__default.default.tmpdir(), `sfile_debug_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`);
473
- await fs__namespace.mkdir(this.debugDir, { recursive: true });
474
- const tasks = [
475
- this.page
476
- .screenshot({
477
- path: path__namespace.default.join(this.debugDir, 'error.png'),
478
- fullPage: true,
479
- })
480
- .then(() => { }),
481
- fs__namespace.writeFile(path__namespace.default.join(this.debugDir, 'error.html'), await this.page.content()),
482
- fs__namespace.writeFile(path__namespace.default.join(this.debugDir, 'error.txt'), errorMessage),
483
- fs__namespace.writeFile(path__namespace.default.join(this.debugDir, 'stages.json'), JSON.stringify(this.stageHistory, null, 2)),
484
- ];
485
- await Promise.all(tasks);
486
- this.logger.info('Debug artifacts saved', { debugDir: this.debugDir });
487
- return this.debugDir;
488
- }
489
- catch (e) {
490
- this.logger.error('Failed to save debug artifacts', { error: e.message });
491
- return null;
492
- }
493
- }
494
- async handleStageError(stage, error) {
495
- if (this.opts.debug) {
496
- await this.saveDebugArtifacts(`Error at stage "${stage}": ${error?.message || 'Unknown error'}`);
497
- }
498
- }
499
- async close() {
500
- const closePromises = [
501
- this.page?.close().catch(() => { }),
502
- this.context?.close().catch(() => { }),
503
- this.browser?.close().catch(() => { }),
504
- ].filter(Boolean);
505
- await Promise.all(closePromises);
506
- this.logger.debug('Browser closed', { stages: this.stageHistory.length });
507
- }
508
- async getPage() {
509
- return this.page;
510
- }
511
- getDebugDir() {
512
- return this.debugDir;
513
- }
514
- getStageHistory() {
515
- return [...this.stageHistory];
516
- }
517
- }
518
-
519
- class Logger {
520
- minLevel;
521
- correlationId;
522
- fileStream = null;
523
- prefix;
524
- constructor(options = {}) {
525
- this.minLevel = options.debugMode ? 'debug' : 'info';
526
- this.correlationId = options.correlationId;
527
- this.prefix = options.prefix || '';
528
- if (options.logFile) {
529
- this.fileStream = fs$1.createWriteStream(options.logFile, { flags: 'a' });
530
- }
531
- }
532
- setCorrelationId(id) {
533
- this.correlationId = id;
534
- }
535
- setDebug(enabled) {
536
- this.minLevel = enabled ? 'debug' : 'info';
537
- }
538
- levelPriority(level) {
539
- return { debug: 0, info: 1, warn: 2, error: 3 }[level];
540
- }
541
- shouldLog(level) {
542
- return this.levelPriority(level) >= this.levelPriority(this.minLevel);
543
- }
544
- format(level, message, context) {
545
- const ts = new Date().toISOString();
546
- const corr = this.correlationId ? ` [${this.correlationId}]` : '';
547
- const prefix = this.prefix ? ` [${this.prefix}]` : '';
548
- const ctx = context ? ` | ${safeStringify(context)}` : '';
549
- return `[${ts}]${corr}${prefix} ${level.toUpperCase()}: ${message}${ctx}`;
550
- }
551
- write(level, message, context) {
552
- if (!this.shouldLog(level))
553
- return;
554
- const formatted = this.format(level, message, context);
555
- const consoleMethod = level === 'error' ? 'error' : level === 'warn' ? 'warn' : 'log';
556
- console[consoleMethod](formatted);
557
- if (this.fileStream?.writable) {
558
- this.fileStream.write(formatted + '\n');
559
- }
560
- }
561
- debug(msg, ctx) {
562
- this.write('debug', msg, ctx);
563
- }
564
- info(msg, ctx) {
565
- this.write('info', msg, ctx);
566
- }
567
- warn(msg, ctx) {
568
- this.write('warn', msg, ctx);
569
- }
570
- error(msg, ctx, err) {
571
- let errorCtx;
572
- if (err) {
573
- const baseObj = ctx && typeof ctx === 'object' && ctx !== null
574
- ? { ...ctx }
575
- : {};
576
- errorCtx = {
577
- ...baseObj,
578
- error: { name: err.name, message: err.message },
579
- };
580
- }
581
- else {
582
- errorCtx = ctx;
583
- }
584
- this.write('error', msg, errorCtx);
585
- }
586
- child(prefix) {
587
- const childOptions = {
588
- debugMode: this.minLevel === 'debug',
589
- ...(this.correlationId !== undefined && { correlationId: this.correlationId }),
590
- prefix: this.prefix ? `${this.prefix}:${prefix}` : prefix,
591
- };
592
- const child = new Logger(childOptions);
593
- if (this.fileStream) {
594
- child.fileStream = this.fileStream;
595
- }
596
- return child;
597
- }
598
- async close() {
599
- if (this.fileStream && !this.fileStream.closed) {
600
- return new Promise((resolve) => this.fileStream?.end(resolve));
601
- }
602
- }
603
- }
604
-
605
- function normalizeOptions(opts) {
606
- const base = {
607
- headless: opts?.headless ?? DEFAULTS.headless,
608
- userAgent: opts?.userAgent ?? DEFAULTS.userAgent,
609
- timeout: opts?.timeout ?? DEFAULTS.timeout,
610
- downloadButtonTimeout: opts?.downloadButtonTimeout ?? DEFAULTS.downloadButtonTimeout,
611
- retries: opts?.retries ?? DEFAULTS.retries,
612
- retryDelay: opts?.retryDelay ?? DEFAULTS.retryDelay,
613
- debug: opts?.debug ?? false,
614
- saveDebugArtifacts: opts?.saveDebugArtifacts ?? DEFAULTS.saveDebugArtifacts,
615
- };
616
- const optional = {
617
- ...(opts?.onProgress !== undefined && { onProgress: opts.onProgress }),
618
- ...(opts?.correlationId !== undefined && { correlationId: opts.correlationId }),
619
- ...(opts?._internal !== undefined && { _internal: opts._internal }),
620
- ...(opts?.logFile !== undefined && { logFile: opts.logFile }),
621
- };
622
- return { ...base, ...optional };
623
- }
624
-
625
- class InputValidator {
626
- static validateUrl(url, allowedDomains = ['sfile.co', 'sfile.mobi']) {
627
- if (!url || typeof url !== 'string') {
628
- throw new ValidationError('URL must be a non-empty string', {
629
- received: typeof url,
630
- url,
631
- });
632
- }
633
- const hasAllowedDomain = allowedDomains.some((domain) => url.includes(domain));
634
- if (!hasAllowedDomain) {
635
- throw new ValidationError(`URL must contain one of: ${allowedDomains.join(', ')}`, {
636
- url,
637
- allowedDomains,
638
- });
639
- }
640
- try {
641
- const parsed = new URL(url);
642
- if (!['http:', 'https:'].includes(parsed.protocol)) {
643
- throw new ValidationError('URL must use http or https protocol', {
644
- url,
645
- protocol: parsed.protocol,
646
- });
647
- }
648
- }
649
- catch (parseErr) {
650
- throw new ValidationError('Invalid URL format', {
651
- url,
652
- parseError: parseErr instanceof Error ? parseErr.message : String(parseErr),
653
- });
654
- }
655
- }
656
- static validateSaveDir(dir) {
657
- if (!dir || typeof dir !== 'string') {
658
- throw new ValidationError('Save directory must be a non-empty string', {
659
- received: typeof dir,
660
- dir,
661
- });
662
- }
663
- }
664
- static sanitizeFilename(name) {
665
- const replacement = DEFAULTS.sanitizeReplacement;
666
- const maxLength = DEFAULTS.maxFilenameLength;
667
- const sanitized = sanitizeFilename(name, replacement);
668
- if (!sanitized || sanitized.length === 0) {
669
- const ext = name.includes('.') ? name.split('.').pop() : 'bin';
670
- return `downloaded_file${ext ? '.' + ext : ''}`.slice(0, maxLength);
671
- }
672
- return sanitized.slice(0, maxLength);
673
- }
674
- static validateOptions(options) {
675
- if (options === undefined || options === null) {
676
- return;
677
- }
678
- if (typeof options !== 'object') {
679
- throw new ValidationError('Options must be an object or undefined', {
680
- received: typeof options,
681
- });
682
- }
683
- const opts = options;
684
- const numericFields = ['timeout', 'retries', 'retryDelay', 'downloadButtonTimeout'];
685
- for (const field of numericFields) {
686
- if (field in opts && opts[field] !== undefined && typeof opts[field] !== 'number') {
687
- throw new ValidationError(`Option '${field}' must be a number`, {
688
- field,
689
- received: typeof opts[field],
690
- value: opts[field],
691
- });
692
- }
693
- }
694
- const booleanFields = ['headless', 'debug', 'saveDebugArtifacts'];
695
- for (const field of booleanFields) {
696
- if (field in opts && opts[field] !== undefined && typeof opts[field] !== 'boolean') {
697
- throw new ValidationError(`Option '${field}' must be a boolean`, {
698
- field,
699
- received: typeof opts[field],
700
- value: opts[field],
701
- });
702
- }
703
- }
704
- const stringFields = ['correlationId', 'logFile', 'userAgent'];
705
- for (const field of stringFields) {
706
- if (field in opts && opts[field] !== undefined && typeof opts[field] !== 'string') {
707
- throw new ValidationError(`Option '${field}' must be a string`, {
708
- field,
709
- received: typeof opts[field],
710
- value: opts[field],
711
- });
712
- }
713
- }
714
- if ('onProgress' in opts &&
715
- opts['onProgress'] !== undefined &&
716
- typeof opts['onProgress'] !== 'function') {
717
- throw new ValidationError(`Option 'onProgress' must be a function`, {
718
- received: typeof opts['onProgress'],
719
- });
720
- }
721
- }
722
- }
723
-
724
- function stripUndefined(obj) {
725
- return Object.fromEntries(Object.entries(obj).filter(([, v]) => v !== undefined));
726
- }
727
- function safeProgress(onProgress, percent, total, meta) {
728
- if (typeof onProgress === 'function') {
729
- try {
730
- onProgress(percent, total, meta);
731
- }
732
- catch (err) {
733
- console.warn('Progress callback error:', err);
734
- }
735
- }
736
- }
737
- async function executeDownload(url, saveDir, opts, logger) {
738
- const startTime = Date.now();
739
- const browserMgr = new BrowserManager(logger.child('BrowserManager'), {
740
- headless: opts.headless,
741
- userAgent: opts.userAgent,
742
- timeout: opts.timeout,
743
- debug: opts.debug,
744
- downloadButtonTimeout: opts.downloadButtonTimeout,
745
- });
746
- let finalPath;
747
- let fileSize;
748
- let method;
749
- try {
750
- logger.info('Starting download workflow', { url });
751
- safeProgress(opts.onProgress, 10, 100, {
752
- stage: 'launch',
753
- message: 'Launching browser',
754
- attempt: 1,
755
- });
756
- await browserMgr.launch();
757
- await browserMgr.goto(url, 'networkidle');
758
- safeProgress(opts.onProgress, 30, 100, { stage: 'navigation', message: 'Page loaded' });
759
- await browserMgr.waitForDownloadButton();
760
- safeProgress(opts.onProgress, 50, 100, {
761
- stage: 'button',
762
- message: 'Download button ready',
763
- });
764
- const intermediateUrl = await browserMgr.getIntermediateUrl();
765
- const autoUrl = intermediateUrl.includes('?')
766
- ? `${intermediateUrl}&auto=1`
767
- : `${intermediateUrl}?auto=1`;
768
- logger.debug('Triggering download', { autoUrl });
769
- safeProgress(opts.onProgress, 70, 100, { stage: 'trigger', message: 'Download triggered' });
770
- let download = await browserMgr.startDownloadAndWait(autoUrl);
771
- if (download) {
772
- const suggested = download.suggestedFilename() || 'file.bin';
773
- const filename = InputValidator.sanitizeFilename(suggested);
774
- finalPath = path__namespace.join(saveDir, filename);
775
- await download.saveAs(finalPath);
776
- const stat = await fs$1.promises.stat(finalPath);
777
- fileSize = stat.size;
778
- method = 'direct';
779
- logger.info('Saved via direct download', { path: finalPath, size: fileSize });
780
- }
781
- else {
782
- logger.warn('Direct download not captured, trying fallback');
783
- const fallback = await browserMgr.fallbackCollectFileResponse();
784
- if (!fallback) {
785
- throw new NetworkError('No download event and no file response found', {
786
- url,
787
- intermediateUrl,
788
- autoUrl,
789
- stage: 'fallbackFailed',
790
- });
791
- }
792
- const { buffer, filename: rawName } = fallback;
793
- const filename = InputValidator.sanitizeFilename(rawName);
794
- finalPath = path__namespace.join(saveDir, filename);
795
- await fs$1.promises.writeFile(finalPath, buffer);
796
- fileSize = buffer.length;
797
- method = 'fallback';
798
- logger.info('Saved via fallback', { path: finalPath, size: fileSize });
799
- }
800
- safeProgress(opts.onProgress, 100, 100, { stage: 'complete', message: 'Download finished' });
801
- const result = {
802
- filePath: finalPath,
803
- size: fileSize,
804
- method,
805
- durationMs: Date.now() - startTime,
806
- attempts: 1,
807
- };
808
- if (opts.correlationId !== undefined) {
809
- result.correlationId = opts.correlationId;
810
- }
811
- return result;
812
- }
813
- catch (err) {
814
- const error = err instanceof Error ? err : new Error(String(err));
815
- const appError = error instanceof AppError
816
- ? error
817
- : new NetworkError(error.message, {
818
- url,
819
- saveDir,
820
- correlationId: opts.correlationId,
821
- originalError: error.message,
822
- errorName: error.name,
823
- });
824
- if (opts.saveDebugArtifacts) {
825
- const debugPath = await browserMgr.saveDebugArtifacts(appError.message);
826
- if (debugPath) {
827
- appError.debugPath = debugPath;
828
- if (appError.context && typeof appError.context === 'object') {
829
- appError.context.debugPath = debugPath;
830
- }
831
- }
832
- }
833
- throw appError;
834
- }
835
- finally {
836
- await browserMgr
837
- .close()
838
- .catch((e) => logger.error('Failed to close browser', { error: e.message }));
839
- await logger.close().catch((e) => console.error('Failed to close logger', e));
840
- }
841
- }
842
- async function downloadSfile(url, saveDir, options) {
843
- const opts = normalizeOptions(options);
844
- const correlationId = opts.correlationId || crypto.randomUUID();
845
- const loggerOptions = {
846
- debugMode: opts.debug,
847
- correlationId,
848
- prefix: 'downloadSfile',
849
- };
850
- if (opts.logFile !== undefined) {
851
- loggerOptions.logFile = opts.logFile;
852
- }
853
- const logger = new Logger(loggerOptions);
854
- InputValidator.validateUrl(url);
855
- InputValidator.validateSaveDir(saveDir);
856
- InputValidator.validateOptions(options);
857
- await fs$1.promises.mkdir(saveDir, { recursive: true });
858
- let lastError;
859
- let attempt = 0;
860
- while (attempt < opts.retries) {
861
- attempt++;
862
- try {
863
- logger.info(`Download attempt ${attempt}/${opts.retries}`, { url });
864
- const result = await executeDownload(url, saveDir, opts, logger);
865
- logger.info(`Download succeeded`, {
866
- duration: result.durationMs,
867
- attempts: attempt,
868
- method: result.method,
869
- });
870
- return {
871
- ...result,
872
- attempts: attempt,
873
- correlationId,
874
- };
875
- }
876
- catch (err) {
877
- lastError = err instanceof Error ? err : new Error(String(err));
878
- const isRetryable = lastError instanceof AppError && lastError.retryable;
879
- const isLastAttempt = attempt >= opts.retries;
880
- if (!isRetryable || isLastAttempt) {
881
- logger.error(`Download failed permanently`, {
882
- error: lastError.message,
883
- attempt,
884
- retryable: isRetryable,
885
- lastAttempt: isLastAttempt,
886
- });
887
- throw lastError;
888
- }
889
- const delay = calculateRetryDelay(attempt, opts.retryDelay, DEFAULTS.maxRetryDelay);
890
- logger.warn(`Retrying download`, {
891
- attempt,
892
- maxAttempts: opts.retries,
893
- delayMs: Math.round(delay),
894
- error: lastError.message,
895
- });
896
- safeProgress(opts.onProgress, 0, 100, {
897
- stage: 'retry',
898
- message: `Retry ${attempt}/${opts.retries}`,
899
- attempt,
900
- });
901
- await sleep(delay);
902
- }
903
- }
904
- throw lastError || new Error('Download failed after all retries');
905
- }
906
- async function downloadSfileSafe(url, saveDir, options) {
907
- try {
908
- const result = await downloadSfile(url, saveDir, options);
909
- return { success: true, value: result };
910
- }
911
- catch (error) {
912
- return { success: false, error: error };
913
- }
914
- }
915
- function createDownloader(defaultOptions) {
916
- const defaults = normalizeOptions(defaultOptions);
917
- return {
918
- async download(url, saveDir, callOptions) {
919
- const merged = stripUndefined({ ...defaults, ...callOptions });
920
- return downloadSfile(url, saveDir, merged);
921
- },
922
- async downloadSafe(url, saveDir, callOptions) {
923
- const merged = stripUndefined({ ...defaults, ...callOptions });
924
- return downloadSfileSafe(url, saveDir, merged);
925
- },
926
- withOptions(newDefaults) {
927
- const merged = stripUndefined({ ...defaults, ...newDefaults });
928
- return createDownloader(merged);
929
- },
930
- };
931
- }
932
-
933
- function isSuccess(result) {
934
- return result.success === true;
935
- }
936
- function isFailure(result) {
937
- return result.success === false;
938
- }
939
- function mapError(result, fn) {
940
- if (!result.success) {
941
- return { success: false, error: fn(result.error) };
942
- }
943
- return result;
944
- }
945
-
946
- exports.AppError = AppError;
947
- exports.BrowserError = BrowserError;
948
- exports.DEFAULTS = DEFAULTS;
949
- exports.FileError = FileError;
950
- exports.InputValidator = InputValidator;
951
- exports.Logger = Logger;
952
- exports.NetworkError = NetworkError;
953
- exports.ValidationError = ValidationError;
954
- exports.calculateRetryDelay = calculateRetryDelay;
955
- exports.createDownloader = createDownloader;
956
- exports.downloadSfile = downloadSfile;
957
- exports.downloadSfileSafe = downloadSfileSafe;
958
- exports.extractFilenameFromContentDisposition = extractFilenameFromContentDisposition;
959
- exports.isAppError = isAppError;
960
- exports.isErr = isFailure;
961
- exports.isError = isError;
962
- exports.isErrorWithCode = isErrorWithCode;
963
- exports.isOk = isSuccess;
964
- exports.isRetryableError = isRetryableError;
965
- exports.mapErr = mapError;
966
- exports.normalizeOptions = normalizeOptions;
967
- exports.safeStringify = safeStringify;
968
- exports.sanitizeFilename = sanitizeFilename;
969
- exports.sleep = sleep;
1
+ Object.defineProperty(exports,"__esModule",{value:!0});const e=require("path"),t=require("fs"),r=require("crypto"),o=require("playwright"),i=require("fs/promises"),s=require("os");function a(e){return e&&e.__esModule?e:{default:e}}function n(e){if(e&&e.__esModule)return e;const t=Object.create(null);if(e)for(const r in e)if("default"!==r){const o=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,o.get?o:{enumerable:!0,get:function(){return e[r]}})}return t.default=e,t}const l=n(e),c=n(i),u=a(s);class d extends Error{timestamp;context;code;retryable;constructor(e,t,r=!1,o){super(e),this.name=this.constructor.name,this.code=t,this.retryable=r,this.timestamp=(new Date).toISOString(),this.context=Object.freeze(o?{...o}:{}),Error.captureStackTrace&&Error.captureStackTrace(this,this.constructor),Object.freeze(this)}toJSON(){return{name:this.name,code:this.code,message:this.message,retryable:this.retryable,timestamp:this.timestamp,context:this.context,stack:"development"===process.env.NODE_ENV?this.stack:void 0}}toString(){return`${this.name} [${this.code}]: ${this.message}`}isCode(e){return this.code===e}isRetryable(){return this.retryable}}class g extends d{constructor(e,t){super(e,"VALIDATION_ERROR",!1,t),Object.freeze(this)}}class h extends d{constructor(e,t){super(e,"NETWORK_ERROR",!0,t),Object.freeze(this)}}class f extends d{constructor(e,t){super(e,"BROWSER_ERROR",!0,t),Object.freeze(this)}}function w(e){return e instanceof d}const p={userAgent:"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36",headless:!0,timeout:6e4,downloadButtonTimeout:3e4,fallbackWaitMs:3e3,retries:3,retryDelay:1e3,maxRetryDelay:3e4,saveDebugArtifacts:!0,maxFilenameLength:255,sanitizeReplacement:"_"};class m{page;logger;constructor(e,t){this.page=e,this.logger=t}async waitForDownloadButton(e){this.logger.debug("Waiting for #download button",{timeout:e});const t=this.page.locator("#download");await t.waitFor({state:"visible",timeout:e}),this.logger.debug("Button is visible, checking if active"),await this.page.waitForFunction(()=>{const e=document.querySelector("#download");if(!e)return!1;const t=e.getAttribute("href"),r=window.getComputedStyle(e),o=e.hasAttribute("disabled")||"true"===e.getAttribute("aria-disabled")||e.classList.contains("disabled");return!(!t||"#"===t||""===t.trim()||"none"===r.pointerEvents||o)},{timeout:e}),this.logger.debug("Download button is active and ready")}async extractIntermediateUrl(){this.logger.debug("Extracting href from #download button");try{const e=await this.page.$eval("#download",e=>e.href);if(!e||"#"===e||""===e.trim())throw new h("Download button href is empty or invalid",{href:e});return e}catch(e){if(e instanceof Error&&e.message?.includes("Element not found"))throw new h("Download button (#download) not found in page",{selector:"#download",originalError:e.message});throw e}}}function b(e,t="_"){return e.replace(/\.\.[\\/]/g,"").replace(/[<>:"/\\|?*\x00-\x1F]/g,t).replace(new RegExp(`${t}+`,"g"),t).trim().slice(0,255)||`file${t}bin`}const y=e=>new Promise(t=>setTimeout(t,e));function v(e,t=0){try{const r=new WeakSet;return JSON.stringify(e,(e,t)=>{if("object"==typeof t&&null!==t){if(r.has(t))return"[Circular]";r.add(t)}return"bigint"==typeof t?t.toString()+"n":t instanceof Error?{name:t.name,message:t.message,stack:t.stack}:t},t)}catch{return"[unserializable]"}}function x(e){if(!e)return null;const t=e.match(/filename\*=UTF-8''([^;\n"]+)/i);if(t?.[1])try{return decodeURIComponent(t[1])}catch{}const r=e.match(/filename\s*=\s*"([^"]+)"/i);if(r?.[1])return r[1];const o=e.match(/filename\s*=\s*([^;,\n"]+)/i);return o?.[1]?o[1].trim():null}function D(e,t,r=3e4){const o=t*Math.pow(2,e-1),i=.3*Math.random()*o;return Math.min(o+i,r)}class S{logger;opts;browser=null;context=null;page=null;interactions=null;debugDir=null;stageHistory=[];constructor(e,t){this.logger=e,this.opts=t}trackStage(e){this.stageHistory.push({stage:e,ts:Date.now()})}async launch(){const e="launch";this.trackStage(e);try{this.logger.info("Launching browser",{headless:this.opts.headless}),this.browser=await o.chromium.launch({headless:this.opts.headless,args:["--no-sandbox","--disable-setuid-sandbox","--disable-dev-shm-usage","--disable-accelerated-2d-canvas","--no-first-run","--no-zygote"]}),this.context=await this.browser.newContext({userAgent:this.opts.userAgent,acceptDownloads:!0,locale:"en-US",timezoneId:"UTC",viewport:{width:1280,height:720}}),await this.context.addCookies([{name:"safe_link_counter",value:"1",domain:".sfile.co",path:"/",expires:Math.floor(Date.now()/1e3)+3600}]),this.page=await this.context.newPage(),this.interactions=new m(this.page,this.logger),this.opts.debug&&this.setupDebugListeners(),this.logger.info("Browser ready")}catch(t){throw await this.handleStageError(e,t),new f(`Failed to launch browser: ${t.message}`,{stage:e,originalError:t.message,userAgent:this.opts.userAgent})}}setupDebugListeners(){this.page&&(this.page.on("console",e=>{const t=e.type(),r=e.text();"error"===t?this.logger.error(`[console] ${r}`,{location:e.location()}):"warning"===t?this.logger.warn(`[console] ${r}`):"debug"===t&&this.logger.debug(`[console] ${r}`)}),this.page.on("pageerror",e=>{this.logger.error("[pageerror]",void 0,e)}),this.page.on("requestfailed",e=>{const t=e.failure();this.logger.warn("[requestfailed]",{url:e.url(),method:e.method(),error:t?.errorText})}))}async goto(e,t="networkidle"){const r="navigation";if(this.trackStage(r),!this.page)throw new f("Page not initialized",{stage:r});try{this.logger.debug(`Navigating to ${e}`,{waitUntil:t,timeout:this.opts.timeout}),await this.page.goto(e,{waitUntil:t,timeout:this.opts.timeout})}catch(o){throw await this.handleStageError(r,o),new h(`Navigation failed: ${o.message}`,{url:e,stage:r,waitUntil:t,timeout:this.opts.timeout,originalError:o.message})}}async waitForDownloadButton(){const e="waitForButton";if(this.trackStage(e),!this.interactions)throw new f("Interactions not ready",{stage:e});const t=this.opts.downloadButtonTimeout??p.downloadButtonTimeout;try{await this.interactions.waitForDownloadButton(t)}catch(r){throw await this.handleStageError(e,r),new h(`Failed to wait for download button: ${r.message}`,{stage:e,timeout:t,originalError:r.message})}}async getIntermediateUrl(){const e="extractUrl";if(this.trackStage(e),!this.interactions)throw new f("Interactions not ready",{stage:e});try{const e=await this.interactions.extractIntermediateUrl();return this.logger.debug("Intermediate URL extracted",{url:e}),e}catch(t){throw await this.handleStageError(e,t),new h(`Failed to extract intermediate URL: ${t.message}`,{stage:e,originalError:t.message})}}async startDownloadAndWait(e){const t="downloadWait";if(this.trackStage(t),!this.page)throw new f("Page not initialized",{stage:t});const r=this.page.waitForEvent("download",{timeout:this.opts.timeout}).catch(e=>(this.logger.debug("Download event timeout",{timeout:this.opts.timeout,error:e.message}),null));this.logger.debug("Navigating to auto download URL",{url:e}),await this.page.goto(e,{waitUntil:"commit",timeout:this.opts.timeout}).catch(e=>{this.logger.warn("Navigation to auto URL failed, continuing anyway",{error:e.message})});const o=await r;return o?(this.logger.info("Download event captured"),o):(this.logger.debug("No download event captured within timeout"),null)}async fallbackCollectFileResponse(){const e="fallbackIntercept";if(this.trackStage(e),!this.page)throw new f("Page not initialized",{stage:e});this.logger.info("Falling back to response interception");const t=[],r=e=>t.push(e);this.page.on("response",r),await y(p.fallbackWaitMs),this.page.off("response",r);const o=[...t].reverse().find(e=>{const t=e.headers(),r=t["content-disposition"],o=t["content-type"],i=e.url();return r&&r.includes("attachment")||i.includes("/downloadfile/")||o&&!o.startsWith("text/html")&&!o.startsWith("application/json")});if(!o)return this.logger.debug("No suitable file response found in fallback",{responseCount:t.length,sampleUrls:t.slice(0,3).map(e=>e.url())}),null;try{const e=await o.body();let t=x(o.headers()["content-disposition"]);if(!t){const e=o.url().split("/");t=e[e.length-1]?.split("?")[0]||"file.bin"}return t=t.replace(/[<>:"/\\|?*]/g,"_"),this.logger.info("Fallback response captured",{filename:t,size:e.length,contentType:o.headers()["content-type"]}),{buffer:e,filename:t}}catch(e){return this.logger.error("Failed to read fallback response body",{error:e.message}),null}}async saveDebugArtifacts(e){if(!this.opts.debug||!this.page)return null;try{this.debugDir=l.default.join(u.default.tmpdir(),`sfile_debug_${Date.now()}_${Math.random().toString(36).slice(2,8)}`),await c.mkdir(this.debugDir,{recursive:!0});const t=[this.page.screenshot({path:l.default.join(this.debugDir,"error.png"),fullPage:!0}).then(()=>{}),c.writeFile(l.default.join(this.debugDir,"error.html"),await this.page.content()),c.writeFile(l.default.join(this.debugDir,"error.txt"),e),c.writeFile(l.default.join(this.debugDir,"stages.json"),JSON.stringify(this.stageHistory,null,2))];return await Promise.all(t),this.logger.info("Debug artifacts saved",{debugDir:this.debugDir}),this.debugDir}catch(e){return this.logger.error("Failed to save debug artifacts",{error:e.message}),null}}async handleStageError(e,t){this.opts.debug&&await this.saveDebugArtifacts(`Error at stage "${e}": ${t?.message||"Unknown error"}`)}async close(){const e=[this.page?.close().catch(()=>{}),this.context?.close().catch(()=>{}),this.browser?.close().catch(()=>{})].filter(Boolean);await Promise.all(e),this.logger.debug("Browser closed",{stages:this.stageHistory.length})}async getPage(){return this.page}getDebugDir(){return this.debugDir}getStageHistory(){return[...this.stageHistory]}}class E{minLevel;correlationId;fileStream=null;prefix;constructor(e={}){this.minLevel=e.debugMode?"debug":"info",this.correlationId=e.correlationId,this.prefix=e.prefix||"",e.logFile&&(this.fileStream=t.createWriteStream(e.logFile,{flags:"a"}))}setCorrelationId(e){this.correlationId=e}setDebug(e){this.minLevel=e?"debug":"info"}levelPriority(e){return{debug:0,info:1,warn:2,error:3}[e]}shouldLog(e){return this.levelPriority(e)>=this.levelPriority(this.minLevel)}format(e,t,r){const o=(new Date).toISOString(),i=this.correlationId?` [${this.correlationId}]`:"",s=this.prefix?` [${this.prefix}]`:"",a=r?` | ${v(r)}`:"";return`[${o}]${i}${s} ${e.toUpperCase()}: ${t}${a}`}write(e,t,r){if(!this.shouldLog(e))return;const o=this.format(e,t,r);console["error"===e?"error":"warn"===e?"warn":"log"](o),this.fileStream?.writable&&this.fileStream.write(o+"\n")}debug(e,t){this.write("debug",e,t)}info(e,t){this.write("info",e,t)}warn(e,t){this.write("warn",e,t)}error(e,t,r){let o;o=r?{...t&&"object"==typeof t&&null!==t?{...t}:{},error:{name:r.name,message:r.message}}:t,this.write("error",e,o)}child(e){const t={debugMode:"debug"===this.minLevel,...void 0!==this.correlationId&&{correlationId:this.correlationId},prefix:this.prefix?`${this.prefix}:${e}`:e},r=new E(t);return this.fileStream&&(r.fileStream=this.fileStream),r}async close(){if(this.fileStream&&!this.fileStream.closed)return new Promise(e=>this.fileStream?.end(e))}}function F(e){return{headless:e?.headless??p.headless,userAgent:e?.userAgent??p.userAgent,timeout:e?.timeout??p.timeout,downloadButtonTimeout:e?.downloadButtonTimeout??p.downloadButtonTimeout,retries:e?.retries??p.retries,retryDelay:e?.retryDelay??p.retryDelay,debug:e?.debug??!1,saveDebugArtifacts:e?.saveDebugArtifacts??p.saveDebugArtifacts,...{...void 0!==e?.onProgress&&{onProgress:e.onProgress},...void 0!==e?.correlationId&&{correlationId:e.correlationId},...void 0!==e?._internal&&{_internal:e._internal},...void 0!==e?.logFile&&{logFile:e.logFile}}}}class k{static validateUrl(e,t=["sfile.co","sfile.mobi"]){if(!e||"string"!=typeof e)throw new g("URL must be a non-empty string",{received:typeof e,url:e});if(!t.some(t=>e.includes(t)))throw new g(`URL must contain one of: ${t.join(", ")}`,{url:e,allowedDomains:t});try{const t=new URL(e);if(!["http:","https:"].includes(t.protocol))throw new g("URL must use http or https protocol",{url:e,protocol:t.protocol})}catch(t){throw new g("Invalid URL format",{url:e,parseError:t instanceof Error?t.message:String(t)})}}static validateSaveDir(e){if(!e||"string"!=typeof e)throw new g("Save directory must be a non-empty string",{received:typeof e,dir:e})}static sanitizeFilename(e){const t=p.maxFilenameLength,r=b(e,p.sanitizeReplacement);if(!r||0===r.length){const r=e.includes(".")?e.split(".").pop():"bin";return("downloaded_file"+(r?"."+r:"")).slice(0,t)}return r.slice(0,t)}static validateOptions(e){if(null==e)return;if("object"!=typeof e)throw new g("Options must be an object or undefined",{received:typeof e});const t=e,r=["timeout","retries","retryDelay","downloadButtonTimeout"];for(const e of r)if(e in t&&void 0!==t[e]&&"number"!=typeof t[e])throw new g(`Option '${e}' must be a number`,{field:e,received:typeof t[e],value:t[e]});const o=["headless","debug","saveDebugArtifacts"];for(const e of o)if(e in t&&void 0!==t[e]&&"boolean"!=typeof t[e])throw new g(`Option '${e}' must be a boolean`,{field:e,received:typeof t[e],value:t[e]});const i=["correlationId","logFile","userAgent"];for(const e of i)if(e in t&&void 0!==t[e]&&"string"!=typeof t[e])throw new g(`Option '${e}' must be a string`,{field:e,received:typeof t[e],value:t[e]});if("onProgress"in t&&void 0!==t.onProgress&&"function"!=typeof t.onProgress)throw new g("Option 'onProgress' must be a function",{received:typeof t.onProgress})}}function I(e){return Object.fromEntries(Object.entries(e).filter(([,e])=>void 0!==e))}function $(e,t,r,o){if("function"==typeof e)try{e(t,r,o)}catch(e){console.warn("Progress callback error:",e)}}async function R(e,r,o,i){const s=Date.now(),a=new S(i.child("BrowserManager"),{headless:o.headless,userAgent:o.userAgent,timeout:o.timeout,debug:o.debug,downloadButtonTimeout:o.downloadButtonTimeout});let n,c,u;try{i.info("Starting download workflow",{url:e}),$(o.onProgress,10,100,{stage:"launch",message:"Launching browser",attempt:1}),await a.launch(),await a.goto(e,"networkidle"),$(o.onProgress,30,100,{stage:"navigation",message:"Page loaded"}),await a.waitForDownloadButton(),$(o.onProgress,50,100,{stage:"button",message:"Download button ready"});const d=await a.getIntermediateUrl(),g=d.includes("?")?`${d}&auto=1`:`${d}?auto=1`;i.debug("Triggering download",{autoUrl:g}),$(o.onProgress,70,100,{stage:"trigger",message:"Download triggered"});let f=await a.startDownloadAndWait(g);if(f){const e=f.suggestedFilename()||"file.bin",o=k.sanitizeFilename(e);n=l.join(r,o),await f.saveAs(n),c=(await t.promises.stat(n)).size,u="direct",i.info("Saved via direct download",{path:n,size:c})}else{i.warn("Direct download not captured, trying fallback");const o=await a.fallbackCollectFileResponse();if(!o)throw new h("No download event and no file response found",{url:e,intermediateUrl:d,autoUrl:g,stage:"fallbackFailed"});const{buffer:s,filename:f}=o,w=k.sanitizeFilename(f);n=l.join(r,w),await t.promises.writeFile(n,s),c=s.length,u="fallback",i.info("Saved via fallback",{path:n,size:c})}$(o.onProgress,100,100,{stage:"complete",message:"Download finished"});const w={filePath:n,size:c,method:u,durationMs:Date.now()-s,attempts:1};return void 0!==o.correlationId&&(w.correlationId=o.correlationId),w}catch(t){const i=t instanceof Error?t:new Error(String(t)),s=i instanceof d?i:new h(i.message,{url:e,saveDir:r,correlationId:o.correlationId,originalError:i.message,errorName:i.name});if(o.saveDebugArtifacts){const e=await a.saveDebugArtifacts(s.message);e&&(s.debugPath=e,s.context&&"object"==typeof s.context&&(s.context.debugPath=e))}throw s}finally{await a.close().catch(e=>i.error("Failed to close browser",{error:e.message})),await i.close().catch(e=>console.error("Failed to close logger",e))}}async function O(e,o,i){const s=F(i),a=s.correlationId||r.randomUUID(),n={debugMode:s.debug,correlationId:a,prefix:"downloadSfile"};void 0!==s.logFile&&(n.logFile=s.logFile);const l=new E(n);let c;k.validateUrl(e),k.validateSaveDir(o),k.validateOptions(i),await t.promises.mkdir(o,{recursive:!0});let u=0;for(;u<s.retries;){u++;try{l.info(`Download attempt ${u}/${s.retries}`,{url:e});const t=await R(e,o,s,l);return l.info("Download succeeded",{duration:t.durationMs,attempts:u,method:t.method}),{...t,attempts:u,correlationId:a}}catch(e){c=e instanceof Error?e:new Error(String(e));const t=c instanceof d&&c.retryable,r=u>=s.retries;if(!t||r)throw l.error("Download failed permanently",{error:c.message,attempt:u,retryable:t,lastAttempt:r}),c;const o=D(u,s.retryDelay,p.maxRetryDelay);l.warn("Retrying download",{attempt:u,maxAttempts:s.retries,delayMs:Math.round(o),error:c.message}),$(s.onProgress,0,100,{stage:"retry",message:`Retry ${u}/${s.retries}`,attempt:u}),await y(o)}}throw c||new Error("Download failed after all retries")}async function P(e,t,r){try{return{success:!0,value:await O(e,t,r)}}catch(e){return{success:!1,error:e}}}exports.AppError=d,exports.BrowserError=f,exports.DEFAULTS=p,exports.FileError=class A extends d{constructor(e,t){super(e,"FILE_ERROR",!1,t),Object.freeze(this)}},exports.InputValidator=k,exports.Logger=E,exports.NetworkError=h,exports.ValidationError=g,exports.calculateRetryDelay=D,exports.createDownloader=function e(t){const r=F(t);return{download:async(e,t,o)=>O(e,t,I({...r,...o})),downloadSafe:async(e,t,o)=>P(e,t,I({...r,...o})),withOptions:t=>e(I({...r,...t}))}},exports.downloadSfile=O,exports.downloadSfileSafe=P,exports.extractFilenameFromContentDisposition=x,exports.isAppError=w,exports.isErr=function(e){return!1===e.success},exports.isError=function U(e){return e instanceof Error||"object"==typeof e&&null!==e&&"message"in e},exports.isErrorWithCode=function(e,t){return w(e)&&e.code===t},exports.isOk=function(e){return!0===e.success},exports.isRetryableError=function j(e){return w(e)&&e.retryable},exports.mapErr=function L(e,t){return e.success?e:{success:!1,error:t(e.error)}},exports.normalizeOptions=F,exports.safeStringify=v,exports.sanitizeFilename=b,exports.sleep=y;
2
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGliLltmb3JtYXRdLmpzLm1hcCIsIm5hbWVzIjpbIk9iamVjdCIsImRlZmluZVByb3BlcnR5IiwiZXhwb3J0cyIsInZhbHVlIiwicGF0aCIsInJlcXVpcmUiLCJmcyQxIiwiY3J5cHRvIiwicGxheXdyaWdodCIsImZzIiwib3MiLCJfaW50ZXJvcERlZmF1bHQiLCJlIiwiX19lc01vZHVsZSIsImRlZmF1bHQiLCJfaW50ZXJvcE5hbWVzcGFjZSIsIm4iLCJjcmVhdGUiLCJrIiwiZCIsImdldE93blByb3BlcnR5RGVzY3JpcHRvciIsImdldCIsImVudW1lcmFibGUiLCJwYXRoX19uYW1lc3BhY2UiLCJmc19fbmFtZXNwYWNlIiwib3NfX2RlZmF1bHQiLCJBcHBFcnJvciIsIkVycm9yIiwidGltZXN0YW1wIiwiY29udGV4dCIsImNvZGUiLCJyZXRyeWFibGUiLCJjb25zdHJ1Y3RvciIsIm1lc3NhZ2UiLCJzdXBlciIsInRoaXMiLCJuYW1lIiwiRGF0ZSIsInRvSVNPU3RyaW5nIiwiZnJlZXplIiwiY2FwdHVyZVN0YWNrVHJhY2UiLCJ0b0pTT04iLCJzdGFjayIsInByb2Nlc3MiLCJlbnYiLCJ1bmRlZmluZWQiLCJ0b1N0cmluZyIsImlzQ29kZSIsImlzUmV0cnlhYmxlIiwiVmFsaWRhdGlvbkVycm9yIiwiTmV0d29ya0Vycm9yIiwiQnJvd3NlckVycm9yIiwiaXNBcHBFcnJvciIsImVyciIsIkRFRkFVTFRTIiwidXNlckFnZW50IiwiaGVhZGxlc3MiLCJ0aW1lb3V0IiwiZG93bmxvYWRCdXR0b25UaW1lb3V0IiwiZmFsbGJhY2tXYWl0TXMiLCJyZXRyaWVzIiwicmV0cnlEZWxheSIsIm1heFJldHJ5RGVsYXkiLCJzYXZlRGVidWdBcnRpZmFjdHMiLCJtYXhGaWxlbmFtZUxlbmd0aCIsInNhbml0aXplUmVwbGFjZW1lbnQiLCJTZmlsZVBhZ2VJbnRlcmFjdGlvbnMiLCJwYWdlIiwibG9nZ2VyIiwid2FpdEZvckRvd25sb2FkQnV0dG9uIiwiZGVidWciLCJidXR0b24iLCJsb2NhdG9yIiwid2FpdEZvciIsInN0YXRlIiwid2FpdEZvckZ1bmN0aW9uIiwiYnRuIiwiZG9jdW1lbnQiLCJxdWVyeVNlbGVjdG9yIiwiaHJlZiIsImdldEF0dHJpYnV0ZSIsInN0eWxlIiwid2luZG93IiwiZ2V0Q29tcHV0ZWRTdHlsZSIsImlzRGlzYWJsZWQiLCJoYXNBdHRyaWJ1dGUiLCJjbGFzc0xpc3QiLCJjb250YWlucyIsInRyaW0iLCJwb2ludGVyRXZlbnRzIiwiZXh0cmFjdEludGVybWVkaWF0ZVVybCIsIiRldmFsIiwiZWwiLCJpbmNsdWRlcyIsInNlbGVjdG9yIiwib3JpZ2luYWxFcnJvciIsInNhbml0aXplRmlsZW5hbWUiLCJyZXBsYWNlbWVudCIsInJlcGxhY2UiLCJSZWdFeHAiLCJzbGljZSIsInNsZWVwIiwibXMiLCJQcm9taXNlIiwicmVzb2x2ZSIsInNldFRpbWVvdXQiLCJzYWZlU3RyaW5naWZ5IiwiaW5kZW50Iiwic2VlbiIsIldlYWtTZXQiLCJKU09OIiwic3RyaW5naWZ5IiwiX2tleSIsInZhbCIsImhhcyIsImFkZCIsImV4dHJhY3RGaWxlbmFtZUZyb21Db250ZW50RGlzcG9zaXRpb24iLCJoZWFkZXIiLCJlbmNvZGVkTWF0Y2giLCJtYXRjaCIsImRlY29kZVVSSUNvbXBvbmVudCIsInF1b3RlZE1hdGNoIiwicGxhaW5NYXRjaCIsImNhbGN1bGF0ZVJldHJ5RGVsYXkiLCJhdHRlbXB0IiwiYmFzZURlbGF5TXMiLCJtYXhEZWxheU1zIiwiZXhwb25lbnRpYWwiLCJNYXRoIiwicG93Iiwiaml0dGVyIiwicmFuZG9tIiwibWluIiwiQnJvd3Nlck1hbmFnZXIiLCJvcHRzIiwiYnJvd3NlciIsImludGVyYWN0aW9ucyIsImRlYnVnRGlyIiwic3RhZ2VIaXN0b3J5IiwidHJhY2tTdGFnZSIsInN0YWdlIiwicHVzaCIsInRzIiwibm93IiwibGF1bmNoIiwiaW5mbyIsImNocm9taXVtIiwiYXJncyIsIm5ld0NvbnRleHQiLCJhY2NlcHREb3dubG9hZHMiLCJsb2NhbGUiLCJ0aW1lem9uZUlkIiwidmlld3BvcnQiLCJ3aWR0aCIsImhlaWdodCIsImFkZENvb2tpZXMiLCJkb21haW4iLCJleHBpcmVzIiwiZmxvb3IiLCJuZXdQYWdlIiwic2V0dXBEZWJ1Z0xpc3RlbmVycyIsImhhbmRsZVN0YWdlRXJyb3IiLCJvbiIsIm1zZyIsInR5cGUiLCJ0ZXh0IiwiZXJyb3IiLCJsb2NhdGlvbiIsIndhcm4iLCJyZXEiLCJmYWlsdXJlIiwidXJsIiwibWV0aG9kIiwiZXJyb3JUZXh0IiwiZ290byIsIndhaXRVbnRpbCIsImdldEludGVybWVkaWF0ZVVybCIsInN0YXJ0RG93bmxvYWRBbmRXYWl0IiwiYXV0b1VybCIsImRvd25sb2FkUHJvbWlzZSIsIndhaXRGb3JFdmVudCIsImNhdGNoIiwiZG93bmxvYWQiLCJmYWxsYmFja0NvbGxlY3RGaWxlUmVzcG9uc2UiLCJyZXNwb25zZXMiLCJoYW5kbGVyIiwicmVzIiwib2ZmIiwiZmlsZVJlc3BvbnNlIiwicmV2ZXJzZSIsImZpbmQiLCJyIiwiaGVhZGVycyIsImRpc3Bvc2l0aW9uIiwiY29udGVudFR5cGUiLCJzdGFydHNXaXRoIiwicmVzcG9uc2VDb3VudCIsImxlbmd0aCIsInNhbXBsZVVybHMiLCJtYXAiLCJidWZmZXIiLCJib2R5IiwiZmlsZW5hbWUiLCJ1cmxQYXJ0cyIsInNwbGl0Iiwic2l6ZSIsImVycm9yTWVzc2FnZSIsImpvaW4iLCJ0bXBkaXIiLCJta2RpciIsInJlY3Vyc2l2ZSIsInRhc2tzIiwic2NyZWVuc2hvdCIsImZ1bGxQYWdlIiwidGhlbiIsIndyaXRlRmlsZSIsImNvbnRlbnQiLCJhbGwiLCJjbG9zZSIsImNsb3NlUHJvbWlzZXMiLCJmaWx0ZXIiLCJCb29sZWFuIiwic3RhZ2VzIiwiZ2V0UGFnZSIsImdldERlYnVnRGlyIiwiZ2V0U3RhZ2VIaXN0b3J5IiwiTG9nZ2VyIiwibWluTGV2ZWwiLCJjb3JyZWxhdGlvbklkIiwiZmlsZVN0cmVhbSIsInByZWZpeCIsIm9wdGlvbnMiLCJkZWJ1Z01vZGUiLCJsb2dGaWxlIiwiY3JlYXRlV3JpdGVTdHJlYW0iLCJmbGFncyIsInNldENvcnJlbGF0aW9uSWQiLCJpZCIsInNldERlYnVnIiwiZW5hYmxlZCIsImxldmVsUHJpb3JpdHkiLCJsZXZlbCIsInNob3VsZExvZyIsImZvcm1hdCIsImNvcnIiLCJjdHgiLCJ0b1VwcGVyQ2FzZSIsIndyaXRlIiwiZm9ybWF0dGVkIiwiY29uc29sZSIsIndyaXRhYmxlIiwiZXJyb3JDdHgiLCJjaGlsZCIsImNoaWxkT3B0aW9ucyIsImNsb3NlZCIsImVuZCIsIm5vcm1hbGl6ZU9wdGlvbnMiLCJvblByb2dyZXNzIiwiX2ludGVybmFsIiwiSW5wdXRWYWxpZGF0b3IiLCJ2YWxpZGF0ZVVybCIsImFsbG93ZWREb21haW5zIiwicmVjZWl2ZWQiLCJzb21lIiwicGFyc2VkIiwiVVJMIiwicHJvdG9jb2wiLCJwYXJzZUVyciIsInBhcnNlRXJyb3IiLCJTdHJpbmciLCJ2YWxpZGF0ZVNhdmVEaXIiLCJkaXIiLCJtYXhMZW5ndGgiLCJzYW5pdGl6ZWQiLCJleHQiLCJwb3AiLCJ2YWxpZGF0ZU9wdGlvbnMiLCJudW1lcmljRmllbGRzIiwiZmllbGQiLCJib29sZWFuRmllbGRzIiwic3RyaW5nRmllbGRzIiwic3RyaXBVbmRlZmluZWQiLCJvYmoiLCJmcm9tRW50cmllcyIsImVudHJpZXMiLCJ2Iiwic2FmZVByb2dyZXNzIiwicGVyY2VudCIsInRvdGFsIiwibWV0YSIsImFzeW5jIiwiZXhlY3V0ZURvd25sb2FkIiwic2F2ZURpciIsInN0YXJ0VGltZSIsImJyb3dzZXJNZ3IiLCJmaW5hbFBhdGgiLCJmaWxlU2l6ZSIsImludGVybWVkaWF0ZVVybCIsInN1Z2dlc3RlZCIsInN1Z2dlc3RlZEZpbGVuYW1lIiwic2F2ZUFzIiwicHJvbWlzZXMiLCJzdGF0IiwiZmFsbGJhY2siLCJyYXdOYW1lIiwicmVzdWx0IiwiZmlsZVBhdGgiLCJkdXJhdGlvbk1zIiwiYXR0ZW1wdHMiLCJhcHBFcnJvciIsImVycm9yTmFtZSIsImRlYnVnUGF0aCIsImRvd25sb2FkU2ZpbGUiLCJyYW5kb21VVUlEIiwibG9nZ2VyT3B0aW9ucyIsImxhc3RFcnJvciIsImR1cmF0aW9uIiwiaXNMYXN0QXR0ZW1wdCIsImxhc3RBdHRlbXB0IiwiZGVsYXkiLCJtYXhBdHRlbXB0cyIsImRlbGF5TXMiLCJyb3VuZCIsImRvd25sb2FkU2ZpbGVTYWZlIiwic3VjY2VzcyIsIkZpbGVFcnJvciIsImNyZWF0ZURvd25sb2FkZXIiLCJkZWZhdWx0T3B0aW9ucyIsImRlZmF1bHRzIiwiY2FsbE9wdGlvbnMiLCJ3aXRoT3B0aW9ucyIsIm5ld0RlZmF1bHRzIiwiaXNFcnIiLCJpc0Vycm9yIiwiaXNFcnJvcldpdGhDb2RlIiwiaXNPayIsImlzUmV0cnlhYmxlRXJyb3IiLCJtYXBFcnIiLCJtYXBFcnJvciIsImZuIl0sInNvdXJjZXMiOlsiMCJdLCJtYXBwaW5ncyI6IkFBRUFBLE9BQU9DLGVBQWVDLFFBQVMsYUFBYyxDQUFFQyxPQUFPLElBRXRELE1BQU1DLEVBQU9DLFFBQVEsUUFDZkMsRUFBT0QsUUFBUSxNQUNmRSxFQUFTRixRQUFRLFVBQ2pCRyxFQUFhSCxRQUFRLGNBQ3JCSSxFQUFLSixRQUFRLGVBQ2JLLEVBQUtMLFFBQVEsTUFFbkIsU0FBU00sRUFBaUJDLEdBQUssT0FBT0EsR0FBS0EsRUFBRUMsV0FBYUQsRUFBSSxDQUFFRSxRQUFTRixFQUFLLENBRTlFLFNBQVNHLEVBQWtCSCxHQUMzQixHQUFJQSxHQUFLQSxFQUFFQyxXQUFZLE9BQU9ELEVBQzlCLE1BQU1JLEVBQUloQixPQUFPaUIsT0FBTyxNQUN4QixHQUFJTCxFQUNKLElBQUssTUFBTU0sS0FBS04sRUFDaEIsR0FBVSxZQUFOTSxFQUFpQixDQUNyQixNQUFNQyxFQUFJbkIsT0FBT29CLHlCQUF5QlIsRUFBR00sR0FDN0NsQixPQUFPQyxlQUFlZSxFQUFHRSxFQUFHQyxFQUFFRSxJQUFNRixFQUFJLENBQ3hDRyxZQUFZLEVBQ1pELElBQUssV0FBYyxPQUFPVCxFQUFFTSxFQUFJLEdBRWhDLENBSUEsT0FEQUYsRUFBRUYsUUFBVUYsRUFD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
970
3
  //# sourceMappingURL=lib.cjs.map