Skip to content
Back to skills

Web Client

ASecurity

Bind OwlMeans shared entrypoint protocols in a browser application. Use when registering client routes, attaching React screens (including lazily-loaded ones), calling API protocols, or configuring the browser context.

  • 3 stars
  • 0 votes
  • 0 copies
  • 0 views
  • Added September 22, 2026
developmentgoreactapifrontend

Works with

  • cli
  • api

Security analysis

A100/100

Scanned October 6, 2026

npx -y skills add owlmeans/common --skill web-client --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Web Client?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Web Client
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/owlmeans-web-client/badge)](https://www.skillsdirectory.com/skills/owlmeans-web-client)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: web-client
description: Bind OwlMeans shared entrypoint protocols in a browser application. Use when registering client routes, attaching React screens (including lazily-loaded ones), calling API protocols, or configuring the browser context.
---

# Browser protocol entrypoints

**Install:** `bun add @owlmeans/web-client@^0.1.18-rc.62`

Shared protocol declarations are immutable. Bind a complete protocol tree for callable API routes,
then bind frontend declarations to screens.

```ts
import { bindAll, bindScreen, entrypoints as frameworkEntrypoints, handler } from '@owlmeans/web-panel'
import { projectProtocols, webProtocols } from 'project-common'
import { ProjectScreen } from './screens/project.js'

export const clientBindings = [
  ...frameworkEntrypoints,
  ...bindAll(projectProtocols),
  bindScreen(webProtocols.project, handler(ProjectScreen)),
]
```

Call a protocol directly. Its request and response types come from its shared contract.

```ts
const project = await context.entrypoint(projectProtocols.get).call({
  params: { id: projectId },
})
```

## Lazily-loaded screens

`lazyHandler` and `lazyComponent` (from `@owlmeans/client`) are re-exported here and by
`@owlmeans/web-panel`, next to `handler`; so are, here only, the chunk-failure tools of
`lazyRetryHelper` — `retryImport`, `isChunkLoadError`, `reloadOnce` and `recoverFromChunkError` (types
`LazyErrorRenderer`, `RetryImportOptions`). A `lazyHandler(...)` result binds exactly like
`handler(Component)`; declare it at module scope, where the bindings live — never inside a render.

```tsx
import { bindScreen, lazyHandler } from '@owlmeans/web-client'

const reportsScreen = lazyHandler(() => import('./screens/reports.js'), 'ReportsScreen', {
  fallback: <Spinner />,
})

export const clientBindings = [
  bindScreen(webProtocols.reports, reportsScreen),
]
// reportsScreen.preload() on hover/focus of a link renders the screen without its fallback.
```

The fallback renders inside the screen's own `Suspense` boundary, so the layout around it stays
mounted while the chunk loads, and the screen's own error boundary keeps a failed chunk from
unmounting it: a fetch failure is retried, then `error` renders — or, without one, the guarded
reload starts. Rules and options: the `client` skill, Code-splitting and Chunk failures.

## Rendering after an async boot

If your app awaits something (e.g. `i18nInstanceHelper.prepareI18n`) before calling `render()`, this is handled
correctly — the render helper checks `document.readyState` rather than unconditionally waiting for
an event that may already have fired. It waits for `DOMContentLoaded` only while the document is
still `loading` and mounts at once otherwise; `renderApp` and `@owlmeans/web-panel`'s `render` both
go through it.

```ts
import { i18nInstanceHelper } from '@owlmeans/client-i18n'

await i18nInstanceHelper.prepareI18n(context.cfg)
renderApp(context)            // or @owlmeans/web-panel's render(context)
```

## Rules

- Declare paths, guards, gates and contracts once in the shared protocol tree.
- Bind every API declaration the browser calls, including route parents.
- Use `bindScreen(protocol, handler(Component))` — or `lazyHandler(...)` — only for frontend route
  declarations.
- Do not replace request/response typing at a call site; update the shared contract instead.
- Keep framework entrypoints and application entrypoints in one registered array, without mutating a
  shared declaration collection.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…