/** `URL`: parses and resolves a url string, and exposes its parts. */ export declare const URL_POLYFILL = "\n // Collapses '.' and '..'. A backslash separates path segments, the way the host parser reads\n // one, so it is folded into '/' first \u2014 otherwise the two disagree about where the host name\n // ends in 'https://a.example\\@b.example/', and guest code reads a host the gateway never calls.\n const normalizePath = (rawPath) => {\n const path = rawPath.replace(/\\\\/g, '/');\n const out = [];\n for (const segment of path.split('/')) {\n if (segment === '.') continue;\n if (segment === '..') { if (out.length > 1) out.pop(); continue; }\n out.push(segment);\n }\n let joined = out.join('/');\n if ((path.endsWith('/.') || path.endsWith('/..')) && !joined.endsWith('/')) joined += '/';\n return joined;\n };\n\n const DEFAULT_PORTS = { 'http:': '80', 'https:': '443', 'ws:': '80', 'wss:': '443', 'ftp:': '21' };\n\n // Percent-encode what cannot travel literally in a url, so a hand-assembled path or query\n // reaches the host parser as the caller meant it. Non-ASCII goes out as UTF-8, in runs, so a\n // surrogate pair is encoded as the one character it stands for.\n const encodeLiterals = (value) =>\n value.replace(/[\\s\"<>\\`{}\\\\^]|[^\\x00-\\x7F]+/g, (chunk) => {\n try { return encodeURIComponent(chunk); } catch (error) { return chunk; }\n });\n\n // A non-ASCII host name is lower-cased but not punycoded \u2014 that needs an IDNA table this sandbox\n // does not carry. The host re-parses the url before it fetches, so the request still goes to the\n // punycoded name; only what guest code reads back differs.\n const parseHostPort = (hostport, scheme) => {\n let hostname = hostport;\n let port = '';\n if (hostport.startsWith('[')) {\n const close = hostport.indexOf(']');\n hostname = hostport.slice(0, close + 1);\n const after = hostport.slice(close + 1);\n if (after.startsWith(':')) port = after.slice(1);\n } else {\n const colon = hostport.lastIndexOf(':');\n if (colon !== -1) { hostname = hostport.slice(0, colon); port = hostport.slice(colon + 1); }\n }\n if (port !== '' && !/^[0-9]+$/.test(port)) return null;\n if (hostname === '') return null;\n return {\n hostname: hostname.toLowerCase(),\n port: DEFAULT_PORTS[scheme] === port ? '' : port,\n // A host written without a port leaves the port alone, rather than clearing it.\n hasPort: port !== '',\n };\n };\n\n const ABSOLUTE_RE = /^([A-Za-z][A-Za-z0-9+\\-.]*):(\\/\\/)?([\\s\\S]*)$/;\n\n const parseAuthorityUrl = (scheme, rest) => {\n const cut = rest.search(/[/\\\\?#]/);\n const authority = cut === -1 ? rest : rest.slice(0, cut);\n let tail = cut === -1 ? '' : rest.slice(cut);\n let username = '';\n let password = '';\n let hostport = authority;\n const at = authority.lastIndexOf('@');\n if (at !== -1) {\n const credentials = authority.slice(0, at);\n hostport = authority.slice(at + 1);\n const colon = credentials.indexOf(':');\n username = colon === -1 ? credentials : credentials.slice(0, colon);\n password = colon === -1 ? '' : credentials.slice(colon + 1);\n }\n const hostPort = parseHostPort(hostport, scheme);\n if (!hostPort) return null;\n let hash = '';\n const hashAt = tail.indexOf('#');\n if (hashAt !== -1) { hash = tail.slice(hashAt); tail = tail.slice(0, hashAt); }\n let search = '';\n const queryAt = tail.indexOf('?');\n if (queryAt !== -1) { search = tail.slice(queryAt); tail = tail.slice(0, queryAt); }\n let pathname = tail === '' ? '/' : tail;\n if (!/^[/\\\\]/.test(pathname)) pathname = '/' + pathname;\n return {\n protocol: scheme,\n username,\n password,\n hostname: hostPort.hostname,\n port: hostPort.port,\n pathname: encodeLiterals(normalizePath(pathname)),\n search: encodeLiterals(search === '?' ? '' : search),\n hash: encodeLiterals(hash === '#' ? '' : hash),\n };\n };\n\n const parseUrl = (input, base) => {\n // A tab or newline inside a url is dropped, not encoded \u2014 the host parser does the same, and\n // a url copied out of a wrapped response body is the usual way one gets in here.\n const str = String(input).trim().replace(/[\\t\\n\\r]/g, '');\n const matched = ABSOLUTE_RE.exec(str);\n // A scheme with no `//` (mailto:, data:) is not a fetch target, so it is not resolved.\n if (matched) return matched[2] ? parseAuthorityUrl(matched[1].toLowerCase() + ':', matched[3]) : null;\n if (base === undefined) return null;\n const resolved = parseUrl(base, undefined);\n if (!resolved) return null;\n if (/^[/\\\\]{2}/.test(str)) return parseAuthorityUrl(resolved.protocol, str.slice(2));\n const parts = { ...resolved };\n if (str.startsWith('#')) {\n parts.hash = encodeLiterals(str === '#' ? '' : str);\n return parts;\n }\n let rest = str;\n let hash = '';\n const hashAt = rest.indexOf('#');\n if (hashAt !== -1) { hash = rest.slice(hashAt); rest = rest.slice(0, hashAt); }\n let search = '';\n const queryAt = rest.indexOf('?');\n if (queryAt !== -1) { search = rest.slice(queryAt); rest = rest.slice(0, queryAt); }\n if (rest !== '') {\n const absolute = /^[/\\\\]/.test(rest)\n ? rest\n : resolved.pathname.slice(0, resolved.pathname.lastIndexOf('/') + 1) + rest;\n parts.pathname = encodeLiterals(normalizePath(absolute));\n }\n // An empty reference with no query of its own keeps the base query (RFC 3986 section 5.3).\n parts.search = rest === '' && search === '' ? resolved.search : encodeLiterals(search === '?' ? '' : search);\n parts.hash = encodeLiterals(hash === '#' ? '' : hash);\n return parts;\n };\n\n const URL = class URL {\n constructor(input, base) {\n const parsed = parseUrl(input, base === undefined ? undefined : String(base));\n if (!parsed) throw new TypeError('Invalid URL: ' + String(input));\n this._parts = parsed;\n this._params = undefined;\n this._edited = false;\n }\n // The query stays exactly as it arrived until searchParams edits it, so reading a url apart\n // and putting it back together does not re-encode what the server sent.\n _applyParams() {\n if (this._edited && this._params) {\n const query = this._params.toString();\n this._parts.search = query ? '?' + query : '';\n this._edited = false;\n }\n }\n // Every part a caller can read, it can also write. Guest code runs sloppy, so a missing\n // setter would swallow `url.host = \u2026` and fetch the address the caller meant to replace.\n get protocol() { return this._parts.protocol; }\n set protocol(value) {\n const next = String(value).toLowerCase().replace(/:$/, '') + ':';\n // Only a scheme that carries an authority can replace one, the way the host parser reads it.\n if (DEFAULT_PORTS[next] !== undefined) this._parts.protocol = next;\n }\n get username() { return this._parts.username; }\n set username(value) { this._parts.username = String(value); }\n get password() { return this._parts.password; }\n set password(value) { this._parts.password = String(value); }\n get hostname() { return this._parts.hostname; }\n set hostname(value) { this._parts.hostname = String(value).toLowerCase(); }\n get port() { return this._parts.port; }\n set port(value) {\n const port = String(value);\n if (port !== '' && !/^[0-9]+$/.test(port)) return;\n this._parts.port = DEFAULT_PORTS[this._parts.protocol] === port ? '' : port;\n }\n get host() {\n return this._parts.port ? this._parts.hostname + ':' + this._parts.port : this._parts.hostname;\n }\n set host(value) {\n const parsed = parseHostPort(String(value), this._parts.protocol);\n if (!parsed) return;\n this._parts.hostname = parsed.hostname;\n if (parsed.hasPort) this._parts.port = parsed.port;\n }\n get origin() { return this._parts.protocol + '//' + this.host; }\n get pathname() { return this._parts.pathname; }\n set pathname(value) {\n const path = String(value);\n this._parts.pathname = encodeLiterals(path.startsWith('/') ? path : '/' + path);\n }\n get search() {\n this._applyParams();\n return this._parts.search;\n }\n set search(value) {\n const query = String(value);\n const body = query.startsWith('?') ? query.slice(1) : query;\n this._parts.search = body ? encodeLiterals('?' + body) : '';\n this._params = undefined;\n this._edited = false;\n }\n get searchParams() {\n if (!this._params) {\n const params = new URLSearchParams(this._parts.search);\n const url = this;\n // Every method that can change the parameters has to mark the query for re-serialization.\n for (const method of ['append', 'set', 'delete', 'sort']) {\n const original = params[method];\n params[method] = function (...args) {\n url._edited = true;\n return original.apply(params, args);\n };\n }\n this._params = params;\n }\n return this._params;\n }\n get hash() { return this._parts.hash; }\n set hash(value) {\n const fragment = String(value);\n this._parts.hash = fragment === ''\n ? ''\n : encodeLiterals(fragment.startsWith('#') ? fragment : '#' + fragment);\n }\n get href() {\n this._applyParams();\n const credentials = this._parts.username\n ? this._parts.username + (this._parts.password ? ':' + this._parts.password : '') + '@'\n : '';\n return this._parts.protocol + '//' + credentials + this.host +\n this._parts.pathname + this._parts.search + this._parts.hash;\n }\n set href(value) {\n const parsed = parseUrl(value, undefined);\n if (!parsed) throw new TypeError('Invalid URL: ' + String(value));\n this._parts = parsed;\n this._params = undefined;\n this._edited = false;\n }\n toString() { return this.href; }\n toJSON() { return this.href; }\n static canParse(input, base) {\n return parseUrl(input, base === undefined ? undefined : String(base)) !== null;\n }\n static parse(input, base) {\n const parsed = parseUrl(input, base === undefined ? undefined : String(base));\n return parsed ? new URL(input, base) : null;\n }\n };\n globalThis.URL = URL;\n"; //# sourceMappingURL=url.d.ts.map