{"version":3,"file":"client.mjs","names":["#fetch","#timeout","#onError","#request","error"],"sources":["../../src/storage-node/client.ts"],"sourcesContent":["// Copyright (c) Mysten Labs, Inc.\n// SPDX-License-Identifier: Apache-2.0\n\nimport { BlobMetadata, BlobMetadataWithId, SliverData } from '../utils/bcs.js';\nimport {\n\tConnectionTimeoutError,\n\tStorageNodeAPIError,\n\tStorageNodeError,\n\tUserAbortError,\n} from './error.js';\nimport type {\n\tGetBlobMetadataRequestInput,\n\tGetBlobMetadataResponse,\n\tGetBlobStatusRequestInput,\n\tGetBlobStatusResponse,\n\tGetDeletableBlobConfirmationRequestInput,\n\tGetDeletableBlobConfirmationResponse,\n\tGetPermanentBlobConfirmationRequestInput,\n\tGetPermanentBlobConfirmationResponse,\n\tGetSliverRequestInput,\n\tGetSliverResponse,\n\tRawGetBlobStatusResponse,\n\tStoreBlobMetadataRequestInput,\n\tStoreBlobMetadataResponse,\n\tStoreSliverRequestInput,\n\tStoreSliverResponse,\n\tStoredOnNodeStatus,\n\tStoredOnNodeStatusResponse,\n} from './types.js';\nimport { mergeHeaders } from './utils.js';\n\nexport type Fetch = (url: RequestInfo, init?: RequestInit) => Promise<Response>;\n\nexport type StorageNodeClientOptions = {\n\t/**\n\t * An optional custom fetch function.\n\t *\n\t * If not provided, defaults to the global `fetch` function (`globalThis.fetch`).\n\t *\n\t * @default globalThis.fetch\n\t */\n\tfetch?: Fetch;\n\n\t/**\n\t * An optional timeout for requests.\n\t * @default 30_000ms (30 seconds)\n\t */\n\ttimeout?: number;\n\n\t/**\n\t * Callback for individual network errors.\n\t */\n\tonError?: (error: Error) => void;\n};\n\nexport type RequestOptions = {\n\tnodeUrl: string;\n\ttimeout?: number;\n\theaders?: ReturnType<typeof mergeHeaders>;\n} & Omit<RequestInit, 'headers'>;\n\nexport class StorageNodeClient {\n\t#fetch: Fetch;\n\t#timeout: number;\n\t#onError?: (error: Error) => void;\n\tconstructor({ fetch: overriddenFetch, timeout, onError }: StorageNodeClientOptions = {}) {\n\t\tthis.#fetch = overriddenFetch ?? globalThis.fetch;\n\t\tthis.#timeout = timeout ?? 30_000;\n\t\tthis.#onError = onError;\n\t}\n\n\t/**\n\t * Gets the metadata associated with a Walrus blob.\n\t */\n\tasync getBlobMetadata(\n\t\t{ blobId }: GetBlobMetadataRequestInput,\n\t\toptions: RequestOptions,\n\t): Promise<GetBlobMetadataResponse> {\n\t\tconst response = await this.#request(`/v1/blobs/${blobId}/metadata`, {\n\t\t\t...options,\n\t\t\theaders: mergeHeaders({ Accept: 'application/octet-stream' }, options.headers),\n\t\t});\n\n\t\tconst bcsBytes = await response.arrayBuffer();\n\t\treturn BlobMetadataWithId.parse(new Uint8Array(bcsBytes));\n\t}\n\n\t/**\n\t * Gets the status associated with a Walrus blob.\n\t */\n\tasync getBlobStatus(\n\t\t{ blobId }: GetBlobStatusRequestInput,\n\t\toptions: RequestOptions,\n\t): Promise<GetBlobStatusResponse> {\n\t\tconst response = await this.#request(`/v1/blobs/${blobId}/status`, options);\n\n\t\tconst json: RawGetBlobStatusResponse = await response.json();\n\t\tconst blobStatus = json.success.data;\n\n\t\tif (blobStatus === 'nonexistent') {\n\t\t\treturn { type: 'nonexistent' };\n\t\t}\n\n\t\tif ('invalid' in blobStatus) {\n\t\t\treturn {\n\t\t\t\ttype: 'invalid',\n\t\t\t\t...blobStatus.invalid,\n\t\t\t};\n\t\t}\n\n\t\tif ('permanent' in blobStatus) {\n\t\t\treturn {\n\t\t\t\ttype: 'permanent',\n\t\t\t\t...blobStatus.permanent,\n\t\t\t};\n\t\t}\n\n\t\tif ('deletable' in blobStatus) {\n\t\t\treturn {\n\t\t\t\ttype: 'deletable',\n\t\t\t\t...blobStatus.deletable,\n\t\t\t};\n\t\t}\n\n\t\tthrow new StorageNodeError(`Unknown blob status received: ${blobStatus}`);\n\t}\n\n\t/**\n\t * Stores the metadata associated with a registered Walrus blob at this storage\n\t * node. This is a pre-requisite for storing the encoded slivers of the blob. The\n\t * ID of the blob must first be registered on Sui, after which storing the metadata\n\t * becomes possible.\n\t *\n\t * This endpoint may return an error if the node has not yet received the\n\t * registration event from the chain.\n\t */\n\tasync storeBlobMetadata(\n\t\t{ blobId, metadata }: StoreBlobMetadataRequestInput,\n\t\toptions: RequestOptions,\n\t): Promise<StoreBlobMetadataResponse> {\n\t\tconst isBcsInput = typeof metadata === 'object' && 'V1' in metadata;\n\t\tconst body = isBcsInput ? BlobMetadata.serialize(metadata).toBytes() : metadata;\n\n\t\tconst response = await this.#request(`/v1/blobs/${blobId}/metadata`, {\n\t\t\t...options,\n\t\t\tmethod: 'PUT',\n\t\t\tbody: body as Uint8Array<ArrayBuffer>,\n\t\t\theaders: mergeHeaders({ 'Content-Type': 'application/octet-stream' }, options.headers),\n\t\t});\n\n\t\tconst json: StoreBlobMetadataResponse = await response.json();\n\t\treturn json;\n\t}\n\n\t/**\n\t * Gets the primary or secondary sliver identified by the specified blob ID and\n\t * index. The index should represent a sliver that is assigned to be stored at one\n\t * of the shards managed by this storage node during this epoch.\n\t */\n\tasync getSliver(\n\t\t{ blobId, sliverPairIndex, sliverType }: GetSliverRequestInput,\n\t\toptions: RequestOptions,\n\t): Promise<GetSliverResponse> {\n\t\tconst response = await this.#request(\n\t\t\t`/v1/blobs/${blobId}/slivers/${sliverPairIndex}/${sliverType}`,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\theaders: mergeHeaders({ Accept: 'application/octet-stream' }, options.headers),\n\t\t\t},\n\t\t);\n\n\t\tconst bcsBytes = await response.arrayBuffer();\n\t\treturn new Uint8Array(bcsBytes);\n\t}\n\n\t/**\n\t * Stores a primary or secondary blob sliver at the storage node.\n\t */\n\tasync storeSliver(\n\t\t{ blobId, sliverPairIndex, sliverType, sliver }: StoreSliverRequestInput,\n\t\toptions: RequestOptions,\n\t): Promise<StoreSliverResponse> {\n\t\tconst isBcsInput = typeof sliver === 'object' && 'symbols' in sliver;\n\t\tconst body = isBcsInput ? SliverData.serialize(sliver).toBytes() : sliver;\n\n\t\tconst response = await this.#request(\n\t\t\t`/v1/blobs/${blobId}/slivers/${sliverPairIndex}/${sliverType}`,\n\t\t\t{\n\t\t\t\t...options,\n\t\t\t\tmethod: 'PUT',\n\t\t\t\tbody: body as Uint8Array<ArrayBuffer>,\n\t\t\t\theaders: mergeHeaders({ 'Content-Type': 'application/octet-stream' }, options.headers),\n\t\t\t},\n\t\t);\n\n\t\tconst json: StoreSliverResponse = await response.json();\n\t\treturn json;\n\t}\n\n\t/**\n\t * Gets a signed storage confirmation from this storage node, indicating that all shards\n\t * assigned to this storage node for the current epoch have stored their respective slivers.\n\t */\n\tasync getDeletableBlobConfirmation(\n\t\t{ blobId, objectId }: GetDeletableBlobConfirmationRequestInput,\n\t\toptions: RequestOptions,\n\t): Promise<GetDeletableBlobConfirmationResponse> {\n\t\tconst response = await this.#request(\n\t\t\t`/v1/blobs/${blobId}/confirmation/deletable/${objectId}`,\n\t\t\toptions,\n\t\t);\n\n\t\tconst json: GetDeletableBlobConfirmationResponse = await response.json();\n\t\treturn json;\n\t}\n\n\t/**\n\t * Gets a signed storage confirmation from this storage node, indicating that all shards\n\t * assigned to this storage node for the current epoch have stored their respective slivers.\n\t */\n\tasync getPermanentBlobConfirmation(\n\t\t{ blobId }: GetPermanentBlobConfirmationRequestInput,\n\t\toptions: RequestOptions,\n\t): Promise<GetPermanentBlobConfirmationResponse> {\n\t\tconst response = await this.#request(`/v1/blobs/${blobId}/confirmation/permanent`, options);\n\n\t\tconst json: GetPermanentBlobConfirmationResponse = await response.json();\n\t\treturn json;\n\t}\n\n\t/**\n\t * Gets the storage status of a sliver at this storage node.\n\t * Returns whether the sliver is stored, buffered (pending registration), or nonexistent.\n\t */\n\tasync getSliverStatus(\n\t\t{ blobId, sliverPairIndex, sliverType }: GetSliverRequestInput,\n\t\toptions: RequestOptions,\n\t): Promise<StoredOnNodeStatus> {\n\t\tconst response = await this.#request(\n\t\t\t`/v1/blobs/${blobId}/slivers/${sliverPairIndex}/${sliverType}/status`,\n\t\t\toptions,\n\t\t);\n\n\t\tconst json: StoredOnNodeStatusResponse = await response.json();\n\t\treturn json.success.data;\n\t}\n\n\t/**\n\t * Gets the storage status of blob metadata at this storage node.\n\t * Returns whether the metadata is stored, buffered (pending registration), or nonexistent.\n\t */\n\tasync getMetadataStatus(\n\t\t{ blobId }: GetBlobMetadataRequestInput,\n\t\toptions: RequestOptions,\n\t): Promise<StoredOnNodeStatus> {\n\t\tconst response = await this.#request(`/v1/blobs/${blobId}/metadata/status`, options);\n\n\t\tconst json: StoredOnNodeStatusResponse = await response.json();\n\t\treturn json.success.data;\n\t}\n\n\tasync #request(path: string, options: RequestOptions) {\n\t\tconst { nodeUrl, signal, timeout, ...init } = options;\n\n\t\tif (signal?.aborted) {\n\t\t\tthrow new UserAbortError();\n\t\t}\n\n\t\tconst timeoutSignal = AbortSignal.timeout(timeout ?? this.#timeout);\n\n\t\tlet response: Response | undefined;\n\n\t\ttry {\n\t\t\tconst fetch = this.#fetch;\n\t\t\tresponse = await fetch(`${nodeUrl}${path}`, {\n\t\t\t\t...init,\n\t\t\t\tsignal: signal ? AbortSignal.any([timeoutSignal, signal]) : timeoutSignal,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tif (signal?.aborted) {\n\t\t\t\tthrow new UserAbortError();\n\t\t\t}\n\n\t\t\tif (error instanceof Error && error.name === 'AbortError') {\n\t\t\t\tconst error = new ConnectionTimeoutError();\n\t\t\t\tthis.#onError?.(error);\n\t\t\t\tthrow error;\n\t\t\t}\n\n\t\t\tthis.#onError?.(error as Error);\n\n\t\t\tthrow error;\n\t\t}\n\n\t\tif (!response.ok) {\n\t\t\tconst errorText = await response.text().catch((reason) => reason);\n\t\t\tconst errorJSON = safeParseJSON(errorText);\n\t\t\tconst errorMessage = errorJSON ? undefined : errorText;\n\t\t\tconst error = StorageNodeAPIError.generate(response.status, errorJSON, errorMessage);\n\t\t\tthis.#onError?.(error);\n\t\t\tthrow error;\n\t\t}\n\n\t\treturn response;\n\t}\n}\n\nfunction safeParseJSON(value: string) {\n\ttry {\n\t\treturn JSON.parse(value);\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n"],"mappings":"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"}