{"version":3,"file":"quilt.mjs","names":["#blob","#readBytesFromSlivers","sliver","#readBytesFromBlob","#readBytes","#cache"],"sources":["../../../src/files/readers/quilt.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { ClientCache } from '@mysten/sui/client';\nimport type { BlobReader } from './blob.js';\nimport { QuiltPatchBlobHeader, QuiltPatchId } from '../../utils/bcs.js';\nimport {\n\tHAS_TAGS_FLAG,\n\tparseQuiltPatchId,\n\tQUILT_PATCH_BLOB_HEADER_SIZE,\n} from '../../utils/quilts.js';\nimport { bcs } from '@mysten/bcs';\nimport { QuiltPatchTags } from '../../utils/bcs.js';\nimport { QuiltIndexV1 } from '../../utils/bcs.js';\nimport { urlSafeBase64 } from '../../utils/index.js';\nimport { QuiltFileReader } from './quilt-file.js';\n\nexport interface QuiltReaderOptions {\n\tblob: BlobReader;\n}\n\nexport class QuiltReader {\n\t#blob: BlobReader;\n\t#cache = new ClientCache();\n\n\tconstructor({ blob }: QuiltReaderOptions) {\n\t\tthis.#blob = blob;\n\t}\n\n\tasync #readBytesFromSlivers(sliver: number, length: number, offset = 0, columnSize?: number) {\n\t\tif (!length) {\n\t\t\treturn new Uint8Array(0);\n\t\t}\n\n\t\t// start loading the first sliver, but don't wait for it (may improve columnSize lookup)\n\t\tthis.#blob.getSecondarySliver({ sliverIndex: sliver }).catch(() => {});\n\n\t\tcolumnSize = columnSize ?? (await this.#blob.getColumnSize());\n\t\tconst columnOffset = Math.floor(offset / columnSize);\n\t\tlet remainingOffset = offset % columnSize;\n\t\tconst bytes = new Uint8Array(length);\n\n\t\tlet bytesRead = 0;\n\n\t\tconst nSlivers = Math.ceil(length / columnSize);\n\t\tconst slivers = new Array(nSlivers)\n\t\t\t.fill(0)\n\t\t\t.map((_, i) => this.#blob.getSecondarySliver({ sliverIndex: sliver + columnOffset + i }));\n\n\t\t// ignore errors from slivers that are not consumed below\n\t\tslivers.forEach((p) => p.catch(() => {}));\n\n\t\tfor (const sliverPromise of slivers) {\n\t\t\tconst sliver = await sliverPromise;\n\t\t\tlet chunk = remainingOffset > 0 ? sliver.subarray(remainingOffset) : sliver;\n\t\t\tremainingOffset -= chunk.length;\n\t\t\tif (chunk.length > length - bytesRead) {\n\t\t\t\tchunk = chunk.subarray(0, length - bytesRead);\n\t\t\t}\n\n\t\t\tbytes.set(chunk, bytesRead);\n\t\t\tbytesRead += chunk.length;\n\n\t\t\tif (bytesRead >= length) {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\treturn bytes;\n\t}\n\n\tasync #readBytesFromBlob(startColumn: number, length: number, offset = 0) {\n\t\tconst result = new Uint8Array(length);\n\n\t\tif (!length) {\n\t\t\treturn result;\n\t\t}\n\t\tconst blob = await this.#blob.getBytes();\n\n\t\tconst [rowSize, symbolSize] = await Promise.all([\n\t\t\tthis.#blob.getRowSize(),\n\t\t\tthis.#blob.getSymbolSize(),\n\t\t]);\n\n\t\tconst nRows = blob.length / rowSize;\n\t\tconst symbolsToSkip = Math.floor(offset / symbolSize);\n\t\tlet remainingOffset = offset % symbolSize;\n\t\tlet currentCol = startColumn + Math.floor(symbolsToSkip / nRows);\n\t\tlet currentRow = symbolsToSkip % nRows;\n\n\t\tlet bytesRead = 0;\n\n\t\twhile (bytesRead < length) {\n\t\t\tconst baseIndex = currentRow * rowSize + currentCol * symbolSize;\n\t\t\tconst startIndex = baseIndex + remainingOffset;\n\t\t\tconst endIndex = Math.min(\n\t\t\t\tbaseIndex + symbolSize,\n\t\t\t\tstartIndex + length - bytesRead,\n\t\t\t\tblob.length,\n\t\t\t);\n\n\t\t\tif (startIndex >= blob.length) {\n\t\t\t\tthrow new Error('Index out of bounds');\n\t\t\t}\n\n\t\t\tconst size = endIndex - startIndex;\n\n\t\t\tfor (let i = 0; i < size; i++) {\n\t\t\t\tresult[bytesRead + i] = blob[startIndex + i];\n\t\t\t}\n\n\t\t\tbytesRead += size;\n\n\t\t\tremainingOffset = 0;\n\n\t\t\tcurrentRow = (currentRow + 1) % nRows;\n\t\t\tif (currentRow === 0) {\n\t\t\t\tcurrentCol += 1;\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\n\tasync #readBytes(sliver: number, length: number, offset = 0, columnSize?: number) {\n\t\tif (this.#blob.hasStartedLoadingFullBlob) {\n\t\t\treturn this.#readBytesFromBlob(sliver, length, offset);\n\t\t}\n\n\t\ttry {\n\t\t\tconst bytes = await this.#readBytesFromSlivers(sliver, length, offset, columnSize);\n\n\t\t\treturn bytes;\n\t\t} catch {\n\t\t\t// fallback to reading the full blob\n\t\t\treturn this.#readBytesFromBlob(sliver, length, offset);\n\t\t}\n\t}\n\n\tasync getBlobHeader(sliverIndex: number) {\n\t\treturn this.#cache.read(['getBlobHeader', sliverIndex.toString()], async () => {\n\t\t\tconst blobHeader = QuiltPatchBlobHeader.parse(\n\t\t\t\tawait this.#readBytes(sliverIndex, QUILT_PATCH_BLOB_HEADER_SIZE),\n\t\t\t);\n\n\t\t\tlet offset = QUILT_PATCH_BLOB_HEADER_SIZE;\n\t\t\tlet blobSize = blobHeader.length;\n\n\t\t\tconst identifierLength = new DataView(\n\t\t\t\t(await this.#readBytes(sliverIndex, 2, offset)).buffer,\n\t\t\t).getUint16(0, true);\n\t\t\tblobSize -= 2 + identifierLength;\n\t\t\toffset += 2;\n\n\t\t\tconst identifier = bcs\n\t\t\t\t.string()\n\t\t\t\t.parse(await this.#readBytes(sliverIndex, identifierLength, offset));\n\n\t\t\toffset += identifierLength;\n\n\t\t\tlet tags: Record<string, string> | null = null;\n\t\t\tif (blobHeader.mask & HAS_TAGS_FLAG) {\n\t\t\t\tconst tagsSize = new DataView(\n\t\t\t\t\t(await this.#readBytes(sliverIndex, 2, offset)).buffer,\n\t\t\t\t).getUint16(0, true);\n\t\t\t\toffset += 2;\n\n\t\t\t\ttags = QuiltPatchTags.parse(await this.#readBytes(sliverIndex, tagsSize, offset));\n\t\t\t\tblobSize -= tagsSize + 2;\n\t\t\t\toffset += tagsSize;\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tidentifier,\n\t\t\t\ttags,\n\t\t\t\tblobSize,\n\t\t\t\tcontentOffset: offset,\n\t\t\t};\n\t\t});\n\t}\n\n\tasync readBlob(sliverIndex: number) {\n\t\tconst { identifier, tags, blobSize, contentOffset } = await this.getBlobHeader(sliverIndex);\n\n\t\tconst blobContents = await this.#readBytes(sliverIndex, blobSize, contentOffset);\n\n\t\treturn {\n\t\t\tidentifier,\n\t\t\ttags,\n\t\t\tblobContents,\n\t\t};\n\t}\n\n\treaderForPatchId(id: string) {\n\t\tconst { quiltId, patchId } = parseQuiltPatchId(id);\n\n\t\tif (quiltId !== this.#blob.blobId) {\n\t\t\tthrow new Error(\n\t\t\t\t`The requested patch ${patchId} is not part of the quilt ${this.#blob.blobId}`,\n\t\t\t);\n\t\t}\n\n\t\treturn new QuiltFileReader({ quilt: this, sliverIndex: patchId.startIndex });\n\t}\n\n\tasync readIndex() {\n\t\tconst header = new DataView((await this.#readBytes(0, 5)).buffer);\n\n\t\tconst version = header.getUint8(0);\n\n\t\tif (version !== 1) {\n\t\t\tthrow new Error(`Unsupported quilt version ${version}`);\n\t\t}\n\n\t\tconst indexSize = header.getUint32(1, true);\n\t\tconst indexBytes = await this.#readBytes(0, indexSize, 5);\n\t\tconst columnSize = await this.#blob.getColumnSize();\n\t\tconst indexSlivers = Math.ceil(indexSize / columnSize);\n\t\tconst index = QuiltIndexV1.parse(indexBytes);\n\n\t\treturn index.patches.map((patch, i) => {\n\t\t\tconst startIndex = i === 0 ? indexSlivers : index.patches[i - 1].endIndex;\n\t\t\tconst reader = new QuiltFileReader({\n\t\t\t\tquilt: this,\n\t\t\t\tsliverIndex: startIndex,\n\t\t\t\tidentifier: patch.identifier,\n\t\t\t\ttags: patch.tags,\n\t\t\t});\n\n\t\t\treturn {\n\t\t\t\tidentifier: patch.identifier,\n\t\t\t\tpatchId: urlSafeBase64(\n\t\t\t\t\tQuiltPatchId.serialize({\n\t\t\t\t\t\tquiltId: this.#blob.blobId,\n\t\t\t\t\t\tpatchId: {\n\t\t\t\t\t\t\tversion: 1,\n\t\t\t\t\t\t\tstartIndex,\n\t\t\t\t\t\t\tendIndex: patch.endIndex,\n\t\t\t\t\t\t},\n\t\t\t\t\t}).toBytes(),\n\t\t\t\t),\n\t\t\t\ttags: patch.tags,\n\t\t\t\treader,\n\t\t\t};\n\t\t});\n\t}\n}\n"],"mappings":"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"}