Manifest Reference
Complete reference for the AppManifest schema used to declare application capabilities, dependencies, permissions, and configuration.
Overview
The manifest is a protobuf-based schema that apps provide during registration via the onRegister lifecycle hook. It declares:
- Identity: App name and authentication certificate
- Frontend: UI mode, assets, and navigation structure
- Backend: API routes, proxying rules, and permissions
- Dependencies: Required apps (HARD/SOFT) with version constraints
- Settings: Configurable parameters with validation and encryption
- Permissions: Required capabilities and exposed permissions
AppManifest (Root)
Based on easy.proto/v2/protos/manifest.proto:
interface AppManifest {
name: string // Unique app identifier (e.g., "todos", "crm")
certificate: Uint8Array // X.509 certificate for verification
web_app: WebApp // Frontend + API configuration
required_permissions: Permission[] // Requested capabilities
dependencies: DependencyRequirement[] // App dependencies
settings: SettingsSchema // Configuration schema
}
Example
{
name: "todos-app",
certificate: certificateBytes,
web_app: {
assets: [...],
ui: {...},
api: {...}
},
required_permissions: [...],
dependencies: [...],
settings: {...}
}
WebApp Structure
Combines frontend and backend contracts:
interface WebApp {
assets: Asset[] // Static files (JS, CSS, HTML, images, fonts)
ui?: UI // UI rendering contract (optional for API-only apps)
api: WebApi // API proxy contract (optional for UI-only apps)
}
Requirements:
- At least one of
uiorapimust be provided - Assets must include entry point referenced in
ui.entry_asset_name
Assets
Static files served by the UI engine:
interface Asset {
name: string // Filename (e.g., "remoteEntry.js", "styles.css")
mime_type: string // Content type (e.g., "application/javascript")
contents: Uint8Array // Raw file contents
signature: Uint8Array // Detached signature for verification
sha256: string // Hex-encoded SHA-256 hash
}
Supported MIME Types
JavaScript:
application/javascripttext/javascript
Stylesheets:
text/css
Markup:
text/html
Data:
application/json
Images:
image/png,image/jpeg,image/svg+xml,image/webp
Fonts:
font/woff2,font/woff
Example
{
name: "remoteEntry.js",
mime_type: "application/javascript",
contents: fileBuffer,
signature: signatureBytes,
sha256: "a3b2c1d4e5f6..."
}
UI Configuration
Based on easy.proto/v2/protos/ui.proto:
interface UI {
mode: UIMode // Loading mechanism
entry_asset_name: string // Entry point filename
exposed_module?: string // Module export (not for WEB_COMPONENT)
route_base: string // Mount path (e.g., "/apps/todos")
ssr: boolean // Server-side rendering support
navigation: NavigationRoute[] // Menu structure (max 3 levels)
}
enum UIMode {
FEDERATION // Webpack Module Federation (recommended)
WEB_COMPONENT // Custom HTML element
ESM_COMPONENT // ES module export
}
UI Modes
FEDERATION (Recommended):
{
mode: UIMode.FEDERATION,
entry_asset_name: "remoteEntry.js",
exposed_module: "./App",
route_base: "/apps/todos",
ssr: false
}
WEB_COMPONENT:
{
mode: UIMode.WEB_COMPONENT,
entry_asset_name: "component.js",
// exposed_module not used
route_base: "/apps/todos"
}
ESM_COMPONENT:
{
mode: UIMode.ESM_COMPONENT,
entry_asset_name: "main.js",
exposed_module: "TodosApp",
route_base: "/apps/todos"
}
Navigation Structure
3-level hierarchical navigation (Rail → Drawer → Collapsible):
interface NavigationRoute {
title: string // Display name (max 100 chars)
href: string // Route path (supports :params)
icon?: string // SVG string, URL, or data URI
required_permissions: string[] // Access control (empty = public)
children: NavigationRoute[] // Sub-routes (max 3 levels total)
metadata: Record<string, string> // Extensibility
}
Navigation Example
{
title: "Projects",
href: "/apps/todos/projects",
icon: "<svg>...</svg>",
required_permissions: ["todos:projects:read"],
children: [
{
title: "Active",
href: "/apps/todos/projects/active",
required_permissions: ["todos:projects:read"],
children: [
{
title: "High Priority",
href: "/apps/todos/projects/active/priority",
required_permissions: ["todos:projects:read"]
}
]
},
{
title: "Archived",
href: "/apps/todos/projects/archived",
required_permissions: ["todos:projects:read"]
}
]
}
Navigation Constraints
- Max Depth: 3 levels (Rail → Drawer → Collapsible)
- Title Length: Max 100 characters
- Path Format: Must start with
/, should start with app'sroute_base - Icon Format: SVG string, URL, or data URI
- Permissions: Empty array = public route
API Configuration
Based on easy.proto/v2/protos/api.proto:
interface WebApi {
base_path: string // Public proxy path (e.g., "/api/apps/todos")
upstream_base_url: string // Internal backend URL (e.g., "http://svc:8080")
strip_base_path: boolean // Remove base_path before forwarding (default: true)
timeout_ms: number // Request timeout in milliseconds
forward_headers: string[] // Header allowlist (lowercase)
routes: RouteSpec[] // Fine-grained routing rules
required_permissions: string[] // Access scopes
default_rate_limit: RateLimit // Global rate limits
health_check: HealthCheck // Upstream health monitoring
openapi_url?: string // API documentation URL
}
API Example
{
base_path: "/api/apps/todos",
upstream_base_url: "http://todos-bff.svc:8080",
strip_base_path: true,
timeout_ms: 30000,
forward_headers: ["authorization", "x-request-id", "content-type"],
routes: [
{
pattern: "/items/**",
methods: ["GET", "POST", "PUT", "DELETE"],
scopes: ["todos:items:read", "todos:items:write"],
timeout_ms: 5000,
rate_limit: { rpm: 100, burst: 20 }
},
{
pattern: "/public/**",
methods: ["GET"],
is_public: true // No authentication required
}
],
required_permissions: ["todos:api:access"],
default_rate_limit: { rpm: 60, burst: 10 },
health_check: {
path: "/health",
interval_seconds: 30,
timeout_ms: 5000,
unhealthy_threshold: 3
}
}
RouteSpec
Fine-grained routing rules:
interface RouteSpec {
pattern: string // Path pattern (prefix or regex)
methods: string[] // HTTP methods (GET, POST, PUT, PATCH, DELETE, etc.)
scopes: string[] // Required RBAC scopes
timeout_ms?: number // Route-specific timeout (overrides default)
rate_limit?: RateLimit // Route-specific limits (overrides default)
is_public: boolean // Skip authentication (default: false)
}
Pattern Types
Prefix Matching (/**):
pattern: "/items/**" // Matches /items, /items/1, /items/1/subtasks
Single Segment (/*):
pattern: "/items/*" // Matches /items/1, but not /items/1/subtasks
Regex (regex:):
pattern: "regex:^/items/\\d+$" // Matches /items/123
Exact:
pattern: "/items" // Only matches /items exactly
Rate Limiting
Request rate limits with burst capacity:
interface RateLimit {
rpm: number // Requests per minute
burst: number // Burst capacity for spikes
}
Hierarchical Application:
- RouteSpec.rate_limit (highest priority)
- WebApi.default_rate_limit (fallback)
- No limit (if neither configured)
Enforcement:
- Route-Level: Applied to all users (key:
route:{routeID}) - Per-User: Applied per authenticated user (key:
{subject}:route:{routeID})
Example
{
rpm: 100, // Allow 100 requests per minute
burst: 20 // Allow bursts up to 20 additional requests
}
Health Checks
Upstream service health monitoring:
interface HealthCheck {
path: string // Health endpoint (e.g., "/health")
interval_seconds: number // Check interval (default: 30)
timeout_ms: number // Check timeout (default: 5000)
unhealthy_threshold: number // Failures before unhealthy (default: 3)
}
Example
{
path: "/health",
interval_seconds: 30,
timeout_ms: 5000,
unhealthy_threshold: 3
}
Permissions
Resource-based access control:
interface Permission {
scope: string // Permission scope (e.g., "read_campaigns_any")
resource_type: string // Target resource (e.g., "campaigns")
reason: string // Request justification
requires_approval: boolean // Admin approval required (default: false)
}
Example
{
scope: "users:read",
resource_type: "users",
reason: "Access user data for profile display",
requires_approval: false
}
Dependencies
App dependencies with version constraints:
interface DependencyRequirement {
app_name: string // Dependent app identifier
kind: DependencyKind // HARD or SOFT
version_constraint?: string // Semantic versioning constraint
}
enum DependencyKind {
HARD // MUST be installed (blocks installation)
SOFT // CAN be installed (provides warnings)
}
Version Constraints
Exact Version:
version_constraint: "1.2.3"
Minimum Version:
version_constraint: ">=1.0.0"
Version Range:
version_constraint: ">=1.0.0 <2.0.0"
Patch Updates:
version_constraint: "~1.2.0" // 1.2.x
Minor + Patch Updates:
version_constraint: "^1.2.0" // 1.x.y
Dependency Example
{
app_name: "auth-service",
kind: DependencyKind.HARD,
version_constraint: ">=2.0.0 <3.0.0"
}
Settings Schema
Configurable parameters with validation:
interface SettingsSchema {
definitions: SettingDefinition[]
}
interface SettingDefinition {
key: string // Setting identifier (unique per app)
data_type: SettingDataType // Value type
required: boolean // Mandatory flag (default: false)
default_value?: string // JSON-encoded default
validation: ValidationRules // Constraints
description: string // User-facing help
sensitive: boolean // Encryption flag (default: false)
ui_hints: UIHints // Form generation hints
}
Data Types
enum SettingDataType {
STRING // Optional string
STRING_REQUIRED // Required string
INT // Optional integer
INT_REQUIRED // Required integer
FLOAT // Optional float
FLOAT_REQUIRED // Required float
BOOL // Optional boolean
BOOL_REQUIRED // Required boolean
STRING_ARRAY // Array of strings
INT_ARRAY // Array of integers
FLOAT_ARRAY // Array of floats
BOOL_ARRAY // Array of booleans
JSON // Optional JSON object
JSON_REQUIRED // Required JSON object
KVPAIR_ARRAY // Array of {key, value} pairs
}
Validation Rules
interface ValidationRules {
min_length?: number // String minimum length
max_length?: number // String maximum length
min?: number // Numeric minimum value
max?: number // Numeric maximum value
pattern?: string // Regex pattern
enum?: string[] // Allowed values
}
UI Hints
interface UIHints {
input_type?: string // Form control type
placeholder?: string // Field placeholder
help_text?: string // Field help text
multiline?: boolean // Textarea mode
step?: number // Numeric step
options?: string[] // Select options
}
Input Types:
text- Single-line text inputpassword- Password field (masked)textarea- Multi-line textselect- Dropdown selectnumber- Numeric inputcheckbox- Boolean checkboxradio- Radio button group
Settings Example
{
definitions: [
{
key: "api_key",
data_type: SettingDataType.STRING_REQUIRED,
required: true,
validation: {
min_length: 8,
max_length: 64,
pattern: "^[A-Za-z0-9_-]+$"
},
description: "API key for external service",
sensitive: true,
ui_hints: {
input_type: "password",
placeholder: "Enter your API key",
help_text: "Contact support to obtain an API key"
}
},
{
key: "max_connections",
data_type: SettingDataType.INT,
default_value: "10",
validation: {
min: 1,
max: 100
},
description: "Maximum database connections",
ui_hints: {
input_type: "number",
step: 1
}
},
{
key: "environment",
data_type: SettingDataType.STRING_REQUIRED,
required: true,
validation: {
enum: ["development", "staging", "production"]
},
description: "Deployment environment",
ui_hints: {
input_type: "select",
options: ["development", "staging", "production"]
}
}
]
}
Complete Manifest Example
const manifest: AppManifest = {
name: "todos-app",
certificate: certificateBytes,
web_app: {
assets: [
{
name: "remoteEntry.js",
mime_type: "application/javascript",
contents: remoteEntryBuffer,
signature: signatureBytes,
sha256: "a3b2c1..."
},
{
name: "styles.css",
mime_type: "text/css",
contents: stylesBuffer,
signature: signatureBytes,
sha256: "d4e5f6..."
}
],
ui: {
mode: UIMode.FEDERATION,
entry_asset_name: "remoteEntry.js",
exposed_module: "./App",
route_base: "/apps/todos",
ssr: false,
navigation: [
{
title: "Projects",
href: "/apps/todos/projects",
icon: "<svg>...</svg>",
required_permissions: ["todos:projects:read"],
children: [
{
title: "Active",
href: "/apps/todos/projects/active",
required_permissions: ["todos:projects:read"]
}
]
}
]
},
api: {
base_path: "/api/apps/todos",
upstream_base_url: "http://todos-bff.svc:8080",
strip_base_path: true,
timeout_ms: 30000,
forward_headers: ["authorization", "x-request-id"],
routes: [
{
pattern: "/items/**",
methods: ["GET", "POST", "PUT", "DELETE"],
scopes: ["todos:items:read", "todos:items:write"],
timeout_ms: 5000,
rate_limit: { rpm: 100, burst: 20 }
}
],
required_permissions: ["todos:api:access"],
default_rate_limit: { rpm: 60, burst: 10 },
health_check: {
path: "/health",
interval_seconds: 30,
timeout_ms: 5000,
unhealthy_threshold: 3
}
}
},
required_permissions: [
{
scope: "users:read",
resource_type: "users",
reason: "Access user data for task assignments",
requires_approval: false
}
],
dependencies: [
{
app_name: "auth-service",
kind: DependencyKind.HARD,
version_constraint: ">=2.0.0 <3.0.0"
},
{
app_name: "analytics",
kind: DependencyKind.SOFT,
version_constraint: ">=1.0.0"
}
],
settings: {
definitions: [
{
key: "database_url",
data_type: SettingDataType.STRING_REQUIRED,
required: true,
description: "PostgreSQL connection URL",
sensitive: true,
ui_hints: {
input_type: "password",
placeholder: "postgresql://user:pass@host:5432/db"
}
}
]
}
}
Validation Rules
Manifest-Level
- name: Must be unique across all apps
- certificate: Valid X.509 certificate required
- web_app: At least one of
uiorapimust be provided
UI-Level
- entry_asset_name: Must reference an asset in
web_app.assets - route_base: Must start with
/ - navigation: Max 3 levels deep
- navigation.title: Max 100 characters
- navigation.href: Must start with
/
API-Level
- base_path: Must start with
/ - upstream_base_url: Valid URL required
- timeout_ms: Must be > 0
- routes.pattern: Valid regex if using
regex:prefix - routes.methods: At least one method required
Settings-Level
- key: Must be unique within app
- data_type: Must be valid SettingDataType
- default_value: Must validate against rules
- validation.pattern: Must be valid regex if provided
- validation.min/max: Min must be less than or equal to max if both provided
Proto File Locations
- Main Manifest:
easy.proto/v2/protos/manifest.proto - UI Configuration:
easy.proto/v2/protos/ui.proto - API Configuration:
easy.proto/v2/protos/api.proto - Common Types:
easy.proto/v2/protos/common.proto
Related Topics
- Node.js SDK Manifest Building - SDK helpers for building manifests
- Marketplace Feature - App registration process
- Settings Service - Settings implementation
- UI Engine - Microfrontend serving
- HTTP Proxy & Routing - API proxying