safe-link-checker 1.0.1 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,83 +2,101 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/safe-link-checker.svg)](https://npmjs.org/package/safe-link-checker)
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
5
- [![Build Status](https://github.com/Rajeev766/safe-link-checker/actions/workflows/ci.yml/badge.svg)](https://github.com/Rajeev766/safe-link-checker/actions)
6
- [![Security Rating](https://img.shields.io/badge/Security-A%2B-success.svg)](#)
7
5
 
8
- An enterprise-grade, lightning-fast Node.js library for validating URLs against phishing, malware, SSRF bypasses, DNS rebinding, and Zip bombs. `SafeLinkChecker` uses consensus-based verification across multiple threat intelligence feeds (URLHaus, OpenPhish) alongside deep heuristics and custom DNS hooks to ensure absolute safety before you fetch or process user-provided URLs.
6
+ An enterprise-grade, lightning-fast **Universal URL Intelligence SDK**. `SafeLinkChecker` protects against phishing, malware, SSRF bypasses, DNS rebinding, and malicious payloads. It works seamlessly across Node.js, React Native, Browser, Next.js, Electron, Bun, and Deno with a unified API.
9
7
 
10
8
  ## Features ✨
11
- - **Zero-Trust Network Operations**: Mitigates Server-Side Request Forgery (SSRF) and DNS Rebinding via native `dns.lookup` hooks.
12
- - **Micro-Optimized Performance**: Capable of processing over 68,000 URLs per second using non-blocking worker pools and LRU caches.
13
- - **Deep Heuristics**: Detects IDN Homograph attacks, mixed scripts, Punycode abuse, protocol downgrades, and redirect loops.
14
- - **Bomb Protection**: Protects against Slowloris attacks, Zip bombs, and compression bombs at the TCP socket level.
15
- - **Dual Build**: Fully tree-shakable ESM and CJS exports.
9
+ - **Write Once, Run Anywhere**: Automatically detects the runtime environment to serve the best implementation.
10
+ - **Frontend Verification**: React Native, Expo, and Web Apps execute fast local checks (URL extraction, punycode, homographs, regex rules) in <10ms.
11
+ - **Backend Verification**: Node.js/Bun servers enrich analysis with deep network checks (DNS rebinding, HTTPS certificates, redirect tracing) and Threat Intelligence Providers (URLHaus, OpenPhish).
12
+ - **Consensus & Policy Engine**: Configurable policies calculate trust scores and decide actions (`allow`, `warn`, `block`).
16
13
 
17
14
  ## Installation 📦
18
15
 
19
16
  ```bash
20
17
  npm install safe-link-checker
21
- # or
22
- yarn add safe-link-checker
23
- # or
24
- pnpm add safe-link-checker
25
18
  ```
26
-
27
- > **Requirements**: Node.js 18.0.0 or later.
19
+ > **One package.** Installs the correct bundle for your platform automatically.
20
+
21
+ ## Compatibility Matrix 📊
22
+
23
+ | Feature \ Platform | Node.js / Bun | React Native / Expo | Browser / Web |
24
+ |:---|:---:|:---:|:---:|
25
+ | URL Normalization | ✅ | ✅ | ✅ |
26
+ | URL Extraction | ✅ | ✅ | ✅ |
27
+ | Regex / Heuristics | ✅ | ✅ | ✅ |
28
+ | Homograph / Punycode| ✅ | ✅ | ✅ |
29
+ | Private IP / SSRF | ✅ | ✅ | ✅ |
30
+ | Explainable Scoring | ✅ | ✅ | ✅ |
31
+ | Cache Engine | ✅ | ✅ | ✅ |
32
+ | DNS Lookup | ✅ | ❌ | ❌ |
33
+ | HTTPS Certificate | ✅ | ❌ | ❌ |
34
+ | Redirect Tracing | ✅ | ❌ | ❌ |
35
+ | Threat Providers | ✅ | ❌ | ❌ |
28
36
 
29
37
  ## Quick Start 🚀
30
38
 
39
+ ### In Node.js / Backend
40
+
31
41
  ```typescript
32
- import { SafeLinkChecker } from 'safe-link-checker';
42
+ import { SafeLinkChecker, verifyLink } from 'safe-link-checker';
33
43
 
44
+ // Uses Node.js networking, DNS, and Threat Intelligence automatically
34
45
  const checker = new SafeLinkChecker({
35
46
  providers: ['urlhaus', 'openphish'],
36
47
  cache: true,
37
- maxRedirects: 5
48
+ checkHttps: true,
38
49
  });
39
50
 
40
- async function run() {
41
- const result = await checker.verify('https://example.com');
42
-
43
- console.log(`Is Safe? ${result.safe}`);
44
- console.log(`Threat Score: ${result.score}/100`);
45
-
46
- if (!result.safe) {
47
- console.log(`Reasons: ${result.reasons.join(', ')}`);
48
- }
49
- }
50
-
51
- run();
51
+ const result = await checker.verify('https://example.com');
52
+ console.log(result.runtime); // 'node'
53
+ console.log(result.decision); // 'allow'
54
+ console.log(result.capabilities.performed); // ['UrlValidation', 'HttpsValidation', ...]
52
55
  ```
53
56
 
54
- ## Batch Processing (68k+ URLs/sec) ⚡️
55
-
56
- You can verify massive lists of URLs concurrently. The engine automatically handles concurrency limits and caches results.
57
+ ### In React Native / Browser (e.g. Chat Composer)
57
58
 
58
59
  ```typescript
59
- const urls = [
60
- 'https://google.com',
61
- 'http://malicious-phishing.com',
62
- 'http://localhost/admin' // Caught by SSRF protection
63
- ];
64
-
65
- const results = await checker.verifyLinks(urls, { timeout: 3000 }, 10); // Concurrency of 10
66
- results.forEach(res => console.log(`${res.url} -> Safe: ${res.safe}`));
60
+ import { SafeLinkChecker, extractUrls } from 'safe-link-checker';
61
+
62
+ // Fast local execution - blocks obvious threats before they are sent
63
+ const checker = new SafeLinkChecker();
64
+
65
+ const text = "Check this out: http://google.com and http://evil.com/exe";
66
+ const urls = extractUrls(text);
67
+
68
+ const results = await checker.verifyLinks(urls);
69
+ const blockedUrls = results.filter(r => r.decision === 'block');
70
+
71
+ if (blockedUrls.length > 0) {
72
+ alert('Malicious link detected! Please remove before sending.');
73
+ }
67
74
  ```
68
75
 
69
- ## Architecture 🏗️
76
+ ## Result Model
70
77
 
71
- `SafeLinkChecker` operates on a **Consensus Engine** and **Plugin Factory** model:
72
- - `Plugins` (e.g., `UrlValidation`, `IpValidation`, `PunycodePlugin`) independently analyze a URL and emit a `CheckResult` with a `scoreImpact`.
73
- - The `ConsensusEngine` aggregates these scores. A score >= 50 triggers a fatal abort.
74
- - `Providers` (e.g., URLHaus, OpenPhish) hit cloud intelligence feeds.
78
+ Both runtimes return the exact same structured result format:
75
79
 
76
- ## Security 🔒
77
- Please review our [Security Policy](SECURITY.md) for reporting vulnerabilities. We take SSRF and DNS rebinding protections extremely seriously.
80
+ ```typescript
81
+ {
82
+ url: 'https://evil.com',
83
+ safe: false,
84
+ decision: 'block',
85
+ score: 100,
86
+ confidence: 90,
87
+ riskLevel: 'DANGEROUS',
88
+ summary: 'Detected suspicious patterns.',
89
+ action: 'block',
90
+ runtime: 'react-native',
91
+ capabilities: {
92
+ performed: ['UrlValidation', 'Punycode', 'Heuristics'],
93
+ skipped: ['dns', 'certificate', 'redirect_trace']
94
+ }
95
+ }
96
+ ```
78
97
 
79
- ## Contributing 🤝
80
- Contributions, issues, and feature requests are welcome!
81
- See the [Contributing Guidelines](CONTRIBUTING.md) to get started.
98
+ ## Security 🔒
99
+ Please review our [Security Policy](SECURITY.md) for reporting vulnerabilities.
82
100
 
83
101
  ## License 📄
84
102
  [MIT](LICENSE) © 2026 Rajeev Choudhary
@@ -0,0 +1 @@
1
+ 'use strict';var chunkK5U3MVS5_cjs=require('../chunk-K5U3MVS5.cjs'),chunkXNJKJHJI_cjs=require('../chunk-XNJKJHJI.cjs');Object.defineProperty(exports,"SafeLinkChecker",{enumerable:true,get:function(){return chunkK5U3MVS5_cjs.c}});Object.defineProperty(exports,"SafeLinkError",{enumerable:true,get:function(){return chunkK5U3MVS5_cjs.a}});Object.defineProperty(exports,"TimeoutError",{enumerable:true,get:function(){return chunkK5U3MVS5_cjs.b}});Object.defineProperty(exports,"extractUrls",{enumerable:true,get:function(){return chunkK5U3MVS5_cjs.f}});Object.defineProperty(exports,"verifyLink",{enumerable:true,get:function(){return chunkK5U3MVS5_cjs.d}});Object.defineProperty(exports,"verifyLinks",{enumerable:true,get:function(){return chunkK5U3MVS5_cjs.e}});Object.defineProperty(exports,"AnalyticsTracker",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.o}});Object.defineProperty(exports,"CloudGateway",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.r}});Object.defineProperty(exports,"ConsensusEngine",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.f}});Object.defineProperty(exports,"DefaultPluginFactory",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.d}});Object.defineProperty(exports,"EventEmitter",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.c}});Object.defineProperty(exports,"LRUCache",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.a}});Object.defineProperty(exports,"MemoryCache",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.a}});Object.defineProperty(exports,"PluginManager",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.e}});Object.defineProperty(exports,"PolicyEngine",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.g}});Object.defineProperty(exports,"RealtimeSubscriptionEngine",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.p}});Object.defineProperty(exports,"ReputationEngine",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.q}});Object.defineProperty(exports,"RuleEnginePlugin",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.h}});Object.defineProperty(exports,"createSecurityReport",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.t}});Object.defineProperty(exports,"defaultCache",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.b}});Object.defineProperty(exports,"formatResult",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.s}});Object.defineProperty(exports,"injectReportHelpers",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.u}});Object.defineProperty(exports,"normalizeLink",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.i}});Object.defineProperty(exports,"validateHeuristics",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.n}});Object.defineProperty(exports,"validateIp",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.k}});Object.defineProperty(exports,"validatePunycode",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.l}});Object.defineProperty(exports,"validateShortener",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.m}});Object.defineProperty(exports,"validateUrl",{enumerable:true,get:function(){return chunkXNJKJHJI_cjs.j}});
@@ -0,0 +1,258 @@
1
+ export { MemoryCache, defaultCache } from '@safe-link-checker/cache/memory.js';
2
+ export { LRUCache } from '@safe-link-checker/cache/lru.js';
3
+ export { EventEmitter } from './core/events.js';
4
+ export { DefaultPluginFactory } from './core/factory.js';
5
+ export { PluginContext, PluginManager, PluginType, VerificationPlugin } from './core/plugin.js';
6
+ export { ConsensusEngine } from './engine/consensus.js';
7
+ export { PolicyEngine } from './engine/policy.js';
8
+ export { RuleEnginePlugin } from './engine/rules.js';
9
+ export { normalizeLink } from './utils/normalize.js';
10
+ export { validateUrl } from './validators/url.js';
11
+ export { validateIp } from './validators/ip.js';
12
+ export { validatePunycode } from './validators/punycode.js';
13
+ export { validateShortener } from './validators/shortener.js';
14
+ export { validateHeuristics } from './validators/heuristic.js';
15
+ export { AnalyticsTracker } from './analytics/tracker.js';
16
+ export { RealtimeSubscriptionEngine } from './realtime/subscription.js';
17
+ export { ReputationEngine, ReputationResult } from './engine/reputation.js';
18
+ export { CloudGateway } from './cloud/gateway.js';
19
+ export { formatResult } from './utils/formatter.js';
20
+ export { ReportData, createSecurityReport, injectReportHelpers } from './utils/report.js';
21
+ export { extractUrls, verifyLink, verifyLinks } from './verify.js';
22
+ export { CheckerOptions, SafeLinkChecker, SafeLinkError, TimeoutError } from './checker.js';
23
+ import './base.js';
24
+ import './validators/https.js';
25
+ import './validators/redirect.js';
26
+
27
+ /**
28
+ * SafeLinkChecker
29
+ * Copyright (c) 2026
30
+ *
31
+ * This source code is licensed under the MIT license found in the
32
+ * LICENSE file in the root directory of this source tree.
33
+ */
34
+ type RiskLevel = 'SAFE' | 'SUSPICIOUS' | 'DANGEROUS';
35
+ type HttpsStatus = 'HTTPS' | 'HTTP_ONLY' | 'CERT_ERROR' | 'TIMEOUT' | 'UNREACHABLE' | 'SKIPPED';
36
+ type RedirectAnomalyKind = 'LOOP' | 'PROTOCOL_DOWNGRADE' | 'MAX_REDIRECTS_EXCEEDED';
37
+ type RiskCategory = 'domain' | 'certificate' | 'redirect' | 'content' | 'network' | 'provider' | 'browser' | 'email' | 'qr' | 'download' | 'behavior' | 'ai' | 'other';
38
+ type RiskSeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';
39
+ type DecisionAction = 'allow' | 'warn' | 'block' | 'unknown' | 'ALLOW' | 'WARN' | 'REVIEW' | 'BLOCK' | 'ESCALATE';
40
+ type Classification = 'trusted' | 'safe' | 'suspicious' | 'unknown' | 'tracking' | 'spam' | 'phishing' | 'malware' | 'credential_theft' | 'scam' | 'brand_impersonation' | 'typosquatting' | 'Safe' | 'Suspicious' | 'Phishing' | 'Malware' | 'Scam' | 'Typosquatting' | 'Brand Impersonation' | 'Tracking' | 'Unsafe' | 'Unknown';
41
+ type ThreatLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL' | 'UNKNOWN';
42
+ interface ObservabilityHooks {
43
+ onStart?: (url: string, options: VerifyOptions) => void;
44
+ onFinish?: (result: VerificationResult) => void;
45
+ onWarning?: (url: string, reasons: string[]) => void;
46
+ onBlocked?: (url: string, reasons: string[]) => void;
47
+ onProvider?: (providerName: string, result: CheckResult) => void;
48
+ onCacheHit?: (url: string) => void;
49
+ onCacheMiss?: (url: string) => void;
50
+ }
51
+ interface VerifyOptions {
52
+ maxRedirects?: number;
53
+ timeout?: number;
54
+ customShorteners?: string[];
55
+ bypassCache?: boolean;
56
+ removeTrackingParams?: boolean;
57
+ checkHttps?: boolean;
58
+ signal?: AbortSignal;
59
+ policy?: string;
60
+ hooks?: ObservabilityHooks;
61
+ realtime?: boolean;
62
+ cloud?: {
63
+ enabled: boolean;
64
+ apiKey: string;
65
+ endpoint?: string;
66
+ };
67
+ telemetry?: {
68
+ enabled: boolean;
69
+ level?: 'anonymous' | 'full';
70
+ };
71
+ debug?: boolean;
72
+ }
73
+ interface CheckResult {
74
+ name: string;
75
+ safe: boolean;
76
+ scoreImpact: number;
77
+ message: string;
78
+ weight?: number;
79
+ fatal?: boolean;
80
+ detector?: string;
81
+ category?: RiskCategory;
82
+ severity?: RiskSeverity;
83
+ confidence?: number;
84
+ scoreContribution?: number;
85
+ title?: string;
86
+ description?: string;
87
+ recommendation?: string;
88
+ references?: string[];
89
+ executionTime?: number;
90
+ timestamp?: number;
91
+ metadata?: Record<string, unknown>;
92
+ }
93
+ interface Provider {
94
+ name: string;
95
+ check(url: string, options?: VerifyOptions): Promise<CheckResult | null>;
96
+ }
97
+ interface RedirectHop {
98
+ url: string;
99
+ statusCode: number;
100
+ }
101
+ interface RedirectTrace {
102
+ chain: string[];
103
+ finalUrl: string;
104
+ redirectCount: number;
105
+ anomalies: RedirectAnomalyKind[];
106
+ }
107
+ interface ExecutionTimeline {
108
+ phase: string;
109
+ startTime: number;
110
+ durationMs: number;
111
+ status: 'success' | 'error' | 'skipped';
112
+ }
113
+ interface RichMetadata {
114
+ favicon?: string;
115
+ title?: string;
116
+ description?: string;
117
+ openGraph?: Record<string, string>;
118
+ twitterCards?: Record<string, string>;
119
+ canonicalUrl?: string;
120
+ detectedBrand?: string;
121
+ detectedLanguage?: string;
122
+ contentType?: string;
123
+ server?: string;
124
+ country?: string;
125
+ hostingProvider?: string;
126
+ asn?: string;
127
+ }
128
+ interface ExecutionStats {
129
+ totalTimeMs: number;
130
+ startTime: number;
131
+ endTime: number;
132
+ }
133
+ interface VerificationMeta {
134
+ mode: 'offline' | 'online' | 'hybrid';
135
+ engine: 'heuristics' | 'network' | 'cloud' | 'combined';
136
+ version: string;
137
+ duration: number;
138
+ cached: boolean;
139
+ cacheSource: 'memory' | 'redis' | 'filesystem' | 'cloud' | 'none';
140
+ timestamp: string;
141
+ }
142
+ interface Evidence {
143
+ id: string;
144
+ title: string;
145
+ category: string;
146
+ status: 'passed' | 'failed' | 'skipped' | 'unknown';
147
+ weight: number;
148
+ message: string;
149
+ recommendation?: string;
150
+ documentationUrl?: string;
151
+ }
152
+ interface Capabilities {
153
+ runtime: string;
154
+ performed: string[];
155
+ skipped: string[];
156
+ }
157
+ interface SecurityBadge {
158
+ label: string;
159
+ variant: 'success' | 'warn' | 'block' | 'unknown' | 'allow';
160
+ icon: string;
161
+ color: string;
162
+ }
163
+ interface VisualScore {
164
+ value: number;
165
+ max: number;
166
+ grade: 'A+' | 'A' | 'B' | 'C' | 'D' | 'F';
167
+ label: string;
168
+ }
169
+ interface ThreatDetails {
170
+ level: string;
171
+ category: string;
172
+ family: string | null;
173
+ techniques: string[];
174
+ }
175
+ interface UrlDetails {
176
+ original: string;
177
+ normalized: string;
178
+ hostname: string;
179
+ domain: string;
180
+ subdomain: string;
181
+ tld: string;
182
+ protocol: string;
183
+ port: string;
184
+ path: string;
185
+ query: string;
186
+ hash: string;
187
+ }
188
+ interface PerformanceMetrics {
189
+ duration: number;
190
+ cacheHit: boolean;
191
+ cacheKey?: string;
192
+ pluginsExecuted: number;
193
+ pluginsSkipped: number;
194
+ }
195
+ interface PluginExecutionDetails {
196
+ plugin: string;
197
+ status: 'passed' | 'failed' | 'skipped';
198
+ duration: number;
199
+ scoreContribution: number;
200
+ }
201
+ interface VerificationResult {
202
+ safe: boolean;
203
+ decision: DecisionAction;
204
+ classification: Classification;
205
+ trustScore: number;
206
+ riskScore: number;
207
+ confidence: number;
208
+ severity: RiskSeverity | string;
209
+ summary: string;
210
+ recommendation: string;
211
+ runtime: string;
212
+ verification: VerificationMeta;
213
+ evidence: Evidence[];
214
+ capabilities: Capabilities;
215
+ badge: SecurityBadge;
216
+ score: VisualScore;
217
+ threat: ThreatDetails;
218
+ url: UrlDetails;
219
+ performance: PerformanceMetrics;
220
+ pluginResults?: PluginExecutionDetails[];
221
+ riskLevel?: RiskLevel;
222
+ reasons?: string[];
223
+ recommendations?: string[];
224
+ checks?: CheckResult[];
225
+ categories?: Record<string, number>;
226
+ providerResults?: CheckResult[];
227
+ redirectChain?: string[];
228
+ redirectTrace?: RedirectTrace;
229
+ fromCache?: boolean;
230
+ action?: string;
231
+ policy?: string;
232
+ timeline?: ExecutionTimeline[];
233
+ execution?: ExecutionStats;
234
+ metadata?: RichMetadata | Record<string, unknown>;
235
+ isSafe?: () => boolean;
236
+ shouldWarn?: () => boolean;
237
+ shouldBlock?: () => boolean;
238
+ toJSON?: () => any;
239
+ toString?: () => string;
240
+ toMarkdown?: () => string;
241
+ toHTML?: () => string;
242
+ export?: (format: 'json' | 'markdown' | 'html') => string;
243
+ }
244
+ interface PickledResult {
245
+ url: string;
246
+ safe: boolean;
247
+ decision: DecisionAction;
248
+ trustScore: number;
249
+ riskScore: number;
250
+ classification: Classification;
251
+ threatLevel: ThreatLevel;
252
+ securityBadge: string;
253
+ riskColor: string;
254
+ summary: string;
255
+ recommendation: string;
256
+ }
257
+
258
+ export type { Capabilities, CheckResult, Classification, DecisionAction, Evidence, ExecutionStats, ExecutionTimeline, HttpsStatus, ObservabilityHooks, PerformanceMetrics, PickledResult, PluginExecutionDetails, Provider, RedirectAnomalyKind, RedirectHop, RedirectTrace, RichMetadata, RiskCategory, RiskLevel, RiskSeverity, SecurityBadge, ThreatDetails, ThreatLevel, UrlDetails, VerificationMeta, VerificationResult, VerifyOptions, VisualScore };
@@ -0,0 +1,258 @@
1
+ export { MemoryCache, defaultCache } from '@safe-link-checker/cache/memory.js';
2
+ export { LRUCache } from '@safe-link-checker/cache/lru.js';
3
+ export { EventEmitter } from './core/events.js';
4
+ export { DefaultPluginFactory } from './core/factory.js';
5
+ export { PluginContext, PluginManager, PluginType, VerificationPlugin } from './core/plugin.js';
6
+ export { ConsensusEngine } from './engine/consensus.js';
7
+ export { PolicyEngine } from './engine/policy.js';
8
+ export { RuleEnginePlugin } from './engine/rules.js';
9
+ export { normalizeLink } from './utils/normalize.js';
10
+ export { validateUrl } from './validators/url.js';
11
+ export { validateIp } from './validators/ip.js';
12
+ export { validatePunycode } from './validators/punycode.js';
13
+ export { validateShortener } from './validators/shortener.js';
14
+ export { validateHeuristics } from './validators/heuristic.js';
15
+ export { AnalyticsTracker } from './analytics/tracker.js';
16
+ export { RealtimeSubscriptionEngine } from './realtime/subscription.js';
17
+ export { ReputationEngine, ReputationResult } from './engine/reputation.js';
18
+ export { CloudGateway } from './cloud/gateway.js';
19
+ export { formatResult } from './utils/formatter.js';
20
+ export { ReportData, createSecurityReport, injectReportHelpers } from './utils/report.js';
21
+ export { extractUrls, verifyLink, verifyLinks } from './verify.js';
22
+ export { CheckerOptions, SafeLinkChecker, SafeLinkError, TimeoutError } from './checker.js';
23
+ import './base.js';
24
+ import './validators/https.js';
25
+ import './validators/redirect.js';
26
+
27
+ /**
28
+ * SafeLinkChecker
29
+ * Copyright (c) 2026
30
+ *
31
+ * This source code is licensed under the MIT license found in the
32
+ * LICENSE file in the root directory of this source tree.
33
+ */
34
+ type RiskLevel = 'SAFE' | 'SUSPICIOUS' | 'DANGEROUS';
35
+ type HttpsStatus = 'HTTPS' | 'HTTP_ONLY' | 'CERT_ERROR' | 'TIMEOUT' | 'UNREACHABLE' | 'SKIPPED';
36
+ type RedirectAnomalyKind = 'LOOP' | 'PROTOCOL_DOWNGRADE' | 'MAX_REDIRECTS_EXCEEDED';
37
+ type RiskCategory = 'domain' | 'certificate' | 'redirect' | 'content' | 'network' | 'provider' | 'browser' | 'email' | 'qr' | 'download' | 'behavior' | 'ai' | 'other';
38
+ type RiskSeverity = 'critical' | 'high' | 'medium' | 'low' | 'info';
39
+ type DecisionAction = 'allow' | 'warn' | 'block' | 'unknown' | 'ALLOW' | 'WARN' | 'REVIEW' | 'BLOCK' | 'ESCALATE';
40
+ type Classification = 'trusted' | 'safe' | 'suspicious' | 'unknown' | 'tracking' | 'spam' | 'phishing' | 'malware' | 'credential_theft' | 'scam' | 'brand_impersonation' | 'typosquatting' | 'Safe' | 'Suspicious' | 'Phishing' | 'Malware' | 'Scam' | 'Typosquatting' | 'Brand Impersonation' | 'Tracking' | 'Unsafe' | 'Unknown';
41
+ type ThreatLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL' | 'UNKNOWN';
42
+ interface ObservabilityHooks {
43
+ onStart?: (url: string, options: VerifyOptions) => void;
44
+ onFinish?: (result: VerificationResult) => void;
45
+ onWarning?: (url: string, reasons: string[]) => void;
46
+ onBlocked?: (url: string, reasons: string[]) => void;
47
+ onProvider?: (providerName: string, result: CheckResult) => void;
48
+ onCacheHit?: (url: string) => void;
49
+ onCacheMiss?: (url: string) => void;
50
+ }
51
+ interface VerifyOptions {
52
+ maxRedirects?: number;
53
+ timeout?: number;
54
+ customShorteners?: string[];
55
+ bypassCache?: boolean;
56
+ removeTrackingParams?: boolean;
57
+ checkHttps?: boolean;
58
+ signal?: AbortSignal;
59
+ policy?: string;
60
+ hooks?: ObservabilityHooks;
61
+ realtime?: boolean;
62
+ cloud?: {
63
+ enabled: boolean;
64
+ apiKey: string;
65
+ endpoint?: string;
66
+ };
67
+ telemetry?: {
68
+ enabled: boolean;
69
+ level?: 'anonymous' | 'full';
70
+ };
71
+ debug?: boolean;
72
+ }
73
+ interface CheckResult {
74
+ name: string;
75
+ safe: boolean;
76
+ scoreImpact: number;
77
+ message: string;
78
+ weight?: number;
79
+ fatal?: boolean;
80
+ detector?: string;
81
+ category?: RiskCategory;
82
+ severity?: RiskSeverity;
83
+ confidence?: number;
84
+ scoreContribution?: number;
85
+ title?: string;
86
+ description?: string;
87
+ recommendation?: string;
88
+ references?: string[];
89
+ executionTime?: number;
90
+ timestamp?: number;
91
+ metadata?: Record<string, unknown>;
92
+ }
93
+ interface Provider {
94
+ name: string;
95
+ check(url: string, options?: VerifyOptions): Promise<CheckResult | null>;
96
+ }
97
+ interface RedirectHop {
98
+ url: string;
99
+ statusCode: number;
100
+ }
101
+ interface RedirectTrace {
102
+ chain: string[];
103
+ finalUrl: string;
104
+ redirectCount: number;
105
+ anomalies: RedirectAnomalyKind[];
106
+ }
107
+ interface ExecutionTimeline {
108
+ phase: string;
109
+ startTime: number;
110
+ durationMs: number;
111
+ status: 'success' | 'error' | 'skipped';
112
+ }
113
+ interface RichMetadata {
114
+ favicon?: string;
115
+ title?: string;
116
+ description?: string;
117
+ openGraph?: Record<string, string>;
118
+ twitterCards?: Record<string, string>;
119
+ canonicalUrl?: string;
120
+ detectedBrand?: string;
121
+ detectedLanguage?: string;
122
+ contentType?: string;
123
+ server?: string;
124
+ country?: string;
125
+ hostingProvider?: string;
126
+ asn?: string;
127
+ }
128
+ interface ExecutionStats {
129
+ totalTimeMs: number;
130
+ startTime: number;
131
+ endTime: number;
132
+ }
133
+ interface VerificationMeta {
134
+ mode: 'offline' | 'online' | 'hybrid';
135
+ engine: 'heuristics' | 'network' | 'cloud' | 'combined';
136
+ version: string;
137
+ duration: number;
138
+ cached: boolean;
139
+ cacheSource: 'memory' | 'redis' | 'filesystem' | 'cloud' | 'none';
140
+ timestamp: string;
141
+ }
142
+ interface Evidence {
143
+ id: string;
144
+ title: string;
145
+ category: string;
146
+ status: 'passed' | 'failed' | 'skipped' | 'unknown';
147
+ weight: number;
148
+ message: string;
149
+ recommendation?: string;
150
+ documentationUrl?: string;
151
+ }
152
+ interface Capabilities {
153
+ runtime: string;
154
+ performed: string[];
155
+ skipped: string[];
156
+ }
157
+ interface SecurityBadge {
158
+ label: string;
159
+ variant: 'success' | 'warn' | 'block' | 'unknown' | 'allow';
160
+ icon: string;
161
+ color: string;
162
+ }
163
+ interface VisualScore {
164
+ value: number;
165
+ max: number;
166
+ grade: 'A+' | 'A' | 'B' | 'C' | 'D' | 'F';
167
+ label: string;
168
+ }
169
+ interface ThreatDetails {
170
+ level: string;
171
+ category: string;
172
+ family: string | null;
173
+ techniques: string[];
174
+ }
175
+ interface UrlDetails {
176
+ original: string;
177
+ normalized: string;
178
+ hostname: string;
179
+ domain: string;
180
+ subdomain: string;
181
+ tld: string;
182
+ protocol: string;
183
+ port: string;
184
+ path: string;
185
+ query: string;
186
+ hash: string;
187
+ }
188
+ interface PerformanceMetrics {
189
+ duration: number;
190
+ cacheHit: boolean;
191
+ cacheKey?: string;
192
+ pluginsExecuted: number;
193
+ pluginsSkipped: number;
194
+ }
195
+ interface PluginExecutionDetails {
196
+ plugin: string;
197
+ status: 'passed' | 'failed' | 'skipped';
198
+ duration: number;
199
+ scoreContribution: number;
200
+ }
201
+ interface VerificationResult {
202
+ safe: boolean;
203
+ decision: DecisionAction;
204
+ classification: Classification;
205
+ trustScore: number;
206
+ riskScore: number;
207
+ confidence: number;
208
+ severity: RiskSeverity | string;
209
+ summary: string;
210
+ recommendation: string;
211
+ runtime: string;
212
+ verification: VerificationMeta;
213
+ evidence: Evidence[];
214
+ capabilities: Capabilities;
215
+ badge: SecurityBadge;
216
+ score: VisualScore;
217
+ threat: ThreatDetails;
218
+ url: UrlDetails;
219
+ performance: PerformanceMetrics;
220
+ pluginResults?: PluginExecutionDetails[];
221
+ riskLevel?: RiskLevel;
222
+ reasons?: string[];
223
+ recommendations?: string[];
224
+ checks?: CheckResult[];
225
+ categories?: Record<string, number>;
226
+ providerResults?: CheckResult[];
227
+ redirectChain?: string[];
228
+ redirectTrace?: RedirectTrace;
229
+ fromCache?: boolean;
230
+ action?: string;
231
+ policy?: string;
232
+ timeline?: ExecutionTimeline[];
233
+ execution?: ExecutionStats;
234
+ metadata?: RichMetadata | Record<string, unknown>;
235
+ isSafe?: () => boolean;
236
+ shouldWarn?: () => boolean;
237
+ shouldBlock?: () => boolean;
238
+ toJSON?: () => any;
239
+ toString?: () => string;
240
+ toMarkdown?: () => string;
241
+ toHTML?: () => string;
242
+ export?: (format: 'json' | 'markdown' | 'html') => string;
243
+ }
244
+ interface PickledResult {
245
+ url: string;
246
+ safe: boolean;
247
+ decision: DecisionAction;
248
+ trustScore: number;
249
+ riskScore: number;
250
+ classification: Classification;
251
+ threatLevel: ThreatLevel;
252
+ securityBadge: string;
253
+ riskColor: string;
254
+ summary: string;
255
+ recommendation: string;
256
+ }
257
+
258
+ export type { Capabilities, CheckResult, Classification, DecisionAction, Evidence, ExecutionStats, ExecutionTimeline, HttpsStatus, ObservabilityHooks, PerformanceMetrics, PickledResult, PluginExecutionDetails, Provider, RedirectAnomalyKind, RedirectHop, RedirectTrace, RichMetadata, RiskCategory, RiskLevel, RiskSeverity, SecurityBadge, ThreatDetails, ThreatLevel, UrlDetails, VerificationMeta, VerificationResult, VerifyOptions, VisualScore };
@@ -0,0 +1 @@
1
+ export{c as SafeLinkChecker,a as SafeLinkError,b as TimeoutError,f as extractUrls,d as verifyLink,e as verifyLinks}from'../chunk-DDF3IZSI.js';export{o as AnalyticsTracker,r as CloudGateway,f as ConsensusEngine,d as DefaultPluginFactory,c as EventEmitter,a as LRUCache,a as MemoryCache,e as PluginManager,g as PolicyEngine,p as RealtimeSubscriptionEngine,q as ReputationEngine,h as RuleEnginePlugin,t as createSecurityReport,b as defaultCache,s as formatResult,u as injectReportHelpers,i as normalizeLink,n as validateHeuristics,k as validateIp,l as validatePunycode,m as validateShortener,j as validateUrl}from'../chunk-LWMILG2I.js';