1+ import validator from "validator" ;
12import { fetch as undiciFetch , EnvHttpProxyAgent } from "undici" ;
23import {
34 EventSource ,
45 type FetchLike ,
56 type EventSourceFetchInit ,
67 type ErrorEvent ,
78} from "eventsource" ;
9+ import url from "node:url" ;
10+ import querystring from "node:querystring" ;
811
912type Severity = "info" | "error" ;
1013
@@ -20,26 +23,6 @@ interface Options {
2023
2124const proxyAgent = new EnvHttpProxyAgent ( ) ;
2225
23- const trimTrailingSlash = ( url : string ) : string => {
24- return url . lastIndexOf ( "/" ) === url . length - 1 ? url . slice ( 0 , - 1 ) : url ;
25- } ;
26-
27- function validateURL ( urlString : string ) : asserts urlString is string {
28- if ( URL . canParse ( urlString ) === false ) {
29- throw new Error ( `The provided URL is invalid.` ) ;
30- }
31-
32- const url = new URL ( urlString ) ;
33-
34- if ( ! url . protocol || ! [ "http:" , "https:" ] . includes ( url . protocol ) ) {
35- throw new Error ( `The provided URL is invalid.` ) ;
36- }
37-
38- if ( ! url . host ) {
39- throw new Error ( `The provided URL is invalid.` ) ;
40- }
41- }
42-
4326class SmeeClient {
4427 #source: string ;
4528 #target: string ;
@@ -67,13 +50,11 @@ class SmeeClient {
6750
6851 const data = JSON . parse ( msg . data ) ;
6952
70- const target = new URL ( this . #target) ;
53+ const target = url . parse ( this . #target, true ) ;
7154
72- if ( this . #queryForwarding && data . query ) {
73- Object . keys ( data . query ) . forEach ( ( key ) => {
74- target . searchParams . set ( key , data . query [ key ] ) ;
75- } ) ;
76- target . search = target . searchParams . toString ( ) ;
55+ if ( this . #queryForwarding) {
56+ const mergedQuery = { ...target . query , ...data . query } ;
57+ target . search = querystring . stringify ( mergedQuery ) ;
7758 }
7859
7960 delete data . query ;
@@ -95,7 +76,7 @@ class SmeeClient {
9576 headers [ "content-type" ] = "application/json" ;
9677
9778 try {
98- const response = await this . #fetch( target , {
79+ const response = await this . #fetch( url . format ( target ) , {
9980 method : "POST" ,
10081 mode : data [ "sec-fetch-mode" ] ,
10182 body,
@@ -121,16 +102,21 @@ class SmeeClient {
121102 queryForwarding = true ,
122103 forward,
123104 } : Options ) {
124- validateURL ( target ) ;
125- validateURL ( source ) ;
126-
127- this . #source = trimTrailingSlash ( new URL ( source ) . toString ( ) ) ;
128- this . #target = trimTrailingSlash ( new URL ( target ) . toString ( ) ) ;
105+ this . #source = source ;
106+ this . #target = target ;
129107 this . #logger = logger ! ;
130108 this . #fetch = fetch ;
131109 this . #queryForwarding = queryForwarding ;
132110 this . #maxConnectionTimeout = maxConnectionTimeout ;
133111 this . #forward = forward ;
112+
113+ if (
114+ ! validator . isURL ( this . #source, {
115+ require_tld : false ,
116+ } )
117+ ) {
118+ throw new Error ( "The provided URL is invalid." ) ;
119+ }
134120 }
135121
136122 static async createChannel ( {
0 commit comments