Custom Validation Hook Context

This document describes the objects, data structures, and utilities available to you when writing custom pre-validation and post-validation hooks. Use this reference to implement custom business logic that executes during the content ingestion process.

Hooks run in a secure, sandboxed JavaScript environment. When your hook executes, the system injects specific objects into the global scope, allowing you to inspect the data package, review job metadata, and report validation results.

Prerequisites

Before writing custom hooks, ensure you are familiar with:

  • JavaScript (ES5/ES6): Hooks are written in standard JavaScript.
  • Data Import Format: Understanding the structure of articles, folders, and topics as defined in the Format Guide .
  • Hook Architecture: Whether you are writing a Pre-Validation hook (runs before standard checks) or a Post-Validation hook (runs after standard checks).

Security and Environment Restrictions

Your code executes in a restricted sandbox. For security reasons, the following capabilities are NOT available:

  • File system access ( fs , __dirname , __filename )
  • Network access (HTTP requests)
  • Module loading ( require )
  • Global process access ( process , global )
  • eval() or dynamic code execution

Allowed Capabilities:

  • Accessing injected objects ( data , metadata , validationResults )
  • Using the provided helpers library
  • Using console.log() for system logging
  • Standard JavaScript logic (loops, conditionals, array manipulation)

Available Objects

The following objects are injected into your hook's scope at runtime.

1. data - Package Content

The data object represents the parsed content from the package being imported. You can inspect this object to validate naming conventions, folder structures, or content requirements.

Structure Overview:

Copy
Copied
data = {
  articles: [],        // Array of article objects
  folders: [],         // Array of folder objects
  portals: [],         // Array of portal objects
  topics: [],          // Array of topic objects
  macros: []           // Array of macro objects
}

Article Object Model: Each item in the articles array contains the following properties:

Copy
Copied
{
  name: "article-name",                    // Required: Article name
  folder: {
    path: "Articles/Content/Shared"        // Required: Full folder path
  },
  content: "content/article.html",         // Path to file OR direct HTML string
  ai: "true",                              // String "true"/"false"
  availabilityDate: "12-22-2024",          // Optional
  metadata: {                              
    description: "Sample Article",
    keywords: "Chat",
    additionalInfo: "Info"
  },
  articleMacro: {                          // Present only if article is a Macro
    name: "CompanySize",
    defaultValue: "<p>[default]</p>"
  },
  customAttributes: [
    { name: "attribute1", value: "value1" }
  ],
  // ... various optional fields (classifications, relatedArticles, etc.)
}

2. metadata - Job Context

The metadata object provides context about the current execution environment and the job itself.

Structure:

Copy
Copied
metadata = {
  packageId: "package-123",    // Unique Job ID
  domain: "example.com",       // Tenant Domain
  tenantId: "tenant-456",      // Tenant ID
  departmentName: "Support"    // (Import workflow only)
}

3. validationResults - Standard Validation Output

Note: This object is available ONLY in Post-Validation hooks.

This object contains the results of the standard system validation that ran immediately before your hook. You can use this to determine if you should block an import based on specific errors.

Structure:

Copy
Copied
validationResults = {
  success: false,
  summary: {
    totalArticles: 100,
    totalErrors: 7,
    invalidAttachments: 5
  },
  errors: [
    {
      type: "attachment_missing",
      articleName: "article-1",
      message: "Attachment 'image.png' not found",
      fix: "Ensure attachment exists in resources folder"
    }
  ],
  warnings: [] 
}

4. helpers - Utility Library

The helpers object provides safe utility functions to handle data checking without throwing runtime errors on undefined properties.

Available Functions:

  • helpers.hasField(obj, field)
    • Returns: boolean
    • Usage: Checks if an object has a specific property.
  • helpers.isNotEmpty(value)
    • Returns: boolean
    • Usage: Checks if a value is not null, undefined, empty string, empty array, or empty object.
  • helpers.isEmpty(value)
    • Returns: boolean
    • Usage: The inverse of isNotEmpty .
  • helpers.isArray(value)
    • Returns: boolean
    • Usage: Validates if a value is an array.
  • helpers.isString(value)
    • Returns: boolean
  • helpers.isNumber(value)
    • Returns: boolean

5. console - Logging

Use console.log() to write messages to the system logs. This is essential for debugging hooks or logging specific validation decisions.

Copy
Copied
console.log('Processing package:', metadata.packageId);
console.log('Found error in article:', article.name);

Execution Contexts

Depending on when your hook runs, different objects are available.

Pre-Validation Hooks

When: Executes BEFORE the standard system validation. Goal: Enforce custom business rules (e.g., "All articles must have a keyword" or "AI must be enabled").

  • data
  • metadata
  • helpers / console
  • validationResults (Not available yet)

Post-Validation Hooks

When: Executes AFTER the standard system validation. Goal: Review system errors and decide if the job should proceed (e.g., "Fail the job if any image attachments are missing").

  • data
  • metadata
  • validationResults
  • helpers / console

Return Value Format

Your hook must return a result object. This object dictates whether the validation process considers the job a success or failure.

Success Scenario

Return this to allow the job to proceed.

Copy
Copied
var result = {
  success: true,
  message: "Custom validation passed."
};
return result;

Failure Scenario

Return this to stop the job and report an error to the user.

Copy
Copied
var result = {
  success: false,
  error: "Critical Business Rule Failed: Articles must have an author.",
  details: {
    failedCount: 5,
    articleNames: ["intro", "setup", "config"]
  }
};
return result;

Example: Pre-Validation Logic

This example demonstrates checking that every article contains a specific metadata field.

Copy
Copied
// Initialize result
var result = { success: true };

// Verify data exists
if (helpers.hasField(data, 'articles') && helpers.isNotEmpty(data.articles)) {
  
  var invalidArticles = [];
  
  // Loop through articles
  for (var i = 0; i < data.articles.length; i++) {
    var article = data.articles[i];
    
    // Check for "name" field
    if (!helpers.hasField(article, 'name')) {
      invalidArticles.push({ index: i, issue: "Missing name" });
      continue;
    }

    // Custom Rule: Check if 'description' exists in metadata
    if (!helpers.hasField(article, 'metadata') || 
        !helpers.hasField(article.metadata, 'description') || 
        helpers.isEmpty(article.metadata.description)) {
          
      invalidArticles.push({ 
        name: article.name, 
        issue: "Missing required description metadata" 
      });
    }
  }
  
  // If we found issues, fail the job
  if (invalidArticles.length > 0) {
    result = {
      success: false,
      error: 'Articles failed custom metadata validation',
      details: {
        count: invalidArticles.length,
        errors: invalidArticles
      }
    };
  }
}

// Return the result object
result;

Example: Post-Validation Logic

This example checks the standard validation results. If there are standard errors, it logs them and fails the job explicitly.

Copy
Copied
var result = { success: true };

// Check if standard validation found errors
if (helpers.hasField(validationResults, 'errors') && validationResults.errors.length > 0) {
  
  var errorCount = validationResults.errors.length;
  console.log('Standard validation found ' + errorCount + ' errors.');

  // Create a summary of error types
  var errorTypes = {};
  validationResults.errors.forEach(function(err) {
    var type = err.type || 'unknown';
    errorTypes[type] = (errorTypes[type] || 0) + 1;
  });

  // Fail the job
  result = {
    success: false,
    error: 'Standard validation failed with ' + errorCount + ' errors.',
    details: {
      summary: errorTypes,
      firstError: validationResults.errors[0].message
    }
  };
}

result;

Best Practices

  • Defensive Coding: Always use helpers.hasField() before accessing nested properties. For example, do not access article.metadata.description directly without checking if article.metadata exists first.
  • Clear Error Messages: When returning success: false , provide a descriptive error string and use the details object to pass relevant data (like lists of failed article names).
  • Logging: Use console.log generously. These logs are saved with the job history and are vital for troubleshooting why a hook failed a package.