Skip to content

Validation

Comprehensive validation utilities for Verdikta manifests and requests using Joi schemas.

Overview

The validation module provides robust schema validation for: - Manifest.json files - Request objects - Configuration objects - Content sanitization

Validator Object

Import

const { validator } = require('@verdikta/common');

Methods

validateManifest(manifest)

Validate a manifest object against the Verdikta manifest schema.

const manifestData = {
  version: "1.0",
  primary: {
    filename: "primary_query.json"
  },
  juryParameters: {
    NUMBER_OF_OUTCOMES: 2,
    AI_NODES: [
      {
        AI_MODEL: "gpt-4o",
        AI_PROVIDER: "OpenAI",
        NO_COUNTS: 1,
        WEIGHT: 0.5
      }
    ]
  }
};

try {
  await validator.validateManifest(manifestData);
  console.log('✅ Manifest is valid');
} catch (error) {
  console.error('❌ Validation failed:', error.details);
}

Parameters: - manifest (Object): Manifest object to validate

Returns: Promise

Throws: ValidationError with detailed error information

validateRequest(request)

Validate a request object for arbitration queries.

const requestData = {
  query: "Should party A receive compensation?",
  references: ["contract.pdf", "evidence.jpg"],
  outcomes: ["Yes, full compensation", "No compensation"]
};

await validator.validateRequest(requestData);

Parameters: - request (Object): Request object to validate

Returns: Promise

Throws: ValidationError

validateConfiguration(config)

Validate a configuration object.

const config = {
  ipfs: {
    gateway: 'https://ipfs.io',
    timeout: 30000
  },
  logging: {
    level: 'info'
  }
};

await validator.validateConfiguration(config);

Parameters: - config (Object): Configuration object to validate

Returns: Promise

Throws: ValidationError

sanitizeContent(content)

Sanitize content for safe processing (removes potentially dangerous characters).

const sanitized = validator.sanitizeContent(userInput);

Parameters: - content (string): Content to sanitize

Returns: string - Sanitized content

Validation Schemas

Manifest Schema

The manifest schema validates the complete structure of a Verdikta manifest:

const manifestSchema = Joi.object({
  version: Joi.string().required(),
  name: Joi.string().optional(),
  primary: Joi.object({
    filename: Joi.string().when('hash', {
      is: Joi.exist(),
      then: Joi.forbidden(),
      otherwise: Joi.required()
    }),
    hash: Joi.string().optional()
  }).required(),
  juryParameters: Joi.object({
    NUMBER_OF_OUTCOMES: Joi.number().integer().min(2).default(2),
    AI_NODES: Joi.array().items(
      Joi.object({
        AI_MODEL: Joi.string().required(),
        AI_PROVIDER: Joi.string().required(),
        NO_COUNTS: Joi.number().integer().min(1).required(),
        WEIGHT: Joi.number().min(0).max(1).required()
      })
    ).default([{
      AI_MODEL: "gpt-4o",
      AI_PROVIDER: "OpenAI", 
      NO_COUNTS: 1,
      WEIGHT: 1.0
    }]),
    ITERATIONS: Joi.number().integer().min(1).default(1)
  }).optional(),
  additional: Joi.array().items(
    Joi.object({
      name: Joi.string().required(),
      type: Joi.string().required(),
      filename: Joi.string().when('hash', {
        is: Joi.exist(),
        then: Joi.forbidden(),
        otherwise: Joi.required()
      }),
      hash: Joi.string().optional(),
      description: Joi.string().optional()
    })
  ).optional(),
  support: Joi.array().items(
    Joi.object({
      hash: Joi.object({
        cid: Joi.string().required(),
        description: Joi.string().optional(),
        id: Joi.number().optional()
      }).required()
    })
  ).optional(),
  bCIDs: Joi.object().pattern(
    Joi.string(),
    Joi.string()
  ).optional(),
  addendum: Joi.string().optional()
});

Request Schema

Validates arbitration request objects:

const requestSchema = Joi.object({
  query: Joi.string().required().min(10).max(5000),
  references: Joi.array().items(Joi.string()).default([]),
  outcomes: Joi.array().items(Joi.string()).min(2).optional(),
  metadata: Joi.object().optional()
});

Configuration Schema

Validates client configuration:

const configSchema = Joi.object({
  ipfs: Joi.object({
    gateway: Joi.string().uri().default('https://ipfs.io'),
    pinningService: Joi.string().uri().default('https://api.pinata.cloud'),
    pinningKey: Joi.string().default(''),
    timeout: Joi.number().integer().min(1000).default(30000),
    retryOptions: Joi.object({
      retries: Joi.number().integer().min(0).default(5),
      factor: Joi.number().min(1).default(2),
      minTimeout: Joi.number().integer().min(100).default(1000),
      maxTimeout: Joi.number().integer().min(1000).default(15000),
      randomize: Joi.boolean().default(true)
    }).default()
  }).default(),
  logging: Joi.object({
    level: Joi.string().valid('debug', 'info', 'warn', 'error').default('info'),
    console: Joi.boolean().default(true),
    file: Joi.boolean().default(false),
    filename: Joi.string().optional()
  }).default(),
  temp: Joi.object({
    dir: Joi.string().default('./tmp')
  }).default()
});

Validation Errors

ValidationError Class

const { ValidationError } = require('@verdikta/common');

class ValidationError extends Error {
  constructor(message, details) {
    super(message);
    this.name = 'ValidationError';
    this.details = details;
  }
}

Error Details

Validation errors include detailed information about what failed:

try {
  await validator.validateManifest(invalidManifest);
} catch (error) {
  if (error instanceof ValidationError) {
    console.log('Error message:', error.message);
    console.log('Validation details:', error.details);

    // Example error.details:
    {
      "version": "\"version\" is required",
      "primary.filename": "\"filename\" is required when \"hash\" is not provided",
      "juryParameters.AI_NODES[0].WEIGHT": "\"WEIGHT\" must be less than or equal to 1"
    }
  }
}

Common Validation Patterns

Conditional Validation

Many fields in manifests are conditionally required:

// Either filename OR hash must be provided (but not both)
const fileReference = {
  filename: "local-file.txt"  // Valid
  // hash: "QmCID"           // Also valid
  // Both would be invalid
};

// Weights must sum to reasonable values
const aiNodes = [
  { AI_MODEL: "gpt-4o", AI_PROVIDER: "OpenAI", NO_COUNTS: 1, WEIGHT: 0.7 },
  { AI_MODEL: "claude-3", AI_PROVIDER: "Anthropic", NO_COUNTS: 1, WEIGHT: 0.3 }
];

Default Value Handling

The validator provides sensible defaults:

// Minimal manifest (defaults will be applied)
const minimalManifest = {
  version: "1.0",
  primary: { filename: "query.json" }
};

// After validation, becomes:
{
  version: "1.0",
  primary: { filename: "query.json" },
  juryParameters: {
    NUMBER_OF_OUTCOMES: 2,
    AI_NODES: [{
      AI_MODEL: "gpt-4o",
      AI_PROVIDER: "OpenAI",
      NO_COUNTS: 1,
      WEIGHT: 1.0
    }],
    ITERATIONS: 1
  }
}

Custom Validation Messages

const customValidator = {
  async validateWithCustomMessages(manifest) {
    try {
      return await validator.validateManifest(manifest);
    } catch (error) {
      if (error instanceof ValidationError) {
        // Customize error messages
        const friendlyErrors = Object.entries(error.details).map(([field, msg]) => {
          switch (field) {
            case 'version':
              return 'Manifest version is required and must be "1.0"';
            case 'primary':
              return 'A primary query file must be specified';
            default:
              return `${field}: ${msg}`;
          }
        });

        throw new ValidationError('Validation failed', friendlyErrors);
      }
      throw error;
    }
  }
};

Content Sanitization

Purpose

Sanitization prevents code injection and ensures safe content processing:

// Potentially dangerous input
const userInput = 'Query with <script>alert("xss")</script> embedded code';

// Sanitized output
const safe = validator.sanitizeContent(userInput);
// Result: 'Query with alert("xss") embedded code'

Sanitization Rules

  • Removes HTML/XML tags
  • Strips potential code injection patterns
  • Preserves basic formatting characters
  • Maintains readability while ensuring safety

Usage in Processing

Sanitization is automatically applied during: - Manifest parsing - Addendum processing - User-provided content integration

// Automatic sanitization in manifest processing
const manifest = await parseManifest('./archive');
// All user content in manifest is automatically sanitized

For more information on validation patterns and error handling, see the Error Handling Guide and Examples.