tizenportal

TizenPortal Bundle Manifest Schema

Version: 1.0
Date: February 11, 2026
Status: Implemented Schema
Runtime Support: This schema is enforced by the TizenPortal bundle manifest validator; the current supported schema version is 1.0.


Overview

This document defines the complete schema for bundle manifest.json files. The manifest serves as the single source of truth for bundle metadata, configuration options, and runtime behavior.


Complete Schema

{
  "name": "string (required)",
  "displayName": "string (required)",
  "version": "string (required)",
  "author": "string (optional)",
  "description": "string (required)",
  "homepage": "string (optional)",
  "requires": ["string array (optional)"],
  "provides": ["string array (optional)"],
  "navigationMode": "string | object (optional)",
  "viewportLock": "string | boolean (optional)",
  "options": ["array of option objects (optional)"],
  "features": "object (optional)"
}

Field Definitions

Core Metadata

name (string, required)

displayName (string, required)

version (string, required)

author (string, optional)

description (string, required)

homepage (string, optional)


Capabilities

requires (array of strings, optional)

provides (array of strings, optional)


Mode Descriptions:


Viewport Configuration

viewportLock (string | boolean, optional)

Values:


Bundle Options

options (array of objects, optional)

Option Object Schema:

{
  "key": "string (required)",
  "label": "string (required)",
  "type": "string (required)",
  "default": "any (optional)",
  "placeholder": "string (optional)",
  "description": "string (optional)",
  "validation": "object (optional)"
}

Option Types:

Example:

"options": [
  {
    "key": "strict",
    "label": "Strict Mode",
    "type": "toggle",
    "default": false,
    "description": "Enable stricter ad blocking rules"
  },
  {
    "key": "allowlistUrl",
    "label": "Allowlist URL",
    "type": "url",
    "placeholder": "https://example.com/allowlist.txt",
    "description": "URL to custom allowlist file"
  },
  {
    "key": "hideCookieBanners",
    "label": "Hide Cookie Banners",
    "type": "toggle",
    "default": false,
    "description": "Automatically hide cookie consent banners"
  }
]

Access in Bundle:

onActivate(window, card) {
  const options = card.bundleOptions || {};
  const strictMode = options.strict !== undefined ? options.strict : false;
  const allowlistUrl = card.bundleOptionData?.allowlistUrl || '';
  
  if (strictMode) {
    // Apply strict rules
  }
  
  if (allowlistUrl) {
    // Load allowlist from URL
  }
}

Feature Overrides

features (object, optional)

Available Features:

"features": {
  "focusStyling": true,
  "focusOutlineMode": "on",
  "focusTransitions": true,
  "focusTransitionMode": "slide",
  "focusTransitionSpeed": "medium",
  "tabindexInjection": true,
  "scrollIntoView": true,
  "safeArea": false,
  "gpuHints": true,
  "cssReset": true,
  "hideScrollbars": false,
  "wrapTextInputs": true,
  "uaMode": "tizen"
}

Example:

"features": {
  "tabindexInjection": false,
  "scrollIntoView": false,
  "hideScrollbars": true
}

Priority: Card override > Bundle default > Global preference


Complete Examples

Minimal Bundle

{
  "name": "my-bundle",
  "displayName": "My Bundle",
  "version": "1.0.0",
  "description": "Basic bundle with focus styling and navigation"
}

Feature Bundle with Options

{
  "name": "adblock",
  "displayName": "Ad Blocker",
  "version": "1.0.0",
  "author": "TizenPortal",
  "description": "Blocks advertisements and tracking scripts for cleaner browsing",
  "provides": ["ad-blocking", "tracker-blocking", "cookie-banner-hiding"],
  "navigationMode": "geometric",
  "viewportLock": false,
  "options": [
    {
      "key": "strict",
      "label": "Strict Mode",
      "type": "toggle",
      "default": false,
      "description": "Enable stricter ad blocking rules"
    },
    {
      "key": "allowlistUrl",
      "label": "Allowlist URL",
      "type": "url",
      "placeholder": "https://example.com/allowlist.txt",
      "description": "URL to custom allowlist file"
    },
    {
      "key": "hideCookieBanners",
      "label": "Hide Cookie Banners",
      "type": "toggle",
      "default": false,
      "description": "Automatically hide cookie consent banners"
    },
    {
      "key": "inlineHeuristics",
      "label": "Inline Ad Heuristics",
      "type": "toggle",
      "default": true,
      "description": "Use heuristics to detect inline ad scripts"
    }
  ],
  "features": {
    "cssReset": false,
    "hideScrollbars": false
  }
}

Site-Specific Bundle

{
  "name": "audiobookshelf",
  "displayName": "Audiobookshelf",
  "version": "1.0.0",
  "author": "TizenPortal",
  "description": "Media controls, library navigation, and player integration for Audiobookshelf",
  "homepage": "https://www.audiobookshelf.org/",
  "requires": ["focus-styling", "media-keys"],
  "provides": ["media-controls", "library-navigation", "player-integration"],
  "navigationMode": {
    "mode": "directional",
    "required": false
  },
  "viewportLock": "force",
  "features": {
    "tabindexInjection": true,
    "scrollIntoView": true,
    "wrapTextInputs": true
  }
}

Implementation Notes

Loading Manifest at Build Time

The manifest should be loaded during the Rollup build and merged with the bundle object:

// rollup.config.js
function generateBundleRegistry() {
  // ... existing code ...
  
  for (var j = 0; j < bundleDirs.length; j++) {
    var name = bundleDirs[j];
    var manifestPath = path.join(bundlesDir, name, 'manifest.json');
    
    if (existsSync(manifestPath)) {
      var manifestContent = readFileSync(manifestPath, 'utf-8');
      // Manifest will be imported and merged at runtime
    }
  }
}

Accessing Manifest in Bundle

// In bundle main.js lifecycle hooks
export default {
  // manifest will be attached automatically at runtime
  
  onActivate(window, card) {
    // Access via this.manifest
    const manifest = this.manifest;
    console.log('Bundle:', manifest.displayName);
    console.log('Version:', manifest.version);
    
    // Or access via bundle reference
    const bundle = TizenPortal.loader.getActiveBundle();
    console.log('Navigation mode:', bundle.manifest.navigationMode);
  }
}

Validation

Runtime should validate manifests on load:


Migration Path

Status: ✅ All phases complete!

Phase 1: Add Manifest Loading ✅ Complete

Phase 2: Move Metadata ✅ Complete

Phase 3: Move Configuration ✅ Complete

Phase 4: Add Features ✅ Complete

manifest.json is now the single source of truth for all bundle configuration.


See Also