# @shopkit/asset-cache

A comprehensive browser-side asset caching solution providing intelligent caching strategies, service worker integration, and Next.js components for optimal performance in e-commerce storefronts.

## Features

- 🚀 **Intelligent Caching**: Multiple caching strategies (cache-first, network-first, stale-while-revalidate)
- 🔄 **Service Worker Integration**: Offline support and background asset management
- ⚡ **Next.js Components**: Drop-in replacements for images and media with built-in caching
- 🏷️ **Tag-based Invalidation**: Efficient cache invalidation using tags
- 📦 **Version Management**: Content-based versioning for reliable cache invalidation
- 🎯 **TypeScript Support**: Full type safety and IntelliSense support
- 🔧 **Configurable**: Flexible configuration options for different use cases

## Installation

```bash
npm install @shopkit/asset-cache
# or
yarn add @shopkit/asset-cache
# or
bun add @shopkit/asset-cache
```

## Quick Start

### 1. Initialize the Asset Cache

```typescript
import { initAssetCache } from '@shopkit/asset-cache';

// Initialize with default settings
await initAssetCache();

// Or with custom configuration
await initAssetCache({
  storageName: 'my-app-cache',
  serviceWorkerEnabled: true,
  serviceWorkerPath: '/custom-sw.js', // Custom service worker path
  manifestPath: '/cache-manifest.json', // Custom manifest path
  debug: true,
  maxSize: 100, // 100MB cache size
  maxAge: 604800 // 7 days TTL
});
```

### 2. Use with Next.js

The package includes Next.js integration templates in the `templates/nextjs-integration/` folder. Copy these files to your project:

```bash
# Copy the Next.js integration files to your project
cp -r node_modules/@shopkit/asset-cache/templates/nextjs-integration/* ./src/lib/asset-cache/
```

Then use the components:

```tsx
import { AssetCacheInitializer, AssetCacheImage } from './lib/asset-cache';

// In your app layout
export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <AssetCacheInitializer
          storageName="my-app-cache"
          serviceWorkerEnabled={true}
          debug={process.env.NODE_ENV === 'development'}
          maxSize={100}
          onInitialized={() => console.log('Asset cache ready!')}
          onError={(error) => console.error('Cache init failed:', error)}
        />
        {children}
      </body>
    </html>
  );
}

// Or with default settings
export default function SimpleLayout({ children }) {
  return (
    <html>
      <body>
        <AssetCacheInitializer />
        {children}
      </body>
    </html>
  );
}

// In your components
export function ProductImage({ src, alt }) {
  return (
    <AssetCacheImage
      src={src}
      alt={alt}
      width={300}
      height={300}
      cacheOptions={{
        ttl: 7 * 24 * 60 * 60, // 7 days
        tags: ['product-images'],
        priority: 'high'
      }}
    />
  );
}
```

### 3. Manual Asset Loading

```typescript
import { AssetLoader } from '@shopkit/asset-cache';

// Preload an asset
await AssetLoader.preload('/images/hero.jpg', {
  ttl: 3600, // 1 hour
  tags: ['hero-images']
});

// Load an asset with caching
const result = await AssetLoader.load('/images/product.jpg');
if (result.success) {
  console.log('Loaded from:', result.fromCache ? 'cache' : 'network');
  // Use result.data (Blob)
}

// Check if an asset is cached
const isCached = await AssetLoader.isCached('/images/product.jpg');

// Invalidate specific assets
await AssetLoader.invalidate('/images/old-product.jpg');

// Invalidate by tag
await AssetLoader.invalidateByTag('product-images');
```

## API Reference

### Core Classes

#### AssetLoader

The main class for loading and managing cached assets.

```typescript
class AssetLoader {
  static async init(config?: AssetLoaderConfig): Promise<void>
  static async preload(url: string, options?: CacheOptions): Promise<void>
  static async load<T>(url: string, options?: CacheOptions): Promise<CacheResult<T>>
  static async isCached(url: string): Promise<boolean>
  static async invalidate(url: string): Promise<void>
  static async invalidateByTag(tag: string): Promise<void>
}
```

#### CacheManager

Manages cache storage and metadata.

```typescript
class CacheManager {
  static async init(cacheName?: string): Promise<void>
  static async addToManifest(url: string, metadata: AssetMetadata): Promise<void>
  static async getAssetMetadata(url: string): Promise<AssetMetadata | null>
  static async removeFromManifest(url: string): Promise<void>
  static async getAssetsByTag(tag: string): Promise<AssetMetadata[]>
}
```

#### VersionManager

Handles asset versioning and cache invalidation.

```typescript
class VersionManager {
  static init(deploymentId?: string): void
  static createVersionedUrl(url: string): string
  static hasVersion(url: string): boolean
  static extractVersion(url: string): string | null
}
```

### Configuration

#### AssetCacheConfig

```typescript
interface AssetCacheConfig {
  enabled?: boolean;            // Default: true - Enable/disable asset cache
  version?: string;             // Default: '1.0.0' - Cache version for invalidation
  debug?: boolean;              // Default: false - Enable debug logging
  storageName?: string;         // Default: 'asset-cache-v1' - Cache storage name
  maxSize?: number;             // Default: 50 - Maximum cache size in MB
  maxAge?: number;              // Default: 86400 - Maximum age in seconds (24 hours)
  serviceWorkerEnabled?: boolean; // Default: true - Enable service worker
  serviceWorkerPath?: string;   // Default: '/sw.js' - Service worker file path
  manifestPath?: string;        // Default: '/manifest.json' - Cache manifest file path
}
```

#### CacheOptions

```typescript
interface CacheOptions {
  ttl?: number;                 // Time to live in seconds
  revalidate?: boolean;         // Whether to revalidate on access
  tags?: string[];              // Cache tags for invalidation
  priority?: 'high' | 'medium' | 'low'; // Priority for preloading
}
```

### Next.js Integration

#### Components

```typescript
// Asset Cache Initializer Component
<AssetCacheInitializer
  storageName="my-app-cache"        // Custom cache name
  serviceWorkerEnabled={true}       // Enable service worker
  debug={false}                     // Enable debug logging
  version="v1.2.3"                 // Cache version for invalidation
  maxSize={100}                     // Maximum cache size in MB
  maxAge={604800}                   // Maximum age in seconds (7 days)
  onInitialized={() => {}}          // Success callback
  onError={(error) => {}}           // Error callback
/>

// Cached Image Component
<AssetCacheImage
  src="/image.jpg"
  alt="Description"
  width={300}
  height={200}
  cacheOptions={{
    ttl: 3600,
    tags: ['images'],
    priority: 'high'
  }}
/>

// Cached Video Component
<AssetCacheVideo
  src="/video.mp4"
  width={640}
  height={360}
  cacheOptions={{
    ttl: 7200,
    tags: ['videos']
  }}
/>
```

#### Hooks

```typescript
// Image caching hook
const { src, loading, error } = useAssetCacheImage('/image.jpg', {
  ttl: 3600,
  tags: ['images']
});

// Video caching hook
const { src, loading, error } = useAssetCacheVideo('/video.mp4', {
  ttl: 7200,
  tags: ['videos']
});

// Asset preloading hook
useAssetCachePreload([
  { url: '/image1.jpg', options: { tags: ['hero'] } },
  { url: '/image2.jpg', options: { tags: ['products'] } }
]);
```

## Caching Strategies

The package includes three built-in caching strategies:

### Cache First
Serves from cache if available, falls back to network.

```typescript
import { cacheFirstStrategy } from '@shopkit/asset-cache/strategies';

const response = await cacheFirstStrategy(request, cacheName);
```

### Network First
Tries network first, falls back to cache if network fails.

```typescript
import { networkFirstStrategy } from '@shopkit/asset-cache/strategies';

const response = await networkFirstStrategy(request, cacheName);
```

### Stale While Revalidate
Serves from cache immediately, updates cache in background.

```typescript
import { staleWhileRevalidateStrategy } from '@shopkit/asset-cache/strategies';

const response = await staleWhileRevalidateStrategy(request, cacheName);
```

## Service Worker Integration

The package automatically registers and manages a service worker for enhanced caching capabilities:

```typescript
import { 
  registerServiceWorker, 
  isServiceWorkerActive,
  sendMessageToSW 
} from '@shopkit/asset-cache/core';

// Register service worker
await registerServiceWorker('/sw.js');

// Check if active
if (isServiceWorkerActive()) {
  // Send message to service worker
  await sendMessageToSW('CACHE_ASSET', { url: '/image.jpg' });
}
```

## Cache Invalidation

### By URL
```typescript
await AssetLoader.invalidate('/specific-image.jpg');
```

### By Tags
```typescript
// Invalidate all product images
await AssetLoader.invalidateByTag('product-images');

// Invalidate multiple tags
await AssetLoader.invalidateByTag('hero-images');
await AssetLoader.invalidateByTag('banner-images');
```

### Version-based
Assets are automatically versioned using content hashes, ensuring cache invalidation when content changes.

## Performance Considerations

- **Selective Caching**: Only cache assets that benefit from caching
- **Size Limits**: Configurable maximum size limits for cached assets
- **TTL Management**: Flexible time-to-live settings per asset type
- **Storage Quotas**: Automatic monitoring of browser storage limits
- **Background Updates**: Stale-while-revalidate for optimal performance

## Browser Support

- Chrome 40+
- Firefox 44+
- Safari 11.1+
- Edge 17+

Requires support for:
- Service Workers
- Cache API
- IndexedDB
- Fetch API

## Templates

The package includes ready-to-use templates for popular frameworks:

### Next.js Integration (`templates/nextjs-integration/`)

Complete Next.js integration with:
- `AssetCacheInitializer.tsx` - Component for app initialization
- `AssetCachedImage.tsx` - Drop-in replacement for Next.js Image (`AssetCacheImage` component, `useAssetCacheImage` hook)
- `AssetCachedVideo.tsx` - Cached video component (`AssetCacheVideo` component, `useAssetCacheVideo` hook)
- `usePreloadAssets.ts` - Hook for asset preloading (`useAssetCachePreload`)
- `initializeAssetCache.ts` - Initialization utilities
- `nextjsConfig.ts` - Next.js specific configuration
- `index.ts` - Main exports file

### Vanilla JavaScript (`templates/vanilla-javascript/`)

Basic implementation examples:
- `basicAssetCaching.ts` - Simple asset caching implementation
- `README.md` - Usage instructions

## Examples

### E-commerce Product Gallery

```typescript
import { AssetLoader } from '@shopkit/asset-cache';

// Preload product images
const productImages = [
  '/products/shoe-1.jpg',
  '/products/shoe-2.jpg',
  '/products/shoe-3.jpg'
];

await Promise.all(
  productImages.map(url => 
    AssetLoader.preload(url, {
      ttl: 24 * 60 * 60, // 24 hours
      tags: ['product-gallery'],
      priority: 'high'
    })
  )
);
```

### Dynamic Content Updates

```typescript
// When products are updated, invalidate related caches
await AssetLoader.invalidateByTag('product-images');
await AssetLoader.invalidateByTag('product-thumbnails');

// Preload new content
await AssetLoader.preload('/new-product-image.jpg', {
  tags: ['product-images']
});
```

## Contributing

See [CONTRIBUTING.md](../../CONTRIBUTING.md) for development setup and contribution guidelines.

## License

MIT License - see [LICENSE](LICENSE) file for details.
