@servlyadmin/runtime-core
Framework-agnostic core renderer for Servly components. This package provides the foundation for rendering Servly components in any JavaScript environment.
Installation
npm install @servlyadmin/runtime-core
yarn add @servlyadmin/runtime-core
pnpm add @servlyadmin/runtime-core
Quick Start
import { render, fetchComponent } from '@servlyadmin/runtime-core';
const { data } = await fetchComponent('my-component-id');
const result = render({
container: document.getElementById('app'),
elements: data.layout,
context: {
props: { title: 'Hello World' },
state: {},
context: {},
},
});
result.update({
props: { title: 'Updated Title' },
state: {},
context: {},
});
result.destroy();
Registry Configuration
By default, components are fetched from Servly's production registry:
- Default URL:
https://core-api.servly.app/v1/views/registry
You can override this if you have a custom registry:
import { setRegistryUrl } from '@servlyadmin/runtime-core';
setRegistryUrl('https://your-api.com/v1/views/registry');
Cache Strategies
The runtime supports three caching strategies to optimize component loading:
localStorage | Persists across browser sessions | Yes | Production apps (default) |
memory | In-memory cache, cleared on page refresh | No | Development, SSR |
none | No caching, always fetches fresh | No | Testing, debugging |
Default: localStorage - Components are cached in the browser's localStorage for fast subsequent loads.
const { data } = await fetchComponent('my-component');
const { data } = await fetchComponent('my-component', {
cacheStrategy: 'memory',
});
const { data } = await fetchComponent('my-component', {
forceRefresh: true,
});
Core Concepts
Layout Elements
Components are defined as a tree of layout elements:
interface LayoutElement {
i: string;
componentId: string;
configuration?: {
classNames?: string;
style?: Record<string, any>;
text?: string;
};
children?: string[];
parent?: string;
}
Binding Context
Data is passed to components through a binding context:
interface BindingContext {
props: Record<string, any>;
state: Record<string, any>;
context: Record<string, any>;
}
Template Bindings
Use {{path}} syntax to bind data:
const elements = [
{
i: 'greeting',
componentId: 'text',
configuration: {
text: 'Hello, {{props.name}}!',
classNames: '{{props.className}}',
},
},
];
API Reference
render(options)
Renders elements to a container.
const result = render({
container: HTMLElement,
elements: LayoutElement[],
context: BindingContext,
eventHandlers?: Record<string, Record<string, (e: Event) => void>>,
});
interface RenderResult {
update(context: BindingContext): void;
destroy(): void;
getElement(id: string): HTMLElement | null;
}
fetchComponent(id, options?)
Fetches a component from the registry.
const { data, fromCache, version } = await fetchComponent('component-id', {
version: 'latest',
cacheStrategy: 'localStorage',
forceRefresh: false,
retryConfig: {
maxRetries: 3,
initialDelay: 1000,
maxDelay: 10000,
backoffMultiplier: 2,
},
});
setRegistryUrl(url)
Configure a custom registry URL.
import { setRegistryUrl, DEFAULT_REGISTRY_URL } from '@servlyadmin/runtime-core';
setRegistryUrl('https://your-api.com/v1/views/registry');
setRegistryUrl(DEFAULT_REGISTRY_URL);
StateManager
Manages component state with subscriptions.
import { StateManager } from '@servlyadmin/runtime-core';
const stateManager = new StateManager({ count: 0 });
stateManager.set('count', 1);
stateManager.get('count');
stateManager.set('user.name', 'John');
const unsubscribe = stateManager.subscribe((event) => {
console.log('State changed:', event.path, event.value);
});
stateManager.clear();
EventSystem
Handles events with plugin-based actions.
import { EventSystem, getEventSystem } from '@servlyadmin/runtime-core';
const eventSystem = getEventSystem();
eventSystem.registerPlugin('my-action', async (action, context) => {
console.log('Action executed with:', action.config);
});
Built-in Plugins
executeCode - Execute arbitrary JavaScript code
state-setState - Update state values
navigateTo - Navigate to URL
localStorage-set/get/remove - LocalStorage operations
sessionStorage-set/get - SessionStorage operations
alert - Show alert dialog
console-log - Log to console
clipboard-copy - Copy text to clipboard
scrollTo - Scroll to element
focus/blur - Focus/blur elements
addClass/removeClass/toggleClass - CSS class manipulation
setAttribute/removeAttribute - Attribute manipulation
dispatchEvent - Dispatch custom events
delay - Add delay between actions
Cache Management
import {
clearAllCaches,
clearMemoryCache,
clearLocalStorageCache,
getMemoryCacheSize
} from '@servlyadmin/runtime-core';
clearAllCaches();
clearMemoryCache();
clearLocalStorageCache();
const size = getMemoryCacheSize();
Bindings
Template resolution utilities.
import { resolveTemplate, hasTemplateSyntax } from '@servlyadmin/runtime-core';
const context = {
props: { name: 'World', count: 42 },
state: {},
context: {},
};
resolveTemplate('Hello, {{props.name}}!', context);
hasTemplateSyntax('{{props.name}}');
hasTemplateSyntax('static text');
Slots
Components can define slots for content injection:
const elements = [
{
i: 'card',
componentId: 'container',
configuration: { classNames: 'card' },
children: ['header-slot', 'content-slot'],
},
{
i: 'header-slot',
componentId: 'slot',
configuration: {
slotName: 'header',
},
parent: 'card',
},
{
i: 'content-slot',
componentId: 'slot',
configuration: {
slotName: 'default',
},
parent: 'card',
},
];
Framework wrappers handle slot content injection automatically.
TypeScript Support
Full TypeScript support with exported types:
import type {
LayoutElement,
BindingContext,
RenderResult,
RenderOptions,
ComponentData,
CacheStrategy,
RetryConfig,
FetchOptions,
FetchResult,
} from '@servlyadmin/runtime-core';
Browser Support
- Chrome 80+
- Firefox 75+
- Safari 13+
- Edge 80+
License
MIT