License Validator
The validator ensures license configurations comply with the NIL Taxonomy specification.
Basic Usage
import { validateLicense } from '@nil-taxonomy/sdk';
const result = validateLicense({
subject_scope: ['name', 'image'],
use_type: ['brand_marketing'],
commercial_scope: 'full_commercial',
// ... other fields
});
if (!result.valid) {
console.error('Validation failed:', result.errors);
}Validation Result
interface ValidationResult {
valid: boolean;
errors?: ValidationError[];
warnings?: ValidationWarning[];
}
interface ValidationError {
field: string;
message: string;
code: string;
value?: any;
}
interface ValidationWarning {
field: string;
message: string;
code: string;
severity: 'low' | 'medium' | 'high';
}Validation Rules
Required Fields
All licenses must include:
{
subject_scope: SubjectScope[], // REQUIRED
use_type: UseType[], // REQUIRED
commercial_scope: CommercialScope, // REQUIRED
exclusivity: Exclusivity, // REQUIRED
territory: Territory, // REQUIRED
term: Term, // REQUIRED (or perpetual)
derivative_rights: DerivativeRights,// REQUIRED
ai_synthetic_use: AISyntheticUse, // REQUIRED
data_use: DataUse, // REQUIRED
attribution: Attribution, // REQUIRED
sublicensing: Sublicensing, // REQUIRED
content_safety: ContentSafety // REQUIRED
}Field-Specific Validation
Subject Scope:
- Must be non-empty array
- Must contain only valid enum values
synthetic_likenessrequiresai_synthetic_useto allow it
Use Type:
- Must be non-empty array
brand_marketingrequirescommercial_scope=full_commercialeducationalrequirescommercial_scope=non_commercial
Territory:
- Must specify at least one of: global, countries, regions, states, cities
- Country codes must be ISO 3166-1 alpha-2
- Cannot mix
global: truewith specific territories
Term:
- Start date must be before end date
- If auto-renew, must specify renewal period
- Perpetual and fixed-term are mutually exclusive
Exclusivity:
- If
category_exclusive, must specify categories - If
full_exclusive, cannot specify categories - Exclusive categories must be valid enum values
Content Safety:
- Restricted categories must be valid enum values
- If morals clause = 'custom', must provide text
- Competitor exclusions must be non-empty if provided
Error Codes
Common validation error codes:
| Code | Description | Example Fix |
|---|---|---|
REQUIRED_FIELD | Missing required field | Add the field |
INVALID_ENUM | Invalid enum value | Use valid taxonomy value |
INVALID_FORMAT | Incorrect data format | Check type (string vs array) |
LOGICAL_CONFLICT | Conflicting values | Adjust incompatible settings |
MISSING_DEPENDENCY | Dependent field missing | Add required related field |
Warnings
Warnings indicate potential issues but don't prevent building:
const result = validateLicense(license);
if (result.valid && result.warnings?.length) {
result.warnings.forEach(warning => {
console.warn(`${warning.severity.toUpperCase()}: ${warning.message}`);
});
}Warning Types
High Severity:
- Unrestricted AI use without approval process
- Full exclusive without specified term
- Marketing data use without opt-in
Medium Severity:
- Global territory with short term
- UGC rights without content safety guardrails
- Perpetual term with auto-renewal
Low Severity:
- Missing attribution for commercial use
- No competitor exclusions for exclusive deals
- Sublicensing allowed without restrictions
Validation Examples
Valid License
const license = {
subject_scope: ['name', 'image'],
use_type: ['brand_marketing'],
commercial_scope: 'full_commercial',
exclusivity: 'none',
territory: { countries: ['US'] },
term: {
start_date: '2024-01-01',
end_date: '2025-12-31',
auto_renew: false
},
derivative_rights: 'limited',
ai_synthetic_use: 'prohibited',
data_use: { level: 'aggregated_anon' },
attribution: 'name_required',
sublicensing: 'prohibited',
content_safety: {
restricted_categories: ['adult', 'tobacco']
}
};
const result = validateLicense(license);
// result.valid = trueInvalid License (Missing Required Field)
const invalidLicense = {
subject_scope: ['name', 'image'],
// Missing required fields
};
const result = validateLicense(invalidLicense);
// result.valid = false
// result.errors = [
// { field: 'use_type', message: 'Required field missing', code: 'REQUIRED_FIELD' },
// { field: 'commercial_scope', ... },
// ...
// ]Invalid Enum Value
const license = {
subject_scope: ['name', 'invalid_value'], // ❌ Invalid
// ...
};
const result = validateLicense(license);
// result.valid = false
// result.errors = [
// {
// field: 'subject_scope',
// message: 'Invalid value: invalid_value',
// code: 'INVALID_ENUM',
// value: 'invalid_value'
// }
// ]Logical Conflict
const license = {
use_type: ['educational'], // ❌ Conflicts with commercial_scope
commercial_scope: 'full_commercial',
// ...
};
const result = validateLicense(license);
// result.valid = false
// result.errors = [
// {
// field: 'commercial_scope',
// message: 'Educational use requires non_commercial scope',
// code: 'LOGICAL_CONFLICT'
// }
// ]Safe Building with tryBuild()
The builder's tryBuild() method returns a result object instead of throwing:
const result = new NILLicenseBuilder()
.setSubjectScope(['name'])
.tryBuild();
if (!result.success) {
console.error('Validation errors:');
result.errors.forEach(err => {
console.error(`- ${err.field}: ${err.message}`);
});
process.exit(1);
}
const license = result.license;Best Practices
1. Always Validate
// ✅ Good: Validate before using
const license = builder.build();
const validation = validateLicense(license);
if (!validation.valid) {
throw new Error('Invalid license');
}
// ❌ Risky: Skip validation
const license = builder.build();
await saveToDB(license); // Might save invalid data2. Handle Warnings
const result = validateLicense(license);
if (result.valid) {
const highRiskWarnings = result.warnings?.filter(
w => w.severity === 'high'
);
if (highRiskWarnings?.length) {
// Require additional review for high-risk configs
await requestManagerApproval(license);
}
}3. Provide User Feedback
const result = validateLicense(userSubmittedLicense);
if (!result.valid) {
return {
success: false,
errors: result.errors.map(e => ({
field: e.field,
message: e.message
}))
};
}Validation in Forms
Example React form validation:
function LicenseForm() {
const [errors, setErrors] = useState<ValidationError[]>([]);
const handleSubmit = () => {
const license = buildLicenseFromForm();
const result = validateLicense(license);
if (!result.valid) {
setErrors(result.errors || []);
return;
}
// Proceed with valid license
saveLicense(license);
};
return (
<form>
{/* Form fields */}
{errors.length > 0 && (
<div className="errors">
{errors.map(err => (
<p key={err.field}>{err.field}: {err.message}</p>
))}
</div>
)}
</form>
);
}