MonoStack

Getting Started

1. Database Schema

Add the files table to your database schema:

import { createFilesTable } from '@repo/storage/database'

// Global database
export const filesTable = createFilesTable()

// Or tenant-scoped
import { tenantSchema } from '@repo/auth/database'
export const filesTable = createFilesTable(tenantSchema)

The table includes columns: name, key, bucket, storage, mimeType, size, and deletedAt.

2. Server File Manager

Create a server-side instance in your app:

// lib/files.server.ts
import { env } from '$env/dynamic/private'
import { getGlobalDb } from '$lib/db/managedDb.server'
import { S3Client } from '@aws-sdk/client-s3'
import { FilesRepository, ServerFileManager } from '@repo/storage/server'

export const serverFileManager = new ServerFileManager({
  repository: new FilesRepository(getGlobalDb),
  s3: {
    client: new S3Client({
      endpoint: env.PRIVATE_S3_ENDPOINT,
      region: 'us-west-1',
      forcePathStyle: true,
      credentials: {
        accessKeyId: env.S3_ACCESS_KEY_ID!,
        secretAccessKey: env.S3_SECRET_ACCESS_KEY!,
      },
    }),
  },
})

3. Basic Upload

Define a schema, create a form, and upload a file:

import { FileInput } from '@repo/storage'
import { zaf } from '@repo/form'
import { z } from 'zod'

export const myFormSchema = z.object({
  name: z.string(),
  file: zaf(z.file(), {
    component: FileInput.Root,
  }),
})
export const createForm = form(myFormSchema, async ({ file, ...data }) => {
  await serverFileManager.createBucket('my-bucket')
  const { createdFile } = await serverFileManager.sync('my-bucket', { file })
  await db.insert(myTable).values({ ...data, fileId: createdFile.id })
})

Next Steps

On this page