or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

data-processing-summary.mdindex.mdnetwork-utilities.mdprotocol-message-utilities.mdrequest-management.mdretry-rate-limiting.mdstorage-services.mdtree-blob-utilities.mdurl-compression.md
tile.json

url-compression.mddocs/

URL Resolution and Compression

Development utilities for URL resolution and optional compression support for storage operations. Includes compression configuration and factory adapters.

Capabilities

URL Resolution (Development/Testing Only)

⚠️ WARNING: InsecureUrlResolver is intended for development and testing scenarios only. Do not use in production environments.

/**
 * Simple URL resolver for development and testing scenarios
 * WARNING: Not for production use - provides minimal security
 */
class InsecureUrlResolver implements IUrlResolver {
  /**
   * @param hostUrl - Base host URL for the service
   * @param ordererUrl - URL for the ordering service
   * @param storageUrl - URL for the storage service
   * @param deltaStreamUrl - URL for delta stream connections
   * @param tenantId - Tenant identifier
   * @param bearer - Authentication bearer token
   * @param isForNodeTest - Whether this is for Node.js testing (optional)
   */
  constructor(
    hostUrl: string,
    ordererUrl: string,
    storageUrl: string,
    deltaStreamUrl: string,
    tenantId: string,
    bearer: string,
    isForNodeTest?: boolean
  );

  /**
   * Resolve a request to a resolved URL
   * @param request - Request to resolve
   * @returns Promise resolving to resolved URL structure
   */
  resolve(request: IRequest): Promise<IResolvedUrl>;

  /**
   * Get absolute URL from resolved URL and relative path
   * @param resolvedUrl - Previously resolved URL
   * @param relativeUrl - Relative URL to append
   * @returns Promise resolving to absolute URL string
   */
  getAbsoluteUrl(resolvedUrl: IResolvedUrl, relativeUrl: string): Promise<string>;

  /**
   * Create request for creating a new document
   * @param fileName - Optional file name for the new document
   * @returns Request object for document creation
   */
  createCreateNewRequest(fileName?: string): IRequest;
}

Usage Example (Development Only):

import { InsecureUrlResolver } from "@fluidframework/driver-utils";

// ⚠️ DEVELOPMENT/TESTING ONLY
const resolver = new InsecureUrlResolver(
  "http://localhost:7070",  // host
  "http://localhost:7070",  // orderer  
  "http://localhost:7070",  // storage
  "ws://localhost:7070",    // delta stream
  "test-tenant",            // tenant ID
  "test-token",             // bearer token
  true                      // for Node.js testing
);

// Resolve a document URL
const resolvedUrl = await resolver.resolve({
  url: "fluid://localhost/test-container",
  headers: {}
});

// Create new document request
const createRequest = resolver.createCreateNewRequest("my-document");
const newDocUrl = await resolver.resolve(createRequest);

Compression Support

Configuration and utilities for enabling compression in storage operations.

/**
 * Available compression algorithms
 */
enum SummaryCompressionAlgorithm {
  None = 0,
  LZ4 = 1
}

/**
 * Configuration for storage compression
 */
interface ICompressionStorageConfig {
  /** Compression algorithm to use */
  algorithm: SummaryCompressionAlgorithm;
  /** Minimum size in bytes before compression is applied */
  minSizeToCompress: number;
}

/**
 * Default compression configuration with LZ4 algorithm
 */
const DefaultCompressionStorageConfig: ICompressionStorageConfig;

/**
 * Blob name for compression metadata headers
 */
const blobHeadersBlobName: string;

/**
 * Applies compression to document service factory based on configuration
 * @param documentServiceFactory - Factory to wrap with compression
 * @param config - Compression configuration or boolean (true = default config)
 * @returns Wrapped factory with compression support
 */
function applyStorageCompression(
  documentServiceFactory: IDocumentServiceFactory, 
  config?: ICompressionStorageConfig | boolean
): IDocumentServiceFactory;

Usage Examples:

import { 
  applyStorageCompression,
  SummaryCompressionAlgorithm,
  ICompressionStorageConfig,
  blobHeadersBlobName
} from "@fluidframework/driver-utils";

// Apply default compression
const compressedFactory = applyStorageCompression(
  originalFactory, 
  true  // Use default settings
);

// Apply custom compression configuration
const customConfig: ICompressionStorageConfig = {
  algorithm: SummaryCompressionAlgorithm.LZ4,
  minSizeToCompress: 1024  // Only compress files > 1KB
};

const customCompressedFactory = applyStorageCompression(
  originalFactory,
  customConfig
);

// Disable compression
const uncompressedFactory = applyStorageCompression(
  originalFactory,
  false
);

// Check for compression headers blob
if (snapshotTree.blobs[blobHeadersBlobName]) {
  console.log("Snapshot contains compression metadata");
}

Advanced Usage Patterns

Development Environment Setup

import { InsecureUrlResolver } from "@fluidframework/driver-utils";

class DevEnvironmentSetup {
  static createDevResolver(
    port: number = 7070,
    tenantId: string = "dev-tenant"
  ): InsecureUrlResolver {
    const baseUrl = `http://localhost:${port}`;
    const wsUrl = `ws://localhost:${port}`;
    
    return new InsecureUrlResolver(
      baseUrl,      // host
      baseUrl,      // orderer
      baseUrl,      // storage  
      wsUrl,        // delta stream
      tenantId,     // tenant
      "dev-token",  // bearer token
      process.env.NODE_ENV === 'test'
    );
  }
  
  static async createDevDocument(
    resolver: InsecureUrlResolver,
    containerName: string
  ): Promise<IResolvedUrl> {
    const createRequest = resolver.createCreateNewRequest(containerName);
    return await resolver.resolve(createRequest);
  }
  
  static async resolveDevDocument(
    resolver: InsecureUrlResolver,
    documentId: string
  ): Promise<IResolvedUrl> {
    return await resolver.resolve({
      url: `fluid://localhost/${documentId}`,
      headers: {}
    });
  }
}

// Usage in development
const devResolver = DevEnvironmentSetup.createDevResolver(7070);
const newDoc = await DevEnvironmentSetup.createDevDocument(devResolver, "test-doc");
const existingDoc = await DevEnvironmentSetup.resolveDevDocument(devResolver, "existing-doc-id");

Compression Strategy Manager

import { 
  applyStorageCompression,
  SummaryCompressionAlgorithm,
  ICompressionStorageConfig
} from "@fluidframework/driver-utils";

class CompressionStrategyManager {
  static readonly STRATEGIES = {
    // No compression - fastest but largest
    none: {
      algorithm: SummaryCompressionAlgorithm.None,
      minSizeToCompress: Number.MAX_SAFE_INTEGER
    },
    
    // Light compression - good for text-heavy documents
    light: {
      algorithm: SummaryCompressionAlgorithm.LZ4,
      minSizeToCompress: 512  // 512 bytes
    },
    
    // Standard compression - balanced performance/size
    standard: {
      algorithm: SummaryCompressionAlgorithm.LZ4,
      minSizeToCompress: 1024  // 1KB
    },
    
    // Aggressive compression - best size but slower
    aggressive: {
      algorithm: SummaryCompressionAlgorithm.LZ4,
      minSizeToCompress: 256  // 256 bytes
    }
  } as const;
  
  static applyStrategy(
    factory: IDocumentServiceFactory,
    strategyName: keyof typeof CompressionStrategyManager.STRATEGIES
  ): IDocumentServiceFactory {
    const config = this.STRATEGIES[strategyName];
    return applyStorageCompression(factory, config);
  }
  
  static createAdaptiveFactory(
    factory: IDocumentServiceFactory,
    networkSpeed: 'fast' | 'medium' | 'slow' = 'medium'
  ): IDocumentServiceFactory {
    const strategyMap = {
      fast: 'light',      // Prioritize speed
      medium: 'standard', // Balanced
      slow: 'aggressive'  // Prioritize bandwidth savings
    } as const;
    
    return this.applyStrategy(factory, strategyMap[networkSpeed]);
  }
  
  static measureCompressionEffectiveness(
    originalSize: number,
    compressedSize: number
  ): CompressionMetrics {
    const compressionRatio = originalSize / compressedSize;
    const spaceSavings = ((originalSize - compressedSize) / originalSize) * 100;
    
    return {
      originalSize,
      compressedSize,
      compressionRatio,
      spaceSavingsPercent: spaceSavings,
      worthwhileCompression: spaceSavings > 20  // >20% savings
    };
  }
}

interface CompressionMetrics {
  originalSize: number;
  compressedSize: number;
  compressionRatio: number;
  spaceSavingsPercent: number;
  worthwhileCompression: boolean;
}

// Usage
const factory = CompressionStrategyManager.applyStrategy(
  baseFactory, 
  'standard'
);

const adaptiveFactory = CompressionStrategyManager.createAdaptiveFactory(
  baseFactory,
  'slow'  // Optimize for slow networks
);

const metrics = CompressionStrategyManager.measureCompressionEffectiveness(
  10240,  // 10KB original
  3072    // 3KB compressed
);
console.log(`Compression saved ${metrics.spaceSavingsPercent.toFixed(1)}%`);

Multi-Environment URL Resolver

import { InsecureUrlResolver } from "@fluidframework/driver-utils";

class MultiEnvironmentUrlResolver {
  private resolvers = new Map<string, InsecureUrlResolver>();
  private currentEnvironment: string = 'development';
  
  constructor() {
    this.setupEnvironments();
  }
  
  private setupEnvironments(): void {
    // Development environment
    this.resolvers.set('development', new InsecureUrlResolver(
      'http://localhost:7070',
      'http://localhost:7070', 
      'http://localhost:7070',
      'ws://localhost:7070',
      'dev-tenant',
      'dev-token',
      false
    ));
    
    // Testing environment
    this.resolvers.set('testing', new InsecureUrlResolver(
      'http://localhost:8080',
      'http://localhost:8080',
      'http://localhost:8080', 
      'ws://localhost:8080',
      'test-tenant',
      'test-token',
      true
    ));
    
    // Local integration environment
    this.resolvers.set('integration', new InsecureUrlResolver(
      'http://integration.local:9090',
      'http://integration.local:9090',
      'http://integration.local:9090',
      'ws://integration.local:9090',
      'integration-tenant',
      'integration-token',
      false
    ));
  }
  
  setEnvironment(env: string): void {
    if (!this.resolvers.has(env)) {
      throw new Error(`Unknown environment: ${env}`);
    }
    this.currentEnvironment = env;
  }
  
  getCurrentResolver(): InsecureUrlResolver {
    const resolver = this.resolvers.get(this.currentEnvironment);
    if (!resolver) {
      throw new Error(`No resolver configured for environment: ${this.currentEnvironment}`);
    }
    return resolver;
  }
  
  async resolve(request: IRequest): Promise<IResolvedUrl> {
    const resolver = this.getCurrentResolver();
    return await resolver.resolve(request);
  }
  
  async createNewDocument(fileName?: string): Promise<IResolvedUrl> {
    const resolver = this.getCurrentResolver();
    const createRequest = resolver.createCreateNewRequest(fileName);
    return await resolver.resolve(createRequest);
  }
  
  addCustomEnvironment(
    name: string, 
    hostUrl: string,
    tenantId: string,
    bearerToken: string
  ): void {
    const resolver = new InsecureUrlResolver(
      hostUrl, hostUrl, hostUrl, 
      hostUrl.replace('http', 'ws'),
      tenantId, bearerToken, false
    );
    
    this.resolvers.set(name, resolver);
  }
  
  get availableEnvironments(): string[] {
    return Array.from(this.resolvers.keys());
  }
  
  get currentEnvironmentName(): string {
    return this.currentEnvironment;
  }
}

// Usage
const multiResolver = new MultiEnvironmentUrlResolver();

// Switch environments
multiResolver.setEnvironment('testing');
const testDoc = await multiResolver.createNewDocument('test-document');

multiResolver.setEnvironment('development');  
const devDoc = await multiResolver.resolve({
  url: 'fluid://localhost/my-document',
  headers: {}
});

// Add custom environment
multiResolver.addCustomEnvironment(
  'staging',
  'https://staging.example.com',
  'staging-tenant',
  'staging-auth-token'
);

multiResolver.setEnvironment('staging');
console.log(`Available environments: ${multiResolver.availableEnvironments.join(', ')}`);

Compression Performance Monitor

import { applyStorageCompression } from "@fluidframework/driver-utils";

class CompressionPerformanceMonitor {
  private metrics = new Map<string, CompressionMetric[]>();
  
  wrapFactoryWithMonitoring(
    factory: IDocumentServiceFactory,
    config: ICompressionStorageConfig,
    label: string = 'default'
  ): IDocumentServiceFactory {
    const compressedFactory = applyStorageCompression(factory, config);
    
    // Wrap with monitoring (simplified implementation)
    return {
      ...compressedFactory,
      createDocumentService: async (...args) => {
        const service = await compressedFactory.createDocumentService(...args);
        return this.wrapServiceWithMonitoring(service, label);
      }
    };
  }
  
  private wrapServiceWithMonitoring(
    service: IDocumentService,
    label: string
  ): IDocumentService {
    return {
      ...service,
      connectToStorage: async () => {
        const storage = await service.connectToStorage();
        return this.wrapStorageWithMonitoring(storage, label);
      }
    };
  }
  
  private wrapStorageWithMonitoring(
    storage: IDocumentStorageService,
    label: string
  ): IDocumentStorageService {
    return {
      ...storage,
      createBlob: async (file: ArrayBufferLike) => {
        const start = performance.now();
        const originalSize = file.byteLength;
        
        const result = await storage.createBlob(file);
        
        const duration = performance.now() - start;
        this.recordMetric(label, {
          operation: 'createBlob',
          originalSize,
          compressedSize: file.byteLength, // Simplified
          duration,
          timestamp: Date.now()
        });
        
        return result;
      }
    };
  }
  
  private recordMetric(label: string, metric: CompressionMetric): void {
    if (!this.metrics.has(label)) {
      this.metrics.set(label, []);
    }
    
    const metrics = this.metrics.get(label)!;
    metrics.push(metric);
    
    // Keep only last 1000 metrics
    if (metrics.length > 1000) {
      metrics.shift();
    }
  }
  
  getMetrics(label: string): CompressionSummary | null {
    const metrics = this.metrics.get(label);
    if (!metrics || metrics.length === 0) {
      return null;
    }
    
    const totalOriginal = metrics.reduce((sum, m) => sum + m.originalSize, 0);
    const totalCompressed = metrics.reduce((sum, m) => sum + m.compressedSize, 0);
    const totalDuration = metrics.reduce((sum, m) => sum + m.duration, 0);
    
    return {
      label,
      operationCount: metrics.length,
      totalOriginalBytes: totalOriginal,
      totalCompressedBytes: totalCompressed,
      totalDurationMs: totalDuration,
      averageDurationMs: totalDuration / metrics.length,
      compressionRatio: totalOriginal / totalCompressed,
      spaceSavingsPercent: ((totalOriginal - totalCompressed) / totalOriginal) * 100
    };
  }
  
  getAllMetrics(): Map<string, CompressionSummary> {
    const summaries = new Map<string, CompressionSummary>();
    
    for (const label of this.metrics.keys()) {
      const summary = this.getMetrics(label);
      if (summary) {
        summaries.set(label, summary);
      }
    }
    
    return summaries;
  }
  
  clearMetrics(label?: string): void {
    if (label) {
      this.metrics.delete(label);
    } else {
      this.metrics.clear();
    }
  }
}

interface CompressionMetric {
  operation: string;
  originalSize: number;
  compressedSize: number;
  duration: number;
  timestamp: number;
}

interface CompressionSummary {
  label: string;
  operationCount: number;
  totalOriginalBytes: number;
  totalCompressedBytes: number;
  totalDurationMs: number;
  averageDurationMs: number;
  compressionRatio: number;
  spaceSavingsPercent: number;
}