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 🙏

© 2025 – Pkg Stats / Ryan Hefner

@digilogiclabs/platform-core

v1.1.0

Published

Vendor-agnostic infrastructure abstraction layer for DLL Platform

Readme

@digilogiclabs/platform-core

Vendor-agnostic infrastructure abstraction layer for building portable, enterprise-grade applications.

Tests Adapters Interfaces

Overview

Platform Core provides a unified API for common infrastructure services, allowing you to swap providers without changing application code. Build once, deploy anywhere.

Features

Core Infrastructure

  • Database - Query builder abstraction (PostgreSQL, Supabase, Memory)
  • Cache - Key-value caching (Redis, Upstash, Memory)
  • Storage - File storage (S3/MinIO/R2, Supabase Storage, Memory)
  • Email - Transactional email (SMTP, Resend, Console, Memory)
  • Queue - Background jobs (BullMQ, Memory)
  • Tracing - Distributed tracing (OpenTelemetry, Memory, Noop)
  • Health Checks - Built-in health monitoring for all services

Enterprise Patterns

  • Middleware - Composable before/after hooks for all operations
  • Hooks - Lifecycle events for database, cache, email, queue operations
  • Resilience - Retry, circuit breaker, timeout, bulkhead, fallback patterns
  • Metrics - Counters, gauges, histograms, timings with tag support

Installation

npm install @digilogiclabs/platform-core
# or
pnpm add @digilogiclabs/platform-core

Optional Peer Dependencies

Install only the providers you need:

# For Supabase database
pnpm add @supabase/supabase-js

# For Upstash cache
pnpm add @upstash/redis

# For S3 storage
pnpm add @aws-sdk/client-s3 @aws-sdk/s3-request-presigner

# For Resend email
pnpm add resend

Quick Start

Development (Memory Adapters)

import { createPlatform } from '@digilogiclabs/platform-core';

// Uses memory adapters by default - no external services needed
const platform = createPlatform();

// Use the platform
const users = await platform.db.from('users').where('active', '=', true).execute();
await platform.cache.set('user:123', users.data[0], 3600);
await platform.email.send({
  to: '[email protected]',
  subject: 'Welcome!',
  text: 'Hello from Platform Core',
});

Production (Real Adapters)

import { createPlatformAsync } from '@digilogiclabs/platform-core';

// Use environment variables to configure providers
const platform = await createPlatformAsync();

// Or configure explicitly
const platform = await createPlatformAsync({
  database: { provider: 'supabase' },
  cache: { provider: 'upstash' },
  storage: { provider: 's3' },
  email: { provider: 'resend' },
});

Environment Variables

# Provider selection
PLATFORM_DB_PROVIDER=memory|supabase
PLATFORM_CACHE_PROVIDER=memory|upstash
PLATFORM_STORAGE_PROVIDER=memory|s3|minio|r2
PLATFORM_EMAIL_PROVIDER=memory|console|resend
PLATFORM_QUEUE_PROVIDER=memory

# Supabase
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_ANON_KEY=your-anon-key
SUPABASE_SERVICE_ROLE_KEY=your-service-role-key

# Upstash
UPSTASH_REDIS_REST_URL=https://your-redis.upstash.io
UPSTASH_REDIS_REST_TOKEN=your-token

# S3 / MinIO / R2
S3_ENDPOINT=https://s3.amazonaws.com
S3_REGION=us-east-1
S3_ACCESS_KEY_ID=your-key
S3_SECRET_ACCESS_KEY=your-secret
S3_BUCKET=your-bucket
S3_FORCE_PATH_STYLE=false

# Resend
RESEND_API_KEY=re_your_api_key
[email protected]

API Reference

Platform

interface IPlatform {
  db: IDatabase;
  cache: ICache;
  storage: IStorage;
  email: IEmail;
  queue: IQueue;

  healthCheck(): Promise<PlatformHealthStatus>;
  close(): Promise<void>;
}

Database

// Query builder
const users = await platform.db
  .from<User>('users')
  .where('active', '=', true)
  .orderBy('created_at', 'desc')
  .limit(10)
  .execute();

// Insert
await platform.db
  .from<User>('users')
  .insert({ name: 'John', email: '[email protected]' })
  .execute();

// Update
await platform.db
  .from<User>('users')
  .where('id', '=', '123')
  .update({ name: 'Jane' })
  .execute();

// Delete
await platform.db
  .from<User>('users')
  .where('id', '=', '123')
  .delete()
  .execute();

Cache

// Basic operations
await platform.cache.set('key', value, 3600); // TTL in seconds
const value = await platform.cache.get<User>('key');
await platform.cache.delete('key');

// Batch operations
const values = await platform.cache.mget(['key1', 'key2', 'key3']);
await platform.cache.mset([
  { key: 'a', value: 1 },
  { key: 'b', value: 2, ttl: 60 },
]);

// Increment/Decrement
const count = await platform.cache.incr('counter');

// Pattern delete
await platform.cache.deletePattern('user:*');

Storage

// Upload
const file = await platform.storage.upload('path/to/file.txt', buffer, {
  contentType: 'text/plain',
});

// Download
const data = await platform.storage.download('path/to/file.txt');

// Get signed URL
const url = await platform.storage.getSignedUrl('path/to/file.txt', 3600);

// Delete
await platform.storage.delete('path/to/file.txt');

// Check existence
const exists = await platform.storage.exists('path/to/file.txt');

Email

// Send email
const result = await platform.email.send({
  to: '[email protected]',
  from: '[email protected]',
  subject: 'Hello',
  text: 'Plain text body',
  html: '<h1>HTML body</h1>',
});

// Batch send
const results = await platform.email.sendBatch([
  { to: '[email protected]', subject: 'A', text: 'A' },
  { to: '[email protected]', subject: 'B', text: 'B' },
]);

Queue

// Add job
const job = await platform.queue.add('sendEmail', {
  userId: '123',
  template: 'welcome',
});

// Process jobs
platform.queue.process(async (job) => {
  console.log('Processing:', job.name, job.data);
  return { success: true };
});

// Get job status
const job = await platform.queue.getJob('job_id');

Health Checks

const health = await platform.healthCheck();

console.log(health);
// {
//   healthy: true,
//   services: {
//     database: true,
//     cache: true,
//     storage: true,
//     email: true,
//     queue: true,
//   },
//   timestamp: 1701234567890,
// }

Testing

Use memory adapters for fast, isolated tests:

import { createPlatform, MemoryDatabase, MemoryCache } from '@digilogiclabs/platform-core';

describe('MyService', () => {
  const platform = createPlatform(); // Uses memory adapters

  beforeEach(async () => {
    // Reset state between tests
    await platform.close();
  });

  it('should create user', async () => {
    const result = await platform.db
      .from('users')
      .insert({ name: 'Test' })
      .execute();

    expect(result.data).toHaveLength(1);
  });
});

Direct Adapter Usage

You can also use adapters directly:

import {
  MemoryDatabase,
  MemoryCache,
  SupabaseDatabase,
  UpstashCache,
  S3Storage,
  ResendEmail,
  ConsoleEmail,
} from '@digilogiclabs/platform-core';

// Create adapters directly
const db = new MemoryDatabase();
const cache = new MemoryCache();
const email = new ConsoleEmail(); // Logs to console

Migration from Direct Provider Usage

Before (Direct Supabase)

import { createClient } from '@supabase/supabase-js';

const supabase = createClient(url, key);
const { data } = await supabase.from('users').select('*').eq('active', true);

After (Platform Core)

import { createPlatformAsync } from '@digilogiclabs/platform-core';

const platform = await createPlatformAsync();
const result = await platform.db.from('users').where('active', '=', true).execute();

Enterprise Patterns

Middleware

Compose middleware for cross-cutting concerns:

import { createMiddlewareChain, createLoggingMiddleware, createMetricsMiddleware } from '@digilogiclabs/platform-core';

const chain = createMiddlewareChain()
  .use(createLoggingMiddleware(logger))
  .use(createMetricsMiddleware(metrics))
  .use({
    name: 'custom',
    before: (ctx) => console.log('Before:', ctx.operation),
    after: (ctx) => console.log('After:', ctx.operation, ctx.duration + 'ms'),
    onError: (ctx, error) => console.error('Error:', error),
  });

// Execute with middleware
const result = await chain.execute(
  { service: 'database', operation: 'query', args: { table: 'users' }, logger, startTime: Date.now(), correlationId: 'abc' },
  async () => db.from('users').execute()
);

Hooks

Register lifecycle hooks for platform events:

import { createHookRegistry } from '@digilogiclabs/platform-core';

const hooks = createHookRegistry(logger);

hooks.register({
  onReady: () => console.log('Platform ready'),
  onShutdown: () => console.log('Shutting down'),
  beforeQuery: ({ table, operation }) => console.log(`Query: ${operation} on ${table}`),
  afterQuery: ({ table, duration }) => console.log(`Query completed in ${duration}ms`),
  onCacheHit: (key, value) => console.log(`Cache hit: ${key}`),
  onCacheMiss: (key) => console.log(`Cache miss: ${key}`),
  onError: ({ service, operation, error }) => console.error(`Error in ${service}.${operation}:`, error),
});

// Execute hooks
await hooks.execute('onReady');
await hooks.execute('beforeQuery', { table: 'users', operation: 'select' });

Resilience Patterns

Retry with Exponential Backoff

import { withRetry, RetryConfigs, RetryPredicates } from '@digilogiclabs/platform-core';

const result = await withRetry(
  () => fetchData(),
  {
    maxAttempts: 3,
    baseDelay: 100,
    maxDelay: 5000,
    backoffMultiplier: 2,
    shouldRetry: RetryPredicates.networkErrors,
  }
);

// Or use presets
const result = await withRetry(() => fetchData(), RetryConfigs.standard);

Circuit Breaker

import { CircuitBreaker, CircuitBreakerRegistry } from '@digilogiclabs/platform-core';

const breaker = new CircuitBreaker({
  failureThreshold: 5,
  resetTimeout: 30000,
  halfOpenRequests: 3,
});

const result = await breaker.execute(() => externalApiCall());

// Or use a registry for named breakers
const registry = new CircuitBreakerRegistry();
const apiBreaker = registry.get('external-api');

Timeout

import { withTimeout, TimeoutError } from '@digilogiclabs/platform-core';

try {
  const result = await withTimeout(() => slowOperation(), 5000);
} catch (error) {
  if (error instanceof TimeoutError) {
    console.log('Operation timed out');
  }
}

Bulkhead (Concurrency Isolation)

import { Bulkhead } from '@digilogiclabs/platform-core';

const bulkhead = new Bulkhead({
  maxConcurrent: 10,
  maxQueued: 100,
  timeout: 30000,
});

const result = await bulkhead.execute(() => cpuIntensiveTask());

Fallback

import { withFallback, FallbackStrategies } from '@digilogiclabs/platform-core';

// Static fallback
const result = await withFallback(
  () => fetchFromApi(),
  FallbackStrategies.value({ cached: true, data: [] })
);

// Dynamic fallback
const result = await withFallback(
  () => fetchFromPrimary(),
  FallbackStrategies.execute(() => fetchFromSecondary())
);

Metrics

Track application metrics with a provider-agnostic interface:

import { MemoryMetrics, createScopedMetrics } from '@digilogiclabs/platform-core';

const metrics = new MemoryMetrics();

// Counter
metrics.increment('api.requests', 1, { method: 'GET', path: '/users' });
metrics.decrement('active.connections');

// Gauge
metrics.gauge('queue.size', 42, { queue: 'emails' });

// Histogram
metrics.histogram('response.size', 1024, { endpoint: '/api/users' });

// Timer
const stopTimer = metrics.startTimer('api.request.duration', { method: 'POST' });
// ... do work ...
stopTimer(); // Records duration

// Timing
metrics.timing('db.query.duration', 42, { table: 'users' });

// Scoped metrics with prefix
const dbMetrics = createScopedMetrics(metrics, 'database', { service: 'users' });
dbMetrics.timing('query', 50); // Records as 'database.query' with service=users tag

// Get summary (for testing)
const summary = metrics.getSummary();
console.log(summary.counters, summary.timings);

Local Development

Start the development infrastructure:

# Start core services (PostgreSQL, Redis, MinIO, MailHog)
./infrastructure/scripts/dev.sh start

# Start with observability (adds Prometheus, Grafana)
./infrastructure/scripts/dev.sh start:obs

# Start with dev tools (adds PgAdmin, RedisInsight)
./infrastructure/scripts/dev.sh start:tools

# Check service health
./infrastructure/scripts/dev.sh health

# Connect to databases
./infrastructure/scripts/dev.sh psql
./infrastructure/scripts/dev.sh redis-cli

Service URLs:

  • PostgreSQL: localhost:5432 (user: dll, pass: development)
  • Redis: localhost:6379 (pass: development)
  • MinIO: localhost:9000 (console: 9001)
  • MailHog: localhost:8025 (SMTP: 1025)
  • Prometheus: localhost:9090 (with observability profile)
  • Grafana: localhost:3001 (with observability profile)

License

MIT