> ## Documentation Index
> Fetch the complete documentation index at: https://juo.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Services

> Domain APIs that blocks call to read and mutate data.

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:

```ts theme={null}
const service = create<Domain>Service(adapter);
```

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:

```ts theme={null}
import {
  provideContext,
  createSubscriptionService,
  createApiSubscriptionAdapter,
  SubscriptionServiceContext,
} from "@juo/blocks";

const root = document.querySelector("juo-context-root") as HTMLElement;

provideContext(
  root,
  SubscriptionServiceContext,
  createSubscriptionService(createApiSubscriptionAdapter({ baseUrl: "/api/v1" })),
);
```

Blocks then call `injectContext(element, SubscriptionServiceContext)` to retrieve it. See [Contexts](/docs/blocks/concepts/contexts) for how that flows through the DOM.

## Result type

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

```ts theme={null}
const result = await subscriptionService.getById(id);

if (result._tag === "Success") {
  console.log(result.data);
} else {
  console.error(result.error);
}
```

## 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](/docs/blocks/concepts/reactivity).

## Adapters: real vs mock

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

```ts theme={null}
import {
  createSubscriptionService,
  createMockSubscriptionAdapter,
} from "@juo/blocks";

provideContext(
  root,
  SubscriptionServiceContext,
  createSubscriptionService(createMockSubscriptionAdapter()),
);
```

## Writing a custom adapter

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

```ts theme={null}
import type { SubscriptionAdapter } from "@juo/blocks";
import {
  createSubscriptionService,
  SubscriptionServiceContext,
  provideContext,
} from "@juo/blocks";

const myAdapter: SubscriptionAdapter = {
  async search() { /* ... */ },
  async getById(id) { /* ... */ },
  async pause(id) { /* ... */ },
  // ...
};

provideContext(root, SubscriptionServiceContext, createSubscriptionService(myAdapter));
```

## Available services

<CardGroup cols={2}>
  <Card title="Subscription" href="/docs/blocks/services/subscription">
    Read, mutate, pause, resume, cancel subscriptions; manage items, discounts, upsells.
  </Card>

  <Card title="Customer" href="/docs/blocks/services/customer">
    Current customer profile and reactive customer state.
  </Card>

  <Card title="Order" href="/docs/blocks/services/order">
    Order history and details.
  </Card>

  <Card title="Product" href="/docs/blocks/services/product">
    Product catalogue lookup and search with variants.
  </Card>

  <Card title="Schedules" href="/docs/blocks/services/schedules">
    Upcoming orders, skip / reschedule.
  </Card>

  <Card title="Login" href="/docs/blocks/services/login">
    Passwordless and social login, token management.
  </Card>

  <Card title="Router" href="/docs/blocks/services/router">
    In-page navigation, decoupled from a specific router.
  </Card>

  <Card title="Workflow" href="/docs/blocks/services/workflow">
    Interactive flow execution — start, respond, observe.
  </Card>
</CardGroup>
