@git-stunts/alfred-live
v0.10.3
Published
In-memory control plane for Alfred: adaptive values, config registry, command router.
Downloads
55
Maintainers
Readme
@git-stunts/alfred-live
.o. oooo .o88o. .o8
.888. `888 888 `" "888
.8"888. 888 o888oo oooo d8b .ooooo. .oooo888
.8' `888. 888 888 `888""8P d88' `88b d88' `888
.88ooo8888. 888 888 888 888ooo888 888 888
.8' `888. 888 888 888 888 .o 888 888
o88o o8888o o888o o888o d888b `Y8bod8P' `Y8bod88P"
,gggg, ,a8a, ,ggg, ,gg ,ggggggg,
d8" "8I ,8" "8,dP""Y8a ,8P,dP""""""Y8b
88 ,dP d8 8bYb, `88 d8'd8' a Y8
8888888P" 88 88 `" 88 88 88 "Y8P'
88 88 88 88 88 `8baaaa
88 Y8 8P I8 8I,d8P""""
,aa,_88 `8, ,8' `8, ,8'd8"
dP" "88P 8888 "8,8" Y8, ,8P Y8,
Yb,_,d88b,,_ `8b, ,d8b, Yb,_,dP `Yba,,_____,
"Y8P" "Y88888"Y88P" "Y8 "Y8P" `"Y8888888
In-memory control plane for Alfred. This package provides live configuration primitives and a command router that work across Node, Bun, Deno, and browsers.
Install
pnpm add @git-stunts/alfred-livenpx jsr add @git-stunts/alfred-liveRoadmap
See the ecosystem roadmap at ROADMAP.md.
Quick Start
import { Adaptive, ConfigRegistry, CommandRouter } from '@git-stunts/alfred-live';
const retryCount = new Adaptive(3);
const registry = new ConfigRegistry();
registry.register('retry/count', retryCount, {
parse: (value) => {
const parsed = Number(value);
if (!Number.isFinite(parsed)) {
throw new Error('retry/count must be a number');
}
return parsed;
},
format: (value) => value.toString(),
});
const router = new CommandRouter(registry);
router.execute({ type: 'read_config', path: 'retry/count' });
router.execute({ type: 'write_config', path: 'retry/count', value: '5' });
router.execute({ type: 'list_config', prefix: 'retry' });Command Channel (JSONL)
Alfred Live exposes a canonical JSONL envelope for sending commands over stdin/stdout. Use the helper functions to decode, validate, and execute.
import {
CommandRouter,
ConfigRegistry,
executeCommandLine,
decodeCommandEnvelope,
encodeCommandEnvelope,
} from '@git-stunts/alfred-live';
const registry = new ConfigRegistry();
const router = new CommandRouter(registry);
const line = JSON.stringify({
id: 'cmd-1',
cmd: 'list_config',
args: { prefix: 'retry' },
});
const decoded = decodeCommandEnvelope(line);
if (!decoded.ok) throw new Error(decoded.error.message);
const resultLine = executeCommandLine(router, line);
if (!resultLine.ok) throw new Error(resultLine.error.message);
console.log(resultLine.data);
const outgoing = encodeCommandEnvelope({
id: 'cmd-2',
cmd: 'read_config',
args: { path: 'retry/count' },
});
if (outgoing.ok) console.log(outgoing.data);Audit + Auth Hooks
Attach audit and auth hooks when executing JSONL command lines. Audits record attempt + result events, and auth runs before validation/execution.
import {
CommandRouter,
ConfigRegistry,
InMemoryAuditSink,
opaqueTokenAuth,
executeCommandLine,
} from '@git-stunts/alfred-live';
const registry = new ConfigRegistry();
const router = new CommandRouter(registry);
const audit = new InMemoryAuditSink();
const auth = opaqueTokenAuth(['secret-token']);
const line = JSON.stringify({
id: 'cmd-1',
cmd: 'list_config',
args: { prefix: 'retry' },
auth: 'secret-token',
});
const resultLine = executeCommandLine(router, line, { audit, auth });
console.log(resultLine.data);
console.log(audit.entries());Pass { includeRaw: true } to executeCommandLine() if you want audit events to include raw payloads.
CLI (alfredctl)
alfredctl emits JSONL commands to stdout. Pipe its output into your control
plane transport (stdin/stdout, ssh, etc.).
alfredctl list retry
alfredctl read retry/count
alfredctl write retry/count 5Live Policies
Live policies are described with a LivePolicyPlan and then bound to a registry
via a ControlPlane. Binding creates the config entries and returns an executable
policy stack.
import { ConfigRegistry, ControlPlane, LivePolicyPlan } from '@git-stunts/alfred-live';
import { Policy } from '@git-stunts/alfred';
const registry = new ConfigRegistry();
const controlPlane = new ControlPlane(registry);
const livePlan = LivePolicyPlan.timeout('timeout', 5_000)
.wrap(
LivePolicyPlan.retry('retry', {
retries: 3,
delay: 150,
maxDelay: 3_000,
backoff: 'exponential',
jitter: 'decorrelated',
})
)
.wrap(
LivePolicyPlan.static(
Policy.circuitBreaker({
threshold: 5,
duration: 60_000,
})
)
)
.wrap(LivePolicyPlan.bulkhead('bulkhead', { limit: 10, queueLimit: 50 }));
const result = controlPlane.registerLivePolicy(livePlan, 'gateway/api');
if (!result.ok) throw new Error(result.error.message);
const { policy } = result.data;
const execution = await policy.execute(() => fetch('https://api.example.com'));
if (!execution.ok) throw new Error(execution.error.message);
// Live update, no redeploy.
registry.write('gateway/api/retry/retries', '5');Path Semantics
- Paths are relative, slash-delimited (
bulkhead/api). - Prefix matching uses path semantics.
- Exact prefix:
bulkheadmatchesbulkheadandbulkhead/api. - Child-only wildcard:
bulkhead/*matches children only (e.g.bulkhead/api), notbulkheaditself. - Glob-style prefix:
bulkhead*matchesbulkheadandbulkhead2.
Examples
alfred-live/examples/control-plane/basic.js— in-process registry + command router usage.alfred-live/examples/control-plane/jsonl-channel.js— JSONL command envelope execution.alfred-live/examples/control-plane/live-policies.js— live policy wrappers driven by registry state.
Status
v0.10.2 control plane primitives implemented:
Adaptive<T>live values with version + updatedAt.ConfigRegistryfor typed config and validation.- Command router for
read_config,write_config,list_config. LivePolicyPlan+ControlPlane.registerLivePolicyfor live policy stacks.- Canonical JSONL command envelope + helpers.
alfredctlCLI for emitting JSONL commands.- Audit-first command pipeline + auth hooks.
