diff --git a/src/blob-store/index.js b/src/blob-store/index.js index 544b2378e..c1a1761f4 100644 --- a/src/blob-store/index.js +++ b/src/blob-store/index.js @@ -4,6 +4,7 @@ import util from 'node:util' import { discoveryKey } from 'hypercore-crypto' import { TypedEmitter } from 'tiny-typed-emitter' import { LiveDownload } from './live-download.js' +/** @import { JsonObject } from 'type-fest' */ /** @import { Readable as NodeReadable } from 'node:stream' */ /** @import { Readable as StreamxReadable, Writable } from 'streamx' */ /** @import { BlobId } from '../types.js' */ @@ -200,7 +201,7 @@ export class BlobStore { * @param {Omit} blobId * @param {Buffer} blob * @param {object} [options] - * @param {{mimeType: string}} [options.metadata] Metadata to store with the blob + * @param {JsonObject} [options.metadata] Metadata to store with the blob * @returns {Promise} discovery key as hex string of hyperdrive where blob is stored */ async put({ type, variant, name }, blob, options) { @@ -212,7 +213,7 @@ export class BlobStore { /** * @param {Omit} blobId * @param {object} [options] - * @param {{mimeType: string}} [options.metadata] Metadata to store with the blob + * @param {JsonObject} [options.metadata] Metadata to store with the blob * @returns {Writable & { driveId: string }} */ createWriteStream({ type, variant, name }, options) { diff --git a/src/fastify-plugins/blobs.js b/src/fastify-plugins/blobs.js index 18c63421a..894595c60 100644 --- a/src/fastify-plugins/blobs.js +++ b/src/fastify-plugins/blobs.js @@ -102,6 +102,7 @@ async function routes(fastify, options) { // Extract the 'mimeType' property of the metadata and use it for the response header if found if ( metadata && + typeof metadata === 'object' && 'mimeType' in metadata && typeof metadata.mimeType === 'string' ) { diff --git a/test/blob-store/blob-store.js b/test/blob-store/blob-store.js index fa7ce293d..c6199271e 100644 --- a/test/blob-store/blob-store.js +++ b/test/blob-store/blob-store.js @@ -153,6 +153,32 @@ test('blobStore.createWriteStream(blobId) and blobStore.createReadStream(blobId) assert.deepEqual(bndlbuf, diskbuf, 'should be equal') }) +test('blobStore.entry includes metadata if present', async () => { + const { blobStore } = testenv() + + const blobId = /** @type {const} */ ({ + type: 'photo', + variant: 'original', + name: 'test-file', + }) + const ws = blobStore.createWriteStream(blobId, { + metadata: { + foo: 'bar', + baz: [1, 2, 3], + }, + }) + await pipeline(fs.createReadStream(new URL(import.meta.url)), ws) + + const entry = await blobStore.entry({ + ...blobId, + driveId: ws.driveId, + }) + assert.deepEqual(entry?.value.metadata, { + foo: 'bar', + baz: [1, 2, 3], + }) +}) + test('blobStore.createReadStream should not wait', async () => { const { blobStore } = testenv() const expected = await readFile(new URL(import.meta.url)) diff --git a/types/hyperdrive.d.ts b/types/hyperdrive.d.ts index 5f7db26f1..3dd708a15 100644 --- a/types/hyperdrive.d.ts +++ b/types/hyperdrive.d.ts @@ -4,6 +4,7 @@ declare module 'hyperdrive' { import Hyperblobs, { BlobId } from 'hyperblobs' import { Readable, Writable } from 'streamx' import { TypedEmitter } from 'tiny-typed-emitter' + import { JsonValue } from 'type-fest' interface HyperdriveOptions { onwait: () => void @@ -39,7 +40,7 @@ declare module 'hyperdrive' { executable: boolean // whether the blob at path is an executable linkname: null | string // if entry not symlink, otherwise a string to the entry this links to blob: BlobId // a Hyperblob id that can be used to fetch the blob associated with this entry - metadata: null | object + metadata: JsonValue } } }