Getting Started

Uplink Protocol

A framework-agnostic protocol for building reusable frontend logic that works across UI frameworks.

ReactVueSvelteVanilla JS

Uplink Protocol: Write Once, Use Everywhere

The Uplink Protocol is a comprehensive system for building UI-agnostic logic that can be reused across different frontend frameworks. It solves the problem of duplicating business logic when working with multiple frameworks or migrating between them.

With Uplink, you can write your core functionality once and then use it with React, Vue, Svelte, or plain JavaScript without any rewrites.

Uplink takes a declarative approach to application logic, allowing developers to define controllers, bindings, and events independently of the UI layer. This results in cleaner separation of concerns, improved testability, and enhanced code reuse.

Reusable Controllers

Create standalone logic controllers with state management that can be used with any UI framework.

Reactive Bindings

Powerful reactive state containers with subscription capabilities that automatically sync UI with underlying state.

Adapter System

Seamless integration with different UI frameworks through a flexible adapter system that speaks the native language of each framework.

Event Emitters

Rich event system for communicating between components and handling user interactions across frameworks.

Type Safety

Full TypeScript support with strong typing for controllers, bindings, and events for improved developer experience.

ESM Modules

Modern ECMAScript Module format for better tree-shaking and more efficient loading.

Installation

Install the core package :

npm
1 npm install @uplink-protocol/core

Install along framework-specific adapters you need :

npm
1 npm install @uplink-protocol/react // or /vue or /svelte or /angular

Protocol Architecture

The Uplink Protocol follows a layered architecture designed for maximum flexibility and reusability:

1. Core Protocol Layer

This layer defines the fundamental interfaces and models that make up the foundation of the protocol:

  • Controllers: Encapsulate business logic and state management
  • Bindings: Reactive state containers with subscription capabilities
  • Event Emitters: Communication channels for broadcasting state changes

2. Adapter Layer

The adapter layer bridges the protocol with specific UI frameworks, translating between protocol operations and framework patterns:

  • Framework Adapters: Connect controllers to specific UI frameworks
  • Adapter Registry: Manages all available adapters
  • Controller Adapter: Provides a unified interface for controllers

3. Integration Layer

The top layer provides framework-specific APIs and hooks for a seamless developer experience:

  • Framework Hooks: useUplink() for React, Vue composables, etc.
  • Integration Utilities: Tools for connecting controllers to framework components
  • Component Bindings: Pre-built UI connections for common patterns

Basic Usage

Creating and using controllers with the Uplink Protocol follows a simple pattern:

Creating a Controller
1import { StandardBinding, EventEmitter } from '@uplink-protocol/core';
2
3class CounterController {
4 constructor() {
5 // Bindings hold reactive state
6 this.bindings = {
7 count: new StandardBinding(0),
8 isEven: new StandardBinding(true)
9 };
10
11 // Methods define controller behavior
12 this.methods = {
13 increment: () => {
14 const newCount = this.bindings.count.current + 1;
15 this.bindings.count.set(newCount);
16 this.bindings.isEven.set(newCount % 2 === 0);
17 this.events.increment.emit(newCount);
18 },
19
20 decrement: () => {
21 const newCount = this.bindings.count.current - 1;
22 this.bindings.count.set(newCount);
23 this.bindings.isEven.set(newCount % 2 === 0);
24 this.events.decrement.emit(newCount);
25 },
26
27 reset: () => {
28 this.bindings.count.set(0);
29 this.bindings.isEven.set(true);
30 }
31 };
32
33 // Events for notifying external systems
34 this.events = {
35 increment: new EventEmitter(),
36 decrement: new EventEmitter()
37 };
38 }
39}

Framework Integration Examples

React
Vue
Svelte
Vanilla JS
1import { useUplink } from '@uplink-protocol/react';
2import { CounterController } from './counter.controller';
3import { useEffect } from 'react';
4
5// Initialize adapter at app entry point
6// import { initializeReactAdapter } from '@uplink-protocol/react';
7// initializeReactAdapter();
8
9function CounterComponent() {
10 // Use the controller with React
11 const { state, methods, events } = useUplink(new CounterController());
12
13 useEffect(() => {
14 // Subscribe to events if needed
15 const unsubscribe = events.increment.subscribe((count) => {
16 console.log(`Counter incremented to ${count}`);
17 });
18
19 return () => unsubscribe();
20 }, [events]);
21
22 return (
23 <div>
24 <h2>Counter: {state.count}</h2>
25 <p>The count is {state.isEven ? 'even' : 'odd'}</p>
26 <button onClick={methods.increment}>Increment</button>
27 <button onClick={methods.decrement}>Decrement</button>
28 <button onClick={methods.reset}>Reset</button>
29 </div>
30 );
31}

Advanced Features

Typed Controllers

When using TypeScript, you can leverage the TypedController interface for strong typing:

1import { TypedController, Binding, EventEmitter, StandardBinding } from '@uplink-protocol/core';
2
3// Define your specific controller types
4interface CounterBindings {
5 count: Binding<number>;
6 isEven: Binding<boolean>;
7}
8
9interface CounterMethods {
10 increment(): void;
11 decrement(): void;
12 reset(): void;
13}
14
15interface CounterEvents {
16 increment: EventEmitter<number>;
17 decrement: EventEmitter<number>;
18}
19
20// Implement with strong typing
21class CounterController implements TypedController<CounterBindings, CounterMethods, CounterEvents> {
22 // ... implementation
23}

Custom Adapters

You can create custom adapters for specific frameworks or use cases:

1import { AdapterInterface, Controller, AdapterRegistry } from '@uplink-protocol/core';
2
3class CustomAdapter implements AdapterInterface {
4 readonly name = 'custom-adapter';
5 readonly version = '1.0.0';
6
7 initialize(config?: any): void {
8 // Initialization logic
9 }
10
11 (controller: Controller, element: HTMLElement): void {
12 // Connect controller to the element
13 }
14
15 // Implement other required methods
16 // ...
17}
18
19// Register the adapter
20const registry = AdapterRegistry.getInstance();
21registry.registerAdapter(new CustomAdapter());
22registry.setDefaultAdapter('custom-adapter');