or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

index.mdupload-http-link.mdutility-functions.md
tile.json

utility-functions.mddocs/

Utility Functions

Utility functions for customizing file detection and FormData handling in apollo-upload-client. These functions are used internally by UploadHttpLink but can be imported directly for custom implementations.

Capabilities

formDataAppendFile

Default implementation for appending files to FormData instances using the standard FormData.append method.

/**
 * The default implementation for the class UploadHttpLink constructor option
 * formDataAppendFile that uses the standard FormData.append method.
 * @param {FormData} formData - Form data to append the specified file to.
 * @param {string} fieldName - Field name for the file.
 * @param {ExtractableFile} file - File to append. Can be File, Blob, or FileList.
 * @returns {void}
 */
export default function formDataAppendFile(
  formData: FormData,
  fieldName: string,
  file: ExtractableFile
): void;

Usage Examples:

import formDataAppendFile from "apollo-upload-client/formDataAppendFile.mjs";

// Basic usage
const formData = new FormData();
const file = new File(["content"], "example.txt", { type: "text/plain" });
formDataAppendFile(formData, "file", file);

// Custom implementation example
const customFormDataAppendFile = (formData, fieldName, file) => {
  if ("name" in file && file.name) {
    // Use filename for files that have names
    formData.append(fieldName, file, file.name);
  } else {
    // Generate filename for files without names (like Blobs)
    const extension = file.type ? file.type.split('/')[1] : 'bin';
    const filename = `upload_${Date.now()}.${extension}`;
    formData.append(fieldName, file, filename);
  }
};

// Use custom implementation with UploadHttpLink
import UploadHttpLink from "apollo-upload-client/UploadHttpLink.mjs";

const link = new UploadHttpLink({
  formDataAppendFile: customFormDataAppendFile,
});

isExtractableFile

Function that determines whether a value is an extractable file. Re-exported from the extract-files package.

/**
 * Checks if a value is an extractable file.
 * Re-exported from the extract-files package.
 * @param {unknown} value - Value to check.
 * @returns {value is ExtractableFile} Is the value an extractable file (FileList, File, or Blob).
 */
export default function isExtractableFile(value: unknown): value is ExtractableFile;

Usage Examples:

import isExtractableFile from "apollo-upload-client/isExtractableFile.mjs";

// Check various file types
const file = new File(["content"], "test.txt");
const blob = new Blob(["content"], { type: "text/plain" });
const fileList = document.querySelector('input[type="file"]').files;
const regularObject = { name: "not-a-file" };

console.log(isExtractableFile(file));      // true
console.log(isExtractableFile(blob));      // true  
console.log(isExtractableFile(fileList));  // true
console.log(isExtractableFile(regularObject)); // false

// Create enhanced file matcher
const isExtractableFileEnhanced = (value) =>
  isExtractableFile(value) ||
  (typeof CustomFile !== "undefined" && value instanceof CustomFile);

// Use custom matcher with UploadHttpLink
import UploadHttpLink from "apollo-upload-client/UploadHttpLink.mjs";

const link = new UploadHttpLink({
  isExtractableFile: isExtractableFileEnhanced,
});

Custom File Detection

For applications that need to support custom file types beyond the default FileList, File, and Blob types:

import isExtractableFile from "apollo-upload-client/isExtractableFile.mjs";
import UploadHttpLink from "apollo-upload-client/UploadHttpLink.mjs";

// Support additional file types
class CustomFile {
  constructor(data, filename) {
    this.data = data;
    this.filename = filename;
  }
}

const customIsExtractableFile = (value) => {
  // Check default types first
  if (isExtractableFile(value)) return true;
  
  // Check custom types
  if (value instanceof CustomFile) return true;
  
  // Check for file-like objects
  if (value && typeof value === 'object' && 'data' in value && 'filename' in value) {
    return true;
  }
  
  return false;
};

// Custom FormData appender for custom file types
const customFormDataAppendFile = (formData, fieldName, file) => {
  if (file instanceof CustomFile) {
    formData.append(fieldName, file.data, file.filename);
  } else if (isExtractableFile(file)) {
    // Use default behavior for standard file types
    if ("name" in file) {
      formData.append(fieldName, file, file.name);
    } else {
      formData.append(fieldName, file);
    }
  } else {
    // Handle other custom file-like objects
    const data = file.data || file;
    const name = file.filename || file.name || 'upload';
    formData.append(fieldName, data, name);
  }
};

const link = new UploadHttpLink({
  isExtractableFile: customIsExtractableFile,
  formDataAppendFile: customFormDataAppendFile,
});

Implementation Details

formDataAppendFile Behavior

The default formDataAppendFile function handles different file types:

  • Files with names: Uses FormData.append(fieldName, file, file.name) to preserve the original filename
  • Files without names (like Blobs): Uses FormData.append(fieldName, file) which results in a default filename

isExtractableFile Types

The default isExtractableFile function recognizes these types as extractable:

  • FileList: From <input type="file" multiple> elements
  • File: Individual file objects, typically from file inputs or drag-and-drop
  • Blob: Raw binary data objects, useful for generated content

Integration with extract-files

The isExtractableFile function is re-exported from the extract-files package, which handles the deep traversal of GraphQL variables to find and extract file objects. The extraction process:

  1. Recursively walks through all variable values
  2. Identifies extractable files using the matcher function
  3. Replaces file references with path strings in the variables
  4. Returns a map of paths to actual file objects for multipart request construction