node-libcurl
Version:
The fastest http(s) client (and much more) for Node.js - Node.js bindings for libcurl
396 lines • 13 kB
TypeScript
/**
* Copyright (c) Jonathan Cardoso Machado. All Rights Reserved.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import './moduleSetup';
import { Readable } from 'stream';
import { CurlMime } from './CurlMime';
import { CurlReadFunc } from './enum/CurlReadFunc';
/**
* Type definition for MIME data callback functions.
*
* @public
*/
export interface MimeDataCallbacks {
/**
* Read callback to provide data chunks.
*
* @param size - Maximum number of bytes to read
* @returns Buffer, string, null for EOF, or CurlReadFunc value (Pause/Abort)
*
* @remarks
* When `CurlReadFunc.Pause` is returned, the transfer will be paused until it is
* explicitly resumed by calling `handle.pause(handle.pauseFlags & ~CurlPause.Recv)`.
* When `CurlReadFunc.Abort` is returned, the transfer will be aborted.
*
* @example
* ```typescript
* read: (size) => {
* if (offset >= data.length) return null // EOF
* const chunk = data.slice(offset, offset + size)
* offset += chunk.length
* return chunk
* }
* ```
*/
read: (size: number) => Buffer | string | null | CurlReadFunc;
/**
* Optional seek callback for repositioning the data stream.
*
* @param offset - The offset to seek to
* @param origin - Seek origin: 0=SEEK_SET, 1=SEEK_CUR, 2=SEEK_END
* @returns `true` if seek succeeded, `false` otherwise
*
* @example
* ```typescript
* seek: (offset, origin) => {
* if (origin === 0) { // SEEK_SET
* currentOffset = offset
* return true
* }
* return false // Other origins not supported
* }
* ```
*/
seek?: (offset: number, origin: number) => boolean;
/**
* Optional cleanup callback called when the part is freed.
*
* @example
* ```typescript
* free: () => {
* console.log('Cleaning up resources')
* }
* ```
*/
free?: () => void;
}
/**
* `CurlMimePart` class that represents a single part in a MIME structure.
* > [C++ source code](https://github.com/JCMais/node-libcurl/blob/master/src/CurlMime.cc)
*
* This class is used to configure individual parts of a multipart form data upload.
* Instances are created by calling {@link CurlMime.addPart}.
*
* @remarks
* Each part can have:
* - A field name (via {@link setName})
* - Data content (via {@link setData}, {@link setFileData}, or {@link setDataCallback})
* - A content mime type (via {@link setType})
* - A file name (via {@link setFileName})
* - Content encoding (via {@link setEncoder})
* - Custom headers (via {@link setHeaders})
* - Nested subparts (via {@link setSubparts})
*
* All setter methods return `this` for method chaining and throw {@link CurlEasyError} on error.
*
* @example
* Basic text field with method chaining:
* ```typescript
* mime.addPart()
* .setName('username')
* .setData('john_doe')
* ```
*
* @example
* File upload with method chaining:
* ```typescript
* mime.addPart()
* .setName('avatar')
* .setFileData('/path/to/image.png')
* .setType('image/png')
* .setFileName('avatar.png')
* ```
*
* @public
*/
declare class CurlMimePart {
/**
* Sets the field name for this MIME part.
*
* @param name - The field name, or `null` to reset
* @returns `this` for method chaining
* @throws {CurlEasyError} Throws on error
*
* @example
* ```typescript
* part.setName('username').setData('john_doe')
* ```
*
* @see {@link https://curl.se/libcurl/c/curl_mime_name.html | curl_mime_name}
*/
setName(name: string | null): this;
/**
* Sets the data content for this MIME part from a string or Buffer.
*
* @param data - The data as a string or Buffer, or `null` to reset
* @returns `this` for method chaining
* @throws {CurlEasyError} Throws on error
*
* @remarks
* The data is copied internally, so it's safe to reuse or modify the
* buffer after calling this method.
*
* @example
* ```typescript
* part
* .setName('file')
* .setData('Hello World')
* .setType('text/plain')
* // or
* part
* .setName('file')
* .setData(Buffer.from([0x48, 0x65, 0x6c, 0x6c, 0x6f]))
* .setType('text/plain')
* ```
*
* @see {@link https://curl.se/libcurl/c/curl_mime_data.html | curl_mime_data}
*/
setData(data: string | Buffer | null): this;
/**
* Sets the data content for this MIME part by reading from a file.
*
* @param filePath - Path to the file, or `null` to reset
* @returns `this` for method chaining
* @throws {CurlEasyError} Throws on error
*
* @remarks
* The file is streamed during transfer for memory efficiency.
* The file must be readable when the transfer starts.
*
* @example
* ```typescript
* part
* .setName('document')
* .setFileData('/path/to/document.pdf')
* .setType('application/pdf')
* ```
*
* @see {@link https://curl.se/libcurl/c/curl_mime_filedata.html | curl_mime_filedata}
*/
setFileData(filePath: string | null): this;
/**
* Sets the content type (MIME type) for this part.
*
* @param mimeType - The MIME type string, or `null` to use default
* @returns `this` for method chaining
* @throws {CurlEasyError} Throws on error
*
* @example
* ```typescript
* part
* .setName('avatar')
* .setFileData('image.png')
* .setType('image/png')
* ```
*
* @see {@link https://curl.se/libcurl/c/curl_mime_type.html | curl_mime_type}
*/
setType(mimeType: string | null): this;
/**
* Sets the remote filename for this part.
*
* @param filename - The filename to send, or `null` to reset
* @returns `this` for method chaining
* @throws {CurlEasyError} Throws on error
*
* @remarks
* This appears in the Content-Disposition header and can be different
* from the actual local filename when using {@link setFileData}.
*
* @example
* ```typescript
* part
* .setName('avatar')
* .setFileData('/tmp/temp123.jpg')
* .setFileName('profile-photo.jpg')
* ```
*
* @see {@link https://curl.se/libcurl/c/curl_mime_filename.html | curl_mime_filename}
*/
setFileName(fileName: string | null): this;
/**
* Sets the content transfer encoding for this part.
*
* @param encoding - Encoding scheme: 'binary', '8bit', '7bit', 'base64', 'quoted-printable', or `null` to disable
* @returns `this` for method chaining
* @throws {CurlEasyError} Throws on error
*
* @remarks
* - 'binary': No encoding, header added
* - '8bit': No encoding, header added
* - '7bit': Validates 7-bit compliance
* - 'base64': Base64 encoding
* - 'quoted-printable': Quoted-printable encoding
*
* Do NOT use encoding with multipart content (subparts).
*
* @example
* ```typescript
* part
* .setName('data')
* .setData(binaryData)
* .setEncoder('base64')
* ```
*
* @see {@link https://curl.se/libcurl/c/curl_mime_encoder.html | curl_mime_encoder}
*/
setEncoder(encoding: 'binary' | '8bit' | '7bit' | 'base64' | 'quoted-printable' | null): this;
/**
* Sets custom headers for this MIME part.
*
* @param headers - Array of header strings, or `null` to reset
* @returns `this` for method chaining
* @throws {CurlEasyError} Throws on error
*
* @remarks
* Each header should be in the format "Header-Name: value".
*
* @example
* ```typescript
* part.setName('doc').setData('content').setHeaders([
* 'Content-ID: <document123>',
* 'X-Custom-Header: custom-value'
* ])
* ```
*
* @see {@link https://curl.se/libcurl/c/curl_mime_headers.html | curl_mime_headers}
*/
setHeaders(headers: string[] | null): this;
/**
* Sets a MIME structure as nested subparts of this part.
*
* @param mime - A CurlMime instance to use as subparts, or `null` to reset
* @returns `this` for method chaining
* @throws {CurlEasyError} Throws on error
*
* @remarks
* Ownership of the MIME structure transfers to this part.
* The subparts MIME object should not be used after this call.
*
* @example
* ```typescript
* const subMime = new CurlMime(curl)
* subMime
* .addPart()
* .setName('nested_field')
* .setData('nested content')
*
* mime
* .addPart()
* .setName('multipart_section')
* .setSubparts(subMime)
* ```
*
* @see {@link https://curl.se/libcurl/c/curl_mime_subparts.html | curl_mime_subparts}
*/
setSubparts(mime: CurlMime | null): this;
/**
* Sets a callback-based mechanism for supplying part content dynamically.
*
* @param size - Expected total size in bytes, -1 works for unknown sizes
* @param callbacks - Object containing read, seek (optional), and free (optional) callbacks
* @returns `this` for method chaining
* @throws {CurlEasyError} Throws on error
*
* @remarks
* Use this for streaming or dynamically generated content. The read callback
* will be called multiple times to supply data chunks. Return `null` from
* the read callback to signal EOF.
*
* @example
* ```typescript
* let currentOffset = 0
* const data = Buffer.from('Large data to stream...')
*
* part
* .setName('stream')
* .setDataCallback(data.length, {
* read: (size) => {
* if (currentOffset >= data.length) return null // EOF
* const chunk = data.slice(currentOffset, currentOffset + size)
* currentOffset += chunk.length
* return chunk
* },
* seek: (offset, origin) => {
* if (origin === 0) { // SEEK_SET
* currentOffset = offset
* return true
* }
* return false
* }
* })
* ```
*
* @see {@link https://curl.se/libcurl/c/curl_mime_data_cb.html | curl_mime_data_cb}
*/
setDataCallback(size: number, callbacks: MimeDataCallbacks): this;
/**
* Sets the data content for this MIME part from a Node.js Readable stream.
*
* @param stream - Node.js Readable stream to read data from
* @param unpause - Callback function to unpause the transfer when data becomes available
* @param size - Optional expected total size in bytes (for Content-Length header)
* @returns `this` for method chaining
* @throws {Error} Throws if stream emits an error
*
* @remarks
* This method provides a wrapper around {@link setDataCallback} for working with
* Node.js streams. The stream is kept in paused mode and data is read synchronously
* when curl requests it. When no data is available, the transfer is paused using
* `CurlReadFunc.Pause`, and the `unpause` callback is invoked when data becomes
* available to resume the transfer.
*
* The `unpause` function should unpause the curl handle's receive operation, typically
* by calling `handle.pause(handle.pauseFlags & ~CurlPause.Recv)`.
*
* For very large files, consider using {@link setFileData} instead, as it streams
* directly from disk without going through Node.js streams.
*
* @example
* Stream from file with unpause:
* ```typescript
* import { createReadStream } from 'fs'
* import { CurlPause } from 'node-libcurl'
*
* const stream = createReadStream('/path/to/file.txt')
* const curl = new Curl()
* const mime = new CurlMime(curl)
*
* mime
* .addPart()
* .setName('document')
* .setDataStream(stream, () => {
* curl.pause(curl.handle.pauseFlags & ~CurlPause.Recv)
* })
* .setType('text/plain')
* ```
*
* @example
* Stream with known size:
* ```typescript
* import { createReadStream, statSync } from 'fs'
* import { CurlPause } from 'node-libcurl'
*
* const filepath = '/path/to/file.txt'
* const size = statSync(filepath).size
* const stream = createReadStream(filepath)
* const curl = new Curl()
* const mime = new CurlMime(curl)
*
* mime
* .addPart()
* .setName('document')
* .setDataStream(
* stream,
* () => curl.pause(curl.handle.pauseFlags & ~CurlPause.Recv),
* size
* )
* ```
*/
setDataStream(stream: Readable, unpause: () => void, size?: number): this;
}
export { CurlMimePart };
//# sourceMappingURL=CurlMimePart.d.ts.map