Fluid container loader providing core container loading functionality for the Fluid Framework
56
Pending
Does it follow best practices?
Impact
56%
0.98xAverage score across 10 eval scenarios
Pending
The risk profile of this skill
The configuration system provides flexible options for customizing loader behavior and integrating with various Fluid Framework services.
The main configuration interface for creating a Loader instance.
interface ILoaderProps {
readonly codeLoader: ICodeDetailsLoader;
readonly configProvider?: IConfigProviderBase;
readonly documentServiceFactory: IDocumentServiceFactory;
readonly logger?: ITelemetryBaseLogger;
readonly options?: ILoaderOptions;
readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
readonly scope?: FluidObject;
readonly urlResolver: IUrlResolver;
}codeLoader: Loads code packages for containersdocumentServiceFactory: Creates document service instances for storage operationsurlResolver: Resolves Fluid URLs to storage locationsconfigProvider: Provides runtime configuration valueslogger: Telemetry logger for monitoring and debuggingoptions: Additional loader behavior optionsprotocolHandlerBuilder: Custom protocol handler factoryscope: Dependency injection scope for servicesInterface representing the services available from a configured loader.
interface ILoaderServices {
readonly codeLoader: ICodeDetailsLoader;
readonly documentServiceFactory: IDocumentServiceFactory;
readonly options: ILoaderOptions;
readonly protocolHandlerBuilder?: ProtocolHandlerBuilder;
readonly scope: FluidObject;
readonly subLogger: ITelemetryLoggerExt;
readonly urlResolver: IUrlResolver;
}import { Loader } from "@fluidframework/container-loader";
import type { ILoaderProps } from "@fluidframework/container-loader";
const loaderProps: ILoaderProps = {
codeLoader: myCodeLoader,
documentServiceFactory: myDocumentServiceFactory,
urlResolver: myUrlResolver
};
const loader = new Loader(loaderProps);import { Loader } from "@fluidframework/container-loader";
import type {
ILoaderProps,
ProtocolHandlerBuilder,
ILoaderOptions
} from "@fluidframework/container-loader";
const protocolHandlerBuilder: ProtocolHandlerBuilder = (
attributes,
snapshot,
sendProposal
) => {
return new CustomProtocolHandler(attributes, snapshot, sendProposal);
};
const loaderOptions: ILoaderOptions = {
maxClientLeaveWaitTime: 30000,
noopCountFrequency: 100,
noopTimeFrequency: 30000,
// Additional options...
};
const advancedLoaderProps: ILoaderProps = {
// Required services
codeLoader: myCodeLoader,
documentServiceFactory: myDocumentServiceFactory,
urlResolver: myUrlResolver,
// Optional configuration
configProvider: myConfigProvider,
logger: myTelemetryLogger,
options: loaderOptions,
protocolHandlerBuilder: protocolHandlerBuilder,
scope: myDependencyScope
};
const loader = new Loader(advancedLoaderProps);
// Access configured services
const services = loader.services;
console.log("Configured options:", services.options);
console.log("Sub-logger available:", !!services.subLogger);import { ConsoleLogger } from "@fluidframework/telemetry-utils";
const devLoaderProps: ILoaderProps = {
codeLoader: myCodeLoader,
documentServiceFactory: localDevServiceFactory,
urlResolver: localUrlResolver,
logger: new ConsoleLogger(), // Verbose logging for debugging
options: {
// Development-friendly options
maxClientLeaveWaitTime: 5000, // Shorter timeouts
enableOfflineLoad: true
}
};import { createChildLogger } from "@fluidframework/telemetry-utils";
const prodLoaderProps: ILoaderProps = {
codeLoader: myCodeLoader,
documentServiceFactory: productionServiceFactory,
urlResolver: productionUrlResolver,
logger: createChildLogger({
namespace: "FluidLoader",
properties: { environment: "production" }
}),
configProvider: productionConfigProvider,
options: {
// Production-optimized options
maxClientLeaveWaitTime: 30000,
enableOfflineLoad: false,
// Performance and reliability settings
}
};import type { IDocumentServiceFactory } from "@fluidframework/driver-definitions";
class CustomDocumentServiceFactory implements IDocumentServiceFactory {
public readonly protocolName = "custom";
async createDocumentService(resolvedUrl, logger, clientDetails) {
// Custom implementation for your storage backend
return new CustomDocumentService(resolvedUrl, logger, clientDetails);
}
async createContainer(createNewSummary, resolvedUrl, logger, clientDetails) {
// Custom container creation logic
return this.createDocumentService(resolvedUrl, logger, clientDetails);
}
}
const loaderProps: ILoaderProps = {
codeLoader: myCodeLoader,
documentServiceFactory: new CustomDocumentServiceFactory(),
urlResolver: myUrlResolver
};import type { IUrlResolver } from "@fluidframework/driver-definitions";
class CustomUrlResolver implements IUrlResolver {
async resolve(request) {
// Custom URL resolution logic
const resolvedUrl = {
type: "fluid",
id: extractIdFromUrl(request.url),
url: transformToStorageUrl(request.url),
tokens: {},
endpoints: {
deltaStorageUrl: "https://my-delta-service.com",
storageUrl: "https://my-storage-service.com"
}
};
return resolvedUrl;
}
async getAbsoluteUrl(resolvedUrl, relativeUrl) {
// Handle relative URL resolution
return `${resolvedUrl.url}/${relativeUrl}`;
}
}
const loaderProps: ILoaderProps = {
codeLoader: myCodeLoader,
documentServiceFactory: myDocumentServiceFactory,
urlResolver: new CustomUrlResolver()
};import type { IConfigProviderBase } from "@fluidframework/core-interfaces";
class AppConfigProvider implements IConfigProviderBase {
getRawFeatureGates() {
return {
"Fluid.Container.enableOfflineLoad": true,
"Fluid.Container.maxReconnectDelayMs": 30000
};
}
getNumber(name: string): number | undefined {
const value = this.getRawFeatureGates()[name];
return typeof value === "number" ? value : undefined;
}
getBoolean(name: string): boolean | undefined {
const value = this.getRawFeatureGates()[name];
return typeof value === "boolean" ? value : undefined;
}
getString(name: string): string | undefined {
const value = this.getRawFeatureGates()[name];
return typeof value === "string" ? value : undefined;
}
}
const loaderProps: ILoaderProps = {
codeLoader: myCodeLoader,
documentServiceFactory: myDocumentServiceFactory,
urlResolver: myUrlResolver,
configProvider: new AppConfigProvider()
};// After creating a loader, access configured services
const loader = new Loader(loaderProps);
const services = loader.services;
// Access specific services
const documentService = await services.documentServiceFactory
.createDocumentService(resolvedUrl, services.subLogger);
// Use sub-logger for consistent telemetry
services.subLogger.sendTelemetryEvent({
eventName: "ContainerLoadAttempt",
properties: { containerId: "my-container" }
});
// Access loader options
if (services.options.enableOfflineLoad) {
console.log("Offline loading is enabled");
}try {
const loader = new Loader(loaderProps);
const container = await loader.resolve(request);
} catch (error) {
// Handle configuration or loading errors
if (error.errorType === "fluidInvalidSchema") {
console.error("Invalid configuration schema:", error);
} else if (error.errorType === "cannotConnect") {
console.error("Cannot connect to service:", error);
}
throw error;
}// Loaders and their services should be properly disposed
const loader = new Loader(loaderProps);
// When shutting down
if (loader.services.documentServiceFactory.dispose) {
loader.services.documentServiceFactory.dispose();
}
// Clean up any custom resources
if (myCustomService.cleanup) {
await myCustomService.cleanup();
}function validateLoaderProps(props: ILoaderProps): void {
if (!props.codeLoader) {
throw new Error("codeLoader is required");
}
if (!props.documentServiceFactory) {
throw new Error("documentServiceFactory is required");
}
if (!props.urlResolver) {
throw new Error("urlResolver is required");
}
// Additional validation as needed
if (props.options?.maxClientLeaveWaitTime &&
props.options.maxClientLeaveWaitTime < 0) {
throw new Error("maxClientLeaveWaitTime must be non-negative");
}
}
// Use validation before creating loader
validateLoaderProps(loaderProps);
const loader = new Loader(loaderProps);evals
scenario-1
scenario-2
scenario-3
scenario-4
scenario-5
scenario-6
scenario-7
scenario-8
scenario-9
scenario-10