_shims/node-runtime.ts (87 lines of code) (raw):
/**
* Disclaimer: modules in _shims aren't intended to be imported by SDK users.
*/
import * as nf from "npm:node-fetch";
import * as fd from "npm:formdata-node";
import { type File, type FilePropertyBag } from "npm:formdata-node";
import KeepAliveAgent from "npm:agentkeepalive";
import { AbortController as AbortControllerPolyfill } from "npm:abort-controller";
import { ReadStream as FsReadStream } from "https://deno.land/std@0.177.0/node/fs.ts";
import { type Agent } from "node:http";
import { FormDataEncoder } from "npm:form-data-encoder";
import { Readable } from "https://deno.land/std@0.177.0/node/stream.ts";
import { type RequestOptions } from "../core.ts";
import { MultipartBody } from "./MultipartBody.ts";
import { type Shims } from "./registry.ts";
import { ReadableStream } from "npm:stream/web";
type FileFromPathOptions = Omit<FilePropertyBag, "lastModified">;
let fileFromPathWarned = false;
/**
* @deprecated use fs.createReadStream('./my/file.txt') instead
*/
async function fileFromPath(path: string): Promise<File>;
async function fileFromPath(path: string, filename?: string): Promise<File>;
async function fileFromPath(
path: string,
options?: FileFromPathOptions,
): Promise<File>;
async function fileFromPath(
path: string,
filename?: string,
options?: FileFromPathOptions,
): Promise<File>;
async function fileFromPath(path: string, ...args: any[]): Promise<File> {
// this import fails in environments that don't handle export maps correctly, like old versions of Jest
const { fileFromPath: _fileFromPath } = await import(
"formdata-node/file-from-path"
);
if (!fileFromPathWarned) {
console.warn(
`fileFromPath is deprecated; use fs.createReadStream(${
JSON.stringify(path)
}) instead`,
);
fileFromPathWarned = true;
}
// @ts-ignore
return await _fileFromPath(path, ...args);
}
const defaultHttpAgent: Agent = new KeepAliveAgent({
keepAlive: true,
timeout: 5 * 60 * 1000,
});
const defaultHttpsAgent: Agent = new KeepAliveAgent.HttpsAgent({
keepAlive: true,
timeout: 5 * 60 * 1000,
});
async function getMultipartRequestOptions<T = Record<string, unknown>>(
form: fd.FormData,
opts: RequestOptions<T>,
): Promise<RequestOptions<T>> {
const encoder = new FormDataEncoder(form);
const readable = Readable.from(encoder);
const body = new MultipartBody(readable);
const headers = {
...opts.headers,
...encoder.headers,
"Content-Length": encoder.contentLength,
};
return { ...opts, body: body as any, headers };
}
export function getRuntime(): Shims {
// Polyfill global object if needed.
if (typeof AbortController === "undefined") {
// @ts-expect-error (the types are subtly different, but compatible in practice)
globalThis.AbortController = AbortControllerPolyfill;
}
return {
kind: "node",
fetch: nf.default,
Request: nf.Request,
Response: nf.Response,
Headers: nf.Headers,
FormData: fd.FormData,
Blob: fd.Blob,
File: fd.File,
ReadableStream,
getMultipartRequestOptions,
getDefaultAgent: (
url: string,
): Agent => (url.startsWith("https")
? defaultHttpsAgent
: defaultHttpAgent),
fileFromPath,
isFsReadStream: (value: any): value is FsReadStream =>
value instanceof FsReadStream,
};
}