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

@npmtapi/tapi-lib-flow-orchestrator-dynamo-db

v1.0.3

Published

A library to manage DYnamoDB for flow orchestrator

Readme

Guía de Uso - tapi-lib-flow-orchestrator-dynamo-db

Descripción

tapi-lib-flow-orchestrator-dynamo-db es una librería de Node.js que proporciona una interfaz simplificada para interactuar con Amazon DynamoDB. Está diseñada específicamente para el orquestador de flujos de TAPI, ofreciendo métodos convenientes para operaciones CRUD y consultas avanzadas.

Instalación

npm install @npmtapi/tapi-lib-flow-orchestrator-dynamo-db

Configuración

Variables de Entorno

La librería utiliza el paquete config para la configuración. Necesitas configurar las siguientes variables:

// config/default.js
module.exports = {
  stateMachine: {
    dynamoService: {
      dynamoTableName: 'tu-tabla-dynamodb',
      dynamoEndpoint: 'http://localhost:8000' // Solo para desarrollo local
    }
  },
  env: 'development', // o 'production', 'test'
  region: 'us-east-1' // o tu región de AWS
};

Configuración de AWS

Asegúrate de tener configuradas tus credenciales de AWS:

export AWS_ACCESS_KEY_ID=tu-access-key
export AWS_SECRET_ACCESS_KEY=tu-secret-key
export AWS_REGION=us-east-1

Uso Básico

Importar la librería

import { dynamoModel } from '@npmtapi/tapi-lib-flow-orchestrator-dynamo-db';

// Obtener instancia del modelo
const model = await dynamoModel();

Operaciones CRUD

1. Crear un Item

// Crear un item simple
const newItem = await model.create({
  id: 'user-123',
  name: 'Juan Pérez',
  email: '[email protected]',
  createdAt: new Date().toISOString()
});

// Crear con opciones
const newItemWithOptions = await model.create({
  id: 'user-124',
  name: 'María García'
}, {
  removeUndefinedValues: true // Elimina valores undefined
});

2. Crear Item Solo Si No Existe

try {
  const result = await model.createIfNotExists({
    id: 'user-123',
    name: 'Juan Pérez',
    email: '[email protected]'
  }, 'id'); // Verifica que 'id' no exista
  
  console.log('Item creado exitosamente');
} catch (error) {
  if (error.name === 'ConditionalCheckFailedException') {
    console.log('El item ya existe');
  }
}

3. Buscar un Item

// Buscar por clave primaria simple
const item = await model.findOne({
  key: { id: 'user-123' }
});

// Buscar por clave compuesta
const item = await model.findOne({
  key: { 
    PK: 'user-123', 
    SK: 'profile' 
  }
});

if (item) {
  console.log('Item encontrado:', item);
} else {
  console.log('Item no encontrado');
}

4. Actualizar un Item

// Actualizar atributos específicos
const updatedItem = await model.update(
  { 
    name: 'Juan Carlos Pérez',
    status: 'active',
    updatedAt: new Date().toISOString()
  },
  { id: 'user-123' } // Clave para identificar el item
);

console.log('Item actualizado:', updatedItem);

5. Eliminar un Item

// Eliminar por clave primaria
const result = await model.delete({
  Key: { id: 'user-123' }
});

// Eliminar por clave compuesta
const result = await model.delete({
  Key: { 
    PK: 'user-123', 
    SK: 'profile' 
  }
});

Consultas Avanzadas

1. Buscar Todos los Items (Scan)

// Buscar todos los items
const { items } = await model.findAll({});

// Buscar con filtro
const { items } = await model.findAll({
  filterExpression: 'status = :status',
  expressionAttributeValues: {
    ':status': 'active'
  }
});

// Buscar con límite
const { items } = await model.findAll({
  limit: 10
});

// Buscar todos ignorando límites por defecto
const { items } = await model.findAll({
  skipIterationsLimit: true
});

2. Consultas por Partition Key (Query)

// Consulta básica por partition key
const { items } = await model.queryAll({
  keyConditionExpression: 'PK = :pk',
  expressionAttributeValues: {
    ':pk': 'user-123'
  }
});

// Consulta con filtro adicional
const { items } = await model.queryAll({
  keyConditionExpression: 'PK = :pk',
  expressionAttributeValues: {
    ':pk': 'user-123'
  },
  filterExpression: 'status = :status',
  expressionAttributeValues: {
    ':pk': 'user-123',
    ':status': 'active'
  }
});

// Consulta con ordenamiento descendente
const { items } = await model.queryAll({
  keyConditionExpression: 'PK = :pk',
  expressionAttributeValues: {
    ':pk': 'user-123'
  },
  scanIndexForward: false, // Orden descendente
  limit: 5
});

3. Consultas con Índices Secundarios

// Consulta usando Global Secondary Index (GSI)
const { items } = await model.queryAll({
  keyConditionExpression: 'GSI1PK = :pk',
  expressionAttributeValues: {
    ':pk': 'email-index'
  },
  indexKey: 'GSI1' // Nombre del índice
});

// Consulta usando Local Secondary Index (LSI)
const { items } = await model.queryAll({
  keyConditionExpression: 'PK = :pk AND LSI1SK = :sk',
  expressionAttributeValues: {
    ':pk': 'user-123',
    ':sk': 'profile'
  },
  indexKey: 'LSI1'
});

4. Obtener el Primer y Último Item

// Obtener el item más reciente
const lastItem = await model.queryLast({
  keyConditionExpression: 'PK = :pk',
  expressionAttributeValues: {
    ':pk': 'chat-session-123'
  }
});

// Obtener el item más antiguo
const firstItem = await model.queryFirst({
  keyConditionExpression: 'PK = :pk',
  expressionAttributeValues: {
    ':pk': 'chat-session-123'
  }
});

Operaciones en Lote

Crear Múltiples Items

const itemsToCreate = [
  { id: 'user-1', name: 'Juan', email: '[email protected]' },
  { id: 'user-2', name: 'María', email: '[email protected]' },
  { id: 'user-3', name: 'Carlos', email: '[email protected]' },
  // ... más items
];

const results = await model.bulkCreate({
  rows: itemsToCreate,
  chunkSize: 25 // Máximo 25 items por lote (límite de DynamoDB)
});

// Verificar resultados
results.forEach((result, index) => {
  if (result.status === 'fulfilled') {
    console.log(`Lote ${index + 1} procesado exitosamente`);
  } else {
    console.log(`Error en lote ${index + 1}:`, result.reason);
  }
});

Manejo de Errores

Errores Personalizados

import { BulkUnprocessedItems } from '@npmtapi/tapi-lib-flow-orchestrator-dynamo-db';

try {
  const result = await model.create({
    // ... datos
  });
} catch (error) {
  if (error.code === 'MissingRequiredParameter') {
    console.log('Falta un parámetro requerido');
  } else if (error instanceof BulkUnprocessedItems) {
    console.log('Algunos items no pudieron ser procesados:', error.processedItemsCount);
  } else {
    console.log('Error de DynamoDB:', error.message);
  }
}

Errores Comunes

  • MissingRequiredParameter: Se lanza cuando no se proporcionan parámetros requeridos
  • ConditionalCheckFailedException: Se lanza cuando createIfNotExists falla porque el item ya existe
  • BulkUnprocessedItems: Se lanza cuando algunos items en operaciones en lote no pudieron ser procesados

Ejemplos de Casos de Uso

1. Sistema de Usuarios

// Crear usuario
const user = await model.create({
  PK: 'USER#123',
  SK: 'PROFILE',
  name: 'Juan Pérez',
  email: '[email protected]',
  status: 'active',
  createdAt: new Date().toISOString()
});

// Buscar usuario
const user = await model.findOne({
  key: { 
    PK: 'USER#123', 
    SK: 'PROFILE' 
  }
});

// Actualizar estado del usuario
const updatedUser = await model.update(
  { status: 'inactive' },
  { PK: 'USER#123', SK: 'PROFILE' }
);

2. Sistema de Mensajes

// Crear mensaje
const message = await model.create({
  PK: 'CHAT#123',
  SK: `MSG#${Date.now()}`,
  content: 'Hola, ¿cómo estás?',
  sender: 'user-456',
  timestamp: new Date().toISOString()
});

// Obtener últimos 10 mensajes del chat
const { items } = await model.queryAll({
  keyConditionExpression: 'PK = :pk',
  expressionAttributeValues: {
    ':pk': 'CHAT#123'
  },
  scanIndexForward: false, // Orden descendente
  limit: 10
});

// Obtener el mensaje más reciente
const lastMessage = await model.queryLast({
  keyConditionExpression: 'PK = :pk',
  expressionAttributeValues: {
    ':pk': 'CHAT#123'
  }
});

3. Sistema de Notificaciones

// Crear notificación
const notification = await model.create({
  PK: 'USER#123',
  SK: `NOTIF#${Date.now()}`,
  type: 'email',
  subject: 'Bienvenido',
  content: 'Gracias por registrarte',
  read: false,
  createdAt: new Date().toISOString()
});

// Buscar notificaciones no leídas
const { items } = await model.queryAll({
  keyConditionExpression: 'PK = :pk',
  expressionAttributeValues: {
    ':pk': 'USER#123'
  },
  filterExpression: 'read = :read',
  expressionAttributeValues: {
    ':pk': 'USER#123',
    ':read': false
  }
});

Configuración para Desarrollo Local

Para desarrollo local, puedes usar DynamoDB Local:

// config/development.js
module.exports = {
  stateMachine: {
    dynamoService: {
      dynamoTableName: 'local-table',
      dynamoEndpoint: 'http://localhost:8000'
    }
  },
  env: 'development',
  region: 'us-east-1'
};

Y ejecutar DynamoDB Local con Docker:

docker run -p 8000:8000 amazon/dynamodb-local

Mejores Prácticas

  1. Usar claves compuestas: Utiliza patrones como PK#123 y SK#PROFILE para mejor organización
  2. Índices apropiados: Crea GSI/LSI según tus patrones de consulta
  3. Manejo de errores: Siempre maneja las excepciones apropiadamente
  4. Operaciones en lote: Usa bulkCreate para insertar múltiples items
  5. Filtros eficientes: Usa queryAll en lugar de findAll cuando sea posible

Limitaciones

  • Máximo 25 items por operación en lote (límite de DynamoDB)
  • Las consultas findAll pueden ser costosas para tablas grandes
  • Los índices secundarios tienen limitaciones de tamaño y rendimiento

Soporte

Para soporte técnico o reportar problemas, contacta al equipo de TAPI.