or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

configuration.mdcontainer-lifecycle.mdindex.mdprotocol-quorum.mdutilities.md
tile.json

utilities.mddocs/

Utilities

The utilities module provides helper functions for container management, URL handling, location redirection, and compatibility checks.

Container Utilities

waitContainerToCatchUp

Waits for a container to finish synchronizing with the latest state from the service.

function waitContainerToCatchUp(container: IContainer): Promise<boolean>;

This function is particularly useful after reconnection events to ensure the container has processed all pending operations.

Usage Example

import { waitContainerToCatchUp } from "@fluidframework/container-loader";

async function handleReconnection(container: IContainer) {
  console.log("Container reconnected, waiting to catch up...");
  
  const success = await waitContainerToCatchUp(container);
  
  if (success) {
    console.log("Container successfully caught up with latest state");
    // Safe to continue with operations
    await performContainerOperations(container);
  } else {
    console.error("Container failed to catch up within timeout");
    // Handle failure scenario
    await handleCatchUpFailure(container);
  }
}

// Use with connection event handlers
container.on("connected", () => handleReconnection(container));

URL and Request Utilities

tryParseCompatibleResolvedUrl

Attempts to parse a URL into a compatible resolved URL structure.

function tryParseCompatibleResolvedUrl(url: string): IParsedUrl | undefined;

Returns a parsed URL object if the URL can be parsed, or undefined if parsing fails.

Usage Example

import { tryParseCompatibleResolvedUrl } from "@fluidframework/container-loader";
import type { IParsedUrl } from "@fluidframework/container-loader";

function handleUrlParsing(urlString: string) {
  const parsedUrl: IParsedUrl | undefined = tryParseCompatibleResolvedUrl(urlString);
  
  if (parsedUrl) {
    console.log("Successfully parsed URL:");
    console.log("  ID:", parsedUrl.id);
    console.log("  Path:", parsedUrl.path);
    console.log("  Query:", parsedUrl.query);
    console.log("  Version:", parsedUrl.version);
    
    // Use parsed components
    if (parsedUrl.version) {
      console.log(`Loading specific version: ${parsedUrl.version}`);
    }
  } else {
    console.log("Unable to parse URL:", urlString);
    // Handle parsing failure
  }
}

resolveWithLocationRedirectionHandling

Resolves requests with automatic handling of location redirection errors.

function resolveWithLocationRedirectionHandling<T>(
  api: (request: IRequest) => Promise<T>, 
  request: IRequest, 
  urlResolver: IUrlResolver, 
  logger?: ITelemetryBaseLogger
): Promise<T>;

This utility wraps API calls to automatically handle location redirection scenarios common in distributed Fluid deployments.

Usage Example

import { 
  resolveWithLocationRedirectionHandling 
} from "@fluidframework/container-loader";
import type { 
  IRequest,
  IUrlResolver,
  ITelemetryBaseLogger 
} from "@fluidframework/container-loader";

async function loadContainerWithRedirection(
  request: IRequest,
  urlResolver: IUrlResolver,
  logger?: ITelemetryBaseLogger
) {
  const containerLoadApi = async (req: IRequest) => {
    // Your container loading logic
    const resolvedUrl = await urlResolver.resolve(req);
    return await loadContainerFromUrl(resolvedUrl);
  };
  
  try {
    const container = await resolveWithLocationRedirectionHandling(
      containerLoadApi,
      request,
      urlResolver,
      logger
    );
    
    console.log("Container loaded successfully:", container.id);
    return container;
  } catch (error) {
    console.error("Failed to load container after redirection handling:", error);
    throw error;
  }
}

Location Redirection Error Handling

function isLocationRedirectionError(error: any): boolean;

Determines if an error is a location redirection error that can be handled automatically.

Usage Example

import { isLocationRedirectionError } from "@fluidframework/container-loader";

async function handleContainerLoadError(error: any, request: IRequest) {
  if (isLocationRedirectionError(error)) {
    console.log("Detected location redirection error");
    
    // Extract new location from error
    const redirectUrl = error.redirectUrl || error.location;
    if (redirectUrl) {
      console.log(`Redirecting to: ${redirectUrl}`);
      
      // Create new request with redirected URL
      const redirectedRequest: IRequest = {
        ...request,
        url: redirectUrl
      };
      
      // Retry with redirected URL
      return await loadContainer(redirectedRequest);
    }
  }
  
  // Not a redirection error, re-throw
  throw error;
}

Paused Container Loading

loadContainerPaused

Loads a container in a paused state, optionally up to a specific sequence number.

function loadContainerPaused(
  loaderProps: ILoaderProps,
  request: IRequest,
  loadToSequenceNumber?: number,
  signal?: AbortSignal,
): Promise<IContainer>;

This function is useful for loading containers for debugging, analysis, or when you need to examine state at a specific point in time.

Usage Example

import { loadContainerPaused } from "@fluidframework/container-loader";
import type { ILoaderProps, IRequest } from "@fluidframework/container-loader";

async function loadContainerForDebugging(
  loaderProps: ILoaderProps,
  request: IRequest,
  targetSequenceNumber?: number
) {
  // Create abort controller for timeout
  const abortController = new AbortController();
  const timeoutId = setTimeout(() => {
    abortController.abort();
  }, 30000); // 30 second timeout
  
  try {
    const pausedContainer = await loadContainerPaused(
      loaderProps,
      request,
      targetSequenceNumber,
      abortController.signal
    );
    
    clearTimeout(timeoutId);
    
    console.log("Container loaded in paused state");
    console.log("Current sequence number:", pausedContainer.deltaManager.lastSequenceNumber);
    
    if (targetSequenceNumber) {
      console.log(`Loaded up to sequence number: ${targetSequenceNumber}`);
    }
    
    // Examine container state while paused
    const snapshot = pausedContainer.serialize();
    console.log("Container snapshot length:", snapshot.length);
    
    // Resume when ready
    pausedContainer.resume();
    
    return pausedContainer;
  } catch (error) {
    clearTimeout(timeoutId);
    if (error.name === 'AbortError') {
      console.error("Container loading timed out");
    } else {
      console.error("Error loading paused container:", error);
    }
    throw error;
  }
}

Type Definitions

IParsedUrl

interface IParsedUrl {
  id: string;
  path: string;
  query: string;
  version: string | undefined;
}

Represents the structure of a parsed Fluid URL with its constituent components.

Compatibility Constants

The loader provides several compatibility constants for version checking and feature detection.

const loaderCoreCompatDetails: ILayerCompatDetails;
const loaderCompatDetailsForRuntime: ILayerCompatDetails;
const runtimeSupportRequirementsForLoader: ILayerCompatSupportRequirements;
const driverSupportRequirementsForLoader: ILayerCompatSupportRequirements;

Usage Example

import { 
  loaderCoreCompatDetails,
  loaderCompatDetailsForRuntime,
  runtimeSupportRequirementsForLoader,
  driverSupportRequirementsForLoader 
} from "@fluidframework/container-loader";

function checkCompatibility() {
  console.log("Loader core compatibility:", loaderCoreCompatDetails);
  console.log("Runtime compatibility requirements:", runtimeSupportRequirementsForLoader);
  console.log("Driver compatibility requirements:", driverSupportRequirementsForLoader);
  
  // Use for version checking and feature detection
  const isCompatible = checkVersionCompatibility(
    runtimeVersion,
    runtimeSupportRequirementsForLoader
  );
  
  if (!isCompatible) {
    throw new Error("Runtime version incompatible with loader requirements");
  }
}

Utility Patterns and Best Practices

Robust Container Loading with Retries

import { 
  resolveWithLocationRedirectionHandling,
  isLocationRedirectionError,
  waitContainerToCatchUp 
} from "@fluidframework/container-loader";

async function robustContainerLoad(
  request: IRequest,
  loaderProps: ILoaderProps,
  maxRetries: number = 3
): Promise<IContainer> {
  const loader = new Loader(loaderProps);
  let lastError: Error | undefined;
  
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
    try {
      // Use redirection handling for robust loading
      const container = await resolveWithLocationRedirectionHandling(
        (req) => loader.resolve(req),
        request,
        loaderProps.urlResolver,
        loaderProps.logger
      );
      
      // Wait for container to catch up
      const success = await waitContainerToCatchUp(container);
      if (!success) {
        throw new Error("Container failed to catch up");
      }
      
      console.log(`Container loaded successfully on attempt ${attempt}`);
      return container;
      
    } catch (error) {
      lastError = error as Error;
      console.warn(`Container load attempt ${attempt} failed:`, error);
      
      if (isLocationRedirectionError(error)) {
        console.log("Redirection error will be retried");
      } else if (attempt === maxRetries) {
        console.error("Max retries exceeded");
        break;
      }
      
      // Exponential backoff
      const delay = Math.pow(2, attempt - 1) * 1000;
      await new Promise(resolve => setTimeout(resolve, delay));
    }
  }
  
  throw lastError || new Error("Container load failed after retries");
}

URL Validation and Normalization

import { tryParseCompatibleResolvedUrl } from "@fluidframework/container-loader";

function validateAndNormalizeUrl(urlString: string): string {
  // First, try to parse the URL
  const parsedUrl = tryParseCompatibleResolvedUrl(urlString);
  
  if (!parsedUrl) {
    throw new Error(`Invalid Fluid URL format: ${urlString}`);
  }
  
  // Validate required components
  if (!parsedUrl.id) {
    throw new Error("URL must contain a valid document ID");
  }
  
  // Normalize the URL components
  const normalizedUrl = constructFluidUrl({
    id: parsedUrl.id.trim(),
    path: parsedUrl.path.startsWith('/') ? parsedUrl.path : `/${parsedUrl.path}`,
    query: parsedUrl.query.startsWith('?') ? parsedUrl.query : `?${parsedUrl.query}`,
    version: parsedUrl.version?.trim()
  });
  
  console.log(`Normalized URL: ${normalizedUrl}`);
  return normalizedUrl;
}

Error Recovery Utilities

async function handleContainerErrors(
  container: IContainer,
  onError: (error: Error) => void
) {
  container.on("closed", (error) => {
    if (error) {
      console.error("Container closed with error:", error);
      
      if (isLocationRedirectionError(error)) {
        console.log("Attempting recovery with redirection");
        // Trigger redirection recovery
      } else {
        onError(error);
      }
    }
  });
  
  container.on("disconnected", async () => {
    console.log("Container disconnected, waiting for reconnection...");
    
    // Set up timeout for reconnection
    const reconnectTimeout = setTimeout(() => {
      console.error("Reconnection timeout exceeded");
      onError(new Error("Failed to reconnect within timeout"));
    }, 30000);
    
    container.once("connected", async () => {
      clearTimeout(reconnectTimeout);
      console.log("Container reconnected");
      
      try {
        const success = await waitContainerToCatchUp(container);
        if (!success) {
          throw new Error("Failed to catch up after reconnection");
        }
        console.log("Container fully synchronized after reconnection");
      } catch (error) {
        onError(error as Error);
      }
    });
  });
}