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

@d2sutils/shopperv2

v1.4.3

Published

This is a simple utility service that provides a set of utility functions for the shopper service.

Downloads

430

Readme

Shopper Utils v2

Version License TypeScript

🇺🇦 Українська версія | 🇬🇧 English Version


🇬🇧 English Version

Description

Shopper Utils v2 is a utility service that provides a set of useful functions for working with the Shopper service. The library is written in TypeScript and includes various services for working with users, locations, caching, and other functionality.

Key Features

  • 👥 User Management - working with users, clients, shoppers, and groups
  • 📍 Locations - retrieving location and location group information
  • 💾 Caching - Redis integration for fast data access
  • 📧 Notifications - sending messages and notifications
  • 🔧 Formatting - utilities for data formatting
  • 📦 Archiving - working with ZIP archives
  • 📊 Logging - integrated logging system
  • 📚 References - powerful ReferenceManager for multilingual dictionaries

Installation

npm install @d2sutils/shopperv2

Quick Start

import { instanceAppV2, user, location, cache } from '@d2sutils/shopperv2';

// Initialize the application
instanceAppV2('your-proxy-url', 'your-secret-key', 'redis://localhost:6379', true);

// Working with users
const users = await user.users({ filter: {}, limit: 10 });
const isClient = await user.isClient(123);
const userName = await user.getNameById(123);

// Working with locations
const locations = await location.all({ filter: {}, limit: 25 });
const groups = await location.groups({ filter: {}, limit: 25 });

// Working with cache
await cache.set('key', 'value', 3600);
const value = await cache.get('key');

// Working with references
import { ReferenceManager } from '@d2sutils/shopperv2';
await ReferenceManager.setReference('countries', countriesData);
const countryName = await ReferenceManager.getNameById('countries', 1, 'en');

API Documentation

User Service

// Get all users
await user.users({ filter: {}, limit: 25 });

// Get clients
await user.clients({ filter: {}, limit: 25 });

// Get shoppers
await user.shoppers({ filter: {}, limit: 25 });

// Check if user is a client
await user.isClient(userId: number | number[]);

// Check if user is a manager
await user.isManager(userId: number | number[]);

// Get user by ID
await user.getById(id: number);

// Get current user
await user.me(token: string);

Location Service

// Get all locations
await location.all({ filter: {}, limit: 25, id?: number });

// Get location groups
await location.groups({ filter: {}, parent_id?: number, limit: 25 });

Cache Service

// Set value in cache
await cache.set(key: string, value: string, ttl?: number);

// Get value from cache
await cache.get(key: string);

// Check if key exists
await cache.has(key: string);

// Delete key
await cache.del(key: string);

// Clear service cache
await cache.clearService(service: string);

// Clear all cache
await cache.flushAll();

Notification Service

// Send notification
await notification.send({
    action: 'email', // action type
    user_id: '123', // user ID
    contact: '[email protected]', // contact
    communication_id: 'comm_123', // communication ID
    communication_name: 'Welcome Email', // communication name
    subject: 'Welcome!', // subject
    message: 'Thank you for registration', // message
    params: { name: 'John' }, // additional parameters
    header: { 'X-Custom': 'value' } // additional headers
});

Format Service

// Apply filter to model
const filteredModel = format.applyFilter({
    model: MyModel,
    filter: { name: 'John', age: 25 },
    config: {
        like: ['name'], // fields for LIKE search
        like_number: ['age'], // numeric fields for LIKE
        in: ['status'], // fields for IN search
        custom: {
            customField: (value) => `custom_${value}`
        }
    }
});

// Format request body
const formattedBody = format.body({
    name: 'John',
    active: 'true', // will be converted to boolean
    data: '{"key": "value"}', // will be parsed as JSON
    items: ['item1', 'item2']
});

Response Utils

// Create success response
const successResponse = responseUtils.success({
    data: { id: 1, name: 'John' },
    message: 'Operation completed successfully'
});

// Create error response
const errorResponse = responseUtils.error({
    message: 'Validation error',
    status: 400
});

// Create paginated response
const paginatedResponse = responseUtils.paginate({
    data: [{ id: 1 }, { id: 2 }],
    total: 100,
    limit: 10,
    page: 1,
    other: { customField: 'value' }
});

ZIP Utils

// Validate postal code for different countries
const isValidZip = validateZip('UA', '12345'); // true for Ukraine
const isValidZipDE = validateZip('DE', '12345'); // true for Germany
const isValidZipGB = validateZip('GB', 'SW1A1AA'); // true for United Kingdom

// Supported countries: AL, AD, AT, BY, BE, BA, BG, HR, CZ, CY, DK, EE, FI, FR, DE, GR, HU, IS, IE, IT, LV, LI, LT, LU, MK, MT, MD, MC, NL, NO, PL, PT, RO, RU, SM, RS, SK, SI, ES, SE, CH, TN, TR, UA, GB, VA

Action Logger

// Get singleton logger instance (uses shared Redis connection)
const logger = ActionLogger.getInstance();

// Log user actions
await logger.logUserAction({
    request_type: 'POST',
    url: '/api/users',
    user_id: 123,
    origin: 'https://example.com',
    referrer: 'https://google.com',
    payload: { name: 'John' },
    session_id: 'session_123',
    response: { success: true }
});

// Disconnect not needed - uses shared connection
// await logger.disconnect(); // no longer needed

ActionLogger Features:

  • ✅ Uses Singleton pattern
  • ✅ Uses shared Redis connection with Cache Service
  • ✅ Automatically initializes when calling getInstance()
  • ✅ No separate Redis configuration needed - uses settings from instanceAppV2

API Utils

// Execute GET request
const data = await api.get('user', 'users', { limit: 10 }, {
    useCache: true,
    cache_options: { ttl: 3600, name: 'users_cache' }
});

// Execute POST request
const result = await api.post('user', 'create', { name: 'John' }, {}, {
    headers: { 'Content-Type': 'application/json' }
});

// Execute PUT request
const updated = await api.put('user', 'update/123', { name: 'Jane' });

// Universal request
const response = await api.request('GET', 'location', 'all', {}, { limit: 25 });

Helper Utilities

// Free port (kill processes occupying it)
await ensurePortFree(3000, 5); // port 3000, 5 retries

// Generate color from string
const color = stringToColor('user123'); // generates hex color
const softColor = stringToColor('user123', true); // soft color

// Sleep execution
await sleep(1000); // pause for 1 second

// Normalize number to string
const normalized = normalNumber(123.456); // "123.46"
const normalizedInt = normalNumber(123); // "123"

// Remove undefined values from object
const cleaned = removeUndefinedDeep({
    name: 'John',
    age: undefined,
    data: { value: 'test', empty: undefined }
}); // { name: 'John', data: { value: 'test' } }

// Slice string with ellipsis
const short = strSlice('Long text for slicing', 10); // "Long text..."

// Filter by date
const items = [
    { name: 'Event 1', date_start: '2024-01-01', date_end: '2024-01-31' },
    { name: 'Event 2', date_start: '2024-02-01', date_end: '2024-02-28' }
];
const filtered = filterByDate(items, '2024-01-15'); // returns Event 1

ReferenceManager - Multilingual Dictionaries

// Create multilingual countries dictionary
const countries = [
    {
        id: 1,
        code: "UA",
        name_en: "Ukraine",
        name_ru: "Украина", 
        name_uk: "Україна"
    }
];
await ReferenceManager.setReference('countries', countries);

// Create dictionary with different field patterns
const regions = [
    {
        id: 3767,
        country: "UA",
        regionEn: "Khersonska Oblast",
        regionRu: "Херсонская область",
        regionUk: "Херсонська область"
    }
];
await ReferenceManager.setReference('regions', regions);

// Create regular users dictionary
const users = [
    {
        id: 1,
        name: "John Smith",
        email: "[email protected]",
        role: "admin"
    }
];
await ReferenceManager.setReference('users', users);

// Get data from multilingual dictionaries
const countryNameEn = await ReferenceManager.getNameById('countries', 1, 'en'); // "Ukraine"
const countryNameUk = await ReferenceManager.getNameById('countries', 1, 'uk'); // "Україна"

// Work with different field patterns (regionEn, regionUk)
const regionNameEn = await ReferenceManager.getLocalizedField('regions', 3767, 'en', 'region');
const regionNameUk = await ReferenceManager.getLocalizedField('regions', 3767, 'uk', 'region');

// Work with regular dictionaries
const userName = await ReferenceManager.getNameById('users', 1, 'name'); // "John Smith"
const userEmail = await ReferenceManager.getFieldById('users', 1, 'email'); // "[email protected]"

// Search in dictionaries
const searchResults = await ReferenceManager.search('countries', 'Ukraine', {
    field: 'name',
    language: 'en'
});

// Batch data retrieval
const countryNames = await ReferenceManager.getBatchNames('countries', [1, 2, 3], 'en');
const userItems = await ReferenceManager.getBatchItems('users', [1, 2]);

// Dictionary metadata
const isMultilingual = await ReferenceManager.isMultilingual('countries'); // true
const languages = await ReferenceManager.getAvailableLanguages('countries'); // ["en", "ru", "uk"]
const fields = await ReferenceManager.getAvailableFields('users'); // ["id", "name", "email", "role"]

// Dictionary management
const allReferences = await ReferenceManager.listReferences();
await ReferenceManager.updateItem('users', 1, { role: 'manager' });
await ReferenceManager.deleteItem('users', 1);
await ReferenceManager.deleteReference('old_reference');

Supported language field patterns:

  • name_en, name_ru, name_uk (underscore)
  • nameEn, nameRu, nameUk (camelCase)
  • regionEn, regionUk, titleEn (camelCase with prefix)
  • NameEn, RegionUk, TitleEn (PascalCase)

Main methods:

  • setReference() - create/update dictionary
  • getReference() - get entire dictionary
  • getById() - get item by ID
  • getNameById() - get name with automatic pattern recognition
  • getLocalizedField() - get language field
  • search() - search by text
  • getBatchNames() - batch name retrieval
  • isMultilingual() - check if multilingual

Configuration

The library supports the following configuration parameters:

  • proxy - proxy server URL
  • secret - secret key for authentication
  • redis_uri - Redis connection URI (optional)
  • debug - debug mode (optional)

Dependencies

  • Node.js 16+
  • Redis 7+ (for caching)
  • TypeScript 5.4+

Redis Architecture

The library uses a single Redis connection for all services:

  • Cache Service - singleton for data caching
  • ActionLogger - singleton, uses shared connection
  • API Utils - uses Cache Service for request caching
  • 🔧 Configured once through instanceAppV2()
  • 🚀 Optimized for performance and resources

🚀 Development

Building the project

npm run build

Development mode

npm run dev

Production mode

npm run prod

Testing

npm test

Publishing

npm run publish

📝 License

This project is licensed under the ISC License - see the LICENSE file for details.


Made with ❤️ by Dev2Studio


🇺🇦 Українська версія | 🇬🇧 English Version