webdav client

repository·master·Indexed 21 days ago

https://github.com/perry-mitchell/webdav-client

A TypeScript-based WebDAV client for NodeJS and browser environments, supporting services like Nextcloud, ownCloud, Box, and Yandex. Version 5.10.0 uses ESM and provides a promise-based API for managing files and directories, streaming remote files, and handling various authentication types including Basic, Digest, and Token auth.

Tokens
4.9K
Snippets
16
Records
18
Agent score
72%

What's inside webdav

  1. Supported environments and versions

    master

    The webdav library is a TypeScript-based client for NodeJS and the browser.

    Version 5 (Current)

    Version 5 uses ESM (ECMAScript Modules). To use it, your environment must be one of the following:

    • A NodeJS project with "type": "module" in package.json.
    • A web project bundled with a tool that handles ESM (e.g., Webpack).
    • A React-Native project.

    NodeJS Support (v5): Node 14+ is supported, though Node 18+ is recommended for active testing.

    Browser Support

    Version 5 provides an ESM-enabled bundle. Unlike version 4, you no longer need a specific web entry point; both webdav and webdav/web work in supported bundlers.

    Warning: Streams (createReadStream and createWriteStream) are not available in the browser and will throw an exception if called.

  2. Configure Authentication Types

    master

    The client automatically detects authentication between AuthType.None and AuthType.Password if no authType is provided. For other types, you must specify them explicitly:

    • Basic/No Auth: Omit username and password from the config.
    • Basic Auth: Provide username and password.
    • Token Auth: Set authType: AuthType.Token and provide a token object containing access_token, token_type, etc.
    • Digest Auth: Set authType: AuthType.Digest and provide username and password. You can also provide a pre-generated ha1 to avoid persisting the password.
    • Auto Detection: Use authType: AuthType.Auto if you are unsure if the server requires digest or password authentication.
    // OAuth Token Example
    createClient(
        "https://address.com",
        {
            authType: AuthType.Token,
            token: {
                access_token: "2YotnFZFEjr1zCsicMWpAA",
                token_type: "example",
                expires_in: 3600,
                refresh_token: "tGzv3JOkF0XG5Qx2TlKWIA",
                example_parameter: "example_value"
            }
        }
    );
    
    // Digest Auth with HA1 Example
    createClient("https://address.com", {
        authType: AuthType.Digest,
        username: "someUser",
        password: "",
        ha1: "your previously generated ha1 here"
    });
  3. Configure React-Native support

    master

    React-Native is supported via a specific build. While imports are usually automatic, you can force the React-Native build by importing from webdav/react-native.

    If the Metro build system fails to resolve the entry point, you may need to configure your babel.config.js using module-resolver to alias webdav to webdav/dist/react-native.

    import { createClient } from "webdav/react-native";
    // babel.config.js example
    module.exports = {
        presets: ["module:metro-react-native-babel-preset"],
        plugins: [
            [
                "module-resolver",
                {
                    alias: {
                        // Point the webdav client entry to the react native build:
                        webdav: "webdav/dist/react-native"
                    },
                    extensions: [".tsx", ".ts", ".js", ".jsx", ".json"]
                }
            ]
        ]
    };
  4. Initialize a WebDAV client with createClient

    master

    To use the library, call the createClient factory function with the WebDAV service URL and a configuration object. The configuration object can include authentication credentials like username and password.

    const { createClient } = require("webdav");
    
    const client = createClient(
        "https://webdav.example.com/marie123",
        {
            username: "marie",
            password: "myS3curePa$$w0rd"
        }
    );
    
    // Get directory contents
    const directoryItems = await client.getDirectoryContents("/");
  5. Configure the Entity Decoder for XML parsing

    master

    The entityDecoder option controls how XML entity references are decoded. Use this to set security limits on entity expansion to prevent attacks.

    const client = createClient("https://some-server.org", {
        username: "user",
        password: "pass",
        entityDecoder: {
            limit: {
                maxTotalExpansions: 1000,
                maxExpandedLength: 50000
            }
        }
    });
  6. Stream Remote Files

    master

    For large files, use streams instead of fetching full contents into memory.

    • createReadStream(filename, options): Returns a Stream.Readable. You can specify a range (start/end bytes) to stream parts of a file.
    • createWriteStream(filename, options, callback): Returns a Stream.Writable. Use options.overwrite (defaults to true) to control if existing files are replaced.
    // Stream a specific range of a file
    client
        .createReadStream(
            "/video.mp4", 
            { range: { start: 0, end: 1024 } }
        ).pipe(fs.createWriteStream("~/video.mp4"));
    
    // Upload a local file using a write stream
    fs
        .createReadStream("~/Music/song.mp3")
        .pipe(client.createWriteStream("/music/song.mp3"));
  7. Fetch File and Directory Contents

    master

    Retrieve data from the server:

    • getDirectoryContents(path, options): Returns an array of FileStat objects. Use options.deep: true for recursive listing and options.glob (using minimatch syntax) to filter files.
    • getFileContents(filename, options): Returns file data. Use options.format: "text" for text files; otherwise, it defaults to "binary" (returning a Buffer).
    • getQuota(options): Returns DiskQuota information (used/available space).
    // Get all PNG/JPG files recursively
    const images = await client.getDirectoryContents("/", { 
        deep: true, 
        glob: "/**/*.{png,jpg,gif}" 
    });
    
    // Fetch a text file
    const str: string = await client.getFileContents("/config.json", { format: "text" });
    
    // Get quota
    const quota = await client.getQuota();
  8. Manage Files and Directories

    master

    Use the following methods to manipulate the remote filesystem:

    • copyFile(filename, destination, options): Copies a file.
    • deleteFile(filename, options): Deletes a file.
    • moveFile(filename, destinationFilename, options): Moves a file.
    • createDirectory(path, options): Creates a directory. If options.recursive is true, it creates parent directories as needed.
    • exists(path, options): Returns true if the path exists, false otherwise.
    // Copy a file
    await client.copyFile("/images/test.jpg", "/public/img/test.jpg");
    
    // Create a directory recursively
    await client.createDirectory("/data/system/storage", { recursive: true });
    
    // Check if a file exists
    if (await client.exists("/some/path") === false) {
        await client.createDirectory("/some/path");
    }
  9. Initialize the client with createClient()

    master

    Import createClient and AuthType from webdav to initialize a connection to a WebDAV server. You can specify the server URL and an options object containing authentication details like authType, username, and password.

    import { AuthType, createClient } from "webdav";
    
    const client = createClient("https://some-server.org", {
        authType: AuthType.Digest,
        username: "user",
        password: "pass"
    });
  10. Register Custom Attribute and Tag Parsers

    master

    You can extend how the client parses XML properties by registering custom parsers. This is useful for converting string attributes or XML tags into specific JavaScript types (like booleans or JSON objects) during stat or getDirectoryContents calls.

    • registerAttributeParser(parser): Parses attributes (e.g., <prop attr="val">).
    • registerTagParser(parser): Parses tag values (e.g., <prop>val</prop>).

    Parsers should return undefined to skip parsing, the unchanged value to use default parsing, or a new value to use the parsed result.

    // Parses all `disabled` attributes to boolean
    function booleanAttributeParser(jPath: string, value: string) {
        if (jPath.endsWith(".disabled")) {
            return value === "true";
        }
        return value;
    }
    await client.registerAttributeParser(booleanAttributeParser);
    
    // Parses JSON values inside specific tags
    function jsonPropParser(jPath: string, value: string) {
        if (jPath.endsWith("prop.json-prop")) {
            return JSON.parse(value);
        }
        return value;
    }
    await client.registerTagParser(jsonPropParser);
  11. Perform Custom WebDAV Requests

    master

    If a specific WebDAV method is not implemented, use customRequest(path, requestOptions) to send a raw request. This method handles boilerplate authentication and headers automatically.

    const resp: Response = await this.client.customRequest("/alrighty.jpg", {
        method: "PROPFIND",
        headers: {
            Accept: "text/plain",
            Depth: "0"
        }
    });