import { parse } from "url" ; import { v4 as uuid } from "uuid" ; import { assert , stringToBuffer , Uint8ArrayToArrayBuffer , unreachableCase , } from "@fluidframework/common-utils" ; import { ISummaryTree , ISnapshotTree , SummaryType } from "@fluidframework/protocol-definitions" ; export interface ISnapshotTreeWithBlobContents extends ISnapshotTree { blobsContents : { [ path ] : ArrayBufferLike ; } ; trees : { [ path ] : ISnapshotTreeWithBlobContents ; } ; } export interface IParsedUrl { id : string ; path : string ; query : string ; /**
     * Null means do not use snapshots, undefined means load latest snapshot
     * otherwise it's version ID passed to IDocumentStorageService.getVersions() to figure out what snapshot to use.
     * If needed, can add undefined which is treated by Container.load() as load latest snapshot.
     */ version : string | null | undefined ; } export function parseUrl ( url ) { const parsed = parse ( url , true ) ; if ( typeof parsed . pathname !== "string" ) { throw new Error ( "Failed to parse pathname" ) ; } const query = parsed . search ?? "" ; const regex = /^\/([^/]*\/[^/]*)(\/?.*)$/ ; const match = regex . exec ( parsed . pathname ) ; return ( match ?. length === 3 ) ? { id : match [ 1 ] , path : match [ 2 ] , query , version : parsed . query . version as string } : undefined ; } param summary function convertSummaryToSnapshotWithEmbeddedBlobContents ( summary ) { const treeNode = { blobs : { } , blobsContents : { } , trees : { } , commits : { } , id : uuid ( ) , unreferenced : summary . unreferenced } ; const keys = Object . keys ( summary . tree ) ; for ( const key of keys ) { const summaryObject = summary . tree [ key ] ; switch ( summaryObject . type ) { case SummaryType . Tree : { treeNode . trees [ key ] = convertSummaryToSnapshotWithEmbeddedBlobContents ( summaryObject ) ; break ; } case SummaryType . Attachment : treeNode . blobs [ key ] = summaryObject . id ; break ; case SummaryType . Blob : { const blobId = uuid ( ) ; treeNode . blobs [ key ] = blobId ; const contentBuffer = typeof summaryObject . content === "string" ? stringToBuffer ( summaryObject . content , "utf8" ) : Uint8ArrayToArrayBuffer ( summaryObject . content ) ; treeNode . blobsContents [ blobId ] = contentBuffer ; break ; } case SummaryType . Handle : throw new Error ( "No handles should be there in summary in detached container!!" ) ; break ; default : { unreachableCase ( summaryObject , `Unknown tree type ${ ( summaryObject as any ) . type }` ) ; } } } return treeNode ; } param protocolSummaryTree param appSummaryTree export function convertProtocolAndAppSummaryToSnapshotTree ( protocolSummaryTree , appSummaryTree ) { const combinedSummary = { type : SummaryType . Tree , tree : { ... appSummaryTree . tree } } ; combinedSummary . tree [ ".protocol" ] = protocolSummaryTree ; const snapshotTreeWithBlobContents = convertSummaryToSnapshotWithEmbeddedBlobContents ( combinedSummary ) ; return snapshotTreeWithBlobContents ; } export const getSnapshotTreeFromSerializedContainer = ( detachedContainerSnapshot ) => { const protocolSummaryTree = detachedContainerSnapshot . tree [ ".protocol" ] as ISummaryTree ; const appSummaryTree = detachedContainerSnapshot . tree [ ".app" ] as ISummaryTree ; assert ( protocolSummaryTree !== undefined && appSummaryTree !== undefined , 0x1e0 ) ; const snapshotTreeWithBlobContents = convertProtocolAndAppSummaryToSnapshotTree ( protocolSummaryTree , appSummaryTree ) ; return snapshotTreeWithBlobContents ; } ;