Overview

I had the opportunity to use IIIF manifest files stored in mdx.jp object storage from NestJS, so here are my notes.

Background

After a brief investigation into mdx.jp object storage, it appeared that CORS settings could not be configured, making it difficult to use IIIF manifest files uploaded to mdx.jp object storage directly from other viewers.

https://tech.ldas.jp/en/posts/ad76f58db4e098/#Note (CORS permission)

Therefore, we use NestJS to load the IIIF manifest files uploaded to object storage and return them.

Source Code

The code is available at the following repository.

https://github.com/nakamura196/nestjs-iiif

Prepare environment variables as follows. Since we use mdx.jp object storage, set S3_ENDPOINT to https://s3ds.mdx.jp.

S3_ENDPOINT=https://s3ds.mdx.jp
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=xxx
S3_SECRET_ACCESS_KEY=xxx
S3_BUCKET_NAME=xxx

Then, using @aws-sdk/client-s3, download and return the IIIF manifest file from object storage as follows.

// src/s3.service.ts
import { Injectable } from '@nestjs/common';
import { S3Client, GetObjectCommand } from '@aws-sdk/client-s3';
import { Readable } from 'stream';
import * as dotenv from 'dotenv';

dotenv.config();

@Injectable()
export class S3Service {
  private readonly s3Client: S3Client;

  constructor() {
    this.s3Client = new S3Client({
      region: process.env.S3_REGION,
      endpoint: process.env.S3_ENDPOINT,
      forcePathStyle: true, // Enable path-style (required for many compatible storage services)
      credentials: {
        accessKeyId: process.env.S3_ACCESS_KEY_ID,
        secretAccessKey: process.env.S3_SECRET_ACCESS_KEY,
      },
    });
  }

  async getJsonFile(key: string): Promise<any> {
    const bucket = process.env.S3_BUCKET_NAME;
    if (!bucket) {
      throw new Error('S3_BUCKET_NAME is not set in environment variables.');
    }
    const command = new GetObjectCommand({ Bucket: bucket, Key: key });
    const response = await this.s3Client.send(command);

    const stream = response.Body as Readable;
    const chunks: Uint8Array[] = [];

    for await (const chunk of stream) {
      chunks.push(chunk);
    }

    const fileContent = Buffer.concat(chunks).toString('utf-8');
    return JSON.parse(fileContent);
  }
}

Summary

I hope this serves as a useful reference for using IIIF manifest files stored in mdx.jp object storage.