Hosted Components LogoHosted-Components

Utility Functions

Utility functions for the Hosted Components Service

Utility Functions

This page documents the various utility functions available in the library.

Tailwind Utilities

cn

A utility function that combines clsx and tailwind-merge for handling Tailwind CSS class names.

import { cn } from '@/lib/utils';

// Usage
cn('base-class', condition && 'conditional-class', 'another-class');

Format Utilities

Card Number Formatting

import { formatCardNumber, unformatCardNumber } from '@/lib/utils';

// Format card number with spaces every 4 digits
formatCardNumber('4111111111111111'); // "4111 1111 1111 1111"

// Remove spaces from card number
unformatCardNumber('4111 1111 1111 1111'); // "4111111111111111"

Expiry Date Formatting

import { formatExpiryDate, unformatExpiryDate } from '@/lib/utils';

// Format expiry date with slash
formatExpiryDate('1223'); // "12 / 23"

// Remove formatting from expiry date
unformatExpiryDate('12 / 23'); // "12/23"

CSS Class Validation

validateClasses

Validates CSS class configurations against predefined rules.

import { validateClasses } from '@/lib/utils';

const classes = {
	button: { 'background-color': 'blue' },
	'button:hover': { 'background-color': 'darkblue' },
};
const validatedClasses = validateClasses(classes);

convertToCssString

Converts validated class rules into a CSS string.

import { convertToCssString } from '@/lib/utils';

const cssString = convertToCssString(validatedClasses);

Font Family Handler

import { handleFontFamily } from '@/lib/utils';

handleFontFamily('Roboto', (fontFamily) => {
	// Handles loading Google Fonts and provides fallback
	console.log(fontFamily); // "'Roboto', Arial, Helvetica, sans-serif"
});

CSS Variables Validation

import { validateCSSVariables } from '@/lib/utils';

const variables = {
	'--primary-color': '#007bff',
	'--font-size': '16px',
};
const validatedVars = validateCSSVariables(variables);

Environment Utilities

Environment Class

A centralized environment utility that provides consistent environment handling across all components.

import { Environment } from '@/lib/utils/environment';

// Get current environment
const env = Environment.getCurrentEnvironment(); // 'production' | 'staging' | 'develop' | 'sandbox'

// Check if production
const isProduction = Environment.isProduction(); // boolean

// Check if local/development
const isLocal = Environment.isLocal(); // boolean

// Get DataDog-specific environment mapping
const ddEnv = Environment.getDatadogEnvironment(); // Maps production -> sydney, others remain same

Environment Mappings:

  • production → DataDog environment: sydney
  • staging → DataDog environment: staging
  • develop / development → DataDog environment: develop
  • sandbox → DataDog environment: sandbox
  • Default fallback: staging

devOnly

A utility function that redirects to the home page if the application is running in production mode.

import { devOnly } from '@/lib/utils';

// Usage in development-only routes
devOnly(); // Redirects to "/" if NODE_ENV is "production"

Token Utilities

validateJWTToken

Validates JWT tokens by checking their format and expiration.

import { validateJWTToken } from '@/lib/utils';

const isValid = validateJWTToken('your.jwt.token');

The function performs the following checks:

  • Verifies the token has three parts separated by dots
  • Validates base64url format for each part
  • Checks token expiration if present
  • Returns true if the token is valid, false otherwise

Server Actions

Server Actions are async functions that are executed on the server-side. These functions can be used in both client and server components, and are specifically designed for creating, updating, or deleting data. For more information, see Next.js Server Actions documentation.

createCardToken

A server action function for creating a payment method token for card payments.

import { createCardToken } from '@/lib/utils';

// Usage
const response = await createCardToken(token, {
	countryCode: 'US',
	accountNumber: '4111111111111111',
	expiryDate: '12/25',
	accountHolderName: 'John Doe',
	termAndConditionAgreed: true,
});

API Utilities

apiRequest

A type-safe utility function for making HTTP requests with built-in error handling, response formatting, and enhanced logging.

import { apiRequest } from '@/lib/utils';

// Example GET request
const response = await apiRequest({
	url: 'https://api.example.com/data',
	method: 'GET',
	token: 'your-auth-token', // Optional
});

// Example POST request with body
const response = await apiRequest({
	url: 'https://api.example.com/data',
	method: 'POST',
	token: 'your-auth-token',
	body: { key: 'value' },
});

// Type-safe response handling
interface UserData {
	id: string;
	name: string;
}

const response = await apiRequest<UserData>({
	url: 'https://api.example.com/user',
	method: 'GET',
});
// response.data will be typed as UserData | null

The function handles:

  • Automatic JSON parsing
  • Error handling with detailed error information
  • Authentication via Bearer token
  • Type-safe responses
  • Enhanced logging with structured DatadogLogger integration
  • Security: Automatic token masking in logs
  • Request/Response tracking for debugging and monitoring

Logging Utilities

DatadogLogger

The DatadogLogger utility provides structured logging with Datadog-compatible format, enhanced security features, and comprehensive tracking capabilities.

Core Features

  • 🔐 Token Masking: Automatically masks sensitive tokens in logs
  • 🎯 Context Management: Provides default contexts when none specified
  • 📊 Payment Stage Tracking: Tracks different stages of payment processing
  • 🌍 Environment Awareness: Adapts logging behavior based on environment
  • ⚡ Production Safety: Filters sensitive data in production environments

Basic Usage

import { DatadogLogger } from '@/lib/utils/datadog-logger';

// Simple info logging
DatadogLogger.info('Operation completed successfully');

// Info with additional data
DatadogLogger.info('Payment processed', {
	paymentId: 'payment-123',
	amount: 100.0,
	currency: 'USD',
});

// Warning logging
DatadogLogger.warn('Rate limit approaching', {
	currentRequests: 95,
	limit: 100,
	timeWindow: '1m',
});

// Error logging
DatadogLogger.error('Payment validation failed', error, {
	paymentId: 'payment-456',
	validationStep: 'card_number',
});

Enhanced Logging with Context and Token

// Enhanced logging with token masking and context
DatadogLogger.info(
	'Payment method created',
	{
		paymentMethodId: 'pm-123',
		paymentStage: 'payment_token_creation',
	},
	token, // Automatically masked in logs
	{
		countryCode: 'AU',
		merchantId: 'merchant-123',
		pageType: 'HPP 2.0',
	}
);

// Context defaults - if no context provided, defaults to 'payment_method_embed'
DatadogLogger.debug('Processing payment', { amount: 100 }, token);

Payment Stage Tracking

Track different stages of the payment process for better monitoring:

// Available payment stages
const paymentStages = {
	initialization: 'initialization',
	payment_method_selection: 'payment_method_selection',
	form_validation: 'form_validation',
	payment_token_creation: 'payment_token_creation',
	customer_linking: 'customer_linking',
	payment_token_creation_failed: 'payment_token_creation_failed',
};

// Usage
DatadogLogger.info(
	'Form validation passed',
	{
		paymentStage: 'form_validation',
		paymentMethodType: 'CARD',
	},
	token,
	context
);

Method Signatures

// All logging methods support enhanced parameters
static info(
	message: string,
	additionalData?: Record<string, unknown>,
	token?: string | null,
	context?: Record<string, unknown>
): void

static warn(
	message: string,
	additionalData?: Record<string, unknown>,
	token?: string | null,
	context?: Record<string, unknown>
): void

static error(
	message: string,
	error?: unknown,
	additionalData?: Record<string, unknown>,
	token?: string | null,
	context?: Record<string, unknown>
): void

static debug(
	message: string,
	additionalData?: Record<string, unknown>,
	token?: string | null,
	context?: Record<string, unknown>
): void

Specialized Logging Methods

// API request logging with automatic token masking
DatadogLogger.apiRequest(
	'Payment API called',
	{
		url: '/api/payments',
		method: 'POST',
		headers: { 'Content-Type': 'application/json' },
		body: { amount: 100 },
	},
	token,
	context
);

// API response logging
DatadogLogger.apiResponse(
	'Payment API response',
	{
		status: 200,
		data: { paymentId: 'payment-123' },
	},
	token,
	context
);

// Database operation logging
DatadogLogger.database(
	'User record created',
	{
		table: 'users',
		operation: 'INSERT',
		recordId: 'user-123',
	},
	token,
	context
);

// Sensitive data logging (dev/staging only)
DatadogLogger.logSensitiveData(
	'Payment details',
	{
		cardNumber: '4111111111111111',
		expiryDate: '12/25',
	},
	token,
	context
);

Token Masking

The logger automatically masks tokens for security:

// Token: "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c"
// Logged as: "eyJhbG************ssw5c"

// Short tokens are completely masked
// Token: "abc123"
// Logged as: "***masked***"

Environment-Specific Behavior

// Production environment
if (Environment.isProduction()) {
	// - Debug logs are filtered out
	// - Sensitive data is never logged
	// - API request/response bodies are sanitized
	// - Enhanced security measures
}

// Development/Staging environment
if (!Environment.isProduction()) {
	// - All log levels available
	// - Sensitive data can be logged with explicit methods
	// - Full request/response logging
	// - Enhanced debugging information
}

Common Patterns

// ✅ Correct usage patterns
DatadogLogger.info('User authenticated successfully', { userId: 'user-123' });
DatadogLogger.error('Authentication failed');
DatadogLogger.error('Database query failed', dbError);
DatadogLogger.error('API request failed', apiError, { endpoint: '/api/payments' });

// Enhanced logging with context and token
DatadogLogger.info('Payment processing started', { paymentStage: 'initialization' }, token, {
	merchantId: 'merchant-123',
	countryCode: 'AU',
});

// ❌ Incorrect usage patterns
// Don't pass empty object as second parameter
DatadogLogger.error('Validation failed', {}); // Wrong!

// Don't pass additional data as second parameter when you mean to pass an error
DatadogLogger.error('Process failed', { step: 'validation' }); // Wrong!

Log Structure

All logs follow a consistent Datadog-compatible structure:

{
	"message": "Payment processed successfully",
	"host": "aws/amplify",
	"service": "hosted-component",
	"env": "sydney", // or staging, develop, sandbox
	"environment": "sydney,frontend", // or stage,frontend
	"application": "hosted-component",
	"timestamp": "2024-01-15T10:30:00.000Z",
	"token": "eyJhbG************ssw5c", // masked
	"context": "payment_method_embed", // or custom context
	"paymentStage": "payment_token_creation",
	"merchantId": "merchant-123",
	"countryCode": "AU",
	"pageType": "HPP 2.0"
}

Production Safe Logger

For legacy compatibility, the ProductionSafeLogger is still available but now uses DatadogLogger internally:

import { ProductionSafeLogger } from '@/lib/utils/production-safe-logger';

// Basic logging (filtered in production)
ProductionSafeLogger.log('Debug information', { data: 'value' });

// Sensitive data logging (dev/staging only)
ProductionSafeLogger.logSensitiveData('Payment details', {
	cardNumber: '4111111111111111',
});

Best Practices

Logging Strategy

  1. Use structured logging: Always include relevant context in your logs
  2. Leverage payment stages: Track the user journey through payment processing
  3. Include tokens safely: Let the logger handle token masking automatically
  4. Provide meaningful contexts: Help with debugging and monitoring
  5. Use appropriate log levels: Info for normal operations, warn for potential issues, error for failures
// Good logging practice
DatadogLogger.info(
	'Payment method selection changed',
	{
		paymentMethodType: 'CARD',
		paymentStage: 'payment_method_selection',
	},
	token,
	{
		merchantId: 'merchant-123',
		countryCode: 'AU',
		pageType: 'HPP 2.0',
	}
);

Security Considerations

  • Never log sensitive data in production
  • Use logSensitiveData() for development-only sensitive information
  • Tokens are automatically masked - no need to handle this manually
  • Always check environment before logging sensitive information

On this page