@paulovila/shared
v1.0.1
Published
Foundation plugin providing shared types, utilities, and localization for all Vetra plugins
Maintainers
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/sharedQuick 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') // falseisValidUrl(url)
Validate URL.
isValidUrl('https://example.com') // true
isValidUrl('not a url') // falseisValidPhone(phone)
Validate phone number.
isValidPhone('+1-234-567-8900') // true
isValidPhone('123') // falseisValidUUID(uuid)
Validate UUID.
isValidUUID('550e8400-e29b-41d4-a716-446655440000') // trueisValidSlug(slug)
Validate slug format.
isValidSlug('valid-slug') // true
isValidSlug('Invalid Slug') // falseminLength(value, min) / maxLength(value, max)
Validate string or array length.
minLength('hello', 3) // true
maxLength('hello', 10) // trueminValue(value, min) / maxValue(value, max)
Validate numeric value.
minValue(10, 5) // true
maxValue(5, 10) // trueUtilities
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(() => {}) // trueConfiguration
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) // truegetApiConfig() / 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:coverageTests are located in tests/unit/ and tests/integration/.
Development
Building
npm run buildType Checking
npm run type-checkLinting
npm run lintContributing
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.