diff --git a/crates/native-sidecar/src/execution/javascript/http.rs b/crates/native-sidecar/src/execution/javascript/http.rs index 6ceb178b43..291303eca5 100644 --- a/crates/native-sidecar/src/execution/javascript/http.rs +++ b/crates/native-sidecar/src/execution/javascript/http.rs @@ -4,6 +4,7 @@ use crate::state::DeferredRpcError; const HTTP_LOOPBACK_REQUEST_TIMEOUT: Duration = Duration::from_secs(30); const VM_FETCH_STREAM_CHUNK_MAX_BYTES: usize = 64 * 1024; const VM_FETCH_STREAM_COUNT_LIMIT: usize = 256; +type VmFetchResponseHead = (u16, String, Vec<(String, String)>, VmFetchBodyMode); fn http_loopback_request_timeout() -> Duration { std::env::var(HTTP_LOOPBACK_REQUEST_TIMEOUT_MS_ENV) @@ -272,7 +273,7 @@ fn parse_stream_response_head( bytes: &[u8], request_method: &str, max_response_bytes: usize, -) -> Result<(u16, String, Vec<(String, String)>, VmFetchBodyMode), SidecarError> { +) -> Result { let text = std::str::from_utf8(bytes).map_err(|error| { SidecarError::Execution(format!( "ERR_AGENTOS_VM_FETCH_INVALID_RESPONSE: response headers were not UTF-8: {error}" diff --git a/packages/build-tools/bridge-src/builtins/url-resolution.ts b/packages/build-tools/bridge-src/builtins/url-resolution.ts deleted file mode 100644 index 8638af1e21..0000000000 --- a/packages/build-tools/bridge-src/builtins/url-resolution.ts +++ /dev/null @@ -1,36 +0,0 @@ -export function resolveRelativeNonFileUrl(raw, baseUrl, posixPath) { - const basePathname = baseUrl.pathname || "/"; - const origin = `${baseUrl.protocol}//${baseUrl.host}`; - if (raw.startsWith("//")) { - return `${baseUrl.protocol}${raw}`; - } - if (raw.startsWith("#")) { - return `${origin}${basePathname}${baseUrl.search || ""}${raw}`; - } - if (raw.startsWith("?")) { - return `${origin}${basePathname}${raw}`; - } - if (raw === "") { - return `${origin}${basePathname}${baseUrl.search || ""}`; - } - const queryIndex = raw.indexOf("?"); - const hashIndex = raw.indexOf("#"); - const searchStart = queryIndex === -1 ? raw.length : queryIndex; - const hashStart = hashIndex === -1 ? raw.length : hashIndex; - const pathEnd = Math.min(searchStart, hashStart); - const relativePath = raw.slice(0, pathEnd); - const suffix = raw.slice(pathEnd); - const baseDirectory = basePathname.endsWith("/") - ? basePathname - : posixPath.dirname(basePathname); - let resolvedPath = relativePath.startsWith("/") - ? posixPath.resolve("/", relativePath) - : posixPath.resolve(baseDirectory, relativePath); - if ( - (relativePath.endsWith("/") || /(^|\/)\.\.?$/.test(relativePath)) && - !resolvedPath.endsWith("/") - ) { - resolvedPath += "/"; - } - return `${origin}${resolvedPath}${suffix}`; -} diff --git a/packages/build-tools/bridge-src/builtins/whatwg-url.ts b/packages/build-tools/bridge-src/builtins/whatwg-url.ts index f422b3c8cd..9a9ef5772a 100644 --- a/packages/build-tools/bridge-src/builtins/whatwg-url.ts +++ b/packages/build-tools/bridge-src/builtins/whatwg-url.ts @@ -1,489 +1,22 @@ -import { builtinPathStdlibModule } from "./builtin-modules.js"; +import { + URL as UpstreamURL, + URLSearchParams as UpstreamURLSearchParams, +} from "whatwg-url"; import { Blob } from "./network.js"; -import { TextDecoder } from "../polyfills/index.js"; -import { urlStdlibModuleNs } from "../prelude.js"; -import { resolveRelativeNonFileUrl } from "./url-resolution.js"; -var inspectCustomSymbol = /* @__PURE__ */ Symbol.for( - "nodejs.util.inspect.custom", -); -var toStringTagSymbol = Symbol.toStringTag; -var ERR_INVALID_THIS = "ERR_INVALID_THIS"; -var ERR_MISSING_ARGS = "ERR_MISSING_ARGS"; -var ERR_INVALID_URL = "ERR_INVALID_URL"; -var ERR_ARG_NOT_ITERABLE = "ERR_ARG_NOT_ITERABLE"; -var ERR_INVALID_TUPLE = "ERR_INVALID_TUPLE"; -var URL_SEARCH_PARAMS_TYPE = "URLSearchParams"; -var kLinkedSearchParams = /* @__PURE__ */ Symbol( - "secureExecLinkedURLSearchParams", -); -var kBlobUrlStore = /* @__PURE__ */ Symbol.for("secureExec.blobUrlStore"); -var kBlobUrlCounter = /* @__PURE__ */ Symbol.for("secureExec.blobUrlCounter"); -var SEARCH_PARAM_METHOD_NAMES = ["append", "delete", "get", "getAll", "has"]; -var SEARCH_PARAM_PAIR_METHOD_NAMES = ["append", "set"]; -var SEARCH_PARAM_SYNC_METHOD_NAMES = ["append", "delete", "set", "sort"]; -var URL_SCHEME_TYPES = { - "http:": 0, - "https:": 2, - "ws:": 4, - "wss:": 5, - "file:": 6, - "ftp:": 8, -}; -var searchParamsBrand = /* @__PURE__ */ new WeakSet(); -var searchParamsState = /* @__PURE__ */ new WeakMap(); -var searchParamsIteratorBrand = /* @__PURE__ */ new WeakSet(); -var searchParamsIteratorState = /* @__PURE__ */ new WeakMap(); +const kBlobUrlStore = /* @__PURE__ */ Symbol.for("secureExec.blobUrlStore"); +const kBlobUrlCounter = /* @__PURE__ */ Symbol.for("secureExec.blobUrlCounter"); + function createNodeTypeError(message, code) { const error = new TypeError(message); error.code = code; return error; } -function createInvalidUrlError() { - const error = new TypeError("Invalid URL"); - error.code = ERR_INVALID_URL; - return error; -} -function createUrlReceiverTypeError() { - return new TypeError("Receiver must be an instance of class URL"); -} + function createMissingArgsError(message) { - return createNodeTypeError(message, ERR_MISSING_ARGS); -} -function createIterableTypeError() { - return createNodeTypeError( - "Query pairs must be iterable", - ERR_ARG_NOT_ITERABLE, - ); -} -function createTupleTypeError() { - return createNodeTypeError( - "Each query pair must be an iterable [name, value] tuple", - ERR_INVALID_TUPLE, - ); -} -function createSymbolStringError() { - return new TypeError("Cannot convert a Symbol value to a string"); -} -function toNodeString(value) { - if (typeof value === "symbol") { - throw createSymbolStringError(); - } - return String(value); -} -function toWellFormedString(value) { - let result = ""; - for (let index = 0; index < value.length; index += 1) { - const codeUnit = value.charCodeAt(index); - if (codeUnit >= 55296 && codeUnit <= 56319) { - const nextIndex = index + 1; - if (nextIndex < value.length) { - const nextCodeUnit = value.charCodeAt(nextIndex); - if (nextCodeUnit >= 56320 && nextCodeUnit <= 57343) { - result += value[index] + value[nextIndex]; - index = nextIndex; - continue; - } - } - result += "\uFFFD"; - continue; - } - if (codeUnit >= 56320 && codeUnit <= 57343) { - result += "\uFFFD"; - continue; - } - result += value[index]; - } - return result; -} -function toNodeUSVString(value) { - return toWellFormedString(toNodeString(value)); -} -function assertUrlSearchParamsReceiver(receiver) { - if (!searchParamsBrand.has(receiver)) { - throw createNodeTypeError( - 'Value of "this" must be of type URLSearchParams', - ERR_INVALID_THIS, - ); - } -} -function assertUrlSearchParamsIteratorReceiver(receiver) { - if (!searchParamsIteratorBrand.has(receiver)) { - throw createNodeTypeError( - 'Value of "this" must be of type URLSearchParamsIterator', - ERR_INVALID_THIS, - ); - } -} -function getUrlSearchParamsImpl(receiver) { - const state = searchParamsState.get(receiver); - if (!state) { - throw createNodeTypeError( - 'Value of "this" must be of type URLSearchParams', - ERR_INVALID_THIS, - ); - } - return state.getImpl(); -} -function countSearchParams(params) { - let count = 0; - for (const _entry of params) { - count++; - } - return count; -} -function isAsciiHexCodeUnit(codeUnit) { - return ( - (codeUnit >= 48 && codeUnit <= 57) || - (codeUnit >= 65 && codeUnit <= 70) || - (codeUnit >= 97 && codeUnit <= 102) - ); -} -function decodeAsciiHexCodeUnit(codeUnit) { - if (codeUnit >= 48 && codeUnit <= 57) { - return codeUnit - 48; - } - if (codeUnit >= 65 && codeUnit <= 70) { - return codeUnit - 55; - } - return codeUnit - 87; -} -function appendUtf8CodePoint(bytes, codePoint) { - if (codePoint <= 127) { - bytes.push(codePoint); - return; - } - if (codePoint <= 2047) { - bytes.push(192 | (codePoint >> 6), 128 | (codePoint & 63)); - return; - } - if (codePoint <= 65535) { - bytes.push( - 224 | (codePoint >> 12), - 128 | ((codePoint >> 6) & 63), - 128 | (codePoint & 63), - ); - return; - } - bytes.push( - 240 | (codePoint >> 18), - 128 | ((codePoint >> 12) & 63), - 128 | ((codePoint >> 6) & 63), - 128 | (codePoint & 63), - ); -} -function decodeFormUrlencodedComponent(value) { - const source = String(value).replace(/\+/g, " "); - let output = ""; - for (let index = 0; index < source.length; index += 1) { - if (source.charCodeAt(index) === 37 && index + 2 < source.length) { - const bytes = []; - let nextIndex = index; - while ( - nextIndex + 2 < source.length && - source.charCodeAt(nextIndex) === 37 - ) { - const high = source.charCodeAt(nextIndex + 1); - const low = source.charCodeAt(nextIndex + 2); - if (!isAsciiHexCodeUnit(high) || !isAsciiHexCodeUnit(low)) { - break; - } - bytes.push( - (decodeAsciiHexCodeUnit(high) << 4) + decodeAsciiHexCodeUnit(low), - ); - nextIndex += 3; - } - if (bytes.length > 0) { - output += new TextDecoder().decode(Uint8Array.from(bytes)); - index = nextIndex - 1; - continue; - } - } - const codePoint = source.codePointAt(index); - output += String.fromCodePoint(codePoint); - if (codePoint > 65535) { - index += 1; - } - } - return output; -} -function serializeFormUrlencodedComponent(value) { - const input = String(value); - const bytes = []; - for (let index = 0; index < input.length; index += 1) { - const codePoint = input.codePointAt(index); - appendUtf8CodePoint(bytes, codePoint); - if (codePoint > 65535) { - index += 1; - } - } - let output = ""; - for (const byte of bytes) { - if (byte === 32) { - output += "+"; - continue; - } - const isAlphaNumeric = - (byte >= 48 && byte <= 57) || - (byte >= 65 && byte <= 90) || - (byte >= 97 && byte <= 122); - if ( - isAlphaNumeric || - byte === 42 || - byte === 45 || - byte === 46 || - byte === 95 - ) { - output += String.fromCharCode(byte); - continue; - } - output += `%${byte.toString(16).toUpperCase().padStart(2, "0")}`; - } - return output; -} -function compareCodeUnitStrings(left, right) { - const minLength = Math.min(left.length, right.length); - for (let index = 0; index < minLength; index += 1) { - const diff = left.charCodeAt(index) - right.charCodeAt(index); - if (diff !== 0) { - return diff; - } - } - return left.length - right.length; -} -function normalizeSearchParamsInit(init) { - if (init && typeof init === "object" && kLinkedSearchParams in init) { - return init; - } - if (init == null) { - return void 0; - } - if (typeof init === "string") { - return toNodeUSVString(init); - } - if (typeof init === "object" || typeof init === "function") { - const iterator2 = init[Symbol.iterator]; - if (iterator2 !== void 0) { - if (typeof iterator2 !== "function") { - throw createIterableTypeError(); - } - const pairs2 = []; - for (const pair of init) { - if (pair == null) { - throw createTupleTypeError(); - } - const pairIterator = pair[Symbol.iterator]; - if (typeof pairIterator !== "function") { - throw createTupleTypeError(); - } - const values = Array.from(pair); - if (values.length !== 2) { - throw createTupleTypeError(); - } - pairs2.push([toNodeUSVString(values[0]), toNodeUSVString(values[1])]); - } - return pairs2; - } - const pairs = []; - for (const key of Reflect.ownKeys(init)) { - if (!Object.prototype.propertyIsEnumerable.call(init, key)) { - continue; - } - pairs.push([toNodeUSVString(key), toNodeUSVString(init[key])]); - } - return pairs; - } - return toNodeUSVString(init); -} -var NativeURLSearchParams = - typeof globalThis.URLSearchParams === "function" && - globalThis.URLSearchParams.__secureExecBootstrapStub !== true - ? globalThis.URLSearchParams - : class URLSearchParams { - constructor(init = "") { - this._pairs = []; - if (typeof init === "string") { - const query = init.replace(/^\?/, ""); - if (!query) { - return; - } - for (const entry of query.split("&")) { - if (!entry) { - continue; - } - const [key, ...rest] = entry.split("="); - this._pairs.push([ - decodeFormUrlencodedComponent(key), - decodeFormUrlencodedComponent(rest.join("=")), - ]); - } - return; - } - if (Array.isArray(init)) { - for (const pair of init) { - if (pair == null || pair.length !== 2) { - continue; - } - this._pairs.push([String(pair[0]), String(pair[1])]); - } - return; - } - if (init && typeof init === "object") { - for (const [key, value] of Object.entries(init)) { - this._pairs.push([String(key), String(value)]); - } - } - } - append(name, value) { - this._pairs.push([String(name), String(value)]); - } - delete(name) { - const key = String(name); - this._pairs = this._pairs.filter(([candidate]) => candidate !== key); - } - get(name) { - const key = String(name); - const match = this._pairs.find(([candidate]) => candidate === key); - return match ? match[1] : null; - } - getAll(name) { - const key = String(name); - return this._pairs - .filter(([candidate]) => candidate === key) - .map(([, value]) => value); - } - has(name) { - const key = String(name); - return this._pairs.some(([candidate]) => candidate === key); - } - set(name, value) { - const key = String(name); - const stringValue = String(value); - const nextPairs = []; - let replaced = false; - for (const [candidate, currentValue] of this._pairs) { - if (candidate !== key) { - nextPairs.push([candidate, currentValue]); - continue; - } - if (!replaced) { - replaced = true; - nextPairs.push([key, stringValue]); - } - } - if (!replaced) { - nextPairs.push([key, stringValue]); - } - this._pairs = nextPairs; - } - sort() { - this._pairs = this._pairs - .map((pair, index) => ({ pair, index })) - .sort((left, right) => { - const diff = compareCodeUnitStrings(left.pair[0], right.pair[0]); - return diff !== 0 ? diff : left.index - right.index; - }) - .map(({ pair }) => pair); - } - entries() { - return this._pairs[Symbol.iterator](); - } - keys() { - return this._pairs.map(([key]) => key)[Symbol.iterator](); - } - values() { - return this._pairs.map(([, value]) => value)[Symbol.iterator](); - } - [Symbol.iterator]() { - return this.entries(); - } - toString() { - return this._pairs - .map( - ([key, value]) => - `${serializeFormUrlencodedComponent(key)}=${serializeFormUrlencodedComponent(value)}`, - ) - .join("&"); - } - }; -function createStandaloneSearchParams(init) { - if (typeof init === "string") { - return new NativeURLSearchParams(init); - } - return init === void 0 - ? new NativeURLSearchParams() - : new NativeURLSearchParams(init); -} -function createCollectionBody(items, options, emptyBody) { - if (items.length === 0) { - return emptyBody; - } - const oneLine = `{ ${items.join(", ")} }`; - const breakLength = options?.breakLength ?? Infinity; - if (oneLine.length <= breakLength) { - return oneLine; - } - return `{ -${items.join(",\n ")} }`; -} -function createUrlContext(url) { - const href = url.href; - const protocolEnd = href.indexOf(":") + 1; - const authIndex = href.indexOf("@"); - const pathnameStart = href.indexOf("/", protocolEnd + 2); - const searchStart = href.indexOf("?"); - const hashStart = href.indexOf("#"); - const usernameEnd = - url.username.length > 0 - ? href.indexOf(":", protocolEnd + 2) - : protocolEnd + 2; - const hostStart = authIndex === -1 ? protocolEnd + 2 : authIndex; - const hostEnd = - pathnameStart === -1 - ? href.length - : pathnameStart - (url.port.length > 0 ? url.port.length + 1 : 0); - const port = url.port.length > 0 ? Number(url.port) : null; - return { - href, - protocol_end: protocolEnd, - username_end: usernameEnd, - host_start: hostStart, - host_end: hostEnd, - pathname_start: pathnameStart === -1 ? href.length : pathnameStart, - search_start: searchStart === -1 ? href.length : searchStart, - hash_start: hashStart === -1 ? href.length : hashStart, - port, - scheme_type: URL_SCHEME_TYPES[url.protocol] ?? 1, - hasPort: url.port.length > 0, - hasSearch: url.search.length > 0, - hasHash: url.hash.length > 0, - }; -} -function formatUrlContext(url, inspect, options) { - const context = createUrlContext(url); - const formatValue = - typeof inspect === "function" - ? (value) => inspect(value, options) - : (value) => JSON.stringify(value); - const portValue = context.port === null ? "null" : String(context.port); - return [ - "URLContext {", - ` href: ${formatValue(context.href)},`, - ` protocol_end: ${context.protocol_end},`, - ` username_end: ${context.username_end},`, - ` host_start: ${context.host_start},`, - ` host_end: ${context.host_end},`, - ` pathname_start: ${context.pathname_start},`, - ` search_start: ${context.search_start},`, - ` hash_start: ${context.hash_start},`, - ` port: ${portValue},`, - ` scheme_type: ${context.scheme_type},`, - " [hasPort]: [Getter],", - " [hasSearch]: [Getter],", - " [hasHash]: [Getter]", - " }", - ].join("\n"); + return createNodeTypeError(message, "ERR_MISSING_ARGS"); } + function getBlobUrlStore() { const globalRecord = globalThis; const existing = globalRecord[kBlobUrlStore]; @@ -494,6 +27,7 @@ function getBlobUrlStore() { globalRecord[kBlobUrlStore] = store; return store; } + function nextBlobUrlId() { const globalRecord = globalThis; const nextId = @@ -503,725 +37,48 @@ function nextBlobUrlId() { globalRecord[kBlobUrlCounter] = nextId + 1; return nextId; } -var URLSearchParamsIterator = class _URLSearchParamsIterator { - constructor(values) { - searchParamsIteratorBrand.add(this); - searchParamsIteratorState.set(this, { values, index: 0 }); - } - next() { - assertUrlSearchParamsIteratorReceiver(this); - const state = searchParamsIteratorState.get(this); - if (state.index >= state.values.length) { - return { value: void 0, done: true }; - } - const value = state.values[state.index]; - state.index += 1; - return { value, done: false }; - } - [inspectCustomSymbol](depth, options, inspect) { - assertUrlSearchParamsIteratorReceiver(this); - if (depth < 0) { - return "[Object]"; - } - const state = searchParamsIteratorState.get(this); - const formatValue = - typeof inspect === "function" - ? (value) => inspect(value, options) - : (value) => JSON.stringify(value); - const remaining = state.values - .slice(state.index) - .map((value) => formatValue(value)); - return `URLSearchParams Iterator ${createCollectionBody(remaining, options, "{ }")}`; - } - get [toStringTagSymbol]() { - if (this !== _URLSearchParamsIterator.prototype) { - assertUrlSearchParamsIteratorReceiver(this); - } - return "URLSearchParams Iterator"; - } -}; -Object.defineProperties(URLSearchParamsIterator.prototype, { - next: { - value: URLSearchParamsIterator.prototype.next, - writable: true, - configurable: true, - enumerable: true, - }, - [Symbol.iterator]: { - value: function iterator() { - assertUrlSearchParamsIteratorReceiver(this); - return this; - }, - writable: true, - configurable: true, - enumerable: false, - }, - [inspectCustomSymbol]: { - value: URLSearchParamsIterator.prototype[inspectCustomSymbol], - writable: true, - configurable: true, - enumerable: false, - }, - [toStringTagSymbol]: { - get: Object.getOwnPropertyDescriptor( - URLSearchParamsIterator.prototype, - toStringTagSymbol, - )?.get, - configurable: true, - enumerable: false, - }, -}); -Object.defineProperty( - Object.getOwnPropertyDescriptor( - URLSearchParamsIterator.prototype, - Symbol.iterator, - )?.value, - "name", - { - value: "entries", - configurable: true, - }, -); -var URLSearchParams = class _URLSearchParams { - constructor(init) { - searchParamsBrand.add(this); - const normalized = normalizeSearchParamsInit(init); - if ( - normalized && - typeof normalized === "object" && - kLinkedSearchParams in normalized - ) { - searchParamsState.set(this, { - getImpl: normalized[kLinkedSearchParams], - }); - return; - } - const impl = createStandaloneSearchParams(normalized); - searchParamsState.set(this, { getImpl: () => impl }); - } - append(name, value) { - assertUrlSearchParamsReceiver(this); - if (arguments.length < 2) { - throw createMissingArgsError( - 'The "name" and "value" arguments must be specified', - ); - } - getUrlSearchParamsImpl(this).append( - toNodeUSVString(name), - toNodeUSVString(value), - ); - } - delete(name) { - assertUrlSearchParamsReceiver(this); - if (arguments.length < 1) { - throw createMissingArgsError('The "name" argument must be specified'); - } - getUrlSearchParamsImpl(this).delete(toNodeUSVString(name)); - } - get(name) { - assertUrlSearchParamsReceiver(this); - if (arguments.length < 1) { - throw createMissingArgsError('The "name" argument must be specified'); - } - return getUrlSearchParamsImpl(this).get(toNodeUSVString(name)); - } - getAll(name) { - assertUrlSearchParamsReceiver(this); - if (arguments.length < 1) { - throw createMissingArgsError('The "name" argument must be specified'); - } - return getUrlSearchParamsImpl(this).getAll(toNodeUSVString(name)); - } - has(name) { - assertUrlSearchParamsReceiver(this); - if (arguments.length < 1) { - throw createMissingArgsError('The "name" argument must be specified'); - } - return getUrlSearchParamsImpl(this).has(toNodeUSVString(name)); - } - set(name, value) { - assertUrlSearchParamsReceiver(this); - if (arguments.length < 2) { - throw createMissingArgsError( - 'The "name" and "value" arguments must be specified', - ); - } - getUrlSearchParamsImpl(this).set( - toNodeUSVString(name), - toNodeUSVString(value), - ); - } - sort() { - assertUrlSearchParamsReceiver(this); - getUrlSearchParamsImpl(this).sort(); - } - entries() { - assertUrlSearchParamsReceiver(this); - return new URLSearchParamsIterator( - Array.from(getUrlSearchParamsImpl(this)), - ); - } - keys() { - assertUrlSearchParamsReceiver(this); - return new URLSearchParamsIterator( - Array.from(getUrlSearchParamsImpl(this).keys()), - ); - } - values() { - assertUrlSearchParamsReceiver(this); - return new URLSearchParamsIterator( - Array.from(getUrlSearchParamsImpl(this).values()), - ); - } - forEach(callback, thisArg) { - assertUrlSearchParamsReceiver(this); - if (typeof callback !== "function") { - throw createNodeTypeError( - 'The "callback" argument must be of type function. Received ' + - (callback === void 0 ? "undefined" : typeof callback), - "ERR_INVALID_ARG_TYPE", - ); - } - for (const [key, value] of getUrlSearchParamsImpl(this)) { - callback.call(thisArg, value, key, this); - } - } - toString() { - assertUrlSearchParamsReceiver(this); - return getUrlSearchParamsImpl(this).toString(); - } - get size() { - assertUrlSearchParamsReceiver(this); - return countSearchParams(getUrlSearchParamsImpl(this)); - } - [inspectCustomSymbol](depth, options, inspect) { - assertUrlSearchParamsReceiver(this); - if (depth < 0) { - return "[Object]"; - } - const formatValue = - typeof inspect === "function" - ? (value) => inspect(value, options) - : (value) => JSON.stringify(value); - const items = Array.from(getUrlSearchParamsImpl(this)).map( - ([key, value]) => `${formatValue(key)} => ${formatValue(value)}`, - ); - return `URLSearchParams ${createCollectionBody(items, options, "{}")}`; - } - get [toStringTagSymbol]() { - if (this !== _URLSearchParams.prototype) { - assertUrlSearchParamsReceiver(this); - } - return URL_SEARCH_PARAMS_TYPE; - } -}; -for (const name of SEARCH_PARAM_METHOD_NAMES) { - Object.defineProperty(URLSearchParams.prototype, name, { - value: URLSearchParams.prototype[name], - writable: true, - configurable: true, - enumerable: true, - }); -} -for (const name of SEARCH_PARAM_PAIR_METHOD_NAMES) { - Object.defineProperty(URLSearchParams.prototype, name, { - value: URLSearchParams.prototype[name], - writable: true, - configurable: true, - enumerable: true, - }); + +const URL2 = UpstreamURL; +const URLSearchParams = UpstreamURLSearchParams; + +if (globalThis.SharedArrayBuffer?.__agentOSBootstrapStub === true) { + delete globalThis.SharedArrayBuffer; } -for (const name of [ - "sort", - "entries", - "forEach", - "keys", - "values", - "toString", -]) { - Object.defineProperty(URLSearchParams.prototype, name, { - value: URLSearchParams.prototype[name], + +Object.defineProperties(URL2, { + createObjectURL: { + value(obj) { + if (typeof Blob === "undefined" || !(obj instanceof Blob)) { + throw createNodeTypeError( + 'The "obj" argument must be an instance of Blob. Received ' + + (obj === null ? "null" : typeof obj), + "ERR_INVALID_ARG_TYPE", + ); + } + const id = `blob:nodedata:${nextBlobUrlId()}`; + getBlobUrlStore().set(id, obj); + return id; + }, writable: true, configurable: true, enumerable: true, - }); -} -Object.defineProperties(URLSearchParams.prototype, { - size: { - get: Object.getOwnPropertyDescriptor(URLSearchParams.prototype, "size") - ?.get, - configurable: true, - enumerable: true, - }, - [Symbol.iterator]: { - value: URLSearchParams.prototype.entries, - writable: true, - configurable: true, - enumerable: false, - }, - [inspectCustomSymbol]: { - value: URLSearchParams.prototype[inspectCustomSymbol], - writable: true, - configurable: true, - enumerable: false, - }, - [toStringTagSymbol]: { - get: Object.getOwnPropertyDescriptor( - URLSearchParams.prototype, - toStringTagSymbol, - )?.get, - configurable: true, - enumerable: false, }, -}); -function canUseNativeUrlImplementation(candidate) { - if ( - typeof candidate !== "function" || - candidate.__secureExecBootstrapStub === true - ) { - return false; - } - try { - return ( - String( - new candidate("./child.mjs", "file:///root/base/entry.mjs").href, - ) === "file:///root/base/child.mjs" - ); - } catch { - return false; - } -} -function ensureTrailingSlashForFilePath(pathname) { - return pathname.endsWith("/") ? pathname : `${pathname}/`; -} -function normalizeRelativeFileUrlInput(input, base) { - const rawInput = String(input ?? ""); - if (!rawInput.startsWith("file:")) { - return { input: rawInput, base }; - } - const relativeMatch = /^file:(\.\.?(?:\/[^?#]*)?)([?#].*)?$/.exec(rawInput); - if (!relativeMatch) { - return { input: rawInput, base }; - } - const relativePath = relativeMatch[1]; - const suffix = relativeMatch[2] ?? ""; - let baseHref = typeof base === "undefined" ? "file:///" : String(base); - try { - const parsedBase = new globalThis.URL(baseHref); - if (parsedBase.protocol !== "file:") { - return { input: rawInput, base }; - } - let basePathname = parsedBase.pathname || "/"; - if (!basePathname.startsWith("/")) { - basePathname = `/${basePathname}`; - } - const baseDirectory = basePathname.endsWith("/") - ? basePathname - : builtinPathStdlibModule.posix.dirname(basePathname); - const resolvedPath = builtinPathStdlibModule.posix.resolve( - baseDirectory, - relativePath, - ); - const needsTrailingSlash = - relativePath === "." || - relativePath === ".." || - relativePath.endsWith("/"); - const normalizedPath = needsTrailingSlash - ? ensureTrailingSlashForFilePath(resolvedPath) - : resolvedPath; - return { - input: `file://${normalizedPath}${suffix}`, - base: void 0, - }; - } catch { - return { input: rawInput, base }; - } -} -var nativeUrlCandidate = - typeof urlStdlibModuleNs?.URL === "function" - ? urlStdlibModuleNs.URL - : typeof urlStdlibModuleNs?.default?.URL === "function" - ? urlStdlibModuleNs.default.URL - : globalThis.URL; -var NativeURL = canUseNativeUrlImplementation(nativeUrlCandidate) - ? nativeUrlCandidate - : class URL { - constructor(url, base) { - const raw = String(url ?? ""); - const hasScheme = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(raw); - if (!hasScheme && typeof base === "undefined") { - throw new TypeError(`Invalid URL: ${raw}`); - } - let full = raw; - if (!hasScheme) { - const baseUrl = new URL(base); - if (baseUrl.protocol === "file:") { - const queryIndex2 = raw.indexOf("?"); - const hashIndex2 = raw.indexOf("#"); - const searchStart2 = queryIndex2 === -1 ? raw.length : queryIndex2; - const hashStart2 = hashIndex2 === -1 ? raw.length : hashIndex2; - const pathEnd2 = Math.min(searchStart2, hashStart2); - const relativePath = raw.slice(0, pathEnd2); - const suffix = raw.slice(pathEnd2); - let basePathname = baseUrl.pathname || "/"; - if (!basePathname.startsWith("/")) { - basePathname = `/${basePathname}`; - } - const baseDirectory = basePathname.endsWith("/") - ? basePathname - : builtinPathStdlibModule.posix.dirname(basePathname); - let resolvedPath = builtinPathStdlibModule.posix.resolve( - baseDirectory, - relativePath, - ); - if ( - (relativePath.endsWith("/") || - /(^|\/)\.\.?$/.test(relativePath)) && - !resolvedPath.endsWith("/") - ) { - resolvedPath += "/"; - } - full = `file://${resolvedPath}${suffix}`; - } else { - full = resolveRelativeNonFileUrl( - raw, - baseUrl, - builtinPathStdlibModule.posix, - ); - } - } - const queryIndex = full.indexOf("?"); - const hashIndex = full.indexOf("#"); - const searchStart = queryIndex === -1 ? full.length : queryIndex; - const hashStart = hashIndex === -1 ? full.length : hashIndex; - const pathEnd = Math.min(searchStart, hashStart); - const searchValue = - queryIndex === -1 ? "" : full.slice(queryIndex, hashStart); - const hashValue = hashIndex === -1 ? "" : full.slice(hashIndex); - const bindSearchParams = (buildHref) => { - this.searchParams = new URLSearchParams(this.search); - for (const method of SEARCH_PARAM_SYNC_METHOD_NAMES) { - const original = this.searchParams[method]?.bind(this.searchParams); - if (!original) { - continue; - } - this.searchParams[method] = (...args) => { - const result = original(...args); - const query = this.searchParams.toString(); - this.search = query ? `?${query}` : ""; - this.href = buildHref(); - return result; - }; - } - }; - if (full.startsWith("file:")) { - let pathname = full.slice(5, pathEnd); - if (pathname.startsWith("//")) { - const authorityMatch = /^\/\/[^/]*(.*)$/.exec(pathname); - pathname = authorityMatch?.[1] || "/"; - } - if (!pathname.startsWith("/")) { - pathname = `/${pathname}`; - } - this.protocol = "file:"; - this.hostname = ""; - this.port = ""; - this.pathname = pathname || "/"; - this.search = searchValue; - this.hash = hashValue; - this.host = ""; - this.href = `file://${this.pathname}${this.search}${this.hash}`; - this.origin = "null"; - bindSearchParams( - () => `file://${this.pathname}${this.search}${this.hash}`, - ); - return; - } - const opaqueSchemeMatch = full.match( - /^([a-zA-Z][a-zA-Z\d+\-.]*:)(?!\/\/)/, - ); - if (opaqueSchemeMatch) { - const protocol = opaqueSchemeMatch[1]; - this.protocol = protocol; - this.hostname = ""; - this.port = ""; - this.host = ""; - this.pathname = full.slice(protocol.length, pathEnd); - this.search = searchValue; - this.hash = hashValue; - this.href = protocol + this.pathname + this.search + this.hash; - this.origin = "null"; - bindSearchParams( - () => protocol + this.pathname + this.search + this.hash, - ); - return; - } - const match = full.match(/^(\w+:)\/\/([^/:?#]+)(:\d+)?(.*)$/); - this.protocol = match?.[1] || ""; - this.hostname = match?.[2] || ""; - this.port = (match?.[3] || "").slice(1); - this.pathname = (match?.[4] || "/").split("?")[0].split("#")[0] || "/"; - this.search = full.includes("?") - ? "?" + full.split("?")[1].split("#")[0] - : ""; - this.hash = full.includes("#") ? "#" + full.split("#")[1] : ""; - this.host = this.hostname + (this.port ? ":" + this.port : ""); - this.href = - this.protocol + - "//" + - this.host + - this.pathname + - this.search + - this.hash; - this.origin = this.protocol + "//" + this.host; - bindSearchParams( - () => - this.protocol + - "//" + - this.host + - this.pathname + - this.search + - this.hash, - ); - } - toString() { - return this.href; + revokeObjectURL: { + value(...args) { + if (args.length < 1) { + throw createMissingArgsError('The "url" argument must be specified'); } - }; -var URL2 = class _URL { - #impl; - #searchParams; - constructor(input, base) { - if (arguments.length < 1) { - throw createMissingArgsError('The "url" argument must be specified'); - } - const normalizedArgs = normalizeRelativeFileUrlInput( - toNodeUSVString(input), - arguments.length >= 2 ? toNodeUSVString(base) : void 0, - ); - try { - this.#impl = - normalizedArgs.base !== void 0 - ? new NativeURL(normalizedArgs.input, normalizedArgs.base) - : new NativeURL(normalizedArgs.input); - } catch { - throw createInvalidUrlError(); - } - } - static canParse(input, base) { - if (arguments.length < 1) { - throw createMissingArgsError('The "url" argument must be specified'); - } - try { - if (arguments.length >= 2) { - new _URL(input, base); - } else { - new _URL(input); + const [url] = args; + if (typeof url === "string") { + getBlobUrlStore().delete(url); } - return true; - } catch { - return false; - } - } - static createObjectURL(obj) { - if (typeof Blob === "undefined" || !(obj instanceof Blob)) { - throw createNodeTypeError( - 'The "obj" argument must be an instance of Blob. Received ' + - (obj === null ? "null" : typeof obj), - "ERR_INVALID_ARG_TYPE", - ); - } - const id = `blob:nodedata:${nextBlobUrlId()}`; - getBlobUrlStore().set(id, obj); - return id; - } - static revokeObjectURL(url) { - if (arguments.length < 1) { - throw createMissingArgsError('The "url" argument must be specified'); - } - if (typeof url !== "string") { - return; - } - getBlobUrlStore().delete(url); - } - get href() { - if (!(this instanceof _URL)) { - throw createUrlReceiverTypeError(); - } - return this.#impl.href; - } - set href(value) { - this.#impl.href = toNodeUSVString(value); - } - get origin() { - return this.#impl.origin; - } - get protocol() { - return this.#impl.protocol; - } - set protocol(value) { - this.#impl.protocol = toNodeUSVString(value); - } - get username() { - return this.#impl.username; - } - set username(value) { - this.#impl.username = toNodeUSVString(value); - } - get password() { - return this.#impl.password; - } - set password(value) { - this.#impl.password = toNodeUSVString(value); - } - get host() { - return this.#impl.host; - } - set host(value) { - this.#impl.host = toNodeUSVString(value); - } - get hostname() { - return this.#impl.hostname; - } - set hostname(value) { - this.#impl.hostname = toNodeUSVString(value); - } - get port() { - return this.#impl.port; - } - set port(value) { - this.#impl.port = toNodeUSVString(value); - } - get pathname() { - return this.#impl.pathname; - } - set pathname(value) { - this.#impl.pathname = toNodeUSVString(value); - } - get search() { - if (!(this instanceof _URL)) { - throw createUrlReceiverTypeError(); - } - return this.#impl.search; - } - set search(value) { - this.#impl.search = toNodeUSVString(value); - } - get searchParams() { - if (!this.#searchParams) { - this.#searchParams = new URLSearchParams({ - [kLinkedSearchParams]: () => this.#impl.searchParams, - }); - } - return this.#searchParams; - } - get hash() { - return this.#impl.hash; - } - set hash(value) { - this.#impl.hash = toNodeUSVString(value); - } - toString() { - if (!(this instanceof _URL)) { - throw createUrlReceiverTypeError(); - } - return this.#impl.href; - } - toJSON() { - if (!(this instanceof _URL)) { - throw createUrlReceiverTypeError(); - } - return this.#impl.href; - } - [inspectCustomSymbol](depth, options, inspect) { - const inspectName = - this.constructor === _URL ? "URL" : this.constructor.name; - if (depth < 0) { - return `${inspectName} {}`; - } - const formatValue = - typeof inspect === "function" - ? (value) => inspect(value, options) - : (value) => JSON.stringify(value); - const lines = [ - `${inspectName} {`, - ` href: ${formatValue(this.href)},`, - ` origin: ${formatValue(this.origin)},`, - ` protocol: ${formatValue(this.protocol)},`, - ` username: ${formatValue(this.username)},`, - ` password: ${formatValue(this.password)},`, - ` host: ${formatValue(this.host)},`, - ` hostname: ${formatValue(this.hostname)},`, - ` port: ${formatValue(this.port)},`, - ` pathname: ${formatValue(this.pathname)},`, - ` search: ${formatValue(this.search)},`, - ` searchParams: ${this.searchParams[inspectCustomSymbol](depth - 1, void 0, inspect)},`, - ` hash: ${formatValue(this.hash)}`, - ]; - if (options?.showHidden) { - lines[lines.length - 1] += ","; - lines.push( - ` [Symbol(context)]: ${formatUrlContext(this, inspect, options)}`, - ); - } - lines.push("}"); - return lines.join("\n"); - } - get [toStringTagSymbol]() { - return "URL"; - } -}; -for (const name of ["toString", "toJSON"]) { - Object.defineProperty(URL2.prototype, name, { - value: URL2.prototype[name], + }, writable: true, configurable: true, enumerable: true, - }); -} -for (const name of [ - "href", - "protocol", - "username", - "password", - "host", - "hostname", - "port", - "pathname", - "search", - "hash", - "origin", - "searchParams", -]) { - const descriptor = Object.getOwnPropertyDescriptor(URL2.prototype, name); - if (!descriptor) { - continue; - } - descriptor.enumerable = true; - Object.defineProperty(URL2.prototype, name, descriptor); -} -Object.defineProperties(URL2.prototype, { - [inspectCustomSymbol]: { - value: URL2.prototype[inspectCustomSymbol], - writable: true, - configurable: true, - enumerable: false, - }, - [toStringTagSymbol]: { - get: Object.getOwnPropertyDescriptor(URL2.prototype, toStringTagSymbol) - ?.get, - configurable: true, - enumerable: false, }, }); -for (const name of ["canParse", "createObjectURL", "revokeObjectURL"]) { - Object.defineProperty(URL2, name, { - value: URL2[name], - writable: true, - configurable: true, - enumerable: true, - }); -} + function installWhatwgUrlGlobals(target = globalThis) { Object.defineProperty(target, "URL", { value: URL2, @@ -1236,60 +93,15 @@ function installWhatwgUrlGlobals(target = globalThis) { enumerable: false, }); } + export { - inspectCustomSymbol, - toStringTagSymbol, - ERR_INVALID_THIS, - ERR_MISSING_ARGS, - ERR_INVALID_URL, - ERR_ARG_NOT_ITERABLE, - ERR_INVALID_TUPLE, - URL_SEARCH_PARAMS_TYPE, - kLinkedSearchParams, - kBlobUrlStore, - kBlobUrlCounter, - SEARCH_PARAM_METHOD_NAMES, - SEARCH_PARAM_PAIR_METHOD_NAMES, - URL_SCHEME_TYPES, - searchParamsBrand, - searchParamsState, - searchParamsIteratorBrand, - searchParamsIteratorState, - createNodeTypeError, - createInvalidUrlError, - createUrlReceiverTypeError, createMissingArgsError, - createIterableTypeError, - createTupleTypeError, - createSymbolStringError, - toNodeString, - toWellFormedString, - toNodeUSVString, - assertUrlSearchParamsReceiver, - assertUrlSearchParamsIteratorReceiver, - getUrlSearchParamsImpl, - countSearchParams, - isAsciiHexCodeUnit, - decodeAsciiHexCodeUnit, - appendUtf8CodePoint, - decodeFormUrlencodedComponent, - serializeFormUrlencodedComponent, - compareCodeUnitStrings, - normalizeSearchParamsInit, - NativeURLSearchParams, - createStandaloneSearchParams, - createCollectionBody, - createUrlContext, - formatUrlContext, + createNodeTypeError, getBlobUrlStore, + installWhatwgUrlGlobals, + kBlobUrlCounter, + kBlobUrlStore, nextBlobUrlId, - URLSearchParamsIterator, - URLSearchParams, - canUseNativeUrlImplementation, - ensureTrailingSlashForFilePath, - normalizeRelativeFileUrlInput, - nativeUrlCandidate, - NativeURL, URL2, - installWhatwgUrlGlobals, + URLSearchParams, }; diff --git a/packages/build-tools/bridge-src/polyfills/text-encoding.ts b/packages/build-tools/bridge-src/polyfills/text-encoding.ts index cbd5dfb055..04b98119cf 100644 --- a/packages/build-tools/bridge-src/polyfills/text-encoding.ts +++ b/packages/build-tools/bridge-src/polyfills/text-encoding.ts @@ -199,7 +199,7 @@ function decodeUtf8(bytes, fatal, stream, encoding) { throw createEncodingInvalidDataError(encoding); } output.push("\uFFFD"); - index += 1; + index += 2; continue; } codePoint = codePoint << 6 | third & 63; @@ -211,7 +211,7 @@ function decodeUtf8(bytes, fatal, stream, encoding) { throw createEncodingInvalidDataError(encoding); } output.push("\uFFFD"); - index += 1; + index += 3; continue; } codePoint = codePoint << 6 | fourth & 63; diff --git a/packages/build-tools/package.json b/packages/build-tools/package.json index 08b1590e5f..a03c2a6df1 100644 --- a/packages/build-tools/package.json +++ b/packages/build-tools/package.json @@ -29,6 +29,7 @@ "readable-stream": "4.7.0", "undici": "^7.24.6", "web-streams-polyfill": "^3.3.3", + "whatwg-url": "15.1.0", "ws": "8.21.0" } } diff --git a/packages/build-tools/scripts/build-v8-bridge.mjs b/packages/build-tools/scripts/build-v8-bridge.mjs index 5aa1338a4a..1e3084b465 100644 --- a/packages/build-tools/scripts/build-v8-bridge.mjs +++ b/packages/build-tools/scripts/build-v8-bridge.mjs @@ -86,6 +86,13 @@ const customAlias = { url: path.join(undiciShimDir, "url.js"), "node:url": path.join(undiciShimDir, "url.js"), "agentos-legacy-url-polyfill": nodeStdlibUrlPackageEntry, + "agentos-text-encoding-polyfill": path.join( + packageRoot, + "bridge-src", + "polyfills", + "text-encoding.ts", + ), + "whatwg-url": require.resolve("whatwg-url"), stream: path.join(undiciShimDir, "stream.js"), "node:stream": path.join(undiciShimDir, "stream.js"), "secure-exec-stream-stdlib": require.resolve("readable-stream"), @@ -399,6 +406,22 @@ async function buildWebStreamsPrelude() { ' WritableStream,', ' TransformStream,', '} from "web-streams-polyfill/ponyfill/es2018";', + 'import { TextDecoder as AgentOSTextDecoder, TextEncoder2 as AgentOSTextEncoder } from "agentos-text-encoding-polyfill";', + 'if (typeof globalThis.TextEncoder === "undefined") {', + " globalThis.TextEncoder = AgentOSTextEncoder;", + "}", + 'if (typeof globalThis.TextDecoder === "undefined") {', + " globalThis.TextDecoder = AgentOSTextDecoder;", + "}", + 'if (typeof globalThis.SharedArrayBuffer === "undefined") {', + " class SharedArrayBufferBootstrapStub {}", + ' Object.defineProperties(SharedArrayBufferBootstrapStub.prototype, {', + ' byteLength: { configurable: true, get() { if (!(this instanceof SharedArrayBufferBootstrapStub)) throw new TypeError("incompatible receiver"); return 0; } },', + ' growable: { configurable: true, get() { if (!(this instanceof SharedArrayBufferBootstrapStub)) throw new TypeError("incompatible receiver"); return false; } },', + " });", + " SharedArrayBufferBootstrapStub.__agentOSBootstrapStub = true;", + " globalThis.SharedArrayBuffer = SharedArrayBufferBootstrapStub;", + "}", 'if (typeof globalThis.ReadableStream === "undefined") {', " globalThis.ReadableStream = ReadableStream;", "}", diff --git a/packages/build-tools/scripts/whatwg-url.test.mjs b/packages/build-tools/scripts/whatwg-url.test.mjs deleted file mode 100644 index cadeff014a..0000000000 --- a/packages/build-tools/scripts/whatwg-url.test.mjs +++ /dev/null @@ -1,22 +0,0 @@ -import assert from "node:assert/strict"; -import test from "node:test"; -import path from "node:path"; -import { resolveRelativeNonFileUrl } from "../bridge-src/builtins/url-resolution.ts"; - -test("fallback URL resolution follows HTTP base URL semantics", () => { - const base = { - protocol: "http:", - host: "example.test:8080", - pathname: "/parent/entry", - search: "?old=1", - }; - const resolve = (input) => resolveRelativeNonFileUrl(input, base, path.posix); - - assert.equal(resolve("/hello?q=1"), "http://example.test:8080/hello?q=1"); - assert.equal(resolve("child"), "http://example.test:8080/parent/child"); - assert.equal(resolve("../child/"), "http://example.test:8080/child/"); - assert.equal(resolve("?next=1"), "http://example.test:8080/parent/entry?next=1"); - assert.equal(resolve("#result"), "http://example.test:8080/parent/entry?old=1#result"); - assert.equal(resolve(""), "http://example.test:8080/parent/entry?old=1"); - assert.equal(resolve("//cdn.test/file.js"), "http://cdn.test/file.js"); -}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index da4abfde05..2ab0b2e609 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2764,6 +2764,9 @@ importers: web-streams-polyfill: specifier: ^3.3.3 version: 3.3.3 + whatwg-url: + specifier: 15.1.0 + version: 15.1.0 ws: specifier: 8.21.0 version: 8.21.0(bufferutil@4.1.0) @@ -13981,6 +13984,10 @@ packages: tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -14651,6 +14658,14 @@ packages: webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + + whatwg-url@15.1.0: + resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} + engines: {node: '>=20'} + whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -26875,6 +26890,10 @@ snapshots: tr46@0.0.3: {} + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + tree-kill@1.2.2: {} trim-lines@3.0.1: {} @@ -27522,6 +27541,13 @@ snapshots: webidl-conversions@3.0.1: {} + webidl-conversions@8.0.1: {} + + whatwg-url@15.1.0: + dependencies: + tr46: 6.0.0 + webidl-conversions: 8.0.1 + whatwg-url@5.0.0: dependencies: tr46: 0.0.3