@j0hanz/superfetch 1.0.0 → 1.0.2

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.
Files changed (70) hide show
  1. package/dist/errors/app-error.d.ts +0 -25
  2. package/dist/errors/app-error.d.ts.map +1 -1
  3. package/dist/errors/app-error.js +0 -34
  4. package/dist/errors/app-error.js.map +1 -1
  5. package/dist/index.js +86 -21
  6. package/dist/index.js.map +1 -1
  7. package/dist/middleware/error-handler.d.ts.map +1 -1
  8. package/dist/middleware/error-handler.js.map +1 -1
  9. package/dist/middleware/rate-limiter.d.ts +1 -0
  10. package/dist/middleware/rate-limiter.d.ts.map +1 -1
  11. package/dist/middleware/rate-limiter.js +29 -10
  12. package/dist/middleware/rate-limiter.js.map +1 -1
  13. package/dist/services/cache.d.ts +9 -5
  14. package/dist/services/cache.d.ts.map +1 -1
  15. package/dist/services/cache.js +67 -28
  16. package/dist/services/cache.js.map +1 -1
  17. package/dist/services/extractor.d.ts +8 -18
  18. package/dist/services/extractor.d.ts.map +1 -1
  19. package/dist/services/extractor.js +28 -31
  20. package/dist/services/extractor.js.map +1 -1
  21. package/dist/services/fetcher.d.ts +6 -2
  22. package/dist/services/fetcher.d.ts.map +1 -1
  23. package/dist/services/fetcher.js +86 -17
  24. package/dist/services/fetcher.js.map +1 -1
  25. package/dist/services/logger.d.ts +1 -1
  26. package/dist/services/logger.d.ts.map +1 -1
  27. package/dist/services/logger.js +14 -4
  28. package/dist/services/logger.js.map +1 -1
  29. package/dist/services/parser.d.ts +2 -0
  30. package/dist/services/parser.d.ts.map +1 -1
  31. package/dist/services/parser.js +42 -11
  32. package/dist/services/parser.js.map +1 -1
  33. package/dist/tools/handlers/fetch-links.tool.d.ts +8 -4
  34. package/dist/tools/handlers/fetch-links.tool.d.ts.map +1 -1
  35. package/dist/tools/handlers/fetch-links.tool.js +40 -21
  36. package/dist/tools/handlers/fetch-links.tool.js.map +1 -1
  37. package/dist/tools/handlers/fetch-markdown.tool.d.ts +7 -8
  38. package/dist/tools/handlers/fetch-markdown.tool.d.ts.map +1 -1
  39. package/dist/tools/handlers/fetch-markdown.tool.js +48 -36
  40. package/dist/tools/handlers/fetch-markdown.tool.js.map +1 -1
  41. package/dist/tools/handlers/fetch-url.tool.d.ts +9 -8
  42. package/dist/tools/handlers/fetch-url.tool.d.ts.map +1 -1
  43. package/dist/tools/handlers/fetch-url.tool.js +55 -39
  44. package/dist/tools/handlers/fetch-url.tool.js.map +1 -1
  45. package/dist/tools/index.d.ts.map +1 -1
  46. package/dist/tools/index.js +42 -0
  47. package/dist/tools/index.js.map +1 -1
  48. package/dist/transformers/jsonl.transformer.d.ts +0 -1
  49. package/dist/transformers/jsonl.transformer.d.ts.map +1 -1
  50. package/dist/transformers/jsonl.transformer.js +27 -22
  51. package/dist/transformers/jsonl.transformer.js.map +1 -1
  52. package/dist/transformers/markdown.transformer.d.ts +1 -2
  53. package/dist/transformers/markdown.transformer.d.ts.map +1 -1
  54. package/dist/transformers/markdown.transformer.js +20 -63
  55. package/dist/transformers/markdown.transformer.js.map +1 -1
  56. package/dist/types/content.types.d.ts +1 -1
  57. package/dist/types/content.types.d.ts.map +1 -1
  58. package/dist/utils/sanitizer.d.ts +6 -2
  59. package/dist/utils/sanitizer.d.ts.map +1 -1
  60. package/dist/utils/sanitizer.js +13 -5
  61. package/dist/utils/sanitizer.js.map +1 -1
  62. package/dist/utils/tool-error-handler.d.ts +18 -0
  63. package/dist/utils/tool-error-handler.d.ts.map +1 -0
  64. package/dist/utils/tool-error-handler.js +27 -0
  65. package/dist/utils/tool-error-handler.js.map +1 -0
  66. package/dist/utils/url-validator.d.ts +1 -0
  67. package/dist/utils/url-validator.d.ts.map +1 -1
  68. package/dist/utils/url-validator.js +39 -6
  69. package/dist/utils/url-validator.js.map +1 -1
  70. package/package.json +79 -80
@@ -1,42 +1,47 @@
1
1
  import { config } from '../config/index.js';
2
2
  import { truncateText } from '../utils/sanitizer.js';
3
- import { logError } from '../services/logger.js';
4
3
  function truncateBlock(block) {
5
4
  const maxLength = config.extraction.maxBlockLength;
6
5
  switch (block.type) {
7
6
  case 'paragraph':
8
7
  case 'heading':
9
- case 'code':
10
- return { ...block, text: truncateText(block.text, maxLength) };
11
- case 'list':
12
- return {
13
- ...block,
14
- items: block.items.map((item) => truncateText(item, maxLength)),
15
- };
8
+ case 'code': {
9
+ const truncated = truncateText(block.text, maxLength);
10
+ return truncated === block.text ? block : { ...block, text: truncated };
11
+ }
12
+ case 'list': {
13
+ const truncatedItems = block.items.map((item) => truncateText(item, maxLength));
14
+ const hasChanges = truncatedItems.some((item, i) => item !== block.items[i]);
15
+ return hasChanges ? { ...block, items: truncatedItems } : block;
16
+ }
16
17
  default:
17
18
  return block;
18
19
  }
19
20
  }
20
21
  export function toJsonl(blocks, metadata) {
21
22
  const lines = [];
22
- if (metadata)
23
- lines.push(JSON.stringify(metadata));
24
- for (const block of blocks) {
25
- lines.push(JSON.stringify(truncateBlock(block)));
23
+ // Minimal metadata - just title and URL for context
24
+ if (metadata) {
25
+ try {
26
+ const minimal = {
27
+ type: metadata.type,
28
+ title: metadata.title,
29
+ url: metadata.url,
30
+ };
31
+ lines.push(JSON.stringify(minimal));
32
+ }
33
+ catch {
34
+ // Skip invalid metadata
35
+ }
26
36
  }
27
- return lines.join('\n');
28
- }
29
- export function fromJsonl(jsonl) {
30
- const lines = jsonl.split('\n').filter((line) => line.trim());
31
- const blocks = [];
32
- for (const line of lines) {
37
+ for (const block of blocks) {
33
38
  try {
34
- blocks.push(JSON.parse(line));
39
+ lines.push(JSON.stringify(truncateBlock(block)));
35
40
  }
36
- catch (error) {
37
- logError('Failed to parse JSONL line', error instanceof Error ? error : undefined);
41
+ catch {
42
+ // Skip blocks that fail to serialize
38
43
  }
39
44
  }
40
- return blocks;
45
+ return lines.join('\n');
41
46
  }
42
47
  //# sourceMappingURL=jsonl.transformer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"jsonl.transformer.js","sourceRoot":"","sources":["../../src/transformers/jsonl.transformer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AAEjD,SAAS,aAAa,CAAC,KAAwB;IAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC;IAEnD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,WAAW,CAAC;QACjB,KAAK,SAAS,CAAC;QACf,KAAK,MAAM;YACT,OAAO,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,EAAE,CAAC;QACjE,KAAK,MAAM;YACT,OAAO;gBACL,GAAG,KAAK;gBACR,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;aAChE,CAAC;QACJ;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,MAA2B,EAAE,QAAwB;IAC3E,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,IAAI,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC;IAEnD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnD,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;IAC9D,MAAM,MAAM,GAAwB,EAAE,CAAC;IAEvC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAsB,CAAC,CAAC;QACrD,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,QAAQ,CAAC,4BAA4B,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC;QACrF,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"jsonl.transformer.js","sourceRoot":"","sources":["../../src/transformers/jsonl.transformer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,SAAS,aAAa,CAAC,KAAwB;IAC7C,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,cAAc,CAAC;IAEnD,QAAQ,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,WAAW,CAAC;QACjB,KAAK,SAAS,CAAC;QACf,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;YACtD,OAAO,SAAS,KAAK,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC;QAC1E,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,CAAC;YACZ,MAAM,cAAc,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAC9C,YAAY,CAAC,IAAI,EAAE,SAAS,CAAC,CAC9B,CAAC;YACF,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,CACpC,CAAC,IAAI,EAAE,CAAC,EAAE,EAAE,CAAC,IAAI,KAAK,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CACrC,CAAC;YACF,OAAO,UAAU,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC;QAClE,CAAC;QACD;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,OAAO,CACrB,MAA2B,EAC3B,QAAwB;IAExB,MAAM,KAAK,GAAa,EAAE,CAAC;IAE3B,oDAAoD;IACpD,IAAI,QAAQ,EAAE,CAAC;QACb,IAAI,CAAC;YACH,MAAM,OAAO,GAAG;gBACd,IAAI,EAAE,QAAQ,CAAC,IAAI;gBACnB,KAAK,EAAE,QAAQ,CAAC,KAAK;gBACrB,GAAG,EAAE,QAAQ,CAAC,GAAG;aAClB,CAAC;YACF,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,wBAAwB;QAC1B,CAAC;IACH,CAAC;IAED,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,IAAI,CAAC;YACH,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;QACnD,CAAC;QAAC,MAAM,CAAC;YACP,qCAAqC;QACvC,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -1,4 +1,3 @@
1
- import type { ContentBlockUnion, MetadataBlock } from '../types/index.js';
1
+ import type { MetadataBlock } from '../types/index.js';
2
2
  export declare function htmlToMarkdown(html: string, metadata?: MetadataBlock): string;
3
- export declare function blocksToMarkdown(blocks: ContentBlockUnion[], metadata?: MetadataBlock): string;
4
3
  //# sourceMappingURL=markdown.transformer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.transformer.d.ts","sourceRoot":"","sources":["../../src/transformers/markdown.transformer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AA6F1E,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,MAAM,CAU7E;AAED,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,iBAAiB,EAAE,EAC3B,QAAQ,CAAC,EAAE,aAAa,GACvB,MAAM,CAcR"}
1
+ {"version":3,"file":"markdown.transformer.d.ts","sourceRoot":"","sources":["../../src/transformers/markdown.transformer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAiDvD,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,aAAa,GAAG,MAAM,CAkB7E"}
@@ -3,20 +3,21 @@ const turndown = new TurndownService({
3
3
  headingStyle: 'atx',
4
4
  codeBlockStyle: 'fenced',
5
5
  emDelimiter: '_',
6
+ bulletListMarker: '-',
6
7
  });
7
- turndown.addRule('removeScripts', {
8
- filter: ['script', 'style', 'noscript'],
8
+ // Remove noise elements
9
+ turndown.addRule('removeNoise', {
10
+ filter: ['script', 'style', 'noscript', 'nav', 'footer', 'aside', 'iframe'],
9
11
  replacement: () => '',
10
12
  });
11
- // Pre-compiled regex patterns for YAML value escaping (performance optimization)
13
+ // Pre-compiled regex patterns
12
14
  const YAML_SPECIAL_CHARS = /[:[\]{}"\n\r'|>&*!?,#]/;
13
15
  const YAML_NUMERIC = /^[\d.]+$/;
14
16
  const YAML_RESERVED_WORDS = /^(true|false|null|yes|no|on|off)$/i;
15
17
  const ESCAPE_BACKSLASH = /\\/g;
16
18
  const ESCAPE_QUOTE = /"/g;
17
19
  const ESCAPE_NEWLINE = /\n/g;
18
- const ESCAPE_CARRIAGE = /\r/g;
19
- const ESCAPE_TAB = /\t/g;
20
+ const MULTIPLE_NEWLINES = /\n{3,}/g;
20
21
  function escapeYamlValue(value) {
21
22
  const needsQuoting = YAML_SPECIAL_CHARS.test(value) ||
22
23
  value.startsWith(' ') ||
@@ -26,79 +27,35 @@ function escapeYamlValue(value) {
26
27
  YAML_RESERVED_WORDS.test(value);
27
28
  if (!needsQuoting)
28
29
  return value;
29
- const escaped = value
30
+ return `"${value
30
31
  .replace(ESCAPE_BACKSLASH, '\\\\')
31
32
  .replace(ESCAPE_QUOTE, '\\"')
32
- .replace(ESCAPE_NEWLINE, '\\n')
33
- .replace(ESCAPE_CARRIAGE, '\\r')
34
- .replace(ESCAPE_TAB, '\\t');
35
- return `"${escaped}"`;
33
+ .replace(ESCAPE_NEWLINE, '\\n')}"`;
36
34
  }
37
35
  function createFrontmatter(metadata) {
38
36
  const lines = ['---'];
39
37
  if (metadata.title)
40
38
  lines.push(`title: ${escapeYamlValue(metadata.title)}`);
41
- if (metadata.description)
42
- lines.push(`description: ${escapeYamlValue(metadata.description)}`);
43
- if (metadata.author)
44
- lines.push(`author: ${escapeYamlValue(metadata.author)}`);
45
39
  if (metadata.url)
46
- lines.push(`url: ${escapeYamlValue(metadata.url)}`);
47
- if (metadata.fetchedAt)
48
- lines.push(`fetched_at: ${escapeYamlValue(metadata.fetchedAt)}`);
40
+ lines.push(`source: ${escapeYamlValue(metadata.url)}`);
49
41
  lines.push('---');
50
42
  return lines.join('\n');
51
43
  }
52
- function tableToMarkdown(table) {
53
- let markdown = '';
54
- if (table.headers && table.headers.length > 0) {
55
- markdown += '| ' + table.headers.join(' | ') + ' |\n';
56
- markdown += '| ' + table.headers.map(() => '---').join(' | ') + ' |\n';
57
- }
58
- for (const row of table.rows) {
59
- markdown += '| ' + row.join(' | ') + ' |\n';
44
+ export function htmlToMarkdown(html, metadata) {
45
+ if (!html || typeof html !== 'string') {
46
+ return metadata ? createFrontmatter(metadata) + '\n\n' : '';
60
47
  }
61
- return markdown.trim();
62
- }
63
- function blockToMarkdown(block) {
64
- switch (block.type) {
65
- case 'metadata':
66
- return '';
67
- case 'heading':
68
- return '#'.repeat(block.level) + ' ' + block.text;
69
- case 'paragraph':
70
- return block.text;
71
- case 'list':
72
- return block.items
73
- .map((item, index) => (block.ordered ? `${index + 1}. ` : '- ') + item)
74
- .join('\n');
75
- case 'code':
76
- return '```' + (block.language || '') + '\n' + block.text + '\n```';
77
- case 'table':
78
- return tableToMarkdown(block);
79
- case 'image':
80
- return `![${block.alt || ''}](${block.src})`;
48
+ let content = '';
49
+ try {
50
+ content = turndown.turndown(html);
51
+ content = content.replace(MULTIPLE_NEWLINES, '\n\n').trim();
81
52
  }
82
- }
83
- export function htmlToMarkdown(html, metadata) {
84
- let markdown = '';
85
- if (metadata) {
86
- markdown += createFrontmatter(metadata);
87
- markdown += '\n\n';
53
+ catch {
54
+ return metadata ? createFrontmatter(metadata) + '\n\n' : '';
88
55
  }
89
- markdown += turndown.turndown(html);
90
- return markdown;
91
- }
92
- export function blocksToMarkdown(blocks, metadata) {
93
- let markdown = '';
94
56
  if (metadata) {
95
- markdown += createFrontmatter(metadata);
96
- markdown += '\n\n';
97
- }
98
- for (const block of blocks) {
99
- markdown += blockToMarkdown(block);
100
- markdown += '\n\n';
57
+ return createFrontmatter(metadata) + '\n\n' + content;
101
58
  }
102
- return markdown.trim();
59
+ return content;
103
60
  }
104
61
  //# sourceMappingURL=markdown.transformer.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"markdown.transformer.js","sourceRoot":"","sources":["../../src/transformers/markdown.transformer.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"markdown.transformer.js","sourceRoot":"","sources":["../../src/transformers/markdown.transformer.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- export type ContentBlockType = 'metadata' | 'heading' | 'paragraph' | 'list' | 'code' | 'table' | 'image';
1
+ type ContentBlockType = 'metadata' | 'heading' | 'paragraph' | 'list' | 'code' | 'table' | 'image';
2
2
  interface ContentBlock {
3
3
  type: ContentBlockType;
4
4
  }
@@ -1 +1 @@
1
- {"version":3,"file":"content.types.d.ts","sourceRoot":"","sources":["../../src/types/content.types.ts"],"names":[],"mappings":"AACA,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,SAAS,GACT,WAAW,GACX,MAAM,GACN,MAAM,GACN,OAAO,GACP,OAAO,CAAC;AAGZ,UAAU,YAAY;IACpB,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAGD,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,YAAa,SAAQ,YAAY;IAChD,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAGD,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;CAClB;AAGD,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,MAAM,iBAAiB,GACzB,aAAa,GACb,YAAY,GACZ,cAAc,GACd,SAAS,GACT,SAAS,GACT,UAAU,GACV,UAAU,CAAC;AAGf,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;CAC/B"}
1
+ {"version":3,"file":"content.types.d.ts","sourceRoot":"","sources":["../../src/types/content.types.ts"],"names":[],"mappings":"AACA,KAAK,gBAAgB,GACjB,UAAU,GACV,SAAS,GACT,WAAW,GACX,MAAM,GACN,MAAM,GACN,OAAO,GACP,OAAO,CAAC;AAGZ,UAAU,YAAY;IACpB,IAAI,EAAE,gBAAgB,CAAC;CACxB;AAGD,MAAM,WAAW,aAAc,SAAQ,YAAY;IACjD,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,YAAa,SAAQ,YAAY;IAChD,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,cAAe,SAAQ,YAAY;IAClD,IAAI,EAAE,WAAW,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,KAAK,EAAE,MAAM,EAAE,CAAC;CACjB;AAGD,MAAM,WAAW,SAAU,SAAQ,YAAY;IAC7C,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IACnB,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;CAClB;AAGD,MAAM,WAAW,UAAW,SAAQ,YAAY;IAC9C,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAGD,MAAM,MAAM,iBAAiB,GACzB,aAAa,GACb,YAAY,GACZ,cAAc,GACd,SAAS,GACT,SAAS,GACT,UAAU,GACV,UAAU,CAAC;AAGf,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,UAAU,GAAG,UAAU,CAAC;CAC/B"}
@@ -1,9 +1,13 @@
1
1
  /**
2
- * Sanitizes text content by removing extra whitespace and special characters
2
+ * Sanitizes text content by collapsing whitespace and trimming
3
+ * Returns empty string for null/undefined input
3
4
  */
4
- export declare function sanitizeText(text: string): string;
5
+ export declare function sanitizeText(text: string | null | undefined): string;
5
6
  /**
6
7
  * Truncates text to a maximum length with ellipsis
8
+ * @param text - Text to truncate
9
+ * @param maxLength - Maximum length (must be > 3 to accommodate ellipsis)
10
+ * @returns Truncated text with ellipsis if needed
7
11
  */
8
12
  export declare function truncateText(text: string, maxLength: number): string;
9
13
  //# sourceMappingURL=sanitizer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../../src/utils/sanitizer.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKjD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAKpE"}
1
+ {"version":3,"file":"sanitizer.d.ts","sourceRoot":"","sources":["../../src/utils/sanitizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,CAIpE;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAQpE"}
@@ -1,16 +1,24 @@
1
1
  /**
2
- * Sanitizes text content by removing extra whitespace and special characters
2
+ * Sanitizes text content by collapsing whitespace and trimming
3
+ * Returns empty string for null/undefined input
3
4
  */
4
5
  export function sanitizeText(text) {
5
- return text
6
- .replace(/\s+/g, ' ') // Replace multiple spaces with single space
7
- .replace(/\n\s*\n/g, '\n') // Remove empty lines
8
- .trim();
6
+ if (text == null)
7
+ return '';
8
+ if (typeof text !== 'string')
9
+ return String(text);
10
+ return text.replace(/\s+/g, ' ').trim();
9
11
  }
10
12
  /**
11
13
  * Truncates text to a maximum length with ellipsis
14
+ * @param text - Text to truncate
15
+ * @param maxLength - Maximum length (must be > 3 to accommodate ellipsis)
16
+ * @returns Truncated text with ellipsis if needed
12
17
  */
13
18
  export function truncateText(text, maxLength) {
19
+ if (maxLength < 4) {
20
+ return text.length > 0 ? text.charAt(0) : '';
21
+ }
14
22
  if (text.length <= maxLength) {
15
23
  return text;
16
24
  }
@@ -1 +1 @@
1
- {"version":3,"file":"sanitizer.js","sourceRoot":"","sources":["../../src/utils/sanitizer.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,IAAI;SACR,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,4CAA4C;SACjE,OAAO,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC,qBAAqB;SAC/C,IAAI,EAAE,CAAC;AACZ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAiB;IAC1D,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;AAClD,CAAC"}
1
+ {"version":3,"file":"sanitizer.js","sourceRoot":"","sources":["../../src/utils/sanitizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,IAA+B;IAC1D,IAAI,IAAI,IAAI,IAAI;QAAE,OAAO,EAAE,CAAC;IAC5B,IAAI,OAAO,IAAI,KAAK,QAAQ;QAAE,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;IAClD,OAAO,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAiB;IAC1D,IAAI,SAAS,GAAG,CAAC,EAAE,CAAC;QAClB,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IAC/C,CAAC;IACD,IAAI,IAAI,CAAC,MAAM,IAAI,SAAS,EAAE,CAAC;QAC7B,OAAO,IAAI,CAAC;IACd,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,SAAS,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC;AAClD,CAAC"}
@@ -0,0 +1,18 @@
1
+ /** MCP SDK-compatible error response (index signature required by SDK) */
2
+ export type ToolErrorResponse = {
3
+ [x: string]: unknown;
4
+ content: {
5
+ type: 'text';
6
+ text: string;
7
+ }[];
8
+ structuredContent: {
9
+ [x: string]: unknown;
10
+ error: string;
11
+ url: string;
12
+ errorCode: string;
13
+ };
14
+ isError: true;
15
+ };
16
+ export declare function createToolErrorResponse(message: string, url: string, code: string): ToolErrorResponse;
17
+ export declare function handleToolError(error: unknown, url: string, fallbackMessage?: string): ToolErrorResponse;
18
+ //# sourceMappingURL=tool-error-handler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-error-handler.d.ts","sourceRoot":"","sources":["../../src/utils/tool-error-handler.ts"],"names":[],"mappings":"AAOA,0EAA0E;AAC1E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACrB,OAAO,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,iBAAiB,EAAE;QACjB,CAAC,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QACrB,KAAK,EAAE,MAAM,CAAC;QACd,GAAG,EAAE,MAAM,CAAC;QACZ,SAAS,EAAE,MAAM,CAAC;KACnB,CAAC;IACF,OAAO,EAAE,IAAI,CAAC;CACf,CAAC;AAEF,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,IAAI,EAAE,MAAM,GACX,iBAAiB,CAOnB;AAED,wBAAgB,eAAe,CAC7B,KAAK,EAAE,OAAO,EACd,GAAG,EAAE,MAAM,EACX,eAAe,SAAqB,GACnC,iBAAiB,CAqBnB"}
@@ -0,0 +1,27 @@
1
+ import { AppError, UrlValidationError, FetchError, TimeoutError, } from '../errors/index.js';
2
+ export function createToolErrorResponse(message, url, code) {
3
+ const structuredContent = { error: message, url, errorCode: code };
4
+ return {
5
+ content: [{ type: 'text', text: JSON.stringify(structuredContent) }],
6
+ structuredContent,
7
+ isError: true,
8
+ };
9
+ }
10
+ export function handleToolError(error, url, fallbackMessage = 'Operation failed') {
11
+ if (error instanceof UrlValidationError) {
12
+ return createToolErrorResponse(error.message, url, 'INVALID_URL');
13
+ }
14
+ if (error instanceof TimeoutError) {
15
+ return createToolErrorResponse(`Request timed out after ${error.timeoutMs}ms`, url, 'TIMEOUT');
16
+ }
17
+ if (error instanceof FetchError) {
18
+ const code = error.httpStatus ? `HTTP_${error.httpStatus}` : 'FETCH_ERROR';
19
+ return createToolErrorResponse(error.message, url, code);
20
+ }
21
+ if (error instanceof AppError) {
22
+ return createToolErrorResponse(error.message, url, error.code);
23
+ }
24
+ const message = error instanceof Error ? error.message : 'Unknown error';
25
+ return createToolErrorResponse(`${fallbackMessage}: ${message}`, url, 'UNKNOWN_ERROR');
26
+ }
27
+ //# sourceMappingURL=tool-error-handler.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tool-error-handler.js","sourceRoot":"","sources":["../../src/utils/tool-error-handler.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,QAAQ,EACR,kBAAkB,EAClB,UAAU,EACV,YAAY,GACb,MAAM,oBAAoB,CAAC;AAe5B,MAAM,UAAU,uBAAuB,CACrC,OAAe,EACf,GAAW,EACX,IAAY;IAEZ,MAAM,iBAAiB,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IACnE,OAAO;QACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,iBAAiB,CAAC,EAAE,CAAC;QACpE,iBAAiB;QACjB,OAAO,EAAE,IAAI;KACd,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,KAAc,EACd,GAAW,EACX,eAAe,GAAG,kBAAkB;IAEpC,IAAI,KAAK,YAAY,kBAAkB,EAAE,CAAC;QACxC,OAAO,uBAAuB,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,aAAa,CAAC,CAAC;IACpE,CAAC;IACD,IAAI,KAAK,YAAY,YAAY,EAAE,CAAC;QAClC,OAAO,uBAAuB,CAC5B,2BAA2B,KAAK,CAAC,SAAS,IAAI,EAC9C,GAAG,EACH,SAAS,CACV,CAAC;IACJ,CAAC;IACD,IAAI,KAAK,YAAY,UAAU,EAAE,CAAC;QAChC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,QAAQ,KAAK,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC;QAC3E,OAAO,uBAAuB,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,IAAI,CAAC,CAAC;IAC3D,CAAC;IACD,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,OAAO,uBAAuB,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;IACzE,OAAO,uBAAuB,CAAC,GAAG,eAAe,KAAK,OAAO,EAAE,EAAE,GAAG,EAAE,eAAe,CAAC,CAAC;AACzF,CAAC"}
@@ -1,5 +1,6 @@
1
1
  /**
2
2
  * Validates and normalizes a URL, blocking SSRF attack vectors
3
+ * @throws {ValidationError} if URL is empty or too long
3
4
  * @throws {UrlValidationError} if URL is invalid or blocked
4
5
  */
5
6
  export declare function validateAndNormalizeUrl(urlString: string): string;
@@ -1 +1 @@
1
- {"version":3,"file":"url-validator.d.ts","sourceRoot":"","sources":["../../src/utils/url-validator.ts"],"names":[],"mappings":"AAgCA;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAoCjE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAQnE"}
1
+ {"version":3,"file":"url-validator.d.ts","sourceRoot":"","sources":["../../src/utils/url-validator.ts"],"names":[],"mappings":"AAyCA;;;;GAIG;AACH,wBAAgB,uBAAuB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CA2EjE;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAQnE"}
@@ -1,4 +1,6 @@
1
- import { UrlValidationError } from '../errors/app-error.js';
1
+ import { UrlValidationError, ValidationError } from '../errors/app-error.js';
2
+ // Maximum URL length to prevent DoS attacks
3
+ const MAX_URL_LENGTH = 2048;
2
4
  // Blocked hosts to prevent SSRF attacks
3
5
  const BLOCKED_HOSTS = new Set([
4
6
  'localhost',
@@ -8,6 +10,8 @@ const BLOCKED_HOSTS = new Set([
8
10
  '169.254.169.254', // AWS metadata endpoint
9
11
  'metadata.google.internal', // GCP metadata
10
12
  'metadata.azure.com', // Azure metadata
13
+ '100.100.100.200', // Alibaba Cloud metadata
14
+ 'instance-data', // Common cloud metadata hostname
11
15
  ]);
12
16
  // Blocked IP patterns (private networks)
13
17
  const BLOCKED_IP_PATTERNS = [
@@ -19,6 +23,10 @@ const BLOCKED_IP_PATTERNS = [
19
23
  /^169\.254\./, // Link-local
20
24
  /^fc00:/i, // IPv6 unique local
21
25
  /^fe80:/i, // IPv6 link-local
26
+ /^::ffff:127\./, // IPv4-mapped IPv6 loopback
27
+ /^::ffff:10\./, // IPv4-mapped IPv6 private
28
+ /^::ffff:172\.(1[6-9]|2\d|3[01])\./, // IPv4-mapped IPv6 private
29
+ /^::ffff:192\.168\./, // IPv4-mapped IPv6 private
22
30
  ];
23
31
  /**
24
32
  * Checks if a hostname matches blocked IP patterns
@@ -28,28 +36,53 @@ function isBlockedIp(hostname) {
28
36
  }
29
37
  /**
30
38
  * Validates and normalizes a URL, blocking SSRF attack vectors
39
+ * @throws {ValidationError} if URL is empty or too long
31
40
  * @throws {UrlValidationError} if URL is invalid or blocked
32
41
  */
33
42
  export function validateAndNormalizeUrl(urlString) {
43
+ // Check for empty or whitespace-only input
44
+ if (!urlString || typeof urlString !== 'string') {
45
+ throw new ValidationError('URL is required');
46
+ }
47
+ const trimmedUrl = urlString.trim();
48
+ if (!trimmedUrl) {
49
+ throw new ValidationError('URL cannot be empty');
50
+ }
51
+ // Check URL length to prevent DoS
52
+ if (trimmedUrl.length > MAX_URL_LENGTH) {
53
+ throw new ValidationError(`URL exceeds maximum length of ${MAX_URL_LENGTH} characters`, { length: trimmedUrl.length, maxLength: MAX_URL_LENGTH });
54
+ }
34
55
  let url;
35
56
  try {
36
- url = new URL(urlString);
57
+ url = new URL(trimmedUrl);
37
58
  }
38
59
  catch {
39
- throw new UrlValidationError(`Invalid URL format`, urlString);
60
+ throw new UrlValidationError(`Invalid URL format`, trimmedUrl);
40
61
  }
41
62
  // Only allow HTTP(S) protocols
42
63
  if (url.protocol !== 'http:' && url.protocol !== 'https:') {
43
- throw new UrlValidationError(`Invalid protocol: ${url.protocol}. Only http: and https: are allowed`, urlString);
64
+ throw new UrlValidationError(`Invalid protocol: ${url.protocol}. Only http: and https: are allowed`, trimmedUrl);
65
+ }
66
+ // Block URLs with credentials (user:pass@host)
67
+ if (url.username || url.password) {
68
+ throw new UrlValidationError('URLs with embedded credentials are not allowed', trimmedUrl);
44
69
  }
45
70
  const hostname = url.hostname.toLowerCase();
71
+ // Block empty hostname
72
+ if (!hostname) {
73
+ throw new UrlValidationError('URL must have a valid hostname', trimmedUrl);
74
+ }
46
75
  // Block known internal/metadata hosts
47
76
  if (BLOCKED_HOSTS.has(hostname)) {
48
- throw new UrlValidationError(`Blocked host: ${hostname}. Internal hosts are not allowed`, urlString);
77
+ throw new UrlValidationError(`Blocked host: ${hostname}. Internal hosts are not allowed`, trimmedUrl);
49
78
  }
50
79
  // Block private IP ranges
51
80
  if (isBlockedIp(hostname)) {
52
- throw new UrlValidationError(`Blocked IP range: ${hostname}. Private IPs are not allowed`, urlString);
81
+ throw new UrlValidationError(`Blocked IP range: ${hostname}. Private IPs are not allowed`, trimmedUrl);
82
+ }
83
+ // Block hostnames that look like they might resolve to internal addresses
84
+ if (hostname.endsWith('.local') || hostname.endsWith('.internal')) {
85
+ throw new UrlValidationError(`Blocked hostname pattern: ${hostname}. Internal domain suffixes are not allowed`, trimmedUrl);
53
86
  }
54
87
  return url.href;
55
88
  }
@@ -1 +1 @@
1
- {"version":3,"file":"url-validator.js","sourceRoot":"","sources":["../../src/utils/url-validator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5D,wCAAwC;AACxC,MAAM,aAAa,GAAG,IAAI,GAAG,CAAC;IAC5B,WAAW;IACX,WAAW;IACX,SAAS;IACT,KAAK;IACL,iBAAiB,EAAE,wBAAwB;IAC3C,0BAA0B,EAAE,eAAe;IAC3C,oBAAoB,EAAE,iBAAiB;CACxC,CAAC,CAAC;AAEH,yCAAyC;AACzC,MAAM,mBAAmB,GAAsB;IAC7C,OAAO,EAAE,kBAAkB;IAC3B,4BAA4B,EAAE,kBAAkB;IAChD,aAAa,EAAE,kBAAkB;IACjC,QAAQ,EAAE,WAAW;IACrB,MAAM,EAAE,kBAAkB;IAC1B,aAAa,EAAE,aAAa;IAC5B,SAAS,EAAE,oBAAoB;IAC/B,SAAS,EAAE,kBAAkB;CAC9B,CAAC;AAEF;;GAEG;AACH,SAAS,WAAW,CAAC,QAAgB;IACnC,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;AACvE,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,uBAAuB,CAAC,SAAiB;IACvD,IAAI,GAAQ,CAAC;IAEb,IAAI,CAAC;QACH,GAAG,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;IAC3B,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,kBAAkB,CAAC,oBAAoB,EAAE,SAAS,CAAC,CAAC;IAChE,CAAC;IAED,+BAA+B;IAC/B,IAAI,GAAG,CAAC,QAAQ,KAAK,OAAO,IAAI,GAAG,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1D,MAAM,IAAI,kBAAkB,CAC1B,qBAAqB,GAAG,CAAC,QAAQ,qCAAqC,EACtE,SAAS,CACV,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC;IAE5C,sCAAsC;IACtC,IAAI,aAAa,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChC,MAAM,IAAI,kBAAkB,CAC1B,iBAAiB,QAAQ,kCAAkC,EAC3D,SAAS,CACV,CAAC;IACJ,CAAC;IAED,0BAA0B;IAC1B,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,kBAAkB,CAC1B,qBAAqB,QAAQ,+BAA+B,EAC5D,SAAS,CACV,CAAC;IACJ,CAAC;IAED,OAAO,GAAG,CAAC,IAAI,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,OAAe;IACxD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QACrC,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC;QACpC,OAAO,MAAM,CAAC,QAAQ,KAAK,UAAU,CAAC,QAAQ,CAAC;IACjD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"url-validator.js","sourceRoot":"","sources":["../../src/utils/url-validator.ts"],"names":[],"mappings":"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"}