summaryrefslogtreecommitdiff
path: root/includes/external/addressbook/node_modules/form-data-encoder
diff options
context:
space:
mode:
authorRaindropsSys <contact@minteck.org>2023-04-06 22:18:28 +0200
committerRaindropsSys <contact@minteck.org>2023-04-06 22:18:28 +0200
commit83354b2b88218090988dd6e526b0a2505b57e0f1 (patch)
treee3c73c38a122a78bb7e66fbb99056407edd9d4b9 /includes/external/addressbook/node_modules/form-data-encoder
parent47b8f2299a483024c4a6a8876af825a010954caa (diff)
downloadpluralconnect-83354b2b88218090988dd6e526b0a2505b57e0f1.tar.gz
pluralconnect-83354b2b88218090988dd6e526b0a2505b57e0f1.tar.bz2
pluralconnect-83354b2b88218090988dd6e526b0a2505b57e0f1.zip
Updated 5 files and added 1110 files (automated)
Diffstat (limited to 'includes/external/addressbook/node_modules/form-data-encoder')
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/FileLike.d.ts23
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/FormDataEncoder.d.ts169
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/FormDataLike.d.ts40
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/index.d.ts5
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/util/Headers.d.ts8
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/util/createBoundary.d.ts12
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/util/escapeName.d.ts10
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/util/getStreamIterator.d.ts6
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFile.d.ts34
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFormData.d.ts7
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFunction.d.ts6
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/util/isPlainObject.d.ts1
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/util/normalizeValue.d.ts10
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/@type/util/proxyHeaders.d.ts2
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/FileLike.js1
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/FormDataEncoder.js134
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/FormDataLike.js1
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/index.js5
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/util/Headers.js1
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/util/createBoundary.js9
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/util/escapeName.js4
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/util/getStreamIterator.js21
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFile.js8
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFormData.js8
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFunction.js1
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/util/isPlainObject.js12
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/util/normalizeValue.js8
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/lib/util/proxyHeaders.js14
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/license21
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/package.json70
-rw-r--r--includes/external/addressbook/node_modules/form-data-encoder/readme.md368
31 files changed, 1019 insertions, 0 deletions
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/FileLike.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/FileLike.d.ts
new file mode 100644
index 0000000..8febb60
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/FileLike.d.ts
@@ -0,0 +1,23 @@
+export interface FileLike {
+ /**
+ * Name of the file referenced by the File object.
+ */
+ readonly name: string;
+ /**
+ * Returns the media type ([`MIME`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types)) of the file represented by a `File` object.
+ */
+ readonly type: string;
+ /**
+ * Size of the file parts in bytes
+ */
+ readonly size: number;
+ /**
+ * The last modified date of the file as the number of milliseconds since the Unix epoch (January 1, 1970 at midnight). Files without a known last modified date return the current date.
+ */
+ readonly lastModified: number;
+ /**
+ * Returns a [`ReadableStream`](https://developer.mozilla.org/en-US/docs/Web/API/ReadableStream) which upon reading returns the data contained within the [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File).
+ */
+ stream(): AsyncIterable<Uint8Array>;
+ readonly [Symbol.toStringTag]: string;
+}
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/FormDataEncoder.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/FormDataEncoder.d.ts
new file mode 100644
index 0000000..24123ab
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/FormDataEncoder.d.ts
@@ -0,0 +1,169 @@
+import type { FormDataEncoderHeaders } from "./util/Headers.js";
+import type { FormDataLike } from "./FormDataLike.js";
+import type { FileLike } from "./FileLike.js";
+export interface FormDataEncoderOptions {
+ /**
+ * When enabled, the encoder will emit additional per part headers, such as `Content-Length`.
+ *
+ * Please note that the web clients do not include these, so when enabled this option might cause an error if `multipart/form-data` does not consider additional headers.
+ *
+ * Defaults to `false`.
+ */
+ enableAdditionalHeaders?: boolean;
+}
+/**
+ * Implements [`multipart/form-data` encoding algorithm](https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart/form-data-encoding-algorithm),
+ * allowing to add support for spec-comliant [`FormData`](https://developer.mozilla.org/en-US/docs/Web/API/FormData) to an HTTP client.
+ */
+export declare class FormDataEncoder {
+ #private;
+ /**
+ * Returns boundary string
+ */
+ readonly boundary: string;
+ /**
+ * Returns Content-Type header
+ */
+ readonly contentType: string;
+ /**
+ * Returns Content-Length header
+ */
+ readonly contentLength: string | undefined;
+ /**
+ * Returns headers object with Content-Type and Content-Length header
+ */
+ readonly headers: Readonly<FormDataEncoderHeaders>;
+ /**
+ * Creates a multipart/form-data encoder.
+ *
+ * @param form FormData object to encode. This object must be a spec-compatible FormData implementation.
+ *
+ * @example
+ *
+ * ```js
+ * import {Readable} from "stream"
+ *
+ * import {FormData, File, fileFromPath} from "formdata-node"
+ * import {FormDataEncoder} from "form-data-encoder"
+ *
+ * import fetch from "node-fetch"
+ *
+ * const form = new FormData()
+ *
+ * form.set("field", "Just a random string")
+ * form.set("file", new File(["Using files is class amazing"], "file.txt"))
+ * form.set("fileFromPath", await fileFromPath("path/to/a/file.txt"))
+ *
+ * const encoder = new FormDataEncoder(form)
+ *
+ * const options = {
+ * method: "post",
+ * headers: encoder.headers,
+ * body: Readable.from(encoder)
+ * }
+ *
+ * const response = await fetch("https://httpbin.org/post", options)
+ *
+ * console.log(await response.json())
+ * ```
+ */
+ constructor(form: FormDataLike);
+ /**
+ * Creates multipart/form-data encoder with custom boundary string.
+ *
+ * @param form FormData object to encode. This object must be a spec-compatible FormData implementation.
+ * @param boundary An optional boundary string that will be used by the encoder. If there's no boundary string is present, Encoder will generate it automatically.
+ */
+ constructor(form: FormDataLike, boundary: string);
+ /**
+ * Creates multipart/form-data encoder with additional options.
+ *
+ * @param form FormData object to encode. This object must be a spec-compatible FormData implementation.
+ * @param options Additional options
+ */
+ constructor(form: FormDataLike, options: FormDataEncoderOptions);
+ constructor(form: FormDataLike, boundary: string, options?: FormDataEncoderOptions);
+ /**
+ * Returns form-data content length
+ *
+ * @deprecated Use FormDataEncoder.contentLength or FormDataEncoder.headers["Content-Length"] instead
+ */
+ getContentLength(): number | undefined;
+ /**
+ * Creates an iterator allowing to go through form-data parts (with metadata).
+ * This method **will not** read the files.
+ *
+ * Using this method, you can convert form-data content into Blob:
+ *
+ * @example
+ *
+ * import {Readable} from "stream"
+ *
+ * import {FormDataEncoder} from "form-data-encoder"
+ *
+ * import {FormData} from "formdata-polyfill/esm-min.js"
+ * import {fileFrom} from "fetch-blob/form.js"
+ * import {File} from "fetch-blob/file.js"
+ * import {Blob} from "fetch-blob"
+ *
+ * import fetch from "node-fetch"
+ *
+ * const form = new FormData()
+ *
+ * form.set("field", "Just a random string")
+ * form.set("file", new File(["Using files is class amazing"]))
+ * form.set("fileFromPath", await fileFrom("path/to/a/file.txt"))
+ *
+ * const encoder = new FormDataEncoder(form)
+ *
+ * const options = {
+ * method: "post",
+ * body: new Blob(encoder, {type: encoder.contentType})
+ * }
+ *
+ * const response = await fetch("https://httpbin.org/post", options)
+ *
+ * console.log(await response.json())
+ */
+ values(): Generator<Uint8Array | FileLike, void, undefined>;
+ /**
+ * Creates an async iterator allowing to perform the encoding by portions.
+ * This method **will** also read files.
+ *
+ * @example
+ *
+ * import {Readable} from "stream"
+ *
+ * import {FormData, File, fileFromPath} from "formdata-node"
+ * import {FormDataEncoder} from "form-data-encoder"
+ *
+ * import fetch from "node-fetch"
+ *
+ * const form = new FormData()
+ *
+ * form.set("field", "Just a random string")
+ * form.set("file", new File(["Using files is class amazing"], "file.txt"))
+ * form.set("fileFromPath", await fileFromPath("path/to/a/file.txt"))
+ *
+ * const encoder = new FormDataEncoder(form)
+ *
+ * const options = {
+ * method: "post",
+ * headers: encoder.headers,
+ * body: Readable.from(encoder.encode()) // or Readable.from(encoder)
+ * }
+ *
+ * const response = await fetch("https://httpbin.org/post", options)
+ *
+ * console.log(await response.json())
+ */
+ encode(): AsyncGenerator<Uint8Array, void, undefined>;
+ /**
+ * Creates an iterator allowing to read through the encoder data using for...of loops
+ */
+ [Symbol.iterator](): Generator<Uint8Array | FileLike, void, undefined>;
+ /**
+ * Creates an **async** iterator allowing to read through the encoder data using for-await...of loops
+ */
+ [Symbol.asyncIterator](): AsyncGenerator<Uint8Array, void, undefined>;
+}
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/FormDataLike.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/FormDataLike.d.ts
new file mode 100644
index 0000000..05824ad
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/FormDataLike.d.ts
@@ -0,0 +1,40 @@
+import { FileLike } from "./FileLike.js";
+/**
+ * A `string` or `File` that represents a single value from a set of `FormData` key-value pairs.
+ */
+export type FormDataEntryValue = string | FileLike;
+/**
+ * This interface reflects minimal shape of the FormData
+ */
+export interface FormDataLike {
+ /**
+ * Appends a new value onto an existing key inside a FormData object,
+ * or adds the key if it does not already exist.
+ *
+ * The difference between `set()` and `append()` is that if the specified key already exists, `set()` will overwrite all existing values with the new one, whereas `append()` will append the new value onto the end of the existing set of values.
+ *
+ * @param name The name of the field whose data is contained in `value`.
+ * @param value The field's value. This can be [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob)
+ or [`File`](https://developer.mozilla.org/en-US/docs/Web/API/File). If none of these are specified the value is converted to a string.
+ * @param fileName The filename reported to the server, when a Blob or File is passed as the second parameter. The default filename for Blob objects is "blob". The default filename for File objects is the file's filename.
+ */
+ append(name: string, value: unknown, fileName?: string): void;
+ /**
+ * Returns all the values associated with a given key from within a `FormData` object.
+ *
+ * @param {string} name A name of the value you want to retrieve.
+ *
+ * @returns An array of `FormDataEntryValue` whose key matches the value passed in the `name` parameter. If the key doesn't exist, the method returns an empty list.
+ */
+ getAll(name: string): FormDataEntryValue[];
+ /**
+ * Returns an [`iterator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols) allowing to go through the `FormData` key/value pairs.
+ * The key of each pair is a string; the value is a [`FormDataValue`](https://developer.mozilla.org/en-US/docs/Web/API/FormDataEntryValue).
+ */
+ entries(): Generator<[string, FormDataEntryValue]>;
+ /**
+ * An alias for FormDataLike#entries()
+ */
+ [Symbol.iterator](): Generator<[string, FormDataEntryValue]>;
+ readonly [Symbol.toStringTag]: string;
+}
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/index.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/index.d.ts
new file mode 100644
index 0000000..4b0c507
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/index.d.ts
@@ -0,0 +1,5 @@
+export * from "./FormDataEncoder.js";
+export * from "./FileLike.js";
+export * from "./FormDataLike.js";
+export * from "./util/isFile.js";
+export * from "./util/isFormData.js";
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/util/Headers.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/Headers.d.ts
new file mode 100644
index 0000000..e018e34
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/Headers.d.ts
@@ -0,0 +1,8 @@
+export interface RawHeaders {
+ "Content-Type": string;
+ "Content-Length"?: string;
+}
+export interface FormDataEncoderHeaders extends RawHeaders {
+ "content-type": string;
+ "content-length"?: string;
+}
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/util/createBoundary.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/createBoundary.d.ts
new file mode 100644
index 0000000..3dd8eac
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/createBoundary.d.ts
@@ -0,0 +1,12 @@
+/**
+ * Generates a boundary string for FormData encoder.
+ *
+ * @api private
+ *
+ * ```js
+ * import createBoundary from "./util/createBoundary"
+ *
+ * createBoundary() // -> n2vw38xdagaq6lrv
+ * ```
+ */
+export declare function createBoundary(): string;
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/util/escapeName.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/escapeName.d.ts
new file mode 100644
index 0000000..aeefc63
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/escapeName.d.ts
@@ -0,0 +1,10 @@
+/**
+ * Escape fieldname following the spec requirements.
+ *
+ * See: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data
+ *
+ * @param name A fieldname to escape
+ *
+ * @api private
+ */
+export declare const escapeName: (name: unknown) => string;
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/util/getStreamIterator.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/getStreamIterator.d.ts
new file mode 100644
index 0000000..d8f3a41
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/getStreamIterator.d.ts
@@ -0,0 +1,6 @@
+/**
+ * Turns ReadableStream into async iterable when the `Symbol.asyncIterable` is not implemented on given stream.
+ *
+ * @param source A ReadableStream to create async iterator for
+ */
+export declare const getStreamIterator: (source: ReadableStream<Uint8Array> | AsyncIterable<Uint8Array>) => AsyncIterable<Uint8Array>;
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFile.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFile.d.ts
new file mode 100644
index 0000000..ba27e13
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFile.d.ts
@@ -0,0 +1,34 @@
+import type { FileLike } from "../FileLike.js";
+/**
+ * Check if given object is `File`.
+ *
+ * Note that this function will return `false` for Blob, because the FormDataEncoder expects FormData to return File when a value is binary data.
+ *
+ * @param value an object to test
+ *
+ * @api public
+ *
+ * This function will return `true` for FileAPI compatible `File` objects:
+ *
+ * ```
+ * import {createReadStream} from "node:fs"
+ *
+ * import {isFile} from "form-data-encoder"
+ *
+ * isFile(new File(["Content"], "file.txt")) // -> true
+ * ```
+ *
+ * However, if you pass a Node.js `Buffer` or `ReadStream`, it will return `false`:
+ *
+ * ```js
+ * import {isFile} from "form-data-encoder"
+ *
+ * isFile(Buffer.from("Content")) // -> false
+ * isFile(createReadStream("path/to/a/file.txt")) // -> false
+ * ```
+ */
+export declare const isFile: (value: unknown) => value is FileLike;
+/**
+ * @deprecated use `isFile` instead
+ */
+export declare const isFileLike: (value: unknown) => value is FileLike;
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFormData.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFormData.d.ts
new file mode 100644
index 0000000..54ea959
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFormData.d.ts
@@ -0,0 +1,7 @@
+import type { FormDataLike } from "../FormDataLike.js";
+/**
+ * Check if given object is FormData
+ *
+ * @param value an object to test
+ */
+export declare const isFormData: (value: unknown) => value is FormDataLike;
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFunction.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFunction.d.ts
new file mode 100644
index 0000000..98d647e
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isFunction.d.ts
@@ -0,0 +1,6 @@
+/**
+ * Checks if given value is a function.
+ *
+ * @api private
+ */
+export declare const isFunction: (value: unknown) => value is Function;
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isPlainObject.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isPlainObject.d.ts
new file mode 100644
index 0000000..b69bc56
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/isPlainObject.d.ts
@@ -0,0 +1 @@
+export declare function isPlainObject(value: unknown): value is object;
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/util/normalizeValue.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/normalizeValue.d.ts
new file mode 100644
index 0000000..a70661b
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/normalizeValue.d.ts
@@ -0,0 +1,10 @@
+/**
+ * Normalize non-File value following the spec requirements.
+ *
+ * See: https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#multipart-form-data
+ *
+ * @param value A value to normalize
+ *
+ * @api private
+ */
+export declare const normalizeValue: (value: unknown) => string;
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/@type/util/proxyHeaders.d.ts b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/proxyHeaders.d.ts
new file mode 100644
index 0000000..504e45e
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/@type/util/proxyHeaders.d.ts
@@ -0,0 +1,2 @@
+import type { FormDataEncoderHeaders, RawHeaders } from "./Headers.js";
+export declare const proxyHeaders: (object: RawHeaders) => FormDataEncoderHeaders;
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/FileLike.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/FileLike.js
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/FileLike.js
@@ -0,0 +1 @@
+export {};
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/FormDataEncoder.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/FormDataEncoder.js
new file mode 100644
index 0000000..eff989a
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/FormDataEncoder.js
@@ -0,0 +1,134 @@
+var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _FormDataEncoder_instances, _FormDataEncoder_CRLF, _FormDataEncoder_CRLF_BYTES, _FormDataEncoder_CRLF_BYTES_LENGTH, _FormDataEncoder_DASHES, _FormDataEncoder_encoder, _FormDataEncoder_footer, _FormDataEncoder_form, _FormDataEncoder_options, _FormDataEncoder_getFieldHeader, _FormDataEncoder_getContentLength;
+import { getStreamIterator } from "./util/getStreamIterator.js";
+import { createBoundary } from "./util/createBoundary.js";
+import { normalizeValue } from "./util/normalizeValue.js";
+import { isPlainObject } from "./util/isPlainObject.js";
+import { proxyHeaders } from "./util/proxyHeaders.js";
+import { isFormData } from "./util/isFormData.js";
+import { escapeName } from "./util/escapeName.js";
+import { isFile } from "./util/isFile.js";
+const defaultOptions = {
+ enableAdditionalHeaders: false
+};
+const readonlyProp = { writable: false, configurable: false };
+export class FormDataEncoder {
+ constructor(form, boundaryOrOptions, options) {
+ _FormDataEncoder_instances.add(this);
+ _FormDataEncoder_CRLF.set(this, "\r\n");
+ _FormDataEncoder_CRLF_BYTES.set(this, void 0);
+ _FormDataEncoder_CRLF_BYTES_LENGTH.set(this, void 0);
+ _FormDataEncoder_DASHES.set(this, "-".repeat(2));
+ _FormDataEncoder_encoder.set(this, new TextEncoder());
+ _FormDataEncoder_footer.set(this, void 0);
+ _FormDataEncoder_form.set(this, void 0);
+ _FormDataEncoder_options.set(this, void 0);
+ if (!isFormData(form)) {
+ throw new TypeError("Expected first argument to be a FormData instance.");
+ }
+ let boundary;
+ if (isPlainObject(boundaryOrOptions)) {
+ options = boundaryOrOptions;
+ }
+ else {
+ boundary = boundaryOrOptions;
+ }
+ if (!boundary) {
+ boundary = createBoundary();
+ }
+ if (typeof boundary !== "string") {
+ throw new TypeError("Expected boundary argument to be a string.");
+ }
+ if (options && !isPlainObject(options)) {
+ throw new TypeError("Expected options argument to be an object.");
+ }
+ __classPrivateFieldSet(this, _FormDataEncoder_form, Array.from(form.entries()), "f");
+ __classPrivateFieldSet(this, _FormDataEncoder_options, { ...defaultOptions, ...options }, "f");
+ __classPrivateFieldSet(this, _FormDataEncoder_CRLF_BYTES, __classPrivateFieldGet(this, _FormDataEncoder_encoder, "f").encode(__classPrivateFieldGet(this, _FormDataEncoder_CRLF, "f")), "f");
+ __classPrivateFieldSet(this, _FormDataEncoder_CRLF_BYTES_LENGTH, __classPrivateFieldGet(this, _FormDataEncoder_CRLF_BYTES, "f").byteLength, "f");
+ this.boundary = `form-data-boundary-${boundary}`;
+ this.contentType = `multipart/form-data; boundary=${this.boundary}`;
+ __classPrivateFieldSet(this, _FormDataEncoder_footer, __classPrivateFieldGet(this, _FormDataEncoder_encoder, "f").encode(`${__classPrivateFieldGet(this, _FormDataEncoder_DASHES, "f")}${this.boundary}${__classPrivateFieldGet(this, _FormDataEncoder_DASHES, "f")}${__classPrivateFieldGet(this, _FormDataEncoder_CRLF, "f").repeat(2)}`), "f");
+ const headers = {
+ "Content-Type": this.contentType
+ };
+ const contentLength = __classPrivateFieldGet(this, _FormDataEncoder_instances, "m", _FormDataEncoder_getContentLength).call(this);
+ if (contentLength) {
+ this.contentLength = contentLength;
+ headers["Content-Length"] = contentLength;
+ }
+ this.headers = proxyHeaders(Object.freeze(headers));
+ Object.defineProperties(this, {
+ boundary: readonlyProp,
+ contentType: readonlyProp,
+ contentLength: readonlyProp,
+ headers: readonlyProp
+ });
+ }
+ getContentLength() {
+ return this.contentLength == null ? undefined : Number(this.contentLength);
+ }
+ *values() {
+ for (const [name, raw] of __classPrivateFieldGet(this, _FormDataEncoder_form, "f")) {
+ const value = isFile(raw) ? raw : __classPrivateFieldGet(this, _FormDataEncoder_encoder, "f").encode(normalizeValue(raw));
+ yield __classPrivateFieldGet(this, _FormDataEncoder_instances, "m", _FormDataEncoder_getFieldHeader).call(this, name, value);
+ yield value;
+ yield __classPrivateFieldGet(this, _FormDataEncoder_CRLF_BYTES, "f");
+ }
+ yield __classPrivateFieldGet(this, _FormDataEncoder_footer, "f");
+ }
+ async *encode() {
+ for (const part of this.values()) {
+ if (isFile(part)) {
+ yield* getStreamIterator(part.stream());
+ }
+ else {
+ yield part;
+ }
+ }
+ }
+ [(_FormDataEncoder_CRLF = new WeakMap(), _FormDataEncoder_CRLF_BYTES = new WeakMap(), _FormDataEncoder_CRLF_BYTES_LENGTH = new WeakMap(), _FormDataEncoder_DASHES = new WeakMap(), _FormDataEncoder_encoder = new WeakMap(), _FormDataEncoder_footer = new WeakMap(), _FormDataEncoder_form = new WeakMap(), _FormDataEncoder_options = new WeakMap(), _FormDataEncoder_instances = new WeakSet(), _FormDataEncoder_getFieldHeader = function _FormDataEncoder_getFieldHeader(name, value) {
+ let header = "";
+ header += `${__classPrivateFieldGet(this, _FormDataEncoder_DASHES, "f")}${this.boundary}${__classPrivateFieldGet(this, _FormDataEncoder_CRLF, "f")}`;
+ header += `Content-Disposition: form-data; name="${escapeName(name)}"`;
+ if (isFile(value)) {
+ header += `; filename="${escapeName(value.name)}"${__classPrivateFieldGet(this, _FormDataEncoder_CRLF, "f")}`;
+ header += `Content-Type: ${value.type || "application/octet-stream"}`;
+ }
+ const size = isFile(value) ? value.size : value.byteLength;
+ if (__classPrivateFieldGet(this, _FormDataEncoder_options, "f").enableAdditionalHeaders === true
+ && size != null
+ && !isNaN(size)) {
+ header += `${__classPrivateFieldGet(this, _FormDataEncoder_CRLF, "f")}Content-Length: ${isFile(value) ? value.size : value.byteLength}`;
+ }
+ return __classPrivateFieldGet(this, _FormDataEncoder_encoder, "f").encode(`${header}${__classPrivateFieldGet(this, _FormDataEncoder_CRLF, "f").repeat(2)}`);
+ }, _FormDataEncoder_getContentLength = function _FormDataEncoder_getContentLength() {
+ let length = 0;
+ for (const [name, raw] of __classPrivateFieldGet(this, _FormDataEncoder_form, "f")) {
+ const value = isFile(raw) ? raw : __classPrivateFieldGet(this, _FormDataEncoder_encoder, "f").encode(normalizeValue(raw));
+ const size = isFile(value) ? value.size : value.byteLength;
+ if (size == null || isNaN(size)) {
+ return undefined;
+ }
+ length += __classPrivateFieldGet(this, _FormDataEncoder_instances, "m", _FormDataEncoder_getFieldHeader).call(this, name, value).byteLength;
+ length += size;
+ length += __classPrivateFieldGet(this, _FormDataEncoder_CRLF_BYTES_LENGTH, "f");
+ }
+ return String(length + __classPrivateFieldGet(this, _FormDataEncoder_footer, "f").byteLength);
+ }, Symbol.iterator)]() {
+ return this.values();
+ }
+ [Symbol.asyncIterator]() {
+ return this.encode();
+ }
+}
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/FormDataLike.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/FormDataLike.js
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/FormDataLike.js
@@ -0,0 +1 @@
+export {};
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/index.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/index.js
new file mode 100644
index 0000000..4b0c507
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/index.js
@@ -0,0 +1,5 @@
+export * from "./FormDataEncoder.js";
+export * from "./FileLike.js";
+export * from "./FormDataLike.js";
+export * from "./util/isFile.js";
+export * from "./util/isFormData.js";
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/util/Headers.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/Headers.js
new file mode 100644
index 0000000..cb0ff5c
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/Headers.js
@@ -0,0 +1 @@
+export {};
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/util/createBoundary.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/createBoundary.js
new file mode 100644
index 0000000..4ed7434
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/createBoundary.js
@@ -0,0 +1,9 @@
+const alphabet = "abcdefghijklmnopqrstuvwxyz0123456789";
+export function createBoundary() {
+ let size = 16;
+ let res = "";
+ while (size--) {
+ res += alphabet[(Math.random() * alphabet.length) << 0];
+ }
+ return res;
+}
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/util/escapeName.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/escapeName.js
new file mode 100644
index 0000000..8b2ce25
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/escapeName.js
@@ -0,0 +1,4 @@
+export const escapeName = (name) => String(name)
+ .replace(/\r/g, "%0D")
+ .replace(/\n/g, "%0A")
+ .replace(/"/g, "%22");
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/util/getStreamIterator.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/getStreamIterator.js
new file mode 100644
index 0000000..f97676a
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/getStreamIterator.js
@@ -0,0 +1,21 @@
+import { isFunction } from "./isFunction.js";
+const isAsyncIterable = (value) => (isFunction(value[Symbol.asyncIterator]));
+async function* readStream(readable) {
+ const reader = readable.getReader();
+ while (true) {
+ const { done, value } = await reader.read();
+ if (done) {
+ break;
+ }
+ yield value;
+ }
+}
+export const getStreamIterator = (source) => {
+ if (isAsyncIterable(source)) {
+ return source;
+ }
+ if (isFunction(source.getReader)) {
+ return readStream(source);
+ }
+ throw new TypeError("Unsupported data source: Expected either ReadableStream or async iterable.");
+};
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFile.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFile.js
new file mode 100644
index 0000000..eec965d
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFile.js
@@ -0,0 +1,8 @@
+import { isFunction } from "./isFunction.js";
+export const isFile = (value) => Boolean(value
+ && typeof value === "object"
+ && isFunction(value.constructor)
+ && value[Symbol.toStringTag] === "File"
+ && isFunction(value.stream)
+ && value.name != null);
+export const isFileLike = isFile;
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFormData.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFormData.js
new file mode 100644
index 0000000..237419f
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFormData.js
@@ -0,0 +1,8 @@
+import { isFunction } from "./isFunction.js";
+export const isFormData = (value) => Boolean(value
+ && isFunction(value.constructor)
+ && value[Symbol.toStringTag] === "FormData"
+ && isFunction(value.append)
+ && isFunction(value.getAll)
+ && isFunction(value.entries)
+ && isFunction(value[Symbol.iterator]));
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFunction.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFunction.js
new file mode 100644
index 0000000..a8dbdc2
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isFunction.js
@@ -0,0 +1 @@
+export const isFunction = (value) => (typeof value === "function");
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isPlainObject.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isPlainObject.js
new file mode 100644
index 0000000..9f3fb7e
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/isPlainObject.js
@@ -0,0 +1,12 @@
+const getType = (value) => (Object.prototype.toString.call(value).slice(8, -1).toLowerCase());
+export function isPlainObject(value) {
+ if (getType(value) !== "object") {
+ return false;
+ }
+ const pp = Object.getPrototypeOf(value);
+ if (pp === null || pp === undefined) {
+ return true;
+ }
+ const Ctor = pp.constructor && pp.constructor.toString();
+ return Ctor === Object.toString();
+}
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/util/normalizeValue.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/normalizeValue.js
new file mode 100644
index 0000000..05e058a
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/normalizeValue.js
@@ -0,0 +1,8 @@
+export const normalizeValue = (value) => String(value)
+ .replace(/\r|\n/g, (match, i, str) => {
+ if ((match === "\r" && str[i + 1] !== "\n")
+ || (match === "\n" && str[i - 1] !== "\r")) {
+ return "\r\n";
+ }
+ return match;
+});
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/lib/util/proxyHeaders.js b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/proxyHeaders.js
new file mode 100644
index 0000000..05a4ab3
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/lib/util/proxyHeaders.js
@@ -0,0 +1,14 @@
+function getProperty(target, prop) {
+ if (typeof prop === "string") {
+ for (const [name, value] of Object.entries(target)) {
+ if (prop.toLowerCase() === name.toLowerCase()) {
+ return value;
+ }
+ }
+ }
+ return undefined;
+}
+export const proxyHeaders = (object) => new Proxy(object, {
+ get: (target, prop) => getProperty(target, prop),
+ has: (target, prop) => getProperty(target, prop) !== undefined
+});
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/license b/includes/external/addressbook/node_modules/form-data-encoder/license
new file mode 100644
index 0000000..0c8fa88
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/license
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2021-present Nick K.
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/package.json b/includes/external/addressbook/node_modules/form-data-encoder/package.json
new file mode 100644
index 0000000..e3dcbcc
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/package.json
@@ -0,0 +1,70 @@
+{
+ "type": "module",
+ "name": "form-data-encoder",
+ "version": "2.1.4",
+ "description": "Encode FormData content into the multipart/form-data format",
+ "repository": "octet-stream/form-data-encoder",
+ "sideEffects": false,
+ "engines": {
+ "node": ">= 14.17"
+ },
+ "keywords": [
+ "form-data",
+ "encoder",
+ "multipart",
+ "files-upload",
+ "async-iterator",
+ "spec-compatible",
+ "form"
+ ],
+ "main": "./lib/index.js",
+ "module": "./lib/index.js",
+ "exports": {
+ "types": "./@type/index.d.ts",
+ "default": "./lib/index.js"
+ },
+ "types": "./@type/index.d.ts",
+ "scripts": {
+ "eslint": "eslint src/**/*.ts",
+ "staged": "lint-staged",
+ "coverage": "c8 npm test",
+ "ci": "c8 npm test && c8 report --reporter=json",
+ "build:types": "tsc --project tsconfig.d.ts.json",
+ "build": "tsc && npm run build:types",
+ "test": "ava --fail-fast",
+ "cleanup": "del-cli @type lib",
+ "prepare": "npm run cleanup && npm run build",
+ "_postinstall": "husky install",
+ "prepublishOnly": "pinst --disable",
+ "postpublish": "pinst --enable"
+ },
+ "author": "Nick K.",
+ "license": "MIT",
+ "devDependencies": {
+ "@octetstream/eslint-config": "6.2.2",
+ "@types/mime-types": "2.1.1",
+ "@types/node": "18.11.9",
+ "@types/sinon": "^10.0.13",
+ "@typescript-eslint/eslint-plugin": "5.44.0",
+ "@typescript-eslint/parser": "5.44.0",
+ "ava": "5.1.0",
+ "c8": "7.12.0",
+ "del-cli": "5.0.0",
+ "eslint": "8.28.0",
+ "eslint-config-airbnb-typescript": "17.0.0",
+ "eslint-import-resolver-typescript": "3.5.2",
+ "eslint-plugin-ava": "13.2.0",
+ "eslint-plugin-import": "^2.26.0",
+ "eslint-plugin-jsx-a11y": "6.6.1",
+ "eslint-plugin-react": "7.31.11",
+ "formdata-node": "5.0.0",
+ "husky": "8.0.2",
+ "lint-staged": "13.0.3",
+ "pinst": "3.0.0",
+ "sinon": "^14.0.2",
+ "ts-node": "10.9.1",
+ "ttypescript": "1.5.13",
+ "typescript": "4.9.3",
+ "web-streams-polyfill": "4.0.0-beta.3"
+ }
+}
diff --git a/includes/external/addressbook/node_modules/form-data-encoder/readme.md b/includes/external/addressbook/node_modules/form-data-encoder/readme.md
new file mode 100644
index 0000000..a8f4190
--- /dev/null
+++ b/includes/external/addressbook/node_modules/form-data-encoder/readme.md
@@ -0,0 +1,368 @@
+# form-data-encoder
+
+Encode `FormData` content into the `multipart/form-data` format
+
+[![Code Coverage](https://codecov.io/github/octet-stream/form-data-encoder/coverage.svg?branch=master)](https://codecov.io/github/octet-stream/form-data-encoder?branch=master)
+[![CI](https://github.com/octet-stream/form-data-encoder/workflows/CI/badge.svg)](https://github.com/octet-stream/form-data-encoder/actions/workflows/ci.yml)
+[![ESLint](https://github.com/octet-stream/form-data-encoder/workflows/ESLint/badge.svg)](https://github.com/octet-stream/form-data-encoder/actions/workflows/eslint.yml)
+
+## Requirements
+
+- Node.js v14.17 or higher;
+- Runtime should support `TextEncoder`, `TextDecoder`, `WeakMap`, `WeakSet` and async generator functions;
+- For TypeScript users: tsc v4.3 or higher.
+
+## Installation
+
+You can install this package using npm:
+
+```sh
+npm install form-data-encoder
+```
+
+Or yarn:
+
+```sh
+yarn add form-data-encoder
+```
+
+Or pnpm:
+
+```sh
+pnpm add form-data-encoder
+```
+
+## Usage
+
+1. To start the encoding process, you need to create a new Encoder instance with the FormData you want to encode:
+
+```js
+import {Readable} from "stream"
+
+import {FormData, File} from "formdata-node"
+import {FormDataEncoder} from "form-data-encoder"
+
+import fetch from "node-fetch"
+
+const form = new FormData()
+
+form.set("greeting", "Hello, World!")
+form.set("file", new File(["On Soviet Moon landscape see binoculars through YOU"], "file.txt"))
+
+const encoder = new FormDataEncoder(form)
+
+const options = {
+ method: "post",
+
+ // Set request headers provided by the Encoder.
+ // The `headers` property has `Content-Type` and `Content-Length` headers.
+ headers: encoder.headers,
+
+ // Create a Readable stream from the Encoder.
+ // You can omit usage of `Readable.from` for HTTP clients whose support async iterables in request body.
+ // The Encoder will yield FormData content portions encoded into the multipart/form-data format as node-fetch consumes the stream.
+ body: Readable.from(encoder.encode()) // or just Readable.from(encoder)
+}
+
+const response = await fetch("https://httpbin.org/post", options)
+
+console.log(await response.json())
+```
+
+2. Encoder support different spec-compatible FormData implementations. Let's try it with [`formdata-polyfill`](https://github.com/jimmywarting/FormData):
+
+```js
+import {Readable} from "stream"
+
+import {FormDataEncoder} from "form-data-encoder"
+import {FormData} from "formdata-polyfill/esm-min.js"
+import {File} from "fetch-blob" // v3
+
+const form = new FormData()
+
+form.set("field", "Some value")
+form.set("file", new File(["File content goes here"], "file.txt"))
+
+const encoder = new FormDataEncoder(form)
+
+const options = {
+ method: "post",
+ headers: encoder.headers,
+ body: Readable.from(encoder)
+}
+
+await fetch("https://httpbin.org/post", options)
+```
+
+3. Because the Encoder is iterable (it has both Symbol.asyncIterator and Symbol.iterator methods), you can use it with different targets. Let's say you want to convert FormData content into `Blob`, for that you can write a function like this:
+
+```js
+import {Readable} from "stream"
+
+import {FormDataEncoder} from "form-data-encoder"
+
+import {FormData, File, Blob, fileFromPath} from "formdata-node"
+
+import fetch from "node-fetch"
+
+const form = new FormData()
+
+form.set("field", "Just a random string")
+form.set("file", new File(["Using files is class amazing"], "file.txt"))
+form.set("fileFromPath", await fileFromPath("path/to/a/file.txt"))
+
+// Note 1: When using with native Blob or fetch-blob@2 you might also need to generate boundary string for your FormDataEncoder instance
+// because Blob will lowercase value of the `type` option and default boundary generator produces a string with both lower and upper cased alphabetical characters. Math.random() should be enough to fix this:
+// const encoder = new FormDataEncoder(form, String(Math.random()))
+const encoder = new FormDataEncoder(form)
+
+const options = {
+ method: "post",
+
+ // Note 2: To use this approach with fetch-blob@2 you probably gonna need to convert the encoder parts output to an array first:
+ // new Blob([...encoder], {type: encoder.contentType})
+ body: new Blob(encoder, {type: encoder.contentType})
+}
+
+const response = await fetch("https://httpbin.org/post", options)
+
+console.log(await response.json())
+```
+
+4. Here's FormData to Blob conversion with async-iterator approach:
+
+```js
+import {FormData} from "formdata-polyfill/esm-min.js"
+import {blobFrom} from "fetch-blob/from.js"
+import {FormDataEncoder} from "form-data-encoder"
+
+import Blob from "fetch-blob"
+import fetch from "node-fetch"
+
+// This approach may require much more RAM compared to the previous one, but it works too.
+async function toBlob(form) {
+ const encoder = new Encoder(form)
+ const chunks = []
+
+ for await (const chunk of encoder) {
+ chunks.push(chunk)
+ }
+
+ return new Blob(chunks, {type: encoder.contentType})
+}
+
+const form = new FormData()
+
+form.set("name", "John Doe")
+form.set("avatar", await blobFrom("path/to/an/avatar.png"), "avatar.png")
+
+const options = {
+ method: "post",
+ body: await toBlob(form)
+}
+
+await fetch("https://httpbin.org/post", options)
+```
+
+5. Another way to convert FormData parts to blob using `form-data-encoder` is making a Blob-ish class:
+
+```js
+import {Readable} from "stream"
+
+import {FormDataEncoder} from "form-data-encoder"
+import {FormData} from "formdata-polyfill/esm-min.js"
+import {blobFrom} from "fetch-blob/from.js"
+
+import Blob from "fetch-blob"
+import fetch from "node-fetch"
+
+class BlobDataItem {
+ constructor(encoder) {
+ this.#encoder = encoder
+ this.#size = encoder.headers["Content-Length"]
+ this.#type = encoder.headers["Content-Type"]
+ }
+
+ get type() {
+ return this.#type
+ }
+
+ get size() {
+ return this.#size
+ }
+
+ stream() {
+ return Readable.from(this.#encoder)
+ }
+
+ get [Symbol.toStringTag]() {
+ return "Blob"
+ }
+}
+
+const form = new FormData()
+
+form.set("name", "John Doe")
+form.set("avatar", await blobFrom("path/to/an/avatar.png"), "avatar.png")
+
+const encoder = new FormDataEncoder(form)
+
+// Note that node-fetch@2 performs more strictness tests for Blob objects, so you may need to do extra steps before you set up request body (like, maybe you'll need to instaniate a Blob with BlobDataItem as one of its blobPart)
+const blob = new BlobDataItem(enocoder) // or new Blob([new BlobDataItem(enocoder)], {type: encoder.contentType})
+
+const options = {
+ method: "post",
+ body: blob
+}
+
+await fetch("https://httpbin.org/post", options)
+```
+
+6. In this example we will pull FormData content into the ReadableStream:
+
+```js
+ // This module is only necessary when you targeting Node.js or need web streams that implement Symbol.asyncIterator
+import {ReadableStream} from "web-streams-polyfill/ponyfill/es2018"
+
+import {FormDataEncoder} from "form-data-encoder"
+import {FormData} from "formdata-node"
+
+import fetch from "node-fetch"
+
+function toReadableStream(encoder) {
+ const iterator = encoder.encode()
+
+ return new ReadableStream({
+ async pull(controller) {
+ const {value, done} = await iterator.next()
+
+ if (done) {
+ return controller.close()
+ }
+
+ controller.enqueue(value)
+ }
+ })
+}
+
+const form = new FormData()
+
+form.set("field", "My hovercraft is full of eels")
+
+const encoder = new FormDataEncoder(form)
+
+const options = {
+ method: "post",
+ headers: encoder.headers,
+ body: toReadableStream(encoder)
+}
+
+// Note that this example requires `fetch` to support Symbol.asyncIterator, which node-fetch lacks of (but will support eventually)
+await fetch("https://httpbin.org/post", options)
+```
+
+7. Speaking of async iterables - if HTTP client supports them, you can use encoder like this:
+
+```js
+import {FormDataEncoder} from "form-data-encoder"
+import {FormData} from "formdata-node"
+
+import fetch from "node-fetch"
+
+const form = new FormData()
+
+form.set("field", "My hovercraft is full of eels")
+
+const encoder = new FormDataEncoder(form)
+
+const options = {
+ method: "post",
+ headers: encoder.headers,
+ body: encoder
+}
+
+await fetch("https://httpbin.org/post", options)
+```
+
+8. ...And for those client whose supporting form-data-encoder out of the box, the usage will be much, much more simpler:
+
+```js
+import {FormData} from "formdata-node" // Or any other spec-compatible implementation
+
+import fetch from "node-fetch"
+
+const form = new FormData()
+
+form.set("field", "My hovercraft is full of eels")
+
+const options = {
+ method: "post",
+ body: form
+}
+
+// Note that node-fetch does NOT support form-data-encoder
+await fetch("https://httpbin.org/post", options)
+```
+
+## API
+
+### `class FormDataEncoder`
+
+##### `constructor(form[, boundary, options]) -> {FormDataEncoder}`
+
+ - **{FormDataLike}** form - FormData object to encode. This object must be a spec-compatible FormData implementation.
+ - **{string}** [boundary] - An optional boundary string that will be used by the encoder. If there's no boundary string is present, FormDataEncoder will generate it automatically.
+ - **{object}** [options] - FormDataEncoder options.
+ - **{boolean}** [options.enableAdditionalHeaders = false] - When enabled, the encoder will emit additional per part headers, such as `Content-Length`. Please note that the web clients do not include these, so when enabled this option might cause an error if `multipart/form-data` does not consider additional headers.
+
+Creates a `multipart/form-data` encoder.
+
+#### Instance properties
+
+##### `boundary -> {string}`
+
+Returns boundary string.
+
+##### `contentType -> {string}`
+
+Returns Content-Type header.
+
+##### `contentLength -> {string}`
+
+Return Content-Length header.
+
+##### `headers -> {object}`
+
+Returns headers object with Content-Type and Content-Length header.
+
+#### Instance methods
+
+##### `values() -> {Generator<Uint8Array | FileLike, void, undefined>}`
+
+Creates an iterator allowing to go through form-data parts (with metadata).
+This method **will not** read the files.
+
+##### `encode() -> {AsyncGenerator<Uint8Array, void, undefined>}`
+
+Creates an async iterator allowing to perform the encoding by portions.
+This method **will** also read files.
+
+##### `[Symbol.iterator]() -> {Generator<Uint8Array | FileLike, void, undefined>}`
+
+An alias for `Encoder#values()` method.
+
+##### `[Symbol.asyncIterator]() -> {AsyncGenerator<Uint8Array, void, undefined>}`
+
+An alias for `Encoder#encode()` method.
+
+### `isFile(value) -> {boolean}`
+
+Check if a value is File-ish object.
+
+ - **{unknown}** value - a value to test
+
+### `isFormData(value) -> {boolean}`
+
+Check if a value is FormData-ish object.
+
+ - **{unknown}** value - a value to test