Patterns at a glance
Choose an Action, interceptor, event or store, with a visual flow and a tiny example.
Start with the job you need. Each diagram explains one mechanism; follow the link for its options.
| You want to | Use | Instead of building |
|---|---|---|
| Request an operation | Action | onClick handlers with hand-kept disabled/busy state |
| Observe or gate an Action | Action interceptor | Wrappers around every call site |
| Trace a service method | Service interceptor | Logging added inside each method |
| Announce a fact to other plugins | Event | A shared event bus or direct calls between features |
| Display changing state | Service store | A second state store mirrored by effects |
| Save a user preference | Settings | Your own storage, form and Settings route |
| Place a widget or navigation item | Slots | A registry or a menu list that every feature edits |
For package responsibilities, see the architecture map.
One Action, several controls
// counter/actions/increment.ts
export default defineAction({
title: 'Increment',
execute: ({ services }) => services.counter.value.increment(),
});Import defineAction from @bitakit/core. Existing bindings reference counter.increment;
each call carries its own input. A slot chooses where a control appears.
One Action, every control
Use Action options for confirmation, concurrency and feedback. Native navigation stays a real link; do not also invoke a handler when following it. See the Action loop diagram for the complete UI → Action → Service → Store → UI cycle.
Gate or observe an Action
// counter/interceptors/audit.ts
import { defineInterceptor } from '@bitakit/core';
export default defineInterceptor({
action: 'counter.increment',
after: ({ id }) => console.debug('Completed:', id),
});Gate or observe an Action
before may be async; false skips. after and onError observe, without replacing results.
See Action interceptors.
Observe a service call
// counter/interceptors/calls.ts
import { defineInterceptor } from '@bitakit/core';
export default defineInterceptor({
service: 'counter.value',
method: 'increment',
before: ({ args }) => console.debug('Called with:', args),
});Observe a service call
Internal self-calls bypass the wrapper. See service interceptors.
Notify other plugins
// counter/events.ts
import { defineEvents, event } from '@bitakit/core';
export default defineEvents({ incremented: event<number>() });// Emit in a Counter Action or service; listen in another service factory.
events.emit('counter.incremented', count);
events.on('counter.incremented', ({ data }) => console.log(data));Notify other plugins
Subscriptions are owned and released. Ordinary emit does not await async handlers; cancelable events await handlers and report whether a listener cancelled. Cancellation is coordination, not server authorization.
Follow current state
// In a service factory, state is the single owner of the value.
const state = store({ count: 0 });
const increment = () => state.set((s) => ({ count: s.count + 1 }));// In a component, read its service; no copied count state or bootstrap effect.
const count = useServiceState('counter.value', (state) => state.count, 0);One store, several readers
See the service lesson for complete files. For persisted preferences,
use defineSettings and useSetting; the runtime settings store remains the value owner.