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

@rodrigopsasaki/vision-typeorm

v0.5.0

Published

TypeORM integration for seamless Vision database operation observability

Readme

@rodrigopsasaki/vision-typeorm

TypeORM integration for seamless Vision database operation observability.

Overview

Vision TypeORM provides comprehensive, zero-configuration observability for your TypeORM database operations. It automatically instruments DataSources, Repositories, EntityManagers, and transactions to give you structured insights into your database layer.

Features

  • 🚀 Zero Configuration: Works out of the box with sensible defaults
  • 🔒 Security First: Automatic sensitive data redaction
  • Performance Optimized: Minimal overhead with selective instrumentation
  • 🏗️ Comprehensive Coverage: DataSource, Repository, EntityManager, QueryRunner, and Transaction instrumentation
  • 🎯 Decorator Support: Advanced instrumentation with decorators
  • 🔍 Rich Context: Detailed operation metadata, timing, and error information
  • 🌐 Microservice Ready: Correlation ID support for distributed tracing

Installation

npm install @rodrigopsasaki/vision-typeorm

Peer Dependencies:

  • @rodrigopsasaki/vision: ^0.3.0
  • typeorm: ^0.3.0

Quick Start

import { DataSource } from "typeorm";
import { vision } from "@rodrigopsasaki/vision";
import { instrumentDataSource } from "@rodrigopsasaki/vision-typeorm";

// 1. Initialize your DataSource as usual
const dataSource = new DataSource({
  type: "postgres",
  host: "localhost",
  port: 5432,
  username: "user",
  password: "password",
  database: "myapp",
  entities: [User, Post],
  synchronize: true,
});

await dataSource.initialize();

// 2. Instrument with Vision (zero configuration!)
const instrumentedDataSource = instrumentDataSource(dataSource);

// 3. Use normally - all operations are automatically observed
await vision.observe("user.create", async () => {
  const userRepository = instrumentedDataSource.getRepository(User);

  const user = await userRepository.save({
    name: "John Doe",
    email: "[email protected]",
  });

  vision.set("user_id", user.id);
  return user;
});

Output:

{
  "name": "user.create",
  "timestamp": "2025-01-15T10:30:00.000Z",
  "data": {
    "user_id": 1
  }
}

{
  "name": "db.user.save",
  "data": {
    "database.operation": "save",
    "database.target": "typeorm",
    "database.entity": "User",
    "database.success": true,
    "database.duration_ms": 15
  }
}

Core API

instrumentDataSource(dataSource, config?)

Instruments a TypeORM DataSource with Vision observability.

import { instrumentDataSource } from "@rodrigopsasaki/vision-typeorm";

const instrumentedDataSource = instrumentDataSource(dataSource, {
  enabled: true,
  logParams: false,
  logQuery: true,
  logResultCount: true,
  redactFields: ["password", "token", "secret"],
});

instrumentRepository(repository, config?)

Instruments a specific Repository instance.

import { instrumentRepository } from "@rodrigopsasaki/vision-typeorm";

const userRepository = dataSource.getRepository(User);
const instrumentedRepository = instrumentRepository(userRepository);

visionTransaction(dataSourceOrManager, transactionFn, config?)

Enhanced transaction wrapper with observability.

import { visionTransaction } from "@rodrigopsasaki/vision-typeorm";

const result = await visionTransaction(dataSource, async (manager) => {
  const userRepository = manager.getRepository(User);
  const user = await userRepository.save(userData);

  const postRepository = manager.getRepository(Post);
  const post = await postRepository.save({ ...postData, userId: user.id });

  return { user, post };
});

Configuration Options

interface VisionTypeOrmConfig {
  // Core settings
  enabled?: boolean; // Default: true

  // Logging control
  logParams?: boolean; // Default: false (security)
  logQuery?: boolean; // Default: true
  logResultCount?: boolean; // Default: true
  logConnectionInfo?: boolean; // Default: false

  // Performance settings
  maxQueryLength?: number; // Default: 1000

  // Operation naming
  includeEntityInName?: boolean; // Default: true
  operationPrefix?: string; // Default: "db"

  // Security
  redactFields?: string[]; // Default: ["password", "token", "secret", "key", "hash"]

  // Selective instrumentation
  instrumentTransactions?: boolean; // Default: true
  instrumentRepositories?: boolean; // Default: true
  instrumentEntityManager?: boolean; // Default: true
}

Advanced Usage

Decorator-Based Instrumentation

import { VisionInstrumented, VisionObserve, VisionParam } from "@rodrigopsasaki/vision-typeorm";

@VisionInstrumented({ logParams: true })
class UserService {
  constructor(private dataSource: DataSource) {}

  @VisionObserve()
  async createUser(@VisionParam("userData") userData: CreateUserDto) {
    const userRepository = this.dataSource.getRepository(User);
    return await userRepository.save(userData);
  }

  async findUserByEmail(email: string) {
    // This method is automatically instrumented by @VisionInstrumented
    const userRepository = this.dataSource.getRepository(User);
    return await userRepository.findOne({ where: { email } });
  }
}

Transaction with Isolation Level

import { visionTransactionWithIsolation } from "@rodrigopsasaki/vision-typeorm";

await visionTransactionWithIsolation(dataSource, "SERIALIZABLE", async (manager) => {
  // Critical operations requiring serializable isolation
  const account = await manager.getRepository(Account).findOne({
    where: { id: accountId },
    lock: { mode: "pessimistic_write" },
  });

  account.balance -= withdrawAmount;
  await manager.getRepository(Account).save(account);

  return account;
});

Manual QueryRunner Management

import { visionQueryRunner } from "@rodrigopsasaki/vision-typeorm";

await visionQueryRunner(dataSource, async (queryRunner) => {
  await queryRunner.connect();
  await queryRunner.startTransaction();

  try {
    const result = await queryRunner.query(
      "INSERT INTO users (name, email) VALUES ($1, $2) RETURNING id",
      ["John Doe", "[email protected]"],
    );

    await queryRunner.commitTransaction();
    return result;
  } catch (error) {
    await queryRunner.rollbackTransaction();
    throw error;
  }
});

Security Features

Automatic Data Redaction

Sensitive fields are automatically redacted from logs:

const config = {
  logParams: true,
  redactFields: ["password", "token", "creditCard", "ssn"],
};

// Input: { name: "John", password: "secret123", email: "[email protected]" }
// Logged: { name: "John", password: "[REDACTED]", email: "[email protected]" }

Query Truncation

Long queries are automatically truncated to prevent log bloat:

const config = {
  maxQueryLength: 200, // Queries longer than 200 chars are truncated
};

Performance Optimization

Production Configuration

const productionConfig = {
  enabled: true,
  logParams: false, // Disable to reduce serialization overhead
  logQuery: false, // Disable in high-frequency scenarios
  logResultCount: true, // Keep for business metrics
  maxQueryLength: 200, // Shorter truncation
  logConnectionInfo: false, // Static information
  instrumentEntityManager: false, // If not using directly
};

Selective Instrumentation

// Only instrument specific components
const config = {
  instrumentRepositories: true,
  instrumentEntityManager: false, // Disable if not used
  instrumentTransactions: true,
};

Error Handling

Vision TypeORM automatically captures and structures database errors:

{
  "name": "db.user.save",
  "data": {
    "database.operation": "save",
    "database.success": false,
    "database.error": "duplicate key value violates unique constraint",
    "database.error_details": {
      "code": "23505",
      "constraint": "users_email_unique",
      "table": "users",
      "column": "email"
    },
    "database.duration_ms": 25
  }
}

Microservice Integration

For distributed systems, use correlation IDs to trace operations across services:

class CorrelationMiddleware {
  static withCorrelationId<T>(id: string, fn: () => Promise<T>): Promise<T> {
    return vision.observe("service.operation", async () => {
      vision.set("correlation_id", id);
      vision.set("service", "user-service");
      return fn();
    });
  }
}

// Usage
await CorrelationMiddleware.withCorrelationId("req_123", async () => {
  const user = await userService.createUser(userData);
  const profile = await profileService.createProfile(user.id);
  return { user, profile };
});

Examples

See the examples/ directory for comprehensive examples:

Integration with Vision Exporters

Vision TypeORM works seamlessly with all Vision exporters:

import { vision } from "@rodrigopsasaki/vision";

vision.init({
  exporters: [
    {
      name: "datadog",
      success: (ctx) => {
        // Send to Datadog APM
        sendToDatadog(ctx);
      },
      error: (ctx, err) => {
        // Send errors to error tracking
        sendErrorToDatadog(ctx, err);
      },
    },
  ],
});

TypeScript Support

Full TypeScript support with enhanced types:

import type {
  VisionDataSource,
  VisionRepository,
  VisionTypeOrmConfig,
} from "@rodrigopsasaki/vision-typeorm";

// Enhanced types provide full IntelliSense support
const repository: VisionRepository<User> = instrumentRepository(userRepository);

Best Practices

  1. Start Simple: Begin with default configuration and customize as needed
  2. Security First: Always configure redactFields for sensitive data
  3. Performance Aware: Disable parameter/query logging in high-frequency operations
  4. Correlation IDs: Implement request tracing for distributed systems
  5. Error Context: Let Vision capture errors while implementing proper business error handling
  6. Selective Instrumentation: Only instrument what you need in performance-critical scenarios

Troubleshooting

Performance Impact

  • Disable logParams and logQuery for high-frequency operations
  • Use shorter maxQueryLength values
  • Consider selective instrumentation

Memory Usage

  • Set appropriate maxQueryLength limits
  • Disable unused instrumentation features

TypeScript Issues

  • Ensure TypeORM peer dependency version compatibility
  • Use proper type imports from the package

Contributing

This is part of the Vision observability framework. For issues, feature requests, or contributions, please visit the main Vision repository.

License

MIT © Rodrigo Sasaki