npm package: @glpkg/fallback
Description: Fallback registry resolver for GitLab Package Manager
Latest version: 0.1.0

# @glpkg/fallback

Local cache fallback for GitLab Package Manager.

Provides local package caching for:
- **Offline access**: Use cached packages when GitLab is unavailable
- **Immediate install after publish**: No need to wait for GitLab indexing

## Installation

```bash
npm install @glpkg/fallback
```

## Usage

### Install Flow

1. Try to fetch package from GitLab registry
2. On failure (404, timeout, etc.) → check local cache
3. Cache hit → use cached package
4. Cache miss → error

```typescript
import { createFallbackResolver } from '@glpkg/fallback';

const resolver = createFallbackResolver({
  host: 'gitlab.example.com',
  token: process.env.GITLAB_TOKEN,
  projectId: 123,
  groupId: 456,
});

// Resolve tarball with local cache fallback
const result = await resolver.resolveTarball(
  { name: '@scope/package', version: '1.0.0' },
  adapter,
  'project-first'
);

if (result.success) {
  console.log(`Tarball from ${result.source}: ${result.tarballPath}`);
} else {
  console.error(`Failed: ${result.error}`);
}
```

### Publish Flow

1. Upload to GitLab
2. Simultaneously save to local cache
3. Other projects can install immediately (no GitLab indexing wait)

```typescript
// After successful GitLab publish
await resolver.cacheForPublish(
  '@scope/package',
  '1.0.0',
  '/path/to/package.tgz',
  'sha512-...'
);

// Now other local projects can install immediately
// even before GitLab indexes the package
```

## API

### FallbackResolver

Resolves packages from GitLab with local cache fallback.

```typescript
const resolver = createFallbackResolver({
  host: 'gitlab.example.com',
  token: 'your-token',
  projectId: 123,      // Optional
  groupId: 456,        // Optional
  timeout: 30000,      // Optional, default: 30s
  localCacheConfig: {  // Optional
    cacheDir: '~/.cache/glpkg/packages'
  }
});

// Get metadata from GitLab (no local cache for metadata)
const metadata = await resolver.resolve(pkg, adapter, 'project-first');

// Get tarball with local cache fallback
const tarball = await resolver.resolveTarball(pkg, adapter, 'project-first');

// Cache tarball during publish
await resolver.cacheForPublish(name, version, tarballPath, shasum);

// Access local cache directly
const cache = resolver.getLocalCache();
```

### LocalPackageCache

File system based package tarball cache.

```typescript
import { createLocalPackageCache } from '@glpkg/fallback';

const cache = createLocalPackageCache({
  cacheDir: '~/.cache/glpkg/packages'  // Optional, this is the default
});

// Save a tarball
await cache.save('@scope/pkg', '1.0.0', '/path/to/package.tgz');

// Save from buffer
await cache.saveFromBuffer('@scope/pkg', '1.0.0', buffer, 'sha512');

// Get cached tarball path
const path = await cache.get('@scope/pkg', '1.0.0');

// Check if cached
const exists = await cache.has('@scope/pkg', '1.0.0');

// List cached versions
const versions = await cache.list('@scope/pkg');

// Delete specific version
await cache.delete('@scope/pkg', '1.0.0');

// Cleanup old packages (default: older than 30 days)
const removed = await cache.cleanup(new Date('2024-01-01'));

// Get cache statistics
const stats = await cache.getStats();

// Clear entire cache
await cache.clear();
```

### CacheManager (Memory Cache)

In-memory cache for metadata (unchanged from before).

```typescript
import { createCacheManager } from '@glpkg/fallback';

const cache = createCacheManager(300000); // 5 min TTL
cache.set('key', data);
const cached = cache.get('key');
```

## Cache Structure

```
~/.cache/glpkg/packages/
├── @scope/
│   └── package-name/
│       ├── 1.0.0/
│       │   ├── package.tgz
│       │   └── metadata.json
│       └── 2.0.0/
│           ├── package.tgz
│           └── metadata.json
└── unscoped-package/
    └── 1.0.0/
        ├── package.tgz
        └── metadata.json
```

## Fallback Strategies

- `project-first`: Try project registry first, fallback to group
- `group-first`: Try group registry first, fallback to project
- `project-only`: Only use project registry
- `group-only`: Only use group registry
- `fastest`: Race both registries, return first success

## Types

- `FallbackResolverConfig` - Resolver configuration
- `LocalPackageCacheConfig` - Cache configuration
- `CacheMetadata` - Metadata stored with cached tarballs
- `LocalCacheEntry` - Cache entry with path and metadata
- `TarballResolveResult` - Result from resolveTarball
- `HealthCheckResult` - Registry health check result

## License

MIT