Docs/Getting Started/Quick Start

    Getting Started

    S3WORM (S3 Wrapped ORM) turns any S3-compatible bucket into a typed JSON document database. Point it at AWS S3, Storj, MinIO, Cloudflare R2, or DigitalOcean Spaces and get a full ORM with entities, repositories, schemas, oplogs, and more -- no traditional database required.

    Install

    S3WORM is published to GitHub Packages. Configure your .npmrc first:

    # .npmrc (project root or home directory)
    @decoperations:registry=https://npm.pkg.github.com
    //npm.pkg.github.com/:_authToken=${GITHUB_TOKEN}
    

    Then install:

    pnpm add @decoperations/s3worm
    

    Requires Node.js 18 or later.

    Create a Client

    The S3Worm class is the main entry point. Pass it your bucket name, endpoint, and credentials:

    import { S3Worm } from "@decoperations/s3worm";
    
    const worm = new S3Worm({
      bucket: "my-app-data",
      endpoint: "https://gateway.storjshare.io",
      region: "us-east-1",
      credentials: {
        accessKeyId: process.env.S3_ACCESS_KEY!,
        secretAccessKey: process.env.S3_SECRET_KEY!,
      },
    });
    

    This works with any S3-compatible provider. Storj, AWS, MinIO, R2 -- just change the endpoint.

    Define an Entity (Class-Based)

    Entities are TypeScript classes that extend Entity. Each entity type declares its storage path via a static getBasePath() method:

    import { Entity } from "@decoperations/s3worm";
    
    class BlogPost extends Entity {
      title: string = "";
      slug: string = "";
      content: string = "";
      published: boolean = false;
      tags: string[] = [];
    
      static getBasePath(): string {
        return "posts";
      }
    }
    

    Every entity automatically gets id, createdAt, and updatedAt fields from the base class. The id is auto-generated on save if not set. Documents are stored as JSON files at {basePath}/{id}.json.

    Get a Repository and Do CRUD

    Use getRepository() to get a typed repository for any entity class:

    const posts = worm.getRepository(BlogPost);
    
    // Create and save
    const post = posts.create({
      title: "Hello World",
      slug: "hello-world",
      content: "My first post.",
      published: true,
      tags: ["intro", "blog"],
    });
    await posts.save(post);
    // post.id is now set (auto-generated nanoid)
    // post.createdAt and post.updatedAt are set
    
    // Find by ID
    const found = await posts.findById(post.id);
    
    // Find all with filtering, sorting, and pagination
    const published = await posts.findAll({
      filter: (p) => p.published === true,
      sort: (a, b) => b.createdAt!.localeCompare(a.createdAt!),
      limit: 10,
      offset: 0,
    });
    
    // Delete
    await posts.delete(post.id);
    

    Schema-Driven Models

    For a more powerful approach, define models in a JSON schema and let S3WORM generate everything for you:

    const worm = new S3Worm({
      bucket: "my-app-data",
      endpoint: "https://gateway.storjshare.io",
      credentials: { accessKeyId: "...", secretAccessKey: "..." },
    });
    
    worm.loadSchema({
      schemaVersion: "1.0",
      sourceOfTruth: "local",
      models: {
        Customer: {
          path: "#org/@customers/(id:uuid)",
          idType: "uuid",
          fields: {
            name: { type: "string", required: true },
            email: { type: "string", required: true },
            status: { type: "string", enum: ["active", "inactive"], default: "active" },
          },
          file: "[profile].json",
          mode: "readwrite",
        },
      },
    });
    
    const customers = worm.model("Customer");
    
    // Create
    const customer = await customers.save({
      name: "Acme Corp",
      email: "hello@acme.com",
    });
    
    // Query
    const active = await customers.findAll({
      filter: { status: "active" },
      sort: { field: "createdAt", order: "desc" },
      limit: 50,
    });
    
    // Find by ID
    const found = await customers.findById(customer.id);
    

    Schema-driven models give you validation, access modes (readonly/readwrite/append), soft delete, oplogs, snapshots, entity links, and more. See the Entity & Repository and Configuration docs for the full picture.

    Run the CLI

    The worm CLI manages schemas, lints bucket structures, runs a local dev server, and generates code:

    # Initialize a new .worm directory with a default schema
    npx worm init
    
    # Validate your schema
    npx worm lint
    
    # Start local dev mode (filesystem-backed, no S3 needed)
    npx worm dev
    
    # Generate TypeScript interfaces from your schema
    npx worm codegen
    
    # Generate TypeScript + Zod validation schemas
    npx worm codegen --zod
    
    # Generate llms.txt for AI tool consumption
    npx worm llms --output llms.txt
    

    The worm dev command starts a local development server backed by the filesystem instead of S3, so you can iterate on your schema without needing cloud credentials.

    Coming soon: worm push, worm pull, worm diff, worm status, and worm serve are planned for upcoming releases. See the Roadmap for details.

    What's Next

    TopicDescription
    InstallationDetailed setup for all environments
    ConfigurationProvider configs, CORS, environment variables
    S3Worm ClientFull API reference for the S3Worm class
    Entity & RepositoryDeep dive into entities and repositories
    Path DSLHow the path language maps to S3 keys