CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-xyo-network--payload-model

Core payload modeling capabilities for the XYO Protocol 2.0 ecosystem, offering TypeScript interfaces and types for defining, validating, and manipulating payloads within the XYO blockchain network.

Overview
Eval results
Files

validation-errors.mddocs/

Validation and Error Handling

Comprehensive validation framework with sync/async validation functions, structured error payload types, and Zod integration for runtime validation within the XYO Protocol 2.0 ecosystem.

Capabilities

Payload Validation Functions

Type definitions for synchronous and asynchronous payload validation functions with flexible validation patterns.

/**
 * Synchronous payload validation function
 * @param payload - Payload to validate
 * @returns Boolean indicating validation result
 */
type SyncPayloadValidationFunction<T extends Payload = Payload> = (payload: T) => boolean;

/**
 * Asynchronous payload validation function  
 * @param payload - Payload to validate
 * @returns Promise resolving to boolean validation result
 */
type AsyncPayloadValidationFunction<T extends Payload = Payload> = (payload: T) => Promise<boolean>;

/**
 * Union type for both sync and async validation functions
 */
type PayloadValidationFunction<T extends Payload = Payload> = 
  SyncPayloadValidationFunction<T> | AsyncPayloadValidationFunction<T>;

Zod Validation Schemas

Zod-based validation schemas for runtime payload validation and type checking with full TypeScript integration.

/**
 * Import Zod for schema validation
 */
import * as z from 'zod';

/**
 * Storage metadata Zod schema
 */
const StorageMetaZod: z.ZodObject<{
  _hash: z.ZodType<Hash>;
  _dataHash: z.ZodType<Hash>;
  _sequence: z.ZodType<string>;
}>;

/**
 * Base payload Zod schema
 */
const PayloadZod: z.ZodObject<{
  schema: z.ZodType<Schema>;
}>;

/**
 * Payload with storage metadata Zod schema
 */
const PayloadWithStorageMetaZod: z.ZodIntersection<
  typeof PayloadZod,
  typeof StorageMetaZod
>;

/**
 * Any payload with flexible additional properties
 */
const AnyPayloadZod: z.ZodObject<{
  schema: z.ZodType<Schema>;
}> & z.ZodCatchall<z.ZodAny>;

/**
 * Any payload with storage metadata
 */
const AnyPayloadWithStorageMetaZod: z.ZodIntersection<
  typeof AnyPayloadZod,
  typeof StorageMetaZod
>;

/**
 * Inferred types from Zod schemas
 */
type PayloadWithStorageMeta = z.infer<typeof PayloadWithStorageMetaZod>;
type AnyPayload = z.infer<typeof AnyPayloadZod>;
type AnyPayloadWithStorageMeta = z.infer<typeof AnyPayloadWithStorageMetaZod>;

/**
 * Helper function to create payload schema with storage metadata
 */
function WithStorageMetaZod<T extends typeof PayloadZod>(valueZod: T): z.ZodIntersection<typeof StorageMetaZod, T>;

Usage Examples:

import { 
  PayloadValidationFunction,
  SyncPayloadValidationFunction,
  AsyncPayloadValidationFunction,
  Payload
} from "@xyo-network/payload-model";

// Define custom payload type
interface UserPayload extends Payload {
  schema: "network.example.user";
  name: string;
  email: string;
  age: number;
}

// Synchronous validation function
const validateUserSync: SyncPayloadValidationFunction<UserPayload> = (payload) => {
  if (!payload.name || payload.name.length < 2) return false;
  if (!payload.email || !payload.email.includes('@')) return false;
  if (!payload.age || payload.age < 0 || payload.age > 150) return false;
  return true;
};

// Asynchronous validation function
const validateUserAsync: AsyncPayloadValidationFunction<UserPayload> = async (payload) => {
  // Simulate async validation (e.g., database check)
  const emailExists = await checkEmailExists(payload.email);
  if (emailExists) return false;
  
  const nameValid = await validateNameFormat(payload.name);
  return nameValid && payload.age >= 18;
};

// Generic validation function
const validateUser: PayloadValidationFunction<UserPayload> = validateUserSync;

// Use validation functions
const userPayload: UserPayload = {
  schema: "network.example.user",
  name: "Alice",
  email: "alice@example.com",
  age: 25
};

// Sync validation
if (validateUserSync(userPayload)) {
  console.log("User payload is valid");
}

// Async validation
const isValid = await validateUserAsync(userPayload);
if (isValid) {
  console.log("User payload passed async validation");
}

// Helper functions (examples)
async function checkEmailExists(email: string): Promise<boolean> {
  // Simulate database check
  return Promise.resolve(false);
}

async function validateNameFormat(name: string): Promise<boolean> {
  // Simulate external validation service
  return Promise.resolve(name.length >= 2 && /^[a-zA-Z\s]+$/.test(name));
}

Module Error System

Structured error payload system for handling and communicating errors within XYO modules and operations.

/**
 * Schema constant for module errors
 */
const ModuleErrorSchema: "network.xyo.error.module";

/**
 * Type alias for module error schema
 */
type ModuleErrorSchema = typeof ModuleErrorSchema;

/**
 * Import JsonValue type from @xylabs/object
 */
import type { JsonValue } from '@xylabs/object';

/**
 * Module error payload type with comprehensive error information
 */
type ModuleError = Payload<{
  /** Additional error details as JSON value */
  details?: JsonValue;
  
  /** Human-readable error message */
  message?: string;
  
  /** Error name or type identifier */
  name?: string;
  
  /** Query hash or schema that caused the error */
  query?: Hash | Schema;
  
  /** Module error schema */
  schema: ModuleErrorSchema;
}>;

/**
 * Type guard for module error validation
 */
function isModuleError(value: unknown): value is ModuleError;

Usage Examples:

import { 
  ModuleError,
  ModuleErrorSchema,
  isModuleError,
  Payload,
  Hash,
  Schema
} from "@xyo-network/payload-model";

// Create basic module error
const basicError: ModuleError = {
  schema: ModuleErrorSchema,
  message: "Validation failed",
  name: "ValidationError"
};

// Create detailed module error
const detailedError: ModuleError = {
  schema: ModuleErrorSchema,
  message: "User payload validation failed",
  name: "UserValidationError",
  details: {
    field: "email",
    reason: "Invalid email format",
    value: "invalid-email",
    code: "EMAIL_INVALID"
  },
  query: "network.example.user" as Schema
};

// Create error with query hash
const queryError: ModuleError = {
  schema: ModuleErrorSchema,
  message: "Query execution failed",
  name: "QueryExecutionError",
  details: {
    timeout: true,
    duration: 30000,
    retries: 3
  },
  query: "0x1234567890abcdef..." as Hash
};

// Error handling utility
function createModuleError(
  message: string,
  name: string,
  details?: any,
  query?: Hash | Schema
): ModuleError {
  return {
    schema: ModuleErrorSchema,
    message,
    name,
    details,
    query
  };
}

// Validate and handle errors
function processPayload(payload: unknown): Payload | ModuleError {
  if (!payload || typeof payload !== 'object') {
    return createModuleError(
      "Invalid payload format",
      "PayloadFormatError",
      { received: typeof payload }
    );
  }

  if (isModuleError(payload)) {
    console.error("Module error detected:", payload.message);
    return payload;
  }

  // Process valid payload
  return payload as Payload;
}

// Error result handling
function handleResult(result: Payload | ModuleError) {
  if (isModuleError(result)) {
    console.error(`Error: ${result.name} - ${result.message}`);
    if (result.details) {
      console.error("Details:", result.details);
    }
    if (result.query) {
      console.error("Related query:", result.query);
    }
    return null;
  }
  
  return result;
}

// Use in validation pipeline
async function validateAndProcess<T extends Payload>(
  payload: T,
  validator: PayloadValidationFunction<T>
): Promise<T | ModuleError> {
  try {
    const isValid = await Promise.resolve(validator(payload));
    
    if (!isValid) {
      return createModuleError(
        "Payload validation failed",
        "ValidationError",
        { schema: payload.schema },
        payload.schema
      );
    }
    
    return payload;
  } catch (error) {
    return createModuleError(
      "Validation process failed", 
      "ValidationProcessError",
      { 
        originalError: error instanceof Error ? error.message : String(error),
        schema: payload.schema
      },
      payload.schema
    );
  }
}

Zod Integration

Runtime validation schemas using Zod for comprehensive payload structure validation and type safety.

/**
 * Base Zod schema for payload validation
 */
const PayloadZod: ZodType<{ schema: Schema }>;

/**
 * Zod schema for storage metadata validation
 */
const StorageMetaZod: ZodType<{
  _hash: Hash;
  _dataHash: Hash;
  _sequence: Sequence;
}>;

/**
 * Zod schema for payload with storage metadata
 */
const PayloadWithStorageMetaZod: ZodType<PayloadWithStorageMeta>;

/**
 * Catch-all Zod schema for any payload with additional properties
 */
const AnyPayloadZod: ZodType<AnyPayload>;

/**
 * Catch-all Zod schema for any payload with storage metadata
 */
const AnyPayloadWithStorageMetaZod: ZodType<AnyPayloadWithStorageMeta>;

/**
 * Helper function to add storage metadata validation to existing schema
 */
function WithStorageMetaZod<T extends typeof PayloadZod>(
  valueZod: T
): ZodType<StorageMeta & z.infer<T>>;

/**
 * Inferred types from Zod schemas
 */
type PayloadWithStorageMeta = z.infer<typeof PayloadWithStorageMetaZod>;
type AnyPayload = z.infer<typeof AnyPayloadZod>;
type AnyPayloadWithStorageMeta = z.infer<typeof AnyPayloadWithStorageMetaZod>;

Usage Examples:

import { 
  PayloadZod,
  AnyPayloadZod,
  StorageMetaZod,
  PayloadWithStorageMetaZod,
  WithStorageMetaZod
} from "@xyo-network/payload-model";
import * as z from "zod";

// Create custom payload schema
const UserPayloadZod = z.object({
  schema: z.literal("network.example.user"),
  name: z.string().min(2).max(50),
  email: z.string().email(),
  age: z.number().int().min(0).max(150),
  preferences: z.object({
    theme: z.enum(["light", "dark"]).optional(),
    notifications: z.boolean().optional()
  }).optional()
});

type UserPayload = z.infer<typeof UserPayloadZod>;

// Validate user payload
const userData = {
  schema: "network.example.user",
  name: "Alice",
  email: "alice@example.com",
  age: 25,
  preferences: {
    theme: "dark",
    notifications: true
  }
};

try {
  const validUser = UserPayloadZod.parse(userData);
  console.log("Valid user:", validUser.name);
} catch (error) {
  if (error instanceof z.ZodError) {
    console.error("Validation errors:", error.errors);
  }
}

// Validate any payload
const unknownPayload = {
  schema: "network.example.unknown",
  data: "some data",
  timestamp: Date.now()
};

const validPayload = AnyPayloadZod.parse(unknownPayload);
console.log("Valid payload schema:", validPayload.schema);

// Add storage metadata to custom schema
const UserWithStorageZod = WithStorageMetaZod(UserPayloadZod);

const userWithStorageData = {
  schema: "network.example.user",
  name: "Bob",
  email: "bob@example.com", 
  age: 30,
  _hash: "0x123...",
  _dataHash: "0x456...",
  _sequence: "1234567890abcdef"
};

const validUserWithStorage = UserWithStorageZod.parse(userWithStorageData);
console.log("User with storage:", validUserWithStorage.name);
console.log("Storage hash:", validUserWithStorage._hash);

// Validation with error handling
function validatePayloadSafely<T>(
  schema: z.ZodType<T>,
  data: unknown
): { success: true; data: T } | { success: false; errors: z.ZodError } {
  try {
    const validated = schema.parse(data);
    return { success: true, data: validated };
  } catch (error) {
    if (error instanceof z.ZodError) {
      return { success: false, errors: error };
    }
    throw error;
  }
}

// Use safe validation
const result = validatePayloadSafely(UserPayloadZod, userData);
if (result.success) {
  console.log("Validated user:", result.data.name);
} else {
  console.error("Validation failed:", result.errors.errors);
}

Advanced Validation Patterns

Complex validation scenarios and patterns for robust payload processing.

/**
 * Schema validation with regex pattern
 */
const SchemaZod: ZodType<Schema>;

/**
 * Schema validation functions
 */
function isSchema(value: unknown): value is Schema;
function asSchema(value: unknown): Schema;

Usage Examples:

import { 
  PayloadValidationFunction,
  ModuleError,
  ModuleErrorSchema,
  createModuleError,
  SchemaZod,
  AnyPayloadZod
} from "@xyo-network/payload-model";
import * as z from "zod";

// Complex validation pipeline
class PayloadValidator {
  private validators: Map<string, PayloadValidationFunction> = new Map();
  private schemas: Map<string, z.ZodType<any>> = new Map();

  // Register schema validator
  registerSchema<T extends Payload>(
    schema: string, 
    zodSchema: z.ZodType<T>,
    customValidator?: PayloadValidationFunction<T>
  ) {
    this.schemas.set(schema, zodSchema);
    if (customValidator) {
      this.validators.set(schema, customValidator);
    }
  }

  // Validate payload with comprehensive error reporting
  async validatePayload(payload: unknown): Promise<{
    valid: boolean;
    payload?: Payload;
    errors: ModuleError[];
  }> {
    const errors: ModuleError[] = [];

    // Basic structure validation
    try {
      const basicPayload = AnyPayloadZod.parse(payload);
      
      // Schema format validation
      if (!SchemaZod.safeParse(basicPayload.schema).success) {
        errors.push({
          schema: ModuleErrorSchema,
          message: "Invalid schema format",
          name: "SchemaFormatError",
          details: { schema: basicPayload.schema }
        });
        return { valid: false, errors };
      }

      // Schema-specific validation
      const zodSchema = this.schemas.get(basicPayload.schema);
      if (zodSchema) {
        const zodResult = zodSchema.safeParse(payload);
        if (!zodResult.success) {
          errors.push({
            schema: ModuleErrorSchema,
            message: "Schema validation failed",
            name: "ZodValidationError",
            details: { 
              errors: zodResult.error.errors,
              schema: basicPayload.schema
            },
            query: basicPayload.schema
          });
        }
      }

      // Custom validation
      const customValidator = this.validators.get(basicPayload.schema);
      if (customValidator) {
        try {
          const isValid = await Promise.resolve(customValidator(basicPayload));
          if (!isValid) {
            errors.push({
              schema: ModuleErrorSchema,
              message: "Custom validation failed",
              name: "CustomValidationError",
              details: { schema: basicPayload.schema },
              query: basicPayload.schema
            });
          }
        } catch (error) {
          errors.push({
            schema: ModuleErrorSchema,
            message: "Custom validation error",
            name: "CustomValidationException",
            details: { 
              error: error instanceof Error ? error.message : String(error),
              schema: basicPayload.schema
            },
            query: basicPayload.schema
          });
        }
      }

      return {
        valid: errors.length === 0,
        payload: errors.length === 0 ? basicPayload : undefined,
        errors
      };

    } catch (error) {
      errors.push({
        schema: ModuleErrorSchema,
        message: "Payload structure validation failed",
        name: "StructureValidationError",
        details: { 
          error: error instanceof Error ? error.message : String(error)
        }
      });
      
      return { valid: false, errors };
    }
  }

  // Batch validation
  async validateBatch(payloads: unknown[]): Promise<{
    valid: Payload[];
    invalid: { payload: unknown; errors: ModuleError[] }[];
  }> {
    const valid: Payload[] = [];
    const invalid: { payload: unknown; errors: ModuleError[] }[] = [];

    for (const payload of payloads) {
      const result = await this.validatePayload(payload);
      if (result.valid && result.payload) {
        valid.push(result.payload);
      } else {
        invalid.push({ payload, errors: result.errors });
      }
    }

    return { valid, invalid };
  }
}

// Usage example
const validator = new PayloadValidator();

// Register user schema
const UserSchema = z.object({
  schema: z.literal("network.example.user"),
  name: z.string().min(2),
  email: z.string().email(),
  age: z.number().int().min(0)
});

const userCustomValidator: PayloadValidationFunction = async (payload) => {
  // Custom business logic validation
  return payload.name !== "admin"; // Example: no admin users allowed
};

validator.registerSchema("network.example.user", UserSchema, userCustomValidator);

// Validate payloads
const testPayloads = [
  { schema: "network.example.user", name: "Alice", email: "alice@example.com", age: 25 },
  { schema: "network.example.user", name: "admin", email: "admin@example.com", age: 35 },
  { schema: "invalid.schema.format", data: "test" },
  "invalid payload"
];

const batchResult = await validator.validateBatch(testPayloads);
console.log(`Valid: ${batchResult.valid.length}, Invalid: ${batchResult.invalid.length}`);

batchResult.invalid.forEach(({ payload, errors }) => {
  console.error("Invalid payload:", errors.map(e => e.message));
});

Advanced Error Handling Patterns

Error Recovery and Transformation

import { ModuleError, ModuleErrorSchema, Payload } from "@xyo-network/payload-model";

// Error recovery utilities
class ErrorRecovery {
  // Attempt to recover from validation errors
  static tryRecover(error: ModuleError, originalPayload: unknown): Payload | null {
    if (error.name === "SchemaFormatError" && error.details?.schema) {
      // Try to fix common schema format issues
      const fixedSchema = this.fixSchemaFormat(error.details.schema);
      if (fixedSchema && typeof originalPayload === 'object' && originalPayload) {
        return { ...(originalPayload as object), schema: fixedSchema };
      }
    }
    
    return null;
  }

  private static fixSchemaFormat(schema: string): string | null {
    // Example: fix common schema format issues
    if (schema.includes("_")) {
      return schema.replace(/_/g, ".");
    }
    if (schema.toUpperCase() === schema) {
      return schema.toLowerCase();
    }
    return null;
  }

  // Transform errors for external reporting
  static transformError(error: ModuleError): {
    code: string;
    message: string;
    details?: any;
  } {
    return {
      code: error.name || "UNKNOWN_ERROR",
      message: error.message || "An unknown error occurred",
      details: error.details
    };
  }
}

Types Reference

Validation Function Types

  • SyncPayloadValidationFunction<T>: Synchronous validation function type
  • AsyncPayloadValidationFunction<T>: Asynchronous validation function type
  • PayloadValidationFunction<T>: Union of sync/async validation functions

Error Types

  • ModuleError: Structured error payload type
  • ModuleErrorSchema: Module error schema constant

Zod Integration Types

  • PayloadWithStorageMeta: Payload with storage metadata (inferred from Zod)
  • AnyPayload: Any payload type (inferred from Zod)
  • AnyPayloadWithStorageMeta: Any payload with storage metadata (inferred from Zod)

Validation Schema Types

  • PayloadZod: Base payload Zod schema
  • StorageMetaZod: Storage metadata Zod schema
  • PayloadWithStorageMetaZod: Payload with storage metadata Zod schema
  • AnyPayloadZod: Catch-all payload Zod schema
  • AnyPayloadWithStorageMetaZod: Catch-all payload with storage metadata Zod schema

Constants

  • ModuleErrorSchema: "network.xyo.error.module"

Functions

  • isModuleError(value): Type guard for module errors
  • WithStorageMetaZod<T>(schema): Add storage metadata validation to Zod schema

Install with Tessl CLI

npx tessl i tessl/npm-xyo-network--payload-model

docs

bundles-queries.md

core-payload-types.md

index.md

storage-metadata.md

type-guards.md

utility-types.md

validation-errors.md

tile.json