@byre/signet
v1.0.0
Published
Protocol-based data transport harness
Maintainers
Readme
@byre/signet
Protocol-based data transport harness for web applications.
Overview
Signet is a minimal, protocol-based data transport library that provides:
- Immutable handler registry keyed by URL protocol
- Handler resolution from URL strings or URL objects
- Operation routing to registered handlers
- Multi-endpoint coordination for store, retrieve, remove, and exists operations
Installation
npm install @byre/signetQuick Start
import {
emptyRegistry,
register,
store,
retrieve
} from '@byre/signet';
import { createRamHandler } from '@byre/signet/handlers';
// Create a registry with the RAM handler
let registry = emptyRegistry;
registry = register(registry, 'ram:', createRamHandler());
// Store data
await store(registry, {
endpoints: ['ram:///user/settings'],
data: { theme: 'dark', fontSize: 16 }
});
// Retrieve data
const results = await retrieve(registry, {
endpoints: ['ram:///user/settings']
});
console.log(results[0].data);
// { theme: 'dark', fontSize: 16 }Core Concepts
Registry
The registry is an immutable Map-like object that maps protocols to handlers:
import { emptyRegistry, register, resolve } from '@byre/signet';
// Start with empty registry
let registry = emptyRegistry;
// Register handlers (returns a new registry)
registry = register(registry, 'ram:', createRamHandler());
registry = register(registry, 'local:', createLocalHandler());
// Resolve a handler from a URL
const handler = resolve('ram:///path', registry);Handlers
Handlers are frozen objects that implement the Signet interface:
// Required methods
handler.$store(url, data, options) // Store data
handler.$retrieve(url, options) // Retrieve data
handler.$remove(url, options) // Remove data
handler.$exists(url, options) // Check existence
// Optional methods
handler.$subscribe(url, callback, options) // Subscribe to changes
handler.$clear(url, options) // Clear all data
handler.$keys(url, options) // List keysOperations
Operations work on arrays of endpoints and return results:
// Store to multiple endpoints
const results = await store(registry, {
endpoints: ['ram:///a', 'local:///b'],
data: { value: 42 }
});
// Each result has: endpoint, status, data?, reason?
results.forEach(r => {
if (r.status === 'fulfilled') {
console.log(`Stored to ${r.endpoint}`);
} else {
console.error(`Failed: ${r.reason.message}`);
}
});Result Shape
All operations return an array of result objects:
interface Result {
endpoint: string; // The endpoint string
status: 'fulfilled' | 'rejected';
data?: any; // Present if fulfilled
reason?: Error; // Present if rejected
}Handlers
RAM Handler
In-memory key-value store. Data is lost on page refresh.
import { createRamHandler } from '@byre/signet/handlers';
const handler = createRamHandler();
registry = register(registry, 'ram:', handler);URL Format: ram:///<path>
Capabilities: subscribe, clear, keys
Local Storage Handler
Browser localStorage persistence.
import { createLocalHandler } from '@byre/signet/handlers';
const handler = createLocalHandler({
prefix: 'myapp:' // Optional namespace prefix
});
registry = register(registry, 'local:', handler);URL Format: local:///<path>
Capabilities: clear, keys
Session Storage Handler
Browser sessionStorage (tab-scoped).
import { createSessionHandler } from '@byre/signet/handlers';
const handler = createSessionHandler({
prefix: 'myapp:'
});
registry = register(registry, 'session:', handler);URL Format: session:///<path>
Capabilities: clear, keys
Echo Handler
Testing utility that returns stored data with metadata.
import { createEchoHandler } from '@byre/signet/handlers';
const handler = createEchoHandler();
registry = register(registry, 'echo:', handler);
// Retrieve returns { value, storedAt, accessCount }URL Format: echo:///<path>
Delay Handler
Testing utility that wraps another handler with configurable delays.
import { createDelayHandler, createRamHandler } from '@byre/signet/handlers';
const delayed = createDelayHandler(createRamHandler(), {
delay: 100, // Base delay in ms
storeDelay: 50, // Override for $store
retrieveDelay: 25, // Override for $retrieve
jitter: 10 // Random +/- jitter
});Advanced Usage
Merge Function
Use merge in retrieve to combine results from multiple endpoints:
const theme = await retrieve(registry, {
endpoints: ['ram:///user/theme', 'ram:///defaults/theme'],
merge: (results) => {
// Return first successful result
const success = results.find(r =>
r.status === 'fulfilled' && r.data !== undefined
);
return success?.data ?? 'light';
}
});Subscriptions
Subscribe to changes at an endpoint:
import { subscribe } from '@byre/signet';
const unsubscribeFns = subscribe(registry, {
endpoints: ['ram:///'], // Empty path for all changes
callback: (event) => {
console.log(event.event); // 'store' | 'remove' | 'clear'
console.log(event.key); // The key that changed
console.log(event.data); // The new data (or undefined)
}
});
// Later: unsubscribe
unsubscribeFns.forEach(fn => fn());API Reference
Registry Functions
emptyRegistry // Empty frozen registry
register(registry, protocol, handler) // Returns new registry
resolve(url, registry) // Returns handler for URLOperations
// Core (always available)
store(registry, { endpoints, data, options? })
retrieve(registry, { endpoints, merge?, options? })
remove(registry, { endpoints, options? })
exists(registry, { endpoints, options? })
// Optional (handler must support)
subscribe(registry, { endpoints, callback, options? })
clear(registry, { endpoints, options? })
keys(registry, { endpoints, options? })Error Types
SignetError // Base class
SignetResolutionError // No handler for protocol
SignetHandlerError // Handler operation failedRunning the Demo
cd examples
npm install
npm run devLicense
MIT
