As of version 1054, TizenPortal uses a unified registry system for managing both features (core enhancements maintained by the project team) and userscripts (user-contributed scripts). This architectural change provides consistency, reduces complexity, and enhances the bundle author experience.
The unified registry (features/registry.js) manages all items with a consistent structure:
{
id: 'unique-identifier',
type: 'feature' | 'userscript',
name: 'internalName',
displayName: 'Display Name',
category: 'category',
description: 'Short description',
defaultEnabled: false,
// Feature-specific (type='feature')
configKeys: ['config', 'keys'],
implementation: { apply(), remove() },
applyArgs: function(config) { return []; },
// Userscript-specific (type='userscript')
source: 'inline' | 'url',
inline: 'script code',
url: 'https://...',
provides: ['feature-name'],
}
Registry items are organized into categories for UI grouping:
Feature Categories:
core - Core functionalitystyling - Visual enhancementsnavigation - Navigation improvementsperformance - Performance optimizationsUserscript Categories:
accessibility - Accessibility enhancementsreading - Reading mode scriptsvideo - Video enhancementsprivacy - Privacy toolsexperimental - Experimental featuresThe unified registry is exposed via:
TizenPortal.registry - Main registry accessTizenPortal.features.registry - Same instance (for feature context)TizenPortal.userscripts.registry - Same instance (for userscript context)Core Methods:
// Registration
TizenPortal.registry.register(itemDef) // Register a new item
// Unified Query API - Single method with optional filters
TizenPortal.registry.query(filters) // Query with filters: { type, category, id }
TizenPortal.registry.query() // Get all items (no filters)
TizenPortal.registry.query({ type: 'feature' }) // Get all features
TizenPortal.registry.query({ type: 'userscript' }) // Get all userscripts
TizenPortal.registry.query({ category: 'styling' }) // Get items by category
TizenPortal.registry.query({ type: 'feature', category: 'styling' }) // Features in category
TizenPortal.registry.query({ id: 'focusStyling' }) // Get specific item
// Convenience methods (delegate to query)
TizenPortal.registry.getAll() // query()
TizenPortal.registry.getById(id) // query({ id })
TizenPortal.registry.getByType(type) // query({ type })
TizenPortal.registry.getByCategory(category, type) // query({ category, type })
TizenPortal.registry.getFeatures() // query({ type: 'feature' })
TizenPortal.registry.getUserscripts() // query({ type: 'userscript' })
TizenPortal.registry.getFeaturesByCategory(cat) // query({ type: 'feature', category })
TizenPortal.registry.getUserscriptsByCategory(cat) // query({ type: 'userscript', category })
// Validation
TizenPortal.registry.checkConflicts(enabledIds) // Check for conflicts
// Constants
TizenPortal.registry.ITEM_TYPES // { FEATURE, USERSCRIPT }
TizenPortal.registry.CATEGORIES // Category constants
query(filters) with optional filter parametersquery()Existing APIs are fully maintained:
// Features API (unchanged)
TizenPortal.features.apply(doc, overrides)
TizenPortal.features.remove(doc)
TizenPortal.features.getAll()
TizenPortal.features.getConfig()
TizenPortal.features.getDefaults()
// Userscripts API (unchanged)
TizenPortal.userscripts.getConfig()
TizenPortal.userscripts.setConfig(cfg)
TizenPortal.userscripts.apply(card, bundle)
TizenPortal.userscripts.clear()
TizenPortal.userscripts.getEnabled()
TizenPortal.userscripts.getForPayload()
import Registry from './registry.js';
import myFeature from './my-feature.js';
Registry.register({
id: 'myFeature',
type: Registry.ITEM_TYPES.FEATURE,
name: 'myFeature',
displayName: 'My Feature',
category: Registry.CATEGORIES.STYLING,
description: 'My awesome feature',
defaultEnabled: true,
configKeys: ['myFeature', 'myFeatureMode'],
implementation: myFeature,
applyArgs: function(config) {
return [config.myFeatureMode || 'default'];
},
});
import Registry from './registry.js';
Registry.register({
id: 'my-userscript',
type: Registry.ITEM_TYPES.USERSCRIPT,
name: 'My Userscript',
displayName: 'My Userscript',
category: Registry.CATEGORIES.ACCESSIBILITY,
description: 'My awesome userscript',
defaultEnabled: false,
source: 'inline',
inline: '(function() { /* code */ })();',
provides: ['my-feature'],
});
query(filters) pattern throughout// Get all items
const all = TizenPortal.registry.query();
// Get all features
const features = TizenPortal.registry.query({ type: 'feature' });
// Get all userscripts
const userscripts = TizenPortal.registry.query({ type: 'userscript' });
// Get items in a category (both types)
const stylingItems = TizenPortal.registry.query({ category: 'styling' });
// Get features in a category
const stylingFeatures = TizenPortal.registry.query({
type: 'feature',
category: 'styling'
});
// Get userscripts in a category
const accessibilityScripts = TizenPortal.registry.query({
type: 'userscript',
category: 'accessibility'
});
// Get a specific item
const focusStyling = TizenPortal.registry.query({ id: 'focusStyling' })[0];
// Or use convenience method
const focusStyling = TizenPortal.registry.getById('focusStyling');
No migration is required for existing code. The unified registry system maintains full backward compatibility with the existing TizenPortal.features and TizenPortal.userscripts APIs.
New code should use the unified query() API for consistency and clarity.
File Structure:
features/registry.js - Unified registry implementation with query APIfeatures/index.js - Feature loader (uses registry)features/userscript-registry.js - Userscript definitions (uses registry)core/index.js - API exposureRegistration Count:
Key Design Decisions:
query(filters) method handles all queriesquery()provides array