Skip to main content
Services are the data layer for blocks. Each service abstracts a domain — subscriptions, customers, orders, products, schedules, auth, routing, workflows — behind a stable interface so blocks stay decoupled from any particular backend.

Pattern

Every service follows the same shape:
The adapter is the I/O layer. Real adapters call the application’s API; mock adapters return static data for development. The service wraps the adapter, manages reactive state, and exposes a stable interface to blocks. Provide each service once on the <juo-context-root> element:
Blocks then call injectContext(element, SubscriptionServiceContext) to retrieve it. See Contexts for how that flows through the DOM.

Result type

All async service methods return a discriminated union — check _tag before reading data:

Reactive state

Where it matters, services expose their state as signals — subscriptionService.current, customerService.current, workflowService.isLoading. Blocks read these signals and re-render automatically. See Reactivity.

Adapters: real vs mock

Every service ships with a mock adapter for development and Storybook:

Writing a custom adapter

If the backend doesn’t match the default adapter, implement the adapter interface and pass it to the service factory:

Available services

Subscription

Read, mutate, pause, resume, cancel subscriptions; manage items, discounts, upsells.

Customer

Current customer profile and reactive customer state.

Order

Order history and details.

Product

Product catalogue lookup and search with variants.

Schedules

Upcoming orders, skip / reschedule.

Login

Passwordless and social login, token management.

Router

In-page navigation, decoupled from a specific router.

Workflow

Interactive flow execution — start, respond, observe.