npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@structcms/api

v0.1.2

Published

Storage, domain API, and delivery API for StructCMS

Readme

@structcms/api

Storage, domain API, delivery API, and content export for StructCMS. Provides Supabase-agnostic adapter interfaces, handler functions for content CRUD, media management, and JSON export.

For architectural context, see ARCHITECTURE.md (Layer 3: Storage, Layer 4: Domain API, Layer 5: Delivery API).

← Back to main README

Installation

npm install @structcms/api

Quick Start

import { createStorageAdapter, createMediaAdapter } from '@structcms/api';
import { createClient } from '@supabase/supabase-js';
import { createNextPagesRoute } from '@structcms/api/next';

// 1. Create Supabase client
const supabase = createClient(
  process.env.SUPABASE_URL!,
  process.env.SUPABASE_SECRET_KEY!
);

// 2. Create adapters
const storageAdapter = createStorageAdapter({ client: supabase });
const mediaAdapter = createMediaAdapter({ client: supabase });

// 3. Create Next.js API route handlers
export const { GET, POST } = createNextPagesRoute({ 
  storageAdapter, 
  mediaAdapter 
});

See examples/test-app/app/api/cms/ for complete route handler implementations.

File Structure

packages/api/
├── src/
│   ├── index.ts                          # Public exports
│   ├── storage/
│   │   ├── types.ts                      # StorageAdapter interface, Page, Navigation types
│   │   ├── supabase-adapter.ts           # Supabase implementation of StorageAdapter
│   │   ├── handlers.ts                   # Page/Navigation CRUD handlers
│   │   └── *.test.ts
│   ├── delivery/
│   │   ├── types.ts                      # PageResponse, NavigationResponse types
│   │   ├── handlers.ts                   # Delivery handlers (list, get by slug)
│   │   └── *.test.ts
│   ├── media/
│   │   ├── types.ts                      # MediaAdapter interface, MediaFile types
│   │   ├── supabase-adapter.ts           # Supabase implementation of MediaAdapter
│   │   ├── handlers.ts                   # Upload, list, delete handlers
│   │   ├── resolve.ts                    # Media reference resolution
│   │   └── *.test.ts
│   ├── export/
│   │   ├── types.ts                      # Export response types
│   │   ├── handlers.ts                   # Export handlers (page, site, navigation)
│   │   └── *.test.ts
│   ├── utils/
│   │   ├── slug.ts                       # Slug generation and uniqueness
│   │   └── sanitize.ts                   # HTML sanitization (XSS protection)
│   └── types/
│       └── database.types.ts             # Generated Supabase types
├── package.json
├── tsconfig.json
└── tsup.config.ts

Key Concepts

Handler Functions

This package exports handler functions, not complete route handlers. This keeps the package framework-agnostic and allows adapter injection. Host projects create thin route handlers that inject their adapters.

Adapter Interfaces

  • StorageAdapter — Interface for page and navigation persistence
  • MediaAdapter — Interface for media file operations

Both have Supabase implementations but the interfaces are Supabase-agnostic for future portability.

HTML Sanitization

Rich text content is sanitized on write using sanitize-html to prevent XSS attacks.

API Reference

Adapter Factories

  • createStorageAdapter({ client }) — Create a Supabase storage adapter
  • createMediaAdapter({ client, bucketName? }) — Create a Supabase media adapter

Storage Handlers

  • handleCreatePage(adapter, input) — Create a page with auto-generated slug
  • handleUpdatePage(adapter, input) — Update an existing page
  • handleDeletePage(adapter, id) — Delete a page by ID
  • handleCreateNavigation(adapter, input) — Create a navigation
  • handleUpdateNavigation(adapter, input) — Update a navigation
  • handleDeleteNavigation(adapter, id) — Delete a navigation

Delivery Handlers

  • handleListPages(adapter, options?) — List pages with optional filtering
  • handleGetPageBySlug(adapter, slug) — Get a single page by slug
  • handleGetNavigation(adapter, name) — Get a navigation by name

Media Handlers

  • handleUploadMedia(adapter, input) — Upload a media file (validates MIME type)
  • handleGetMedia(adapter, id) — Get media by ID
  • handleListMedia(adapter, filter?) — List media files
  • handleDeleteMedia(adapter, id) — Delete a media file
  • resolveMediaReferences(adapter, sections) — Resolve media IDs to URLs in section data

Allowed MIME types: image/jpeg, image/png, image/gif, image/webp, image/svg+xml

Export Handlers

  • handleExportPage(adapter, mediaAdapter, slug) — Export a single page with resolved media
  • handleExportAllPages(adapter, mediaAdapter) — Export all pages
  • handleExportNavigations(adapter) — Export all navigations
  • handleExportSite(adapter, mediaAdapter) — Full site export (pages + navigations + media)

Next.js Preset Factories

  • createNextPagesRoute({ storageAdapter, mediaAdapter }) — List and create pages
  • createNextPageBySlugRoute({ storageAdapter, mediaAdapter }) — Get page by slug
  • createNextPageByIdRoute({ storageAdapter }) — Update/delete page by ID
  • createNextMediaRoute({ mediaAdapter }) — List and upload media
  • createNextMediaByIdRoute({ mediaAdapter }) — Delete media by ID
  • createNextNavigationRoute({ storageAdapter }) — List and create navigation
  • createNextNavigationByIdRoute({ storageAdapter }) — Update/delete navigation by ID

Error Classes

  • StorageError — Thrown by storage adapter on database errors
  • StorageValidationError — Thrown on validation failures (empty title, duplicate slug). Has code property.
  • MediaError — Thrown by media adapter on storage/database errors
  • MediaValidationError — Thrown on validation failures (invalid MIME type). Has code property.

Constants

  • ALLOWED_MIME_TYPES — Readonly array of allowed MIME types

Utilities

  • generateSlug(title) — Generate a URL-safe slug from a title
  • ensureUniqueSlug(slug, existingSlugs) — Ensure slug uniqueness by appending a suffix if needed

Dependencies

| Package | Purpose | |---------|---------| | @supabase/supabase-js | Database and storage client | | sanitize-html | Server-side HTML sanitization for XSS protection |

Database

Migrations live in supabase/migrations/ at the monorepo root. See ARCHITECTURE.md for the database schema.

Development

# Run tests (watch mode)
pnpm test

# Run tests once
pnpm test run

# Build
pnpm build

# Type check
pnpm typecheck

# Regenerate Supabase types
pnpm gen:types

← Back to main README