@paulovila/shared

v1.0.1

Published

Foundation plugin providing shared types, utilities, and localization for all Vetra plugins

Readme

@vetra/shared

Foundation plugin providing shared types, utilities, and localization for all Vetra plugins.

Overview

@vetra/shared is the foundational plugin that all other Vetra plugins depend on. It provides:

  • Shared Types - Common interfaces and types for plugins
  • Localization Utilities - Multi-locale support (English/Spanish)
  • Validation Helpers - Common validation functions
  • Utility Functions - Deep merge, type guards, string/array/object utilities
  • Configuration Management - Environment and feature flag handling
  • Constants - Shared constants for all plugins

Installation

npm install @vetra/shared
# or
pnpm add @vetra/shared

Quick Start

Basic Usage

import { sharedPlugin } from '@vetra/shared'
import { buildConfig } from 'payload'

export default buildConfig({
  plugins: [
    sharedPlugin({
      enabled: true,
      debug: process.env.NODE_ENV === 'development',
    }),
  ],
})

Using Localization Utilities

import {
  getLocalizedValue,
  setLocalizedValue,
  getDocumentLocales,
} from '@vetra/shared'

// Get localized value with fallback
const title = getLocalizedValue(document, 'title', 'es', 'en')

// Set localized value
const updated = setLocalizedValue(document, 'title', 'Hola', 'es')

// Get all locales in document
const locales = getDocumentLocales(document)

Using Validation Helpers

import {
  isValidEmail,
  isValidUrl,
  isValidPhone,
  minLength,
  maxLength,
} from '@vetra/shared'

// Validate email
if (isValidEmail(email)) {
  // Valid email
}

// Validate length
if (minLength(password, 8) && maxLength(password, 128)) {
  // Valid password length
}

Using Utility Functions

import {
  deepMerge,
  toKebabCase,
  removeDuplicates,
  getNestedValue,
} from '@vetra/shared'

// Deep merge objects
const merged = deepMerge(target, source)

// Convert to kebab-case
const slug = toKebabCase('HelloWorld') // 'hello-world'

// Remove duplicates
const unique = removeDuplicates([1, 2, 2, 3, 3, 3]) // [1, 2, 3]

// Get nested value
const value = getNestedValue(obj, 'user.profile.name')

API Reference

Localization

getLocalizedValue(data, field, locale, fallbackLocale)

Get localized value with fallback support.

const title = getLocalizedValue(
  { title_en: 'Hello', title_es: 'Hola' },
  'title',
  'es',
  'en'
) // 'Hola'

setLocalizedValue(data, field, value, locale)

Set localized value for a specific locale.

const updated = setLocalizedValue(
  { title_en: 'Hello' },
  'title',
  'Hola',
  'es'
) // { title_en: 'Hello', title_es: 'Hola' }

getDocumentLocales(data)

Get all locales present in a document.

const locales = getDocumentLocales({
  title_en: 'Hello',
  title_es: 'Hola',
}) // ['en', 'es']

mergeLocalizedDocuments(target, source, preserveFields)

Merge localized documents with custom field preservation.

const merged = mergeLocalizedDocuments(
  { id: '1', title_en: 'Hello' },
  { title_es: 'Hola' },
  ['id']
)

translate(translations, key, locale, defaultValue)

Translate a key using a translation object.

const translations = {
  en: { greeting: 'Hello' },
  es: { greeting: 'Hola' },
}

const greeting = translate(translations, 'greeting', 'es')
// 'Hola'

formatLocalizedDate(date, locale, options)

Format a date for a specific locale.

const formatted = formatLocalizedDate(
  new Date(),
  'es',
  { year: 'numeric', month: 'long', day: 'numeric' }
)

formatLocalizedCurrency(amount, currency, locale)

Format currency for a specific locale.

const formatted = formatLocalizedCurrency(1234.56, 'USD', 'en')
// '$1,234.56'

Validation

isValidEmail(email)

Validate email address.

isValidEmail('[email protected]') // true
isValidEmail('invalid.email') // false

isValidUrl(url)

Validate URL.

isValidUrl('https://example.com') // true
isValidUrl('not a url') // false

isValidPhone(phone)

Validate phone number.

isValidPhone('+1-234-567-8900') // true
isValidPhone('123') // false

isValidUUID(uuid)

Validate UUID.

isValidUUID('550e8400-e29b-41d4-a716-446655440000') // true

isValidSlug(slug)

Validate slug format.

isValidSlug('valid-slug') // true
isValidSlug('Invalid Slug') // false

minLength(value, min) / maxLength(value, max)

Validate string or array length.

minLength('hello', 3) // true
maxLength('hello', 10) // true

minValue(value, min) / maxValue(value, max)

Validate numeric value.

minValue(10, 5) // true
maxValue(5, 10) // true

Utilities

deepMerge(target, source)

Deep merge two objects.

const merged = deepMerge(
  { a: 1, b: { c: 2 } },
  { b: { d: 3 }, e: 4 }
)
// { a: 1, b: { c: 2, d: 3 }, e: 4 }

toKebabCase(str) / toCamelCase(str) / toPascalCase(str) / toSnakeCase(str)

Convert string case.

toKebabCase('helloWorld') // 'hello-world'
toCamelCase('hello-world') // 'helloWorld'
toPascalCase('hello-world') // 'HelloWorld'
toSnakeCase('helloWorld') // 'hello_world'

removeDuplicates(array, key)

Remove duplicates from array.

removeDuplicates([1, 2, 2, 3, 3, 3]) // [1, 2, 3]

// With key function
removeDuplicates(
  [{ id: 1 }, { id: 2 }, { id: 1 }],
  (item) => item.id
) // [{ id: 1 }, { id: 2 }]

flatten(array, depth)

Flatten nested array.

flatten([1, [2, 3], [4, [5, 6]]]) // [1, 2, 3, 4, 5, 6]
flatten([1, [2, [3, 4]]], 1) // [1, 2, [3, 4]]

groupBy(array, key)

Group array items by key.

groupBy(
  [
    { type: 'a', value: 1 },
    { type: 'b', value: 2 },
    { type: 'a', value: 3 },
  ],
  (item) => item.type
)
// { a: [{ type: 'a', value: 1 }, { type: 'a', value: 3 }], b: [...] }

sortBy(array, key, order)

Sort array by key.

sortBy(
  [{ value: 3 }, { value: 1 }, { value: 2 }],
  (item) => item.value,
  'asc'
) // [{ value: 1 }, { value: 2 }, { value: 3 }]

getNestedValue(obj, path, defaultValue)

Get nested value from object.

getNestedValue(
  { user: { profile: { name: 'John' } } },
  'user.profile.name'
) // 'John'

setNestedValue(obj, path, value)

Set nested value in object.

const obj = {}
setNestedValue(obj, 'user.profile.name', 'John')
// { user: { profile: { name: 'John' } } }

pick(obj, keys) / omit(obj, keys)

Pick or omit specific keys from object.

pick({ a: 1, b: 2, c: 3 }, ['a', 'c']) // { a: 1, c: 3 }
omit({ a: 1, b: 2, c: 3 }, ['b']) // { a: 1, c: 3 }

Type Guards

import {
  isPlainObject,
  isArray,
  isString,
  isNumber,
  isBoolean,
  isNullOrUndefined,
  isEmpty,
  isDate,
  isFunction,
} from '@vetra/shared'

isPlainObject({}) // true
isArray([]) // true
isString('hello') // true
isNumber(123) // true
isBoolean(true) // true
isNullOrUndefined(null) // true
isEmpty('') // true
isDate(new Date()) // true
isFunction(() => {}) // true

Configuration

getEnvironmentConfig()

Get environment configuration.

const config = getEnvironmentConfig()
// { nodeEnv: 'development', isDevelopment: true, ... }

getFeatureFlags(prefix)

Get feature flags from environment variables.

const flags = getFeatureFlags('FEATURE_')
// { kyc_enabled: true, kyb_enabled: false, ... }

isFeatureEnabled(flags, name, defaultValue)

Check if feature flag is enabled.

isFeatureEnabled(flags, 'kyc_enabled', false) // true

getApiConfig() / getDatabaseConfig() / getCacheConfig()

Get configuration from environment variables.

const apiConfig = getApiConfig()
// { baseUrl: 'http://localhost:3000', timeout: 30000, ... }

Constants

Locales

import { SUPPORTED_LOCALES, DEFAULT_LOCALE } from '@vetra/shared'

SUPPORTED_LOCALES // ['en', 'es']
DEFAULT_LOCALE // 'en'

Workflow

import {
  WORKFLOW_STATUSES,
  BLOCK_TYPES,
  ENGINE_TYPES,
  PRIORITY_LEVELS,
} from '@vetra/shared'

WORKFLOW_STATUSES // { PENDING: 'pending', PROCESSING: 'processing', ... }
BLOCK_TYPES // { KYC: 'kyc', DOCUMENT_UPLOAD: 'document_upload', ... }
ENGINE_TYPES // { OCR: 'ocr', FACE_RECOGNITION: 'face_recognition', ... }
PRIORITY_LEVELS // { LOW: 'low', MEDIUM: 'medium', HIGH: 'high', CRITICAL: 'critical' }

Error Codes

import { ERROR_CODES } from '@vetra/shared'

ERROR_CODES // { LOCALE_NOT_SUPPORTED: 'LOCALE_NOT_SUPPORTED', ... }

Types

Plugin Types

import type {
  BasePluginOptions,
  PluginConfig,
  ResolvedPluginConfig,
} from '@vetra/shared'

Localization Types

import type {
  LocalizedValue,
  LocalizedDocument,
  LocalizationOptions,
  LocaleContext,
} from '@vetra/shared'

Workflow Types

import type {
  WorkflowConfig,
  WorkflowTemplate,
  WorkflowInstance,
  BlockConfig,
  BlockInstance,
  BlockResult,
} from '@vetra/shared'

Error Types

import { VetraError } from '@vetra/shared'
import type { ErrorDetails } from '@vetra/shared'

throw new VetraError({
  code: 'VALIDATION_FAILED',
  message: 'Validation failed',
  statusCode: 400,
})

Testing

Run tests with coverage:

npm run test:coverage

Tests are located in tests/unit/ and tests/integration/.

Development

Building

npm run build

Type Checking

npm run type-check

Linting

npm run lint

Contributing

Contributions are welcome! Please ensure:

  • All tests pass
  • Code coverage remains >80%
  • TypeScript strict mode is satisfied
  • Code follows the project style guide

License

MIT

Support

For issues, questions, or contributions, please refer to the main Vetra3 repository.