diff --git a/sdk/src/polyfill/fetch.ts b/sdk/src/polyfill/fetch.ts index 5651eeb74..76ab149b2 100644 --- a/sdk/src/polyfill/fetch.ts +++ b/sdk/src/polyfill/fetch.ts @@ -4,30 +4,44 @@ import $mime from "mime/lite"; const oldFetch = globalThis.fetch; -// We always polyfill fetch because Node's fetch doesn't support file URLs. -(globalThis.fetch as any) = async function (resource: URL | RequestInfo, options: RequestInit | undefined): Promise { - const request = new Request(resource, options); - const url = new URL(request.url); +async function supportsFetch() { + try { + await oldFetch(new URL("file:")); + return true; - if (url.protocol === "file:") { - const readStream = $fs.createReadStream(url); + } catch (e) { + return false; + } +} - const headers: HeadersInit = {}; - const type = $mime.getType(url.pathname); +if (!(await supportsFetch())) { + // We always polyfill fetch because Node's fetch doesn't support file URLs. + (globalThis.fetch as any) = async function (resource: URL | RequestInfo, options: RequestInit | undefined): Promise { + const request = new Request(resource, options); - if (type) { - headers["Content-Type"] = type; - } + const url = new URL(request.url); - return new Response(readStream as any, { - status: 200, - statusText: "OK", - headers, - }); + if (url.protocol === "file:") { + const readStream = $fs.createReadStream(url); - } else { - return await oldFetch(request); - } -}; + const headers: HeadersInit = {}; + + const type = $mime.getType(url.pathname); + + if (type) { + headers["Content-Type"] = type; + } + + return new Response(readStream as any, { + status: 200, + statusText: "OK", + headers, + }); + + } else { + return await oldFetch(request); + } + }; +} diff --git a/sdk/src/polyfill/worker.ts b/sdk/src/polyfill/worker.ts index 7e05d61a9..8ef0edba5 100644 --- a/sdk/src/polyfill/worker.ts +++ b/sdk/src/polyfill/worker.ts @@ -10,90 +10,92 @@ if (globalThis.navigator == null) { } as Navigator; } -globalThis.Worker = class Worker extends EventTarget { - private _worker: import("node:worker_threads").Worker; +if (globalThis.Worker == null) { + globalThis.Worker = class Worker extends EventTarget { + private _worker: import("node:worker_threads").Worker; - constructor(url: string | URL, options?: WorkerOptions | undefined) { - super(); + constructor(url: string | URL, options?: WorkerOptions | undefined) { + super(); - if (url instanceof URL) { - if (url.protocol !== "file:") { - throw new Error("Worker only supports file: URLs"); + if (url instanceof URL) { + if (url.protocol !== "file:") { + throw new Error("Worker only supports file: URLs"); + } + + url = url.href; + + } else { + throw new Error("Filepaths are unreliable, use `new URL(\"...\", import.meta.url)` instead."); } - url = url.href; + if (!options || options.type !== "module") { + throw new Error("Workers must use \`type: \"module\"\`"); + } - } else { - throw new Error("Filepaths are unreliable, use `new URL(\"...\", import.meta.url)` instead."); + const code = ` + import("node:worker_threads") + .then(({ workerData }) => { + return import(workerData.polyfill) + .then(() => import(workerData.url)) + }) + .catch((e) => { + // TODO maybe it should send a message to the parent? + console.error(e.stack); + }); + `; + + this._worker = new $worker.Worker(code, { + eval: true, + workerData: { + url, + polyfill: new URL("node-polyfill.js", import.meta.url).href, + }, + }); + + this._worker.on("message", (data) => { + this.dispatchEvent(new MessageEvent("message", { data })); + }); + + this._worker.on("messageerror", (error) => { + throw new Error("UNIMPLEMENTED"); + }); + + this._worker.on("error", (error) => { + // TODO attach the error to the event somehow + const event = new Event("error"); + this.dispatchEvent(event); + }); } - if (!options || options.type !== "module") { - throw new Error("Workers must use \`type: \"module\"\`"); + set onmessage(f: () => void) { + throw new Error("UNIMPLEMENTED"); } - const code = ` - import("node:worker_threads") - .then(({ workerData }) => { - return import(workerData.polyfill) - .then(() => import(workerData.url)) - }) - .catch((e) => { - // TODO maybe it should send a message to the parent? - console.error(e.stack); - }); - `; - - this._worker = new $worker.Worker(code, { - eval: true, - workerData: { - url, - polyfill: new URL("node-polyfill.js", import.meta.url).href, - }, - }); - - this._worker.on("message", (data) => { - this.dispatchEvent(new MessageEvent("message", { data })); - }); - - this._worker.on("messageerror", (error) => { + set onmessageerror(f: () => void) { throw new Error("UNIMPLEMENTED"); - }); - - this._worker.on("error", (error) => { - // TODO attach the error to the event somehow - const event = new Event("error"); - this.dispatchEvent(event); - }); - } - - set onmessage(f: () => void) { - throw new Error("UNIMPLEMENTED"); - } - - set onmessageerror(f: () => void) { - throw new Error("UNIMPLEMENTED"); - } + } - set onerror(f: () => void) { - throw new Error("UNIMPLEMENTED"); - } + set onerror(f: () => void) { + throw new Error("UNIMPLEMENTED"); + } - postMessage(message: any, transfer: Array): void; - postMessage(message: any, options?: StructuredSerializeOptions | undefined): void; - postMessage(value: any, transfer: any) { - this._worker.postMessage(value, transfer); - } + postMessage(message: any, transfer: Array): void; + postMessage(message: any, options?: StructuredSerializeOptions | undefined): void; + postMessage(value: any, transfer: any) { + this._worker.postMessage(value, transfer); + } - terminate() { - this._worker.terminate(); - } + terminate() { + this._worker.terminate(); + } - // This is Node-specific, it allows the process to exit - // even if the Worker is still running. - unref() { - this._worker.unref(); - } -}; + // This is Node-specific, it allows the process to exit + // even if the Worker is still running. + unref() { + this._worker.unref(); + } + }; +} if (!$worker.isMainThread) { diff --git a/sdk/src/polyfill/xmlhttprequest.ts b/sdk/src/polyfill/xmlhttprequest.ts index 616d9d91b..65d6d1949 100644 --- a/sdk/src/polyfill/xmlhttprequest.ts +++ b/sdk/src/polyfill/xmlhttprequest.ts @@ -1,154 +1,156 @@ import $request from "sync-request"; -globalThis.XMLHttpRequest = class extends EventTarget implements XMLHttpRequest { - public static readonly UNSENT = 0; - public static readonly OPENED = 1; - public static readonly HEADERS_RECEIVED = 2; - public static readonly LOADING = 3; - public static readonly DONE = 4; - - public readonly UNSENT = XMLHttpRequest.UNSENT; - public readonly OPENED = XMLHttpRequest.OPENED; - public readonly HEADERS_RECEIVED = XMLHttpRequest.HEADERS_RECEIVED; - public readonly LOADING = XMLHttpRequest.LOADING; - public readonly DONE = XMLHttpRequest.DONE; - - public responseType!: XMLHttpRequestResponseType; - public withCredentials!: boolean; - public timeout!: number; - - public readonly readyState!: number; - public readonly response!: ArrayBuffer | Blob | Document | string | null; - public readonly responseText!: string; - public readonly responseURL!: string; - public readonly responseXML!: Document | null; - public readonly status!: number; - public readonly statusText!: string; - public readonly upload!: XMLHttpRequestUpload; - - private _url!: string | URL | null; - private _mime!: string; - - constructor() { - super(); - - this._reset(); - - this._mime = "text/xml"; - } - - private _reset() { - (this as any).readyState = XMLHttpRequest.UNSENT; - (this as any).response = null; - (this as any).responseText = ""; - (this as any).responseType = ""; - (this as any).responseURL = ""; - (this as any).responseXML = null; - (this as any).status = 0; - (this as any).statusText = ""; - (this as any).timeout = 0; - (this as any).upload = null; - (this as any).withCredentials = false; - - this._url = null; - } - - private _success() { - (this as any).readyState = XMLHttpRequest.DONE; - (this as any).status = 200; - (this as any).statusText = "OK"; - } +if (globalThis.XMLHttpRequest == null) { + globalThis.XMLHttpRequest = class extends EventTarget implements XMLHttpRequest { + public static readonly UNSENT = 0; + public static readonly OPENED = 1; + public static readonly HEADERS_RECEIVED = 2; + public static readonly LOADING = 3; + public static readonly DONE = 4; + + public readonly UNSENT = XMLHttpRequest.UNSENT; + public readonly OPENED = XMLHttpRequest.OPENED; + public readonly HEADERS_RECEIVED = XMLHttpRequest.HEADERS_RECEIVED; + public readonly LOADING = XMLHttpRequest.LOADING; + public readonly DONE = XMLHttpRequest.DONE; + + public responseType!: XMLHttpRequestResponseType; + public withCredentials!: boolean; + public timeout!: number; + + public readonly readyState!: number; + public readonly response!: ArrayBuffer | Blob | Document | string | null; + public readonly responseText!: string; + public readonly responseURL!: string; + public readonly responseXML!: Document | null; + public readonly status!: number; + public readonly statusText!: string; + public readonly upload!: XMLHttpRequestUpload; + + private _url!: string | URL | null; + private _mime!: string; + + constructor() { + super(); + + this._reset(); + + this._mime = "text/xml"; + } - public set onabort(value: () => void) { - throw new Error("Not implemented"); - } + private _reset() { + (this as any).readyState = XMLHttpRequest.UNSENT; + (this as any).response = null; + (this as any).responseText = ""; + (this as any).responseType = ""; + (this as any).responseURL = ""; + (this as any).responseXML = null; + (this as any).status = 0; + (this as any).statusText = ""; + (this as any).timeout = 0; + (this as any).upload = null; + (this as any).withCredentials = false; + + this._url = null; + } - public set onerror(value: () => void) { - throw new Error("Not implemented"); - } + private _success() { + (this as any).readyState = XMLHttpRequest.DONE; + (this as any).status = 200; + (this as any).statusText = "OK"; + } - public set onreadystatechange(value: () => void) { - throw new Error("Not implemented"); - } + public set onabort(value: () => void) { + throw new Error("Not implemented"); + } - public set onloadstart(value: () => void) { - throw new Error("Not implemented"); - } + public set onerror(value: () => void) { + throw new Error("Not implemented"); + } - public set onload(value: () => void) { - throw new Error("Not implemented"); - } + public set onreadystatechange(value: () => void) { + throw new Error("Not implemented"); + } - public set onloadend(value: () => void) { - throw new Error("Not implemented"); - } + public set onloadstart(value: () => void) { + throw new Error("Not implemented"); + } - public set onprogress(value: () => void) { - throw new Error("Not implemented"); - } + public set onload(value: () => void) { + throw new Error("Not implemented"); + } - public set ontimeout(value: () => void) { - throw new Error("Not implemented"); - } + public set onloadend(value: () => void) { + throw new Error("Not implemented"); + } - public abort() { - throw new Error("Not implemented"); - } + public set onprogress(value: () => void) { + throw new Error("Not implemented"); + } - public overrideMimeType(mime: string) { - this._mime = mime; - } + public set ontimeout(value: () => void) { + throw new Error("Not implemented"); + } - public getResponseHeader(): string | null { - throw new Error("Not implemented"); - } + public abort() { + throw new Error("Not implemented"); + } - public getAllResponseHeaders(): string { - throw new Error("Not implemented"); - } + public overrideMimeType(mime: string) { + this._mime = mime; + } - public setRequestHeader() { - throw new Error("Not implemented"); - } + public getResponseHeader(): string | null { + throw new Error("Not implemented"); + } - public open(method: string, url: string | URL, async: boolean = true, username?: string | null | undefined, password?: string | null | undefined): void { - if (async) { - throw new Error("Async XMLHttpRequest is not implemented yet"); + public getAllResponseHeaders(): string { + throw new Error("Not implemented"); } - if (method !== "GET") { - throw new Error("Non-GET requests are not implemented yet"); + public setRequestHeader() { + throw new Error("Not implemented"); } - this._reset(); + public open(method: string, url: string | URL, async: boolean = true, username?: string | null | undefined, password?: string | null | undefined): void { + if (async) { + throw new Error("Async XMLHttpRequest is not implemented yet"); + } + + if (method !== "GET") { + throw new Error("Non-GET requests are not implemented yet"); + } - this._url = url; - } + this._reset(); - public send(body: null = null) { - if (body !== null) { - throw new Error("XMLHttpRequest send body is not implemented yet"); + this._url = url; } - if (!this._url) { - throw new Error("You must call open before you call send"); - } + public send(body: null = null) { + if (body !== null) { + throw new Error("XMLHttpRequest send body is not implemented yet"); + } - const response = $request("GET", this._url, { - headers: { - "Content-Type": this._mime, + if (!this._url) { + throw new Error("You must call open before you call send"); } - }); - const buffer = (response.body as Buffer).buffer as any; + const response = $request("GET", this._url, { + headers: { + "Content-Type": this._mime, + } + }); + + const buffer = (response.body as Buffer).buffer as any; - const responseText = new TextDecoder("iso-8859-5", { fatal: true }).decode(buffer); + const responseText = new TextDecoder("iso-8859-5", { fatal: true }).decode(buffer); - (this as any).response = (this as any).responseText = responseText; + (this as any).response = (this as any).responseText = responseText; - this._url = null; + this._url = null; - this._success(); - } -}; + this._success(); + } + }; +}