sfiledl 2.0.1 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/build/lib.mjs CHANGED
@@ -1,105 +1,354 @@
1
- const COLORS = {
2
- RESET: "\x1b[0m",
3
- BRIGHT: "\x1b[1m",
4
- YELLOW: "\x1b[33m",
5
- RED: "\x1b[31m",
6
- CYAN: "\x1b[36m",
7
- GRAY: "\x1b[90m",
8
- };
9
- var LibraryStatus;
10
- (function (LibraryStatus) {
11
- LibraryStatus["UNDER_CONSTRUCTION"] = "UNDER_CONSTRUCTION";
12
- LibraryStatus["STABLE"] = "STABLE";
13
- LibraryStatus["DEPRECATED"] = "DEPRECATED";
14
- })(LibraryStatus || (LibraryStatus = {}));
15
- const LIB_INFO = {
16
- name: "MySuperFramework",
17
- currentVersion: "2.0.1-dev",
18
- previousVersion: "1.0.2",
19
- status: LibraryStatus.UNDER_CONSTRUCTION,
20
- isDeprecated: true,
21
- message: "This version represents a complete architectural refactor from CLI to framework. Not stable.",
1
+ import path from 'path';
2
+ import * as fs from 'fs/promises';
3
+ import fs__default from 'fs/promises';
4
+ import { chromium } from 'playwright';
5
+ import os from 'os';
6
+
7
+ class AppError extends Error {
8
+ code;
9
+ retryable;
10
+ timestamp;
11
+ context;
12
+ constructor(message, code, retryable = false, context) {
13
+ super(message);
14
+ this.code = code;
15
+ this.retryable = retryable;
16
+ this.name = this.constructor.name;
17
+ this.timestamp = new Date().toISOString();
18
+ this.context = context ? { ...context } : undefined;
19
+ Error.captureStackTrace?.(this, this.constructor);
20
+ }
21
+ toJSON() {
22
+ return {
23
+ name: this.name,
24
+ message: this.message,
25
+ code: this.code,
26
+ retryable: this.retryable,
27
+ timestamp: this.timestamp,
28
+ context: this.context,
29
+ };
30
+ }
31
+ }
32
+
33
+ class ValidationError extends AppError {
34
+ constructor(message, context) {
35
+ super(message, 'VALIDATION_ERROR', false, context);
36
+ }
37
+ }
38
+ class NetworkError extends AppError {
39
+ constructor(message, context) {
40
+ super(message, 'NETWORK_ERROR', true, context);
41
+ }
42
+ }
43
+ class FileError extends AppError {
44
+ constructor(message, context) {
45
+ super(message, 'FILE_ERROR', false, context);
46
+ }
47
+ }
48
+ class BrowserError extends AppError {
49
+ constructor(message, context) {
50
+ super(message, 'BROWSER_ERROR', true, context);
51
+ }
52
+ }
53
+
54
+ const DEFAULTS = {
55
+ userAgent: 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',
56
+ headless: true,
57
+ timeout: 100000,
58
+ downloadButtonTimeout: 100000,
59
+ fallbackWaitMs: 5000,
22
60
  };
23
- let warningDisplayed = false;
24
- function stripAnsi(text) {
25
- return text.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "");
61
+
62
+ class SfilePageInteractions {
63
+ page;
64
+ logger;
65
+ constructor(page, logger) {
66
+ this.page = page;
67
+ this.logger = logger;
68
+ }
69
+ async waitForDownloadButton(timeout) {
70
+ this.logger.debug('Waiting for #download button to be visible');
71
+ const button = this.page.locator('#download');
72
+ await button.waitFor({ state: 'visible', timeout });
73
+ this.logger.debug('Waiting for button to become active (href != "#" and pointerEvents != "none")');
74
+ await this.page.waitForFunction(() => {
75
+ const btn = document.querySelector('#download');
76
+ if (!btn)
77
+ return false;
78
+ const href = btn.getAttribute('href');
79
+ const style = window.getComputedStyle(btn);
80
+ return href && href !== '#' && style.pointerEvents !== 'none';
81
+ }, { timeout });
82
+ }
83
+ async extractIntermediateUrl() {
84
+ this.logger.debug('Extracting href from #download');
85
+ const href = await this.page.$eval('#download', (el) => el.href);
86
+ if (!href || href === '#') {
87
+ throw new NetworkError('Download button href is invalid', { href });
88
+ }
89
+ return href;
90
+ }
26
91
  }
27
- function isDevelopmentVersion() {
28
- return LIB_INFO.status === LibraryStatus.UNDER_CONSTRUCTION;
92
+
93
+ function sanitizeFilename(name, replacement = '_') {
94
+ const sanitized = name
95
+ .replace(/[<>:"/\\|?*\x00-\x1F]/g, replacement)
96
+ .replace(new RegExp(`${replacement}+`, 'g'), replacement)
97
+ .trim()
98
+ .slice(0, 255);
99
+ return sanitized || 'file.bin';
29
100
  }
30
- class LibStatus {
31
- static instance;
32
- constructor() {
33
- this.displayDeveloperWarning();
34
- }
35
- static getInstance() {
36
- if (!LibStatus.instance) {
37
- LibStatus.instance = new LibStatus();
101
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
102
+ function safeStringify(value) {
103
+ try {
104
+ return JSON.stringify(value);
105
+ }
106
+ catch {
107
+ return '[unserializable]';
108
+ }
109
+ }
110
+
111
+ class BrowserManager {
112
+ logger;
113
+ opts;
114
+ browser = null;
115
+ context = null;
116
+ page = null;
117
+ interactions = null;
118
+ debugDir = null;
119
+ constructor(logger, opts) {
120
+ this.logger = logger;
121
+ this.opts = opts;
122
+ }
123
+ async launch() {
124
+ try {
125
+ this.logger.info('Launching browser', { headless: this.opts.headless });
126
+ this.browser = await chromium.launch({
127
+ headless: this.opts.headless,
128
+ args: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],
129
+ });
130
+ this.context = await this.browser.newContext({
131
+ userAgent: this.opts.userAgent,
132
+ acceptDownloads: true,
133
+ locale: 'en-US',
134
+ });
135
+ await this.context.addCookies([
136
+ {
137
+ name: 'safe_link_counter',
138
+ value: '1',
139
+ domain: '.sfile.co',
140
+ path: '/',
141
+ expires: Math.floor(Date.now() / 1000) + 3600,
142
+ },
143
+ ]);
144
+ this.page = await this.context.newPage();
145
+ this.interactions = new SfilePageInteractions(this.page, this.logger);
146
+ if (this.opts.debug) {
147
+ this.page.on('console', (msg) => {
148
+ if (msg.type() === 'error')
149
+ this.logger.error(`[console] ${msg.text()}`);
150
+ else if (msg.type() === 'warning')
151
+ this.logger.warn(`[console] ${msg.text()}`);
152
+ });
153
+ this.page.on('pageerror', (err) => this.logger.error(`[pageerror] ${err.message}`));
154
+ }
155
+ this.logger.info('Browser ready');
156
+ }
157
+ catch (err) {
158
+ throw new BrowserError(`Failed to launch browser: ${err.message}`);
38
159
  }
39
- return LibStatus.instance;
40
160
  }
41
- displayDeveloperWarning() {
42
- if (typeof console === "undefined" || typeof console.warn !== "function") {
43
- return;
161
+ async goto(url, waitUntil = 'networkidle') {
162
+ if (!this.page)
163
+ throw new BrowserError('Page not initialized');
164
+ try {
165
+ this.logger.debug(`Navigating to ${url} (waitUntil=${waitUntil})`);
166
+ await this.page.goto(url, { waitUntil, timeout: this.opts.timeout });
44
167
  }
45
- if (warningDisplayed) {
46
- return;
168
+ catch (err) {
169
+ throw new NetworkError(`Navigation failed: ${err.message}`, { url });
47
170
  }
48
- if (typeof process !== "undefined" && process.env && process.env['MY_SUPER_FRAMEWORK_SUPPRESS_WARNING'] === "true") {
171
+ }
172
+ async waitForDownloadButton() {
173
+ if (!this.interactions)
174
+ throw new BrowserError('Interactions not ready');
175
+ await this.interactions.waitForDownloadButton(DEFAULTS.downloadButtonTimeout);
176
+ }
177
+ async getIntermediateUrl() {
178
+ if (!this.interactions)
179
+ throw new BrowserError('Interactions not ready');
180
+ return this.interactions.extractIntermediateUrl();
181
+ }
182
+ async startDownloadAndWait(autoUrl) {
183
+ if (!this.page)
184
+ throw new BrowserError('Page not initialized');
185
+ const downloadPromise = this.page
186
+ .waitForEvent('download', { timeout: this.opts.timeout })
187
+ .catch((err) => {
188
+ this.logger.warn(`Download event wait failed: ${err.message}`);
189
+ return null;
190
+ });
191
+ this.logger.debug(`Navigating to auto URL: ${autoUrl}`);
192
+ await this.page.goto(autoUrl, { waitUntil: 'commit', timeout: this.opts.timeout });
193
+ const download = await downloadPromise;
194
+ if (download) {
195
+ this.logger.info('Download event captured');
196
+ return download;
197
+ }
198
+ return null;
199
+ }
200
+ async fallbackCollectFileResponse() {
201
+ if (!this.page)
202
+ throw new BrowserError('Page not initialized');
203
+ this.logger.warn('Falling back to response interception');
204
+ const responses = [];
205
+ const handler = (res) => responses.push(res);
206
+ this.page.on('response', handler);
207
+ await sleep(DEFAULTS.fallbackWaitMs);
208
+ this.page.off('response', handler);
209
+ const fileResponse = [...responses].reverse().find((r) => {
210
+ const disposition = r.headers()['content-disposition'];
211
+ return ((disposition && disposition.includes('attachment')) ||
212
+ r.url().includes('/downloadfile/'));
213
+ });
214
+ if (!fileResponse)
215
+ return null;
216
+ const buffer = await fileResponse.body();
217
+ let filename = fileResponse.url().split('/').pop()?.split('?')[0] || 'file.bin';
218
+ filename = filename.replace(/[<>:"/\\|?*]/g, '_');
219
+ return { buffer, filename };
220
+ }
221
+ async saveDebugArtifacts(errorMessage) {
222
+ if (!this.page)
49
223
  return;
224
+ try {
225
+ this.debugDir = path.join(os.tmpdir(), `sfile_debug_${Date.now()}`);
226
+ await fs.mkdir(this.debugDir, { recursive: true });
227
+ await Promise.all([
228
+ this.page.screenshot({
229
+ path: path.join(this.debugDir, 'error.png'),
230
+ fullPage: true,
231
+ }),
232
+ fs.writeFile(path.join(this.debugDir, 'error.html'), await this.page.content()),
233
+ fs.writeFile(path.join(this.debugDir, 'error.txt'), errorMessage),
234
+ ]);
235
+ this.logger.info(`Debug artifacts saved to ${this.debugDir}`);
50
236
  }
51
- const border = `${COLORS.GRAY}${"=".repeat(80)}${COLORS.RESET}`;
52
- const label = `${COLORS.YELLOW}${COLORS.BRIGHT}[WARNING]${COLORS.RESET}`;
53
- const highlight = `${COLORS.CYAN}`;
54
- console.warn(`\n${border}`);
55
- console.warn(`${label} DEVELOPMENT VERSION IN USE`);
56
- console.warn(`${COLORS.GRAY}Library: ${COLORS.RESET}${highlight}${LIB_INFO.name}${COLORS.RESET}`);
57
- console.warn(`${COLORS.GRAY}Current Version: ${COLORS.RESET}${highlight}${LIB_INFO.currentVersion}${COLORS.RESET}`);
58
- console.warn(`${COLORS.GRAY}Previous Version: ${COLORS.RESET}${highlight}${LIB_INFO.previousVersion}${COLORS.RESET}`);
59
- console.warn(`${COLORS.GRAY}Architecture: ${COLORS.RESET}${highlight}CLI -> Framework (Full Refactor)${COLORS.RESET}`);
60
- console.warn(`\n${COLORS.RED}${COLORS.BRIGHT}DO NOT USE IN PRODUCTION ENVIRONMENTS${COLORS.RESET}`);
61
- console.warn(`${COLORS.GRAY}API stability is not guaranteed. Breaking changes may occur without notice.${COLORS.RESET}`);
62
- console.warn(`${COLORS.GRAY}To suppress this warning, set env MY_SUPER_FRAMEWORK_SUPPRESS_WARNING=true${COLORS.RESET}`);
63
- console.warn(`${border}\n`);
64
- warningDisplayed = true;
65
- }
66
- suppressWarning() {
67
- warningDisplayed = true;
68
- }
69
- ensureStable() {
70
- if (LIB_INFO.status === LibraryStatus.UNDER_CONSTRUCTION) {
71
- const errorMessage = `${COLORS.RED}${COLORS.BRIGHT}[${LIB_INFO.name}] Stability Check Failed${COLORS.RESET}\n` +
72
- `${COLORS.GRAY}Library version ${LIB_INFO.currentVersion} is under active development.${COLORS.RESET}\n` +
73
- `${COLORS.GRAY}Current status: ${LIB_INFO.status}${COLORS.RESET}`;
74
- throw new Error(stripAnsi(errorMessage));
237
+ catch (e) {
238
+ this.logger.error(`Failed to save debug artifacts: ${e.message}`);
75
239
  }
76
240
  }
77
- getVersion() {
78
- return LIB_INFO.currentVersion;
79
- }
80
- getInfo() {
81
- return LIB_INFO;
241
+ async close() {
242
+ if (this.page)
243
+ await this.page.close().catch(() => { });
244
+ if (this.context)
245
+ await this.context.close().catch(() => { });
246
+ if (this.browser)
247
+ await this.browser.close().catch(() => { });
248
+ this.logger.debug('Browser closed');
82
249
  }
83
250
  }
84
- function initFramework() {
85
- const message = `${COLORS.RED}${COLORS.BRIGHT}[${LIB_INFO.name}] Initialization Blocked${COLORS.RESET}\n` +
86
- `${COLORS.GRAY}Framework is undergoing complete architectural refactor.${COLORS.RESET}\n` +
87
- `${COLORS.GRAY}Migration path: v${LIB_INFO.previousVersion} (CLI) -> v${LIB_INFO.currentVersion} (Framework)${COLORS.RESET}\n` +
88
- `${COLORS.GRAY}Status: ${LIB_INFO.status}${COLORS.RESET}`;
89
- throw new Error(stripAnsi(message));
251
+
252
+ class Logger {
253
+ minLevel;
254
+ constructor(debugMode = false) {
255
+ this.minLevel = debugMode ? 'debug' : 'info';
256
+ }
257
+ setDebug(enabled) {
258
+ this.minLevel = enabled ? 'debug' : 'info';
259
+ }
260
+ shouldLog(level) {
261
+ const levels = { debug: 0, info: 1, warn: 2, error: 3 };
262
+ return levels[level] >= levels[this.minLevel];
263
+ }
264
+ log(level, message, context) {
265
+ if (!this.shouldLog(level))
266
+ return;
267
+ const ts = new Date().toISOString();
268
+ const ctx = context ? ` ${safeStringify(context)}` : '';
269
+ console.log(`[${ts}] ${level.toUpperCase()}: ${message}${ctx}`);
270
+ }
271
+ debug(msg, ctx) {
272
+ this.log('debug', msg, ctx);
273
+ }
274
+ info(msg, ctx) {
275
+ this.log('info', msg, ctx);
276
+ }
277
+ warn(msg, ctx) {
278
+ this.log('warn', msg, ctx);
279
+ }
280
+ error(msg, ctx) {
281
+ this.log('error', msg, ctx);
282
+ }
90
283
  }
91
- function isStable() {
92
- return LIB_INFO.status !== LibraryStatus.UNDER_CONSTRUCTION;
284
+
285
+ function normalizeOptions(opts) {
286
+ return {
287
+ headless: opts?.headless ?? DEFAULTS.headless,
288
+ debug: opts?.debug ?? false,
289
+ userAgent: opts?.userAgent ?? DEFAULTS.userAgent,
290
+ timeout: opts?.timeout ?? DEFAULTS.timeout,
291
+ };
93
292
  }
94
- function assertStable() {
95
- if (LIB_INFO.status === LibraryStatus.UNDER_CONSTRUCTION) {
96
- throw new Error(`[${LIB_INFO.name}] Cannot use unstable version ${LIB_INFO.currentVersion} in production. ` +
97
- `Status: ${LIB_INFO.status}`);
293
+
294
+ async function downloadSfile(url, saveDir, options) {
295
+ const opts = normalizeOptions(options);
296
+ const logger = new Logger(opts.debug);
297
+ if (!url || !url.includes('sfile.co')) {
298
+ throw new ValidationError('URL must contain sfile.co', { url });
299
+ }
300
+ await fs__default.mkdir(saveDir, { recursive: true });
301
+ const browserMgr = new BrowserManager(logger, {
302
+ headless: opts.headless,
303
+ userAgent: opts.userAgent,
304
+ timeout: opts.timeout,
305
+ debug: opts.debug,
306
+ });
307
+ try {
308
+ await browserMgr.launch();
309
+ await browserMgr.goto(url, 'networkidle');
310
+ await browserMgr.waitForDownloadButton();
311
+ const intermediateUrl = await browserMgr.getIntermediateUrl();
312
+ const autoUrl = intermediateUrl.includes('?')
313
+ ? `${intermediateUrl}&auto=1`
314
+ : `${intermediateUrl}?auto=1`;
315
+ let download = await browserMgr.startDownloadAndWait(autoUrl);
316
+ let finalPath;
317
+ let fileSize;
318
+ let method;
319
+ if (download) {
320
+ const suggested = download.suggestedFilename() || 'file.bin';
321
+ const filename = sanitizeFilename(suggested);
322
+ finalPath = path.join(saveDir, filename);
323
+ await download.saveAs(finalPath);
324
+ const stat = await fs__default.stat(finalPath);
325
+ fileSize = stat.size;
326
+ method = 'direct';
327
+ logger.info(`Saved via direct download: ${finalPath} (${fileSize} bytes)`);
328
+ }
329
+ else {
330
+ const fallback = await browserMgr.fallbackCollectFileResponse();
331
+ if (!fallback) {
332
+ throw new NetworkError('No download event and no file response found');
333
+ }
334
+ const { buffer, filename: rawName } = fallback;
335
+ const filename = sanitizeFilename(rawName);
336
+ finalPath = path.join(saveDir, filename);
337
+ await fs__default.writeFile(finalPath, buffer);
338
+ fileSize = buffer.length;
339
+ method = 'fallback';
340
+ logger.info(`Saved via fallback: ${finalPath} (${fileSize} bytes)`);
341
+ }
342
+ return { filePath: finalPath, size: fileSize, method };
343
+ }
344
+ catch (err) {
345
+ await browserMgr.saveDebugArtifacts(err.message);
346
+ throw err;
347
+ }
348
+ finally {
349
+ await browserMgr.close();
98
350
  }
99
- }
100
- if (isDevelopmentVersion()) {
101
- LibStatus.getInstance();
102
351
  }
103
352
 
104
- export { LIB_INFO, LibStatus, LibraryStatus, assertStable, initFramework, isDevelopmentVersion, isStable };
353
+ export { AppError, BrowserError, FileError, NetworkError, ValidationError, downloadSfile };
105
354
  //# sourceMappingURL=lib.mjs.map
package/build/lib.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"lib.mjs","sources":["../lib/lib.ts"],"sourcesContent":["/**\n * ====================================================================================================\n * WARNING: LIBRARY UNDER ACTIVE DEVELOPMENT - NOT FOR PRODUCTION USE\n * ====================================================================================================\n * \n * Status: DEPRECATED / UNSTABLE\n * Previous Version: 1.0.2 (CLI-based architecture)\n * Target Version: 2.0.1 (Full framework architecture)\n * \n * BREAKING CHANGES NOTICE:\n * - This library is undergoing a complete rewrite and architectural refactor.\n * - Legacy CLI-based implementation has been entirely removed.\n * - New framework-based architecture is currently under active development.\n * \n * PRODUCTION USE PROHIBITED:\n * - API surface is subject to change without notice.\n * - No backward compatibility guarantees.\n * - Use exclusively for development and testing purposes.\n * \n * ====================================================================================================\n */\n\n// ANSI color codes for terminal output\nconst COLORS = {\n RESET: \"\\x1b[0m\",\n BRIGHT: \"\\x1b[1m\",\n YELLOW: \"\\x1b[33m\",\n RED: \"\\x1b[31m\",\n CYAN: \"\\x1b[36m\",\n GRAY: \"\\x1b[90m\",\n} as const;\n\n/**\n * Development status of the library.\n */\nexport enum LibraryStatus {\n /** Library is under active construction, not ready for production. */\n UNDER_CONSTRUCTION = \"UNDER_CONSTRUCTION\",\n /** Library is stable and ready for production. (Future use) */\n STABLE = \"STABLE\",\n /** Library is deprecated. (Future use) */\n DEPRECATED = \"DEPRECATED\",\n}\n\n/**\n * Library metadata.\n */\nexport const LIB_INFO = {\n name: \"MySuperFramework\",\n currentVersion: \"2.0.1-dev\",\n previousVersion: \"1.0.2\",\n status: LibraryStatus.UNDER_CONSTRUCTION,\n isDeprecated: true,\n message: \"This version represents a complete architectural refactor from CLI to framework. Not stable.\",\n} as const;\n\n// Flag to ensure warning is displayed only once\nlet warningDisplayed = false;\n\n/**\n * Utility function to strip ANSI escape codes from a string.\n * Supports common ANSI sequences (colors, styles, etc.).\n * @param text - Text containing ANSI escape sequences.\n * @returns Plain text without ANSI formatting.\n */\nfunction stripAnsi(text: string): string {\n // Matches ANSI escape sequences: \\x1b[ (or \\u001b[) followed by any number of parameters and ending with a letter\n return text.replace(/\\x1b\\[[0-9;]*[a-zA-Z]/g, \"\");\n}\n\n/**\n * Checks if the library is currently in development mode.\n * @returns `true` if the library status is `UNDER_CONSTRUCTION`.\n */\nexport function isDevelopmentVersion(): boolean {\n return LIB_INFO.status === LibraryStatus.UNDER_CONSTRUCTION;\n}\n\n/**\n * Primary class for library status management and developer notifications.\n * Provides programmatic access to version information and stability checks.\n */\nexport class LibStatus {\n private static instance: LibStatus | undefined;\n\n private constructor() {\n this.displayDeveloperWarning();\n }\n\n /**\n * Gets the singleton instance of LibStatus.\n * @returns The LibStatus instance.\n */\n public static getInstance(): LibStatus {\n if (!LibStatus.instance) {\n LibStatus.instance = new LibStatus();\n }\n return LibStatus.instance;\n }\n\n /**\n * Outputs formatted warning message to console upon library initialization.\n * Uses ANSI color codes for enhanced visibility in terminal environments.\n * The warning is displayed only once per process, unless suppressed.\n */\n private displayDeveloperWarning(): void {\n // Skip if console is not available or warning already displayed\n if (typeof console === \"undefined\" || typeof console.warn !== \"function\") {\n return;\n }\n if (warningDisplayed) {\n return;\n }\n // Check environment variable to suppress warning (e.g., for testing)\n // Use bracket notation to avoid TypeScript index signature error\n if (typeof process !== \"undefined\" && process.env && process.env['MY_SUPER_FRAMEWORK_SUPPRESS_WARNING'] === \"true\") {\n return;\n }\n\n const border = `${COLORS.GRAY}${\"=\".repeat(80)}${COLORS.RESET}`;\n const label = `${COLORS.YELLOW}${COLORS.BRIGHT}[WARNING]${COLORS.RESET}`;\n const highlight = `${COLORS.CYAN}`;\n\n console.warn(`\\n${border}`);\n console.warn(`${label} DEVELOPMENT VERSION IN USE`);\n console.warn(`${COLORS.GRAY}Library: ${COLORS.RESET}${highlight}${LIB_INFO.name}${COLORS.RESET}`);\n console.warn(`${COLORS.GRAY}Current Version: ${COLORS.RESET}${highlight}${LIB_INFO.currentVersion}${COLORS.RESET}`);\n console.warn(`${COLORS.GRAY}Previous Version: ${COLORS.RESET}${highlight}${LIB_INFO.previousVersion}${COLORS.RESET}`);\n console.warn(`${COLORS.GRAY}Architecture: ${COLORS.RESET}${highlight}CLI -> Framework (Full Refactor)${COLORS.RESET}`);\n console.warn(`\\n${COLORS.RED}${COLORS.BRIGHT}DO NOT USE IN PRODUCTION ENVIRONMENTS${COLORS.RESET}`);\n console.warn(`${COLORS.GRAY}API stability is not guaranteed. Breaking changes may occur without notice.${COLORS.RESET}`);\n console.warn(`${COLORS.GRAY}To suppress this warning, set env MY_SUPER_FRAMEWORK_SUPPRESS_WARNING=true${COLORS.RESET}`);\n console.warn(`${border}\\n`);\n\n warningDisplayed = true;\n }\n\n /**\n * Suppresses the development warning for this instance.\n * Useful when you need to programmatically disable the warning (e.g., in tests).\n */\n public suppressWarning(): void {\n warningDisplayed = true;\n }\n\n /**\n * Validates library stability status.\n * @throws Error if library is marked as unstable or under construction.\n */\n public ensureStable(): void {\n if (LIB_INFO.status === LibraryStatus.UNDER_CONSTRUCTION) {\n const errorMessage = `${COLORS.RED}${COLORS.BRIGHT}[${LIB_INFO.name}] Stability Check Failed${COLORS.RESET}\\n` +\n `${COLORS.GRAY}Library version ${LIB_INFO.currentVersion} is under active development.${COLORS.RESET}\\n` +\n `${COLORS.GRAY}Current status: ${LIB_INFO.status}${COLORS.RESET}`;\n\n throw new Error(stripAnsi(errorMessage));\n }\n }\n\n /**\n * Returns the current library version string.\n * @returns Version identifier in semver format.\n */\n public getVersion(): string {\n return LIB_INFO.currentVersion;\n }\n\n /**\n * Returns detailed library metadata.\n * @returns Readonly object containing library information.\n */\n public getInfo(): Readonly<typeof LIB_INFO> {\n return LIB_INFO;\n }\n}\n\n/**\n * Placeholder entry point for framework initialization.\n * Intentionally throws error to prevent usage during development phase.\n * @throws Error indicating framework is not ready for use.\n */\nexport function initFramework(): never {\n const message = `${COLORS.RED}${COLORS.BRIGHT}[${LIB_INFO.name}] Initialization Blocked${COLORS.RESET}\\n` +\n `${COLORS.GRAY}Framework is undergoing complete architectural refactor.${COLORS.RESET}\\n` +\n `${COLORS.GRAY}Migration path: v${LIB_INFO.previousVersion} (CLI) -> v${LIB_INFO.currentVersion} (Framework)${COLORS.RESET}\\n` +\n `${COLORS.GRAY}Status: ${LIB_INFO.status}${COLORS.RESET}`;\n\n throw new Error(stripAnsi(message));\n}\n\n/**\n * Type guard to check if current version is stable.\n * @returns `false` if library is under construction, `true` otherwise.\n */\nexport function isStable(): boolean {\n return LIB_INFO.status !== LibraryStatus.UNDER_CONSTRUCTION;\n}\n\n/**\n * Throws an error if the library is not stable.\n * Use this at the start of your application to ensure you're not using an unstable version.\n * @throws Error when library is under construction.\n */\nexport function assertStable(): void {\n if (LIB_INFO.status === LibraryStatus.UNDER_CONSTRUCTION) {\n throw new Error(\n `[${LIB_INFO.name}] Cannot use unstable version ${LIB_INFO.currentVersion} in production. ` +\n `Status: ${LIB_INFO.status}`\n );\n }\n}\n\n// Immediate execution block: displays warning upon module import (only once)\n// Does not throw to allow type-checking and development workflows\nif (isDevelopmentVersion()) {\n // Trigger singleton instantiation which displays the warning\n LibStatus.getInstance();\n}"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"lib.mjs","sources":["../lib/errors/base.ts","../lib/errors/errors.ts","../lib/config/defaults.ts","../lib/browser/page-interactions.ts","../lib/utils/helpers.ts","../lib/browser/browser-manager.ts","../lib/utils/logger.ts","../lib/config/schema.ts","../lib/core/downloader.ts"],"sourcesContent":["export abstract class AppError extends Error {\n\tpublic readonly timestamp: string\n\tpublic readonly context: Record<string, unknown> | undefined\n\tconstructor(\n\t\tmessage: string,\n\t\tpublic readonly code: string,\n\t\tpublic readonly retryable: boolean = false,\n\t\tcontext?: Record<string, unknown>,\n\t) {\n\t\tsuper(message)\n\t\tthis.name = this.constructor.name\n\t\tthis.timestamp = new Date().toISOString()\n\t\tthis.context = context ? { ...context } : undefined\n\t\tError.captureStackTrace?.(this, this.constructor)\n\t}\n\ttoJSON() {\n\t\treturn {\n\t\t\tname: this.name,\n\t\t\tmessage: this.message,\n\t\t\tcode: this.code,\n\t\t\tretryable: this.retryable,\n\t\t\ttimestamp: this.timestamp,\n\t\t\tcontext: this.context,\n\t\t}\n\t}\n}\n","import { AppError } from './base.js'\nexport class ValidationError extends AppError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'VALIDATION_ERROR', false, context)\n\t}\n}\nexport class NetworkError extends AppError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'NETWORK_ERROR', true, context)\n\t}\n}\nexport class FileError extends AppError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'FILE_ERROR', false, context)\n\t}\n}\nexport class BrowserError extends AppError {\n\tconstructor(message: string, context?: Record<string, unknown>) {\n\t\tsuper(message, 'BROWSER_ERROR', true, context)\n\t}\n}\n","export const DEFAULTS = {\n\tuserAgent:\n\t\t'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36',\n\theadless: true,\n\ttimeout: 100000,\n\tdownloadButtonTimeout: 100000,\n\tfallbackWaitMs: 5000,\n}\n","import { Page } from 'playwright'\nimport { Logger } from '../utils/logger.js'\nimport { NetworkError } from '../errors/index.js'\nexport class SfilePageInteractions {\n\tconstructor(\n\t\tprivate page: Page,\n\t\tprivate logger: Logger,\n\t) {}\n\tasync waitForDownloadButton(timeout: number): Promise<void> {\n\t\tthis.logger.debug('Waiting for #download button to be visible')\n\t\tconst button = this.page.locator('#download')\n\t\tawait button.waitFor({ state: 'visible', timeout })\n\t\tthis.logger.debug(\n\t\t\t'Waiting for button to become active (href != \"#\" and pointerEvents != \"none\")',\n\t\t)\n\t\tawait this.page.waitForFunction(\n\t\t\t() => {\n\t\t\t\tconst btn = document.querySelector('#download') as HTMLAnchorElement | null\n\t\t\t\tif (!btn) return false\n\t\t\t\tconst href = btn.getAttribute('href')\n\t\t\t\tconst style = window.getComputedStyle(btn)\n\t\t\t\treturn href && href !== '#' && style.pointerEvents !== 'none'\n\t\t\t},\n\t\t\t{ timeout },\n\t\t)\n\t}\n\tasync extractIntermediateUrl(): Promise<string> {\n\t\tthis.logger.debug('Extracting href from #download')\n\t\tconst href = await this.page.$eval('#download', (el) => (el as HTMLAnchorElement).href)\n\t\tif (!href || href === '#') {\n\t\t\tthrow new NetworkError('Download button href is invalid', { href })\n\t\t}\n\t\treturn href\n\t}\n}\n","export function sanitizeFilename(name: string, replacement = '_'): string {\n\tconst sanitized = name\n\t\t.replace(/[<>:\"/\\\\|?*\\x00-\\x1F]/g, replacement)\n\t\t.replace(new RegExp(`${replacement}+`, 'g'), replacement)\n\t\t.trim()\n\t\t.slice(0, 255)\n\treturn sanitized || 'file.bin'\n}\nexport const sleep = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))\nexport function safeStringify(value: unknown): string {\n\ttry {\n\t\treturn JSON.stringify(value)\n\t} catch {\n\t\treturn '[unserializable]'\n\t}\n}\n","import { chromium, Browser, BrowserContext, Page, Download, Response } from 'playwright'\nimport * as fs from 'fs/promises'\nimport path from 'path'\nimport os from 'os'\nimport { Logger } from '../utils/logger.js'\nimport { BrowserError, NetworkError } from '../errors/index.js'\nimport { DEFAULTS } from '../config/defaults.js'\nimport { SfilePageInteractions } from './page-interactions.js'\nimport { sleep } from '../utils/helpers.js'\nexport interface BrowserManagerOptions {\n\theadless: boolean\n\tuserAgent: string\n\ttimeout: number\n\tdebug: boolean\n}\nexport class BrowserManager {\n\tprivate browser: Browser | null = null\n\tprivate context: BrowserContext | null = null\n\tprivate page: Page | null = null\n\tprivate interactions: SfilePageInteractions | null = null\n\tprivate debugDir: string | null = null\n\tconstructor(\n\t\tprivate logger: Logger,\n\t\tprivate opts: BrowserManagerOptions,\n\t) {}\n\tasync launch(): Promise<void> {\n\t\ttry {\n\t\t\tthis.logger.info('Launching browser', { headless: this.opts.headless })\n\t\t\tthis.browser = await chromium.launch({\n\t\t\t\theadless: this.opts.headless,\n\t\t\t\targs: ['--no-sandbox', '--disable-setuid-sandbox', '--disable-dev-shm-usage'],\n\t\t\t})\n\t\t\tthis.context = await this.browser.newContext({\n\t\t\t\tuserAgent: this.opts.userAgent,\n\t\t\t\tacceptDownloads: true,\n\t\t\t\tlocale: 'en-US',\n\t\t\t})\n\t\t\tawait this.context.addCookies([\n\t\t\t\t{\n\t\t\t\t\tname: 'safe_link_counter',\n\t\t\t\t\tvalue: '1',\n\t\t\t\t\tdomain: '.sfile.co',\n\t\t\t\t\tpath: '/',\n\t\t\t\t\texpires: Math.floor(Date.now() / 1000) + 3600,\n\t\t\t\t},\n\t\t\t])\n\t\t\tthis.page = await this.context.newPage()\n\t\t\tthis.interactions = new SfilePageInteractions(this.page, this.logger)\n\t\t\tif (this.opts.debug) {\n\t\t\t\tthis.page.on('console', (msg) => {\n\t\t\t\t\tif (msg.type() === 'error') this.logger.error(`[console] ${msg.text()}`)\n\t\t\t\t\telse if (msg.type() === 'warning') this.logger.warn(`[console] ${msg.text()}`)\n\t\t\t\t})\n\t\t\t\tthis.page.on('pageerror', (err) => this.logger.error(`[pageerror] ${err.message}`))\n\t\t\t}\n\t\t\tthis.logger.info('Browser ready')\n\t\t} catch (err: any) {\n\t\t\tthrow new BrowserError(`Failed to launch browser: ${err.message}`)\n\t\t}\n\t}\n\tasync goto(\n\t\turl: string,\n\t\twaitUntil: 'load' | 'networkidle' | 'commit' = 'networkidle',\n\t): Promise<void> {\n\t\tif (!this.page) throw new BrowserError('Page not initialized')\n\t\ttry {\n\t\t\tthis.logger.debug(`Navigating to ${url} (waitUntil=${waitUntil})`)\n\t\t\tawait this.page.goto(url, { waitUntil, timeout: this.opts.timeout })\n\t\t} catch (err: any) {\n\t\t\tthrow new NetworkError(`Navigation failed: ${err.message}`, { url })\n\t\t}\n\t}\n\tasync waitForDownloadButton(): Promise<void> {\n\t\tif (!this.interactions) throw new BrowserError('Interactions not ready')\n\t\tawait this.interactions.waitForDownloadButton(DEFAULTS.downloadButtonTimeout)\n\t}\n\tasync getIntermediateUrl(): Promise<string> {\n\t\tif (!this.interactions) throw new BrowserError('Interactions not ready')\n\t\treturn this.interactions.extractIntermediateUrl()\n\t}\n\tasync startDownloadAndWait(autoUrl: string): Promise<Download | null> {\n\t\tif (!this.page) throw new BrowserError('Page not initialized')\n\t\tconst downloadPromise = this.page\n\t\t\t.waitForEvent('download', { timeout: this.opts.timeout })\n\t\t\t.catch((err) => {\n\t\t\t\tthis.logger.warn(`Download event wait failed: ${err.message}`)\n\t\t\t\treturn null\n\t\t\t})\n\t\tthis.logger.debug(`Navigating to auto URL: ${autoUrl}`)\n\t\tawait this.page.goto(autoUrl, { waitUntil: 'commit', timeout: this.opts.timeout })\n\t\tconst download = await downloadPromise\n\t\tif (download) {\n\t\t\tthis.logger.info('Download event captured')\n\t\t\treturn download\n\t\t}\n\t\treturn null\n\t}\n\tasync fallbackCollectFileResponse(): Promise<{ buffer: Buffer; filename: string } | null> {\n\t\tif (!this.page) throw new BrowserError('Page not initialized')\n\t\tthis.logger.warn('Falling back to response interception')\n\t\tconst responses: Response[] = []\n\t\tconst handler = (res: Response) => responses.push(res)\n\t\tthis.page.on('response', handler)\n\t\tawait sleep(DEFAULTS.fallbackWaitMs)\n\t\tthis.page.off('response', handler)\n\t\tconst fileResponse = [...responses].reverse().find((r) => {\n\t\t\tconst disposition = r.headers()['content-disposition']\n\t\t\treturn (\n\t\t\t\t(disposition && disposition.includes('attachment')) ||\n\t\t\t\tr.url().includes('/downloadfile/')\n\t\t\t)\n\t\t})\n\t\tif (!fileResponse) return null\n\t\tconst buffer = await fileResponse.body()\n\t\tlet filename = fileResponse.url().split('/').pop()?.split('?')[0] || 'file.bin'\n\t\tfilename = filename.replace(/[<>:\"/\\\\|?*]/g, '_')\n\t\treturn { buffer, filename }\n\t}\n\tasync saveDebugArtifacts(errorMessage: string): Promise<void> {\n\t\tif (!this.page) return\n\t\ttry {\n\t\t\tthis.debugDir = path.join(os.tmpdir(), `sfile_debug_${Date.now()}`)\n\t\t\tawait fs.mkdir(this.debugDir, { recursive: true })\n\t\t\tawait Promise.all([\n\t\t\t\tthis.page.screenshot({\n\t\t\t\t\tpath: path.join(this.debugDir, 'error.png'),\n\t\t\t\t\tfullPage: true,\n\t\t\t\t}),\n\t\t\t\tfs.writeFile(path.join(this.debugDir, 'error.html'), await this.page.content()),\n\t\t\t\tfs.writeFile(path.join(this.debugDir, 'error.txt'), errorMessage),\n\t\t\t])\n\t\t\tthis.logger.info(`Debug artifacts saved to ${this.debugDir}`)\n\t\t} catch (e: any) {\n\t\t\tthis.logger.error(`Failed to save debug artifacts: ${e.message}`)\n\t\t}\n\t}\n\tasync close(): Promise<void> {\n\t\tif (this.page) await this.page.close().catch(() => {})\n\t\tif (this.context) await this.context.close().catch(() => {})\n\t\tif (this.browser) await this.browser.close().catch(() => {})\n\t\tthis.logger.debug('Browser closed')\n\t}\n}\n","import { safeStringify } from './helpers.js'\ntype LogLevel = 'debug' | 'info' | 'warn' | 'error'\nexport class Logger {\n\tprivate minLevel: LogLevel\n\tconstructor(debugMode = false) {\n\t\tthis.minLevel = debugMode ? 'debug' : 'info'\n\t}\n\tsetDebug(enabled: boolean) {\n\t\tthis.minLevel = enabled ? 'debug' : 'info'\n\t}\n\tprivate shouldLog(level: LogLevel): boolean {\n\t\tconst levels: Record<LogLevel, number> = { debug: 0, info: 1, warn: 2, error: 3 }\n\t\treturn levels[level] >= levels[this.minLevel]\n\t}\n\tprivate log(level: LogLevel, message: string, context?: any) {\n\t\tif (!this.shouldLog(level)) return\n\t\tconst ts = new Date().toISOString()\n\t\tconst ctx = context ? ` ${safeStringify(context)}` : ''\n\t\tconsole.log(`[${ts}] ${level.toUpperCase()}: ${message}${ctx}`)\n\t}\n\tdebug(msg: string, ctx?: any) {\n\t\tthis.log('debug', msg, ctx)\n\t}\n\tinfo(msg: string, ctx?: any) {\n\t\tthis.log('info', msg, ctx)\n\t}\n\twarn(msg: string, ctx?: any) {\n\t\tthis.log('warn', msg, ctx)\n\t}\n\terror(msg: string, ctx?: any) {\n\t\tthis.log('error', msg, ctx)\n\t}\n}\n","import { DEFAULTS } from './defaults.js'\nexport interface DownloadOptions {\n\theadless?: boolean\n\tdebug?: boolean\n\tuserAgent?: string\n\ttimeout?: number\n}\nexport interface DownloadResult {\n\tfilePath: string\n\tsize: number\n\tmethod: 'direct' | 'fallback'\n}\nexport function normalizeOptions(opts?: DownloadOptions) {\n\treturn {\n\t\theadless: opts?.headless ?? DEFAULTS.headless,\n\t\tdebug: opts?.debug ?? false,\n\t\tuserAgent: opts?.userAgent ?? DEFAULTS.userAgent,\n\t\ttimeout: opts?.timeout ?? DEFAULTS.timeout,\n\t}\n}\n","import path from 'path'\nimport fs from 'fs/promises'\nimport { BrowserManager } from '../browser/browser-manager.js'\nimport { Logger } from '../utils/logger.js'\nimport { ValidationError, NetworkError } from '../errors/index.js'\nimport { DownloadOptions, DownloadResult, normalizeOptions } from '../config/schema.js'\nimport { sanitizeFilename } from '../utils/helpers.js'\nexport async function downloadSfile(\n\turl: string,\n\tsaveDir: string,\n\toptions?: DownloadOptions,\n): Promise<DownloadResult> {\n\tconst opts = normalizeOptions(options)\n\tconst logger = new Logger(opts.debug)\n\tif (!url || !url.includes('sfile.co')) {\n\t\tthrow new ValidationError('URL must contain sfile.co', { url })\n\t}\n\tawait fs.mkdir(saveDir, { recursive: true })\n\tconst browserMgr = new BrowserManager(logger, {\n\t\theadless: opts.headless,\n\t\tuserAgent: opts.userAgent,\n\t\ttimeout: opts.timeout,\n\t\tdebug: opts.debug,\n\t})\n\ttry {\n\t\tawait browserMgr.launch()\n\t\tawait browserMgr.goto(url, 'networkidle')\n\t\tawait browserMgr.waitForDownloadButton()\n\t\tconst intermediateUrl = await browserMgr.getIntermediateUrl()\n\t\tconst autoUrl = intermediateUrl.includes('?')\n\t\t\t? `${intermediateUrl}&auto=1`\n\t\t\t: `${intermediateUrl}?auto=1`\n\t\tlet download = await browserMgr.startDownloadAndWait(autoUrl)\n\t\tlet finalPath: string\n\t\tlet fileSize: number\n\t\tlet method: 'direct' | 'fallback'\n\t\tif (download) {\n\t\t\tconst suggested = download.suggestedFilename() || 'file.bin'\n\t\t\tconst filename = sanitizeFilename(suggested)\n\t\t\tfinalPath = path.join(saveDir, filename)\n\t\t\tawait download.saveAs(finalPath)\n\t\t\tconst stat = await fs.stat(finalPath)\n\t\t\tfileSize = stat.size\n\t\t\tmethod = 'direct'\n\t\t\tlogger.info(`Saved via direct download: ${finalPath} (${fileSize} bytes)`)\n\t\t} else {\n\t\t\tconst fallback = await browserMgr.fallbackCollectFileResponse()\n\t\t\tif (!fallback) {\n\t\t\t\tthrow new NetworkError('No download event and no file response found')\n\t\t\t}\n\t\t\tconst { buffer, filename: rawName } = fallback\n\t\t\tconst filename = sanitizeFilename(rawName)\n\t\t\tfinalPath = path.join(saveDir, filename)\n\t\t\tawait fs.writeFile(finalPath, buffer)\n\t\t\tfileSize = buffer.length\n\t\t\tmethod = 'fallback'\n\t\t\tlogger.info(`Saved via fallback: ${finalPath} (${fileSize} bytes)`)\n\t\t}\n\t\treturn { filePath: finalPath, size: fileSize, method }\n\t} catch (err: any) {\n\t\tawait browserMgr.saveDebugArtifacts(err.message)\n\t\tthrow err\n\t} finally {\n\t\tawait browserMgr.close()\n\t}\n}\n"],"names":["fs"],"mappings":";;;;;;AAAM,MAAgB,QAAS,SAAQ,KAAK,CAAA;AAK1B,IAAA,IAAA;AACA,IAAA,SAAA;AALD,IAAA,SAAS;AACT,IAAA,OAAO;AACvB,IAAA,WAAA,CACC,OAAe,EACC,IAAY,EACZ,SAAA,GAAqB,KAAK,EAC1C,OAAiC,EAAA;QAEjC,KAAK,CAAC,OAAO,CAAC;QAJE,IAAA,CAAA,IAAI,GAAJ,IAAI;QACJ,IAAA,CAAA,SAAS,GAAT,SAAS;QAIzB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI;QACjC,IAAI,CAAC,SAAS,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACzC,QAAA,IAAI,CAAC,OAAO,GAAG,OAAO,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,SAAS;QACnD,KAAK,CAAC,iBAAiB,GAAG,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC;IAClD;IACA,MAAM,GAAA;QACL,OAAO;YACN,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,SAAS,EAAE,IAAI,CAAC,SAAS;YACzB,OAAO,EAAE,IAAI,CAAC,OAAO;SACrB;IACF;AACA;;ACxBK,MAAO,eAAgB,SAAQ,QAAQ,CAAA;IAC5C,WAAA,CAAY,OAAe,EAAE,OAAiC,EAAA;QAC7D,KAAK,CAAC,OAAO,EAAE,kBAAkB,EAAE,KAAK,EAAE,OAAO,CAAC;IACnD;AACA;AACK,MAAO,YAAa,SAAQ,QAAQ,CAAA;IACzC,WAAA,CAAY,OAAe,EAAE,OAAiC,EAAA;QAC7D,KAAK,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,CAAC;IAC/C;AACA;AACK,MAAO,SAAU,SAAQ,QAAQ,CAAA;IACtC,WAAA,CAAY,OAAe,EAAE,OAAiC,EAAA;QAC7D,KAAK,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,CAAC;IAC7C;AACA;AACK,MAAO,YAAa,SAAQ,QAAQ,CAAA;IACzC,WAAA,CAAY,OAAe,EAAE,OAAiC,EAAA;QAC7D,KAAK,CAAC,OAAO,EAAE,eAAe,EAAE,IAAI,EAAE,OAAO,CAAC;IAC/C;AACA;;ACpBM,MAAM,QAAQ,GAAG;AACvB,IAAA,SAAS,EACR,iHAAiH;AAClH,IAAA,QAAQ,EAAE,IAAI;AACd,IAAA,OAAO,EAAE,MAAM;AACf,IAAA,qBAAqB,EAAE,MAAM;AAC7B,IAAA,cAAc,EAAE,IAAI;CACpB;;MCJY,qBAAqB,CAAA;AAExB,IAAA,IAAA;AACA,IAAA,MAAA;IAFT,WAAA,CACS,IAAU,EACV,MAAc,EAAA;QADd,IAAA,CAAA,IAAI,GAAJ,IAAI;QACJ,IAAA,CAAA,MAAM,GAAN,MAAM;IACZ;IACH,MAAM,qBAAqB,CAAC,OAAe,EAAA;AAC1C,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC;QAC/D,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC;AAC7C,QAAA,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;AACnD,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAChB,+EAA+E,CAC/E;AACD,QAAA,MAAM,IAAI,CAAC,IAAI,CAAC,eAAe,CAC9B,MAAK;YACJ,MAAM,GAAG,GAAG,QAAQ,CAAC,aAAa,CAAC,WAAW,CAA6B;AAC3E,YAAA,IAAI,CAAC,GAAG;AAAE,gBAAA,OAAO,KAAK;YACtB,MAAM,IAAI,GAAG,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC;YACrC,MAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC,GAAG,CAAC;YAC1C,OAAO,IAAI,IAAI,IAAI,KAAK,GAAG,IAAI,KAAK,CAAC,aAAa,KAAK,MAAM;AAC9D,QAAA,CAAC,EACD,EAAE,OAAO,EAAE,CACX;IACF;AACA,IAAA,MAAM,sBAAsB,GAAA;AAC3B,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gCAAgC,CAAC;QACnD,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,EAAE,KAAM,EAAwB,CAAC,IAAI,CAAC;AACvF,QAAA,IAAI,CAAC,IAAI,IAAI,IAAI,KAAK,GAAG,EAAE;YAC1B,MAAM,IAAI,YAAY,CAAC,iCAAiC,EAAE,EAAE,IAAI,EAAE,CAAC;QACpE;AACA,QAAA,OAAO,IAAI;IACZ;AACA;;SClCe,gBAAgB,CAAC,IAAY,EAAE,WAAW,GAAG,GAAG,EAAA;IAC/D,MAAM,SAAS,GAAG;AAChB,SAAA,OAAO,CAAC,wBAAwB,EAAE,WAAW;AAC7C,SAAA,OAAO,CAAC,IAAI,MAAM,CAAC,CAAA,EAAG,WAAW,CAAA,CAAA,CAAG,EAAE,GAAG,CAAC,EAAE,WAAW;AACvD,SAAA,IAAI;AACJ,SAAA,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;IACf,OAAO,SAAS,IAAI,UAAU;AAC/B;AACO,MAAM,KAAK,GAAG,CAAC,EAAU,KAAK,IAAI,OAAO,CAAC,CAAC,OAAO,KAAK,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC;AAChF,SAAU,aAAa,CAAC,KAAc,EAAA;AAC3C,IAAA,IAAI;AACH,QAAA,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;IAC7B;AAAE,IAAA,MAAM;AACP,QAAA,OAAO,kBAAkB;IAC1B;AACD;;MCAa,cAAc,CAAA;AAOjB,IAAA,MAAA;AACA,IAAA,IAAA;IAPD,OAAO,GAAmB,IAAI;IAC9B,OAAO,GAA0B,IAAI;IACrC,IAAI,GAAgB,IAAI;IACxB,YAAY,GAAiC,IAAI;IACjD,QAAQ,GAAkB,IAAI;IACtC,WAAA,CACS,MAAc,EACd,IAA2B,EAAA;QAD3B,IAAA,CAAA,MAAM,GAAN,MAAM;QACN,IAAA,CAAA,IAAI,GAAJ,IAAI;IACV;AACH,IAAA,MAAM,MAAM,GAAA;AACX,QAAA,IAAI;AACH,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,mBAAmB,EAAE,EAAE,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC;AACvE,YAAA,IAAI,CAAC,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;AACpC,gBAAA,QAAQ,EAAE,IAAI,CAAC,IAAI,CAAC,QAAQ;AAC5B,gBAAA,IAAI,EAAE,CAAC,cAAc,EAAE,0BAA0B,EAAE,yBAAyB,CAAC;AAC7E,aAAA,CAAC;YACF,IAAI,CAAC,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;AAC5C,gBAAA,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS;AAC9B,gBAAA,eAAe,EAAE,IAAI;AACrB,gBAAA,MAAM,EAAE,OAAO;AACf,aAAA,CAAC;AACF,YAAA,MAAM,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC;AAC7B,gBAAA;AACC,oBAAA,IAAI,EAAE,mBAAmB;AACzB,oBAAA,KAAK,EAAE,GAAG;AACV,oBAAA,MAAM,EAAE,WAAW;AACnB,oBAAA,IAAI,EAAE,GAAG;AACT,oBAAA,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,IAAI;AAC7C,iBAAA;AACD,aAAA,CAAC;YACF,IAAI,CAAC,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE;AACxC,YAAA,IAAI,CAAC,YAAY,GAAG,IAAI,qBAAqB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC;AACrE,YAAA,IAAI,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE;gBACpB,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,SAAS,EAAE,CAAC,GAAG,KAAI;AAC/B,oBAAA,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,OAAO;AAAE,wBAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,UAAA,EAAa,GAAG,CAAC,IAAI,EAAE,CAAA,CAAE,CAAC;AACnE,yBAAA,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,SAAS;AAAE,wBAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA,UAAA,EAAa,GAAG,CAAC,IAAI,EAAE,CAAA,CAAE,CAAC;AAC/E,gBAAA,CAAC,CAAC;gBACF,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,WAAW,EAAE,CAAC,GAAG,KAAK,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,YAAA,EAAe,GAAG,CAAC,OAAO,CAAA,CAAE,CAAC,CAAC;YACpF;AACA,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC;QAClC;QAAE,OAAO,GAAQ,EAAE;YAClB,MAAM,IAAI,YAAY,CAAC,CAAA,0BAAA,EAA6B,GAAG,CAAC,OAAO,CAAA,CAAE,CAAC;QACnE;IACD;AACA,IAAA,MAAM,IAAI,CACT,GAAW,EACX,YAA+C,aAAa,EAAA;QAE5D,IAAI,CAAC,IAAI,CAAC,IAAI;AAAE,YAAA,MAAM,IAAI,YAAY,CAAC,sBAAsB,CAAC;AAC9D,QAAA,IAAI;YACH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,cAAA,EAAiB,GAAG,CAAA,YAAA,EAAe,SAAS,CAAA,CAAA,CAAG,CAAC;YAClE,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;QACrE;QAAE,OAAO,GAAQ,EAAE;AAClB,YAAA,MAAM,IAAI,YAAY,CAAC,CAAA,mBAAA,EAAsB,GAAG,CAAC,OAAO,CAAA,CAAE,EAAE,EAAE,GAAG,EAAE,CAAC;QACrE;IACD;AACA,IAAA,MAAM,qBAAqB,GAAA;QAC1B,IAAI,CAAC,IAAI,CAAC,YAAY;AAAE,YAAA,MAAM,IAAI,YAAY,CAAC,wBAAwB,CAAC;QACxE,MAAM,IAAI,CAAC,YAAY,CAAC,qBAAqB,CAAC,QAAQ,CAAC,qBAAqB,CAAC;IAC9E;AACA,IAAA,MAAM,kBAAkB,GAAA;QACvB,IAAI,CAAC,IAAI,CAAC,YAAY;AAAE,YAAA,MAAM,IAAI,YAAY,CAAC,wBAAwB,CAAC;AACxE,QAAA,OAAO,IAAI,CAAC,YAAY,CAAC,sBAAsB,EAAE;IAClD;IACA,MAAM,oBAAoB,CAAC,OAAe,EAAA;QACzC,IAAI,CAAC,IAAI,CAAC,IAAI;AAAE,YAAA,MAAM,IAAI,YAAY,CAAC,sBAAsB,CAAC;AAC9D,QAAA,MAAM,eAAe,GAAG,IAAI,CAAC;AAC3B,aAAA,YAAY,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE;AACvD,aAAA,KAAK,CAAC,CAAC,GAAG,KAAI;YACd,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA,4BAAA,EAA+B,GAAG,CAAC,OAAO,CAAA,CAAE,CAAC;AAC9D,YAAA,OAAO,IAAI;AACZ,QAAA,CAAC,CAAC;QACH,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,wBAAA,EAA2B,OAAO,CAAA,CAAE,CAAC;QACvD,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;AAClF,QAAA,MAAM,QAAQ,GAAG,MAAM,eAAe;QACtC,IAAI,QAAQ,EAAE;AACb,YAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,yBAAyB,CAAC;AAC3C,YAAA,OAAO,QAAQ;QAChB;AACA,QAAA,OAAO,IAAI;IACZ;AACA,IAAA,MAAM,2BAA2B,GAAA;QAChC,IAAI,CAAC,IAAI,CAAC,IAAI;AAAE,YAAA,MAAM,IAAI,YAAY,CAAC,sBAAsB,CAAC;AAC9D,QAAA,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,uCAAuC,CAAC;QACzD,MAAM,SAAS,GAAe,EAAE;AAChC,QAAA,MAAM,OAAO,GAAG,CAAC,GAAa,KAAK,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC;QACtD,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,EAAE,OAAO,CAAC;AACjC,QAAA,MAAM,KAAK,CAAC,QAAQ,CAAC,cAAc,CAAC;QACpC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC;AAClC,QAAA,MAAM,YAAY,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,KAAI;YACxD,MAAM,WAAW,GAAG,CAAC,CAAC,OAAO,EAAE,CAAC,qBAAqB,CAAC;YACtD,QACC,CAAC,WAAW,IAAI,WAAW,CAAC,QAAQ,CAAC,YAAY,CAAC;gBAClD,CAAC,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC;AAEpC,QAAA,CAAC,CAAC;AACF,QAAA,IAAI,CAAC,YAAY;AAAE,YAAA,OAAO,IAAI;AAC9B,QAAA,MAAM,MAAM,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE;QACxC,IAAI,QAAQ,GAAG,YAAY,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,UAAU;QAC/E,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,eAAe,EAAE,GAAG,CAAC;AACjD,QAAA,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE;IAC5B;IACA,MAAM,kBAAkB,CAAC,YAAoB,EAAA;QAC5C,IAAI,CAAC,IAAI,CAAC,IAAI;YAAE;AAChB,QAAA,IAAI;AACH,YAAA,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,eAAe,IAAI,CAAC,GAAG,EAAE,CAAA,CAAE,CAAC;AACnE,YAAA,MAAM,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;YAClD,MAAM,OAAO,CAAC,GAAG,CAAC;AACjB,gBAAA,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC;oBACpB,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC;AAC3C,oBAAA,QAAQ,EAAE,IAAI;iBACd,CAAC;gBACF,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;AAC/E,gBAAA,EAAE,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,EAAE,YAAY,CAAC;AACjE,aAAA,CAAC;YACF,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,CAAA,yBAAA,EAA4B,IAAI,CAAC,QAAQ,CAAA,CAAE,CAAC;QAC9D;QAAE,OAAO,CAAM,EAAE;YAChB,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,CAAA,gCAAA,EAAmC,CAAC,CAAC,OAAO,CAAA,CAAE,CAAC;QAClE;IACD;AACA,IAAA,MAAM,KAAK,GAAA;QACV,IAAI,IAAI,CAAC,IAAI;AAAE,YAAA,MAAM,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;QACtD,IAAI,IAAI,CAAC,OAAO;AAAE,YAAA,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;QAC5D,IAAI,IAAI,CAAC,OAAO;AAAE,YAAA,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,KAAK,CAAC,MAAK,EAAE,CAAC,CAAC;AAC5D,QAAA,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,gBAAgB,CAAC;IACpC;AACA;;MC5IY,MAAM,CAAA;AACV,IAAA,QAAQ;IAChB,WAAA,CAAY,SAAS,GAAG,KAAK,EAAA;AAC5B,QAAA,IAAI,CAAC,QAAQ,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM;IAC7C;AACA,IAAA,QAAQ,CAAC,OAAgB,EAAA;AACxB,QAAA,IAAI,CAAC,QAAQ,GAAG,OAAO,GAAG,OAAO,GAAG,MAAM;IAC3C;AACQ,IAAA,SAAS,CAAC,KAAe,EAAA;AAChC,QAAA,MAAM,MAAM,GAA6B,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE;QACjF,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC;IAC9C;AACQ,IAAA,GAAG,CAAC,KAAe,EAAE,OAAe,EAAE,OAAa,EAAA;AAC1D,QAAA,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC;YAAE;QAC5B,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;AACnC,QAAA,MAAM,GAAG,GAAG,OAAO,GAAG,CAAA,CAAA,EAAI,aAAa,CAAC,OAAO,CAAC,CAAA,CAAE,GAAG,EAAE;AACvD,QAAA,OAAO,CAAC,GAAG,CAAC,CAAA,CAAA,EAAI,EAAE,KAAK,KAAK,CAAC,WAAW,EAAE,KAAK,OAAO,CAAA,EAAG,GAAG,CAAA,CAAE,CAAC;IAChE;IACA,KAAK,CAAC,GAAW,EAAE,GAAS,EAAA;QAC3B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC;IAC5B;IACA,IAAI,CAAC,GAAW,EAAE,GAAS,EAAA;QAC1B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC;IAC3B;IACA,IAAI,CAAC,GAAW,EAAE,GAAS,EAAA;QAC1B,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC;IAC3B;IACA,KAAK,CAAC,GAAW,EAAE,GAAS,EAAA;QAC3B,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,EAAE,GAAG,CAAC;IAC5B;AACA;;ACpBK,SAAU,gBAAgB,CAAC,IAAsB,EAAA;IACtD,OAAO;AACN,QAAA,QAAQ,EAAE,IAAI,EAAE,QAAQ,IAAI,QAAQ,CAAC,QAAQ;AAC7C,QAAA,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,KAAK;AAC3B,QAAA,SAAS,EAAE,IAAI,EAAE,SAAS,IAAI,QAAQ,CAAC,SAAS;AAChD,QAAA,OAAO,EAAE,IAAI,EAAE,OAAO,IAAI,QAAQ,CAAC,OAAO;KAC1C;AACF;;ACZO,eAAe,aAAa,CAClC,GAAW,EACX,OAAe,EACf,OAAyB,EAAA;AAEzB,IAAA,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC;IACtC,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC;IACrC,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,CAAC,UAAU,CAAC,EAAE;QACtC,MAAM,IAAI,eAAe,CAAC,2BAA2B,EAAE,EAAE,GAAG,EAAE,CAAC;IAChE;AACA,IAAA,MAAMA,WAAE,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;AAC5C,IAAA,MAAM,UAAU,GAAG,IAAI,cAAc,CAAC,MAAM,EAAE;QAC7C,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,SAAS,EAAE,IAAI,CAAC,SAAS;QACzB,OAAO,EAAE,IAAI,CAAC,OAAO;QACrB,KAAK,EAAE,IAAI,CAAC,KAAK;AACjB,KAAA,CAAC;AACF,IAAA,IAAI;AACH,QAAA,MAAM,UAAU,CAAC,MAAM,EAAE;QACzB,MAAM,UAAU,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC;AACzC,QAAA,MAAM,UAAU,CAAC,qBAAqB,EAAE;AACxC,QAAA,MAAM,eAAe,GAAG,MAAM,UAAU,CAAC,kBAAkB,EAAE;AAC7D,QAAA,MAAM,OAAO,GAAG,eAAe,CAAC,QAAQ,CAAC,GAAG;cACzC,CAAA,EAAG,eAAe,CAAA,OAAA;AACpB,cAAE,CAAA,EAAG,eAAe,CAAA,OAAA,CAAS;QAC9B,IAAI,QAAQ,GAAG,MAAM,UAAU,CAAC,oBAAoB,CAAC,OAAO,CAAC;AAC7D,QAAA,IAAI,SAAiB;AACrB,QAAA,IAAI,QAAgB;AACpB,QAAA,IAAI,MAA6B;QACjC,IAAI,QAAQ,EAAE;YACb,MAAM,SAAS,GAAG,QAAQ,CAAC,iBAAiB,EAAE,IAAI,UAAU;AAC5D,YAAA,MAAM,QAAQ,GAAG,gBAAgB,CAAC,SAAS,CAAC;YAC5C,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC;AACxC,YAAA,MAAM,QAAQ,CAAC,MAAM,CAAC,SAAS,CAAC;YAChC,MAAM,IAAI,GAAG,MAAMA,WAAE,CAAC,IAAI,CAAC,SAAS,CAAC;AACrC,YAAA,QAAQ,GAAG,IAAI,CAAC,IAAI;YACpB,MAAM,GAAG,QAAQ;YACjB,MAAM,CAAC,IAAI,CAAC,CAAA,2BAAA,EAA8B,SAAS,CAAA,EAAA,EAAK,QAAQ,CAAA,OAAA,CAAS,CAAC;QAC3E;aAAO;AACN,YAAA,MAAM,QAAQ,GAAG,MAAM,UAAU,CAAC,2BAA2B,EAAE;YAC/D,IAAI,CAAC,QAAQ,EAAE;AACd,gBAAA,MAAM,IAAI,YAAY,CAAC,8CAA8C,CAAC;YACvE;YACA,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,GAAG,QAAQ;AAC9C,YAAA,MAAM,QAAQ,GAAG,gBAAgB,CAAC,OAAO,CAAC;YAC1C,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC;YACxC,MAAMA,WAAE,CAAC,SAAS,CAAC,SAAS,EAAE,MAAM,CAAC;AACrC,YAAA,QAAQ,GAAG,MAAM,CAAC,MAAM;YACxB,MAAM,GAAG,UAAU;YACnB,MAAM,CAAC,IAAI,CAAC,CAAA,oBAAA,EAAuB,SAAS,CAAA,EAAA,EAAK,QAAQ,CAAA,OAAA,CAAS,CAAC;QACpE;QACA,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE;IACvD;IAAE,OAAO,GAAQ,EAAE;QAClB,MAAM,UAAU,CAAC,kBAAkB,CAAC,GAAG,CAAC,OAAO,CAAC;AAChD,QAAA,MAAM,GAAG;IACV;YAAU;AACT,QAAA,MAAM,UAAU,CAAC,KAAK,EAAE;IACzB;AACD;;;;"}
package/changelog CHANGED
@@ -1,3 +1,95 @@
1
+ commit 549aec09f8297318fcf52d69bc8262d78d769e0d
2
+ Author: neuxdotdev <neuxdev1@gmail.com>
3
+ Date: Thu Apr 2 11:31:54 2026 +0700
4
+
5
+ chore(release): bump version to 2.1.1 for new download implementation
6
+
7
+ commit 54147f326795e40dd6e8e6f08e70fb7323ab2f25
8
+ Author: neuxdotdev <neuxdev1@gmail.com>
9
+ Date: Thu Apr 2 11:31:54 2026 +0700
10
+
11
+ refactor(lib): simplify entry point to re-export core modules only
12
+
13
+ commit c82f51154fa17e8533b32c85c218644f46d2067a
14
+ Author: neuxdotdev <neuxdev1@gmail.com>
15
+ Date: Thu Apr 2 11:31:50 2026 +0700
16
+
17
+ feat(core): implement downloadSfile function with direct/fallback download strategies
18
+
19
+ commit 84a9e5db96eee8cd195a46b934f792d8c94461c0
20
+ Author: neuxdotdev <neuxdev1@gmail.com>
21
+ Date: Thu Apr 2 11:31:45 2026 +0700
22
+
23
+ feat(browser): implement BrowserManager for Playwright lifecycle and fallback handling
24
+
25
+ commit 8fb98f7b6da4717e27ddf019f1962fe25734cc45
26
+ Author: neuxdotdev <neuxdev1@gmail.com>
27
+ Date: Thu Apr 2 11:31:44 2026 +0700
28
+
29
+ feat(browser): implement SfilePageInteractions for button wait and URL extraction
30
+
31
+ commit 0e5fa3e6fa007baaf2baa60ce6be475792ae7376
32
+ Author: neuxdotdev <neuxdev1@gmail.com>
33
+ Date: Thu Apr 2 11:31:40 2026 +0700
34
+
35
+ feat(config): define DownloadOptions, DownloadResult types and normalizeOptions
36
+
37
+ commit 0271fcd44dc7d6ad5889e94f67af50f21afe23f6
38
+ Author: neuxdotdev <neuxdev1@gmail.com>
39
+ Date: Thu Apr 2 11:31:39 2026 +0700
40
+
41
+ feat(config): add DEFAULTS constants for browser and timeout settings
42
+
43
+ commit 5c2b9514892096756f817d9c7302b80a4c0bdbdc
44
+ Author: neuxdotdev <neuxdev1@gmail.com>
45
+ Date: Thu Apr 2 11:31:34 2026 +0700
46
+
47
+ feat(errors): export all error classes from index
48
+
49
+ commit 39e37b2392132c6e2f50544f363b6fef18a3693f
50
+ Author: neuxdotdev <neuxdev1@gmail.com>
51
+ Date: Thu Apr 2 11:31:34 2026 +0700
52
+
53
+ feat(errors): implement ValidationError, NetworkError, FileError, BrowserError
54
+
55
+ commit 113aa52b8c10c3dceae6dab54fb793a713c85d48
56
+ Author: neuxdotdev <neuxdev1@gmail.com>
57
+ Date: Thu Apr 2 11:31:34 2026 +0700
58
+
59
+ feat(errors): create abstract AppError base class with metadata
60
+
61
+ commit 632e1716941f317ef34e33131e8db22a745e812b
62
+ Author: neuxdotdev <neuxdev1@gmail.com>
63
+ Date: Thu Apr 2 11:31:28 2026 +0700
64
+
65
+ feat(utils): add Result type and ok/err helper functions
66
+
67
+ commit 404af4c69d443e1722bb74aa9e5dbc4391dcd77e
68
+ Author: neuxdotdev <neuxdev1@gmail.com>
69
+ Date: Thu Apr 2 11:31:28 2026 +0700
70
+
71
+ feat(utils): implement Logger class with level-based filtering
72
+
73
+ commit a590df93fe4476306a694f9475ae1ce27af74fd0
74
+ Author: neuxdotdev <neuxdev1@gmail.com>
75
+ Date: Thu Apr 2 11:31:27 2026 +0700
76
+
77
+ feat(utils): add helper functions for filename sanitization and sleep
78
+
79
+ commit 02745291f00d47110f673b1b923f108e55e331fc
80
+ Author: neuxdotdev <neuxdev1@gmail.com>
81
+ Date: Thu Apr 2 02:02:27 2026 +0700
82
+
83
+ remake prepublish scripts
84
+
85
+ commit a88b254acafbad32719b67c096fb3420ed813aa0
86
+ Author: neuxdotdev <neuxdev1@gmail.com>
87
+ Date: Thu Apr 2 02:01:54 2026 +0700
88
+
89
+ release: v2.0.1
90
+
91
+ delete ci for auto publihs
92
+
1
93
  commit c63b25ce873bcba391cf66dc52c3c04fb8eb9306
2
94
  Author: neuxdotdev <neuxdev1@gmail.com>
3
95
  Date: Thu Apr 2 01:50:16 2026 +0700
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sfiledl",
3
- "version": "2.0.1",
3
+ "version": "2.1.1",
4
4
  "description": "Implement and automate downloading of any file from sfile.co with javascripts library, written entirely in typescripts",
5
5
  "type": "module",
6
6
  "main": "./build/lib.cjs",
@@ -9,7 +9,7 @@
9
9
  "license": "AGPL-3.0-only",
10
10
  "files": [
11
11
  "build",
12
- "readme",
12
+ "readme.md",
13
13
  "license",
14
14
  "changelog"
15
15
  ],