# Pandino
> OSGi-Style modular framework for TypeScript providing dynamic service discovery, bundle system, and declarative dependency injection.
## Overview
Pandino brings OSGi concepts to TypeScript. It provides a central service registry where services are registered by interface name and discovered dynamically using LDAP filter expressions. Applications are structured as bundles -- self-contained modules with independent lifecycles. The Service Component Runtime (SCR) activates decorated classes and resolves their dependencies automatically.
Pandino runs in the browser and in Node.js. It works standalone or with React via dedicated hooks.
## Packages
- @pandino/pandino: Core framework with service registry, bundle system, EventAdmin, ConfigurationAdmin, LogService, and SCR
- @pandino/decorators: TypeScript decorators for declarative service components (@Component, @Service, @Reference, @Activate, @Deactivate, @Modified, @Property, @ConfigurationPolicy, @Factory, @Immediate, @Scope)
- @pandino/react-hooks: React integration with hooks (useService, useServiceTracker, useRegisterService, useBundle, useBundleContext) and components (PandinoProvider, ServiceConsumer, ComponentProxy, BundleInfo)
- @pandino/rollup-bundle-plugin: Rollup/Vite plugin that auto-discovers @Component classes and emits Pandino bundle modules at build time
## Installation
Core only:
npm install @pandino/pandino reflect-metadata
With decorators:
npm install @pandino/pandino @pandino/decorators reflect-metadata
With React:
npm install @pandino/pandino @pandino/react-hooks reflect-metadata
Build plugin:
npm install -D @pandino/rollup-bundle-plugin
TypeScript requirements:
experimentalDecorators: true
emitDecoratorMetadata: true
## Documentation
- [What is Pandino?](https://blackbelttechnology.github.io/pandino/introduction/what-is-pandino)
- [Getting Started](https://blackbelttechnology.github.io/pandino/introduction/getting-started)
- [Architecture](https://blackbelttechnology.github.io/pandino/introduction/architecture)
- [Core Framework Guide](https://blackbelttechnology.github.io/pandino/guide/core-framework)
- [Decorators Guide](https://blackbelttechnology.github.io/pandino/guide/decorators)
- [React Hooks Guide](https://blackbelttechnology.github.io/pandino/guide/react-hooks)
- [Rollup Plugin Guide](https://blackbelttechnology.github.io/pandino/guide/rollup-plugin)
- [Services Concept](https://blackbelttechnology.github.io/pandino/concepts/services)
- [Bundles Concept](https://blackbelttechnology.github.io/pandino/concepts/bundles)
- [Declarative Services](https://blackbelttechnology.github.io/pandino/concepts/declarative-services)
- [Configuration](https://blackbelttechnology.github.io/pandino/concepts/configuration)
- [Events](https://blackbelttechnology.github.io/pandino/concepts/events)
- [Extender Pattern](https://blackbelttechnology.github.io/pandino/patterns/extender-pattern)
- [Whiteboard Pattern](https://blackbelttechnology.github.io/pandino/patterns/whiteboard-pattern)
- [Fragment Pattern](https://blackbelttechnology.github.io/pandino/patterns/fragment-pattern)
- [API Reference: Core](https://blackbelttechnology.github.io/pandino/api/core)
- [API Reference: Decorators](https://blackbelttechnology.github.io/pandino/api/decorators)
- [API Reference: React Hooks](https://blackbelttechnology.github.io/pandino/api/react-hooks)
- [API Reference: Rollup Plugin](https://blackbelttechnology.github.io/pandino/api/rollup-plugin)
## Key Concepts
### Service Registration
Services are registered in a central registry under interface names with optional metadata properties:
context.registerService('DatabaseService', impl, { 'db.type': 'mysql', 'service.ranking': 100 });
Consumers discover services by interface and LDAP filter expressions:
const refs = context.getServiceReferences('DatabaseService', '(db.type=mysql)');
const service = context.getService(refs[0]);
Higher service.ranking values take priority when multiple services match.
Common LDAP filter forms:
(key=value) -- equality
(key>=value) -- greater-or-equal
(&(a=1)(b=2)) -- AND
(|(a=1)(b=2)) -- OR
(!(key=value)) -- NOT
### Bundle System
Bundles are self-contained modules with BundleActivator (start/stop lifecycle):
export default {
headers: { bundleSymbolicName: 'com.example.db', bundleVersion: '1.0.0' },
activator: { start(ctx) { ctx.registerService(...) }, stop() {} },
components: [MyComponent],
};
Bundle lifecycle states: INSTALLED -> RESOLVED -> STARTING -> ACTIVE -> STOPPING -> UNINSTALLED.
Bundles can be installed at bootstrap via PandinoProvider bundles prop, via context.installBundle(), or auto-generated by @pandino/rollup-bundle-plugin.
Fragment bundles attach to a host via the fragmentHost header and contribute components/resources.
### Declarative Services (SCR)
Classes decorated with @Component and @Service are activated by the Service Component Runtime. Dependencies declared with @Reference are injected automatically:
@Component({ name: 'order.service', immediate: true })
@Service({ interfaces: ['OrderService'] })
class OrderServiceImpl {
@Reference({ interface: 'UserService' })
private userService?: UserService;
@Activate
activate(context: ComponentContext): void { }
}
Lifecycle callbacks: @Activate (receives ComponentContext), @Deactivate, @Modified (on config change).
@Reference options:
interface: string -- service interface to bind
cardinality: '1..1' | '0..1' | '1..n' | '0..n'
policy: 'static' | 'dynamic'
target: string -- LDAP filter for the reference
Configuration policies: 'optional' (default), 'require', 'ignore'.
Service scopes: 'singleton' (default), 'bundle', 'prototype'.
### Built-in Services
- LogService: Centralized logging (error, warn, info, debug). Obtain via context.getServiceReference('LogService').
- EventAdmin: Topic-based pub/sub. sendEvent (sync), postEvent (async). Subscribe by registering EventHandler with event.topics property.
- ConfigurationAdmin: Runtime config. getConfiguration(pid), config.update(props). ManagedService receives updates via updated() callback.
- ServiceTracker: Tracks matching services with addingService/modifiedService/removedService callbacks.
- ServiceComponentRuntime: Activates @Component classes. Usually automatic; manual via scr.registerComponent(Class, bundleId).
### React Integration
PandinoProvider bootstraps the framework and installs bundles:
useService(interface, filter?) resolves a single service. Returns { service, loading, error }.
useServiceTracker(interface, filter?) tracks all matching services. Returns { services, loading, error }.
useRegisterService(interface, impl, properties?) registers a service for the component's lifetime.
useBundle(idOrName) returns a bundle by id or symbolic name.
useBundleContext() returns the raw BundleContext.
Components: ServiceConsumer (render prop), ComponentProxy (renders a service as a React component), BundleInfo (shows bundle details).
### Rollup/Vite Build Plugin
Auto-discovers @Component decorated classes and produces BundleModule:
import pandinoBundle from '@pandino/rollup-bundle-plugin';
pandinoBundle({ virtualId: 'pandino:bundle:alpha', include: ['src/alpha/**/*.ts'] });
Consume via import('pandino:bundle:alpha'). Call once per bundle.
## License
Eclipse Public License - v 2.0