npm package: @netgen/storyblok-cache
Description: A generic cache mapping package for Storyblok that tracks relationships between stories for intelligent cache invalidation.
Latest version: 0.1.1

# @netgen/storyblok-cache

A generic cache mapping package for Storyblok that tracks relationships between stories for intelligent cache invalidation.

## Features

- **Database Agnostic**: Works with any SQL database through a simple interface
- **Generic**: No Storyblok-specific dependencies in the core package
- **Type Safe**: Full TypeScript support
- **Flexible**: Easy to integrate with any project structure

## Installation

```bash
npm install @netgen/storyblok-cache
```

## Usage

### 1. Create a Database Adapter

```typescript
import { neon } from "@neondatabase/serverless";
import type { DatabaseClient } from "@netgen/storyblok-cache";

// Create Neon client once and reuse it (important for performance!)
const sqlFunction = neon(process.env.NEON_DATABASE_URL!);

const neonAdapter: DatabaseClient = {
  query: async (sql: TemplateStringsArray, ...params: any[]) => {
    return await sqlFunction(sql, ...params);
  },
  execute: async (sql: TemplateStringsArray, ...params: any[]) => {
    await sqlFunction(sql, ...params);
  },
};
```

### 2. Create Cache Instance

```typescript
import { StoryblokCache } from "@netgen/storyblok-cache";

const cache = new StoryblokCache({
  db: neonAdapter,
  getCurrentPageSlug: () => getCurrentPageSlug(), // Function to get current page slug
  disabled: false, // Optional: disable cache mapping (default: false)
});
```

#### Disable Cache Mapping

You can disable cache mapping in several ways:

```typescript
// Disable in development
const cache = new StoryblokCache({
  db: neonAdapter,
  getCurrentPageSlug: () => getCurrentPageSlug(),
  disabled: process.env.NODE_ENV === "development",
});

// Disable when database URL is not available
const cache = new StoryblokCache({
  db: neonAdapter,
  getCurrentPageSlug: () => getCurrentPageSlug(),
  disabled: !process.env.NEON_DATABASE_URL,
});

// Always disabled
const cache = new StoryblokCache({
  db: neonAdapter,
  getCurrentPageSlug: () => getCurrentPageSlug(),
  disabled: true,
});
```

### 3. Integrate with SiteApi

```typescript
export class CustomSiteApi extends SiteApi<AnyStoryblokBlock> {
  public getStoriesWithCache = async (...args: any[]) => {
    const result = await this.getStories(...args);
    await cache.processResponse(result);
    return result;
  };
}
```

## Database Schema

The package automatically creates the following table:

```sql
CREATE TABLE IF NOT EXISTS page_references (
  id SERIAL PRIMARY KEY,
  current_page VARCHAR(255) NOT NULL,
  referenced_page VARCHAR(255) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  UNIQUE(current_page, referenced_page)
);
```

## API Reference

### `StoryblokCache`

Main cache class that processes Storyblok responses and tracks relationships.

**Constructor:**
- `db: DatabaseClient` - Database adapter
- `getCurrentPageSlug: () => string | null` - Function to get current page slug
- `disabled?: boolean` - Optional flag to disable cache mapping (default: false)

**Methods:**
- `processResponse(response: any): Promise<void>` - Process a Storyblok response and add cache mappings

**Note:** When `disabled: true`, the cache will use a no-op implementation that doesn't perform any database operations.

### `DatabaseClient`

Interface for database adapters:

```typescript
interface DatabaseClient {
  query: (sql: TemplateStringsArray, ...params: any[]) => Promise<any[]>;
  execute: (sql: TemplateStringsArray, ...params: any[]) => Promise<void>;
}
```

## License

Private package for Netgen projects.