PAIPAI

@pai/files-mongo

MongoDB GridFS-backed FileProvider implementation.

Package: @pai/files-mongo

GridFS-backed FileProvider for persistent MongoDB deployments. It stores attachment bytes in a GridFS bucket and stores PAI scope metadata in the GridFS file document under metadata.pai.

Use it when your deployment already uses MongoDB for durable application state and you want attachments to live beside that data rather than on local disk.

import { createMongoFileProvider } from "@pai/files-mongo";

export const files = createMongoFileProvider({
  url: process.env.MONGO_URL!,
  bucketName: "pai_files",
});

Inject an existing Mongo database when the host application already owns the connection lifecycle:

import { createMongoFileProvider } from "@pai/files-mongo";

export const files = createMongoFileProvider({
  db: mongoose.connection.db,
  bucketName: "fs",
});

Options

type MongoFileProviderOptions =
  | {
      url: string;
      dbName?: string;
      bucketName?: string;
      chunkSizeBytes?: number;
      generateId?: () => ObjectId | string;
      parseId?: (fileId: string) => ObjectId | string;
      stringifyId?: (id: ObjectId | string) => string;
      beforeSave?: FileProviderBeforeSaveHook;
      maxFileBytes?: number | false;
      metadata?: (input: SaveFileInput) => Document | Promise<Document | undefined>;
      fileDocument?: (context: MongoFileDocumentContext) => Document | Promise<Document | undefined>;
      isReadable?: (context: MongoFileAccessContext) => boolean | Promise<boolean>;
    }
  | {
      db: MongoFileProviderDatabase;
      bucket?: MongoGridFsBucket;
      bucketName?: string;
      chunkSizeBytes?: number;
      generateId?: () => ObjectId | string;
      parseId?: (fileId: string) => ObjectId | string;
      stringifyId?: (id: ObjectId | string) => string;
      beforeSave?: FileProviderBeforeSaveHook;
      maxFileBytes?: number | false;
      metadata?: (input: SaveFileInput) => Document | Promise<Document | undefined>;
      fileDocument?: (context: MongoFileDocumentContext) => Document | Promise<Document | undefined>;
      isReadable?: (context: MongoFileAccessContext) => boolean | Promise<boolean>;
    };

bucketName defaults to "pai_files". Pass "fs" to use the conventional legacy GridFS bucket collections fs.files and fs.chunks.

beforeSave runs before GridFS upload. Use it for synchronous file validation or normalization, such as virus scanning before bytes are persisted.

When set, maxFileBytes rejects oversized saves while bytes are streamed into GridFS.

fileDocument lets host applications merge top-level fields into the GridFS file document after upload. Use it for application-owned metadata such as owner, organization, scan status, or ACL data. The provider-owned metadata.pai namespace is always restored after this hook and cannot be overridden.

isReadable lets host applications hide files that exist in GridFS but should not be exposed through PAI yet, such as files still awaiting malware scanning. The same gate applies to list, so an enumerated page never exposes a file that head or read would hide.

Listing And Indexes

list({ scopeKey, userKey?, threadId?, limit, pageToken? }) returns newest-first file metadata from one exact scope. userKey selects immutable creator provenance under metadata.pai.userKey; it is not an authorization rule. threadId selects the origin association under metadata.pai.threadId; transcripts remain the source of truth for every thread that references a file.

initialize() creates compound indexes for the four portable query shapes:

{ "metadata.pai.scopeKey": 1, uploadDate: -1, _id: -1 }
{
  "metadata.pai.scopeKey": 1,
  "metadata.pai.threadId": 1,
  uploadDate: -1,
  _id: -1,
}
{
  "metadata.pai.scopeKey": 1,
  "metadata.pai.userKey": 1,
  uploadDate: -1,
  _id: -1,
}
{
  "metadata.pai.scopeKey": 1,
  "metadata.pai.userKey": 1,
  "metadata.pai.threadId": 1,
  uploadDate: -1,
  _id: -1,
}

Conformance

createMongoFileProvider passes the full @pai/files/test conformance suite:

import { createFileProviderConformanceSuite } from "@pai/files/test";
import { createMongoFileProvider } from "@pai/files-mongo";

createFileProviderConformanceSuite({
  name: "createMongoFileProvider",
  createProvider: () =>
    createMongoFileProvider({
      url: process.env.MONGO_URL!,
      dbName: "pai",
      bucketName: "pai_files_test",
    }),
});

On this page