SIGN IN SIGN UP

feat(react)!: cascade layer, read-only mode, returnTo, and observe requirements (#97)

## Summary

Four things the Samva dashboard lane (#98) hit while adopting
`@domainkit/react`, plus the React
half of core's observe change.

## The stylesheet ships in a cascade layer — breaking

Part selectors were unlayered, so `[data-domainkit-part="domain-flow"]`
outranked a host's
`@layer utilities` and Samva laid parts out through the `style` prop.
Every rule now sits in
`@layer domainkit`, which puts the whole stylesheet below any unlayered
host rule.

**A host that relied on the package winning must now opt in**, by
ordering a layer of its own below
it:

```css
@layer domainkit, app;
```

An artifact test asserts the built stylesheet carries nothing outside
the layer, and a Playwright
case proves a host utility class beats a part.

## The member view

```tsx
<DomainKit.Root transport={transport} readOnly>
  <Domain.Flow domain="app.example.com" requirements={requirements} />
</DomainKit.Root>
```

Status, records, and evidence render; connect, detach, disconnect,
review, approve, decline, and
cleanup do not. `Domain.Flow` takes the same flag for one domain among
several, and `useReadOnly()`
tells a host's own part which mode it is in.

Capability gating is the other half and is unchanged: a group the
transport never declares still
never renders. `readOnly` covers the authorization a transport cannot
express — a member who reaches
the same routes and would get a 403 from any write.

Observation stays available, because checking DNS reads the world rather
than changing the domain. A
host whose `Identity.authorize` denies `observe` to members passes
`slots={{ verification: () => null }}`.

## The interactive connect comes back

`Connect.useController`, `Connect.Flow`, and `Domain.Flow` take
`returnTo`, defaulting to the page
the customer is on and read when they connect rather than when the flow
renders. `null` sends none
and leaves the server's `defaultReturnTo` in charge; a per-call
`ConnectInput.returnTo` still wins.

## Verification no longer waits for an attachment

`Verify.useController` takes `requirements` and `Domain.Flow` passes its
own, so core's new
`observe(domain, { requirements })` verifies a domain with nothing
attached instead of failing
`InvalidInput` on the missing receipt. The set is keyed by content, so
an inline array does not send
the mount effect observing in a loop.

## Screenshots

| Read-only | Host utility beats a part |
| --- | --- |
| ![Read-only
flow](https://github.com/user-attachments/assets/421c65f2-8518-49a5-b601-655ab5615ddf)
| ![Host
override](https://github.com/user-attachments/assets/93db2797-c073-4855-bf7b-f46093a187a4)
|

## Tests

- 39 unit cases, 5 artifact cases, 10 Playwright cases.
- Each behaviour has a check that fails without it: the layer (artifact
and browser), `returnTo`
(default, explicit, and opted out), read-only (root, per flow, and off),
and observe requirements
  (argument list, and no re-observe on an inline array).

`bun run --filter @domainkit/react release:check` and the root
`release:check` are green.
S
Saatvik Arya committed
22b0c5958aad7eac218e2680b3e4982f2e1f9367
Parent: af128b0
Committed by GitHub <noreply@github.com> on 9/3/2026, 8:36:30 PM