@owlmeans/client 0.1.18-rc.4 → 0.1.18-rc.40
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +231 -54
- package/agent-meta/manifest.json +2 -2
- package/agent-meta/skills/client/SKILL.md +194 -19
- package/build/context.d.ts.map +1 -1
- package/build/context.js +1 -3
- package/build/context.js.map +1 -1
- package/build/entrypoint.d.ts +3 -0
- package/build/entrypoint.d.ts.map +1 -0
- package/build/entrypoint.js +4 -0
- package/build/entrypoint.js.map +1 -0
- package/build/helper.js +3 -3
- package/build/helper.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/build/navigate.d.ts.map +1 -1
- package/build/navigate.js +15 -18
- package/build/navigate.js.map +1 -1
- package/build/router.d.ts.map +1 -1
- package/build/router.js +12 -6
- package/build/router.js.map +1 -1
- package/build/services/debug.js.map +1 -1
- package/build/store.d.ts +19 -3
- package/build/store.d.ts.map +1 -1
- package/build/store.js +57 -50
- package/build/store.js.map +1 -1
- package/build/types.d.ts +16 -5
- package/build/types.d.ts.map +1 -1
- package/build/utils/entrypoint.d.ts +3 -0
- package/build/utils/entrypoint.d.ts.map +1 -0
- package/build/utils/{module.js → entrypoint.js} +2 -2
- package/build/utils/entrypoint.js.map +1 -0
- package/build/utils/index.d.ts +1 -1
- package/build/utils/index.d.ts.map +1 -1
- package/build/utils/index.js +1 -1
- package/build/utils/index.js.map +1 -1
- package/build/utils/route.d.ts.map +1 -1
- package/build/utils/route.js +12 -6
- package/build/utils/route.js.map +1 -1
- package/build/utils/router.d.ts +4 -4
- package/build/utils/router.d.ts.map +1 -1
- package/build/utils/router.js +8 -8
- package/build/utils/router.js.map +1 -1
- package/package.json +12 -12
- package/src/context.ts +1 -4
- package/src/entrypoint.ts +6 -0
- package/src/helper.tsx +6 -6
- package/src/index.ts +1 -1
- package/src/navigate.ts +16 -19
- package/src/router.ts +14 -10
- package/src/services/debug.ts +2 -2
- package/src/store.ts +71 -54
- package/src/types.ts +18 -5
- package/src/utils/{module.ts → entrypoint.ts} +2 -2
- package/src/utils/index.ts +1 -1
- package/src/utils/route.tsx +15 -8
- package/src/utils/router.ts +11 -11
- package/build/module.d.ts +0 -3
- package/build/module.d.ts.map +0 -1
- package/build/module.js +0 -4
- package/build/module.js.map +0 -1
- package/build/utils/module.d.ts +0 -3
- package/build/utils/module.d.ts.map +0 -1
- package/build/utils/module.js.map +0 -1
- package/src/module.ts +0 -6
package/README.md
CHANGED
|
@@ -1,92 +1,269 @@
|
|
|
1
1
|
# @owlmeans/client
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
3
|
+
The platform-agnostic React client framework that [`@owlmeans/web-client`](../web-client) (browser)
|
|
4
|
+
and the native client are built on. It provides the client context factory, the `App`/`Router`
|
|
5
|
+
mounts, alias-free navigation, the screen hooks (`useEntrypoint`, `useStoreModel`, `useStoreList`,
|
|
6
|
+
`useValue`, `useToggle`), and the modal and debug services. A browser application normally builds
|
|
7
|
+
its context with `makeContext` from [`@owlmeans/web-panel`](../web-panel) and mounts it with
|
|
8
|
+
`renderApp` from `@owlmeans/web-client`. `@owlmeans/web-client` does not re-export the hooks
|
|
9
|
+
listed here. `web-panel` re-exports `useNavigate`, `useValue` and `useEntrypoint`, while
|
|
10
|
+
`useStoreModel` and `useStoreList` are available only from this package. A cross-platform package
|
|
11
|
+
imports everything from here. Server code never uses this package; its equivalent is
|
|
12
|
+
[`@owlmeans/server-context`](../server-context).
|
|
12
13
|
|
|
13
14
|
## Installation
|
|
14
15
|
|
|
15
16
|
```bash
|
|
16
|
-
bun add @owlmeans/client
|
|
17
|
+
bun add @owlmeans/client@^0.1.18-rc.40
|
|
17
18
|
```
|
|
18
19
|
|
|
20
|
+
`react` and `@remix-run/router` are peer dependencies.
|
|
21
|
+
|
|
22
|
+
## Concepts
|
|
23
|
+
|
|
24
|
+
- **Client context**: `makeClientContext(cfg)` builds on `@owlmeans/client-context` and adds the
|
|
25
|
+
default state resource, the config and plugin resources, the modal and debug services, the
|
|
26
|
+
rerender hook and `context.router()`. Platform factories (`web-client`, `web-panel`) compose it,
|
|
27
|
+
and an app's own `makeContext` composes theirs.
|
|
28
|
+
- **Screen**: a frontend entrypoint protocol (`route(alias, path, frontend(...))`) bound to a
|
|
29
|
+
component with `bindScreen(protocol, handler(Component))`. The router mounts only frontend
|
|
30
|
+
entrypoints, and each nests under its `parent`.
|
|
31
|
+
- **Routed component**: a `RoutedComponent` receives `{ alias, path, params, context }`, and
|
|
32
|
+
`useEntrypoint()` reads the same values anywhere below it.
|
|
33
|
+
- **Navigator**: `useNavigate()` addresses entrypoints, not URLs. The target entrypoint builds its
|
|
34
|
+
own `url(request)`, and the active router plugin performs the navigation.
|
|
35
|
+
- **Store hooks**: `useStoreModel` and `useStoreList` subscribe to a [`@owlmeans/state`](../state)
|
|
36
|
+
resource through `useSyncExternalStore`. `useValue` renders an async result.
|
|
37
|
+
- **Modal stack**: `context.modal().request(Body)` pushes a body onto a stack rendered by a surface
|
|
38
|
+
the app mounts once, and resolves when the body answers.
|
|
39
|
+
|
|
19
40
|
## Usage
|
|
20
41
|
|
|
21
|
-
|
|
42
|
+
### Declare screens, bind them, mount the app
|
|
22
43
|
|
|
23
|
-
|
|
24
|
-
import { useStoreModel, useStoreList } from '@owlmeans/client'
|
|
44
|
+
Screen protocols are declared in the shared `common` package and bound in the web app:
|
|
25
45
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
46
|
+
```ts
|
|
47
|
+
// common: entrypoints.ts
|
|
48
|
+
import { openProtocol } from '@owlmeans/entrypoint'
|
|
49
|
+
import { DEFAULT_GUARD } from '@owlmeans/auth-common'
|
|
50
|
+
import { frontend, route } from '@owlmeans/route'
|
|
51
|
+
|
|
52
|
+
const projectBase = openProtocol(route('app:project', '/project/:projectId', frontend()), { guards: DEFAULT_GUARD })
|
|
31
53
|
|
|
32
|
-
|
|
54
|
+
export const appScreens = {
|
|
55
|
+
project: {
|
|
56
|
+
base: projectBase,
|
|
57
|
+
dashboard: openProtocol(route('app:project:dashboard', '/dashboard', frontend({ parent: projectBase }))),
|
|
58
|
+
settings: openProtocol(route('app:project:settings', '/settings', frontend({ parent: projectBase }))),
|
|
59
|
+
},
|
|
60
|
+
} as const
|
|
61
|
+
```
|
|
33
62
|
|
|
34
|
-
```
|
|
35
|
-
|
|
63
|
+
```tsx
|
|
64
|
+
// web: entrypoints.ts and main.tsx
|
|
65
|
+
import { bindAll, bindScreen, handler, renderApp } from '@owlmeans/web-client'
|
|
36
66
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
67
|
+
export const entrypoints = [
|
|
68
|
+
...bindAll({ project: appProtocols.project }), // backend calls
|
|
69
|
+
bindScreen(appScreens.project.base, handler(ProjectLayout)),
|
|
70
|
+
bindScreen(appScreens.project.dashboard, handler(DashboardScreen)),
|
|
71
|
+
bindScreen(appScreens.project.settings, handler(SettingsScreen)),
|
|
72
|
+
]
|
|
41
73
|
|
|
42
|
-
|
|
43
|
-
|
|
74
|
+
const context = makeContext(config) // the app's single factory
|
|
75
|
+
context.registerEntrypoints(entrypoints)
|
|
76
|
+
renderApp(context, undefined, <ModalSurface />) // children render before the router
|
|
44
77
|
```
|
|
45
78
|
|
|
46
|
-
|
|
79
|
+
Outside the browser (a native shell, a test harness) the platform-agnostic mount is
|
|
80
|
+
`<App context={context} />`. `noRouter` skips the router, and `provide` overrides how routes are
|
|
81
|
+
compiled.
|
|
47
82
|
|
|
48
|
-
|
|
49
|
-
|
|
83
|
+
### A routed screen that loads, stores and renders
|
|
84
|
+
|
|
85
|
+
```tsx
|
|
86
|
+
import { useEntrypoint, useStoreModel, useValue } from '@owlmeans/client'
|
|
87
|
+
import type { RoutedComponent } from '@owlmeans/client'
|
|
88
|
+
|
|
89
|
+
export const DashboardScreen: RoutedComponent = () => {
|
|
90
|
+
const context = useContext() // the app's typed wrapper
|
|
91
|
+
const { params } = useEntrypoint<{ projectId?: string }>()
|
|
92
|
+
const projectId = params.projectId
|
|
50
93
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
94
|
+
// Load once per id, write the answer into the store, render from the store.
|
|
95
|
+
useValue(async cancel => {
|
|
96
|
+
if (projectId == null) {
|
|
97
|
+
return null
|
|
98
|
+
}
|
|
99
|
+
const project = await context.entrypoint(appProtocols.project.get).call({ params: { id: projectId } })
|
|
100
|
+
if (cancel?.current !== true) {
|
|
101
|
+
await context.getStateResource(PROJECTS).save(project)
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
return project
|
|
105
|
+
}, [projectId])
|
|
106
|
+
|
|
107
|
+
const project = useStoreModel<Project>(projectId, PROJECTS)
|
|
108
|
+
if (project.empty) {
|
|
109
|
+
return <Spinner />
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return <ProjectBoard project={project.record} onRename={title => project.update({ title })} />
|
|
54
113
|
}
|
|
55
114
|
```
|
|
56
115
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
### `useStoreModel<T>(id?, opts?): StateModel<T>`
|
|
116
|
+
The app's `useContext` is typically `() => useBasicContext<Config, Context>()` over the one exported
|
|
117
|
+
here (or re-exported by `web-panel`), so app-level accessors are typed.
|
|
60
118
|
|
|
61
|
-
|
|
119
|
+
### Navigate by protocol
|
|
62
120
|
|
|
63
|
-
|
|
121
|
+
```tsx
|
|
122
|
+
import { useNavigate } from '@owlmeans/client'
|
|
64
123
|
|
|
65
|
-
|
|
124
|
+
export const ProjectTabs: FC<{ projectId: string }> = ({ projectId }) => {
|
|
125
|
+
const nav = useNavigate()
|
|
66
126
|
|
|
67
|
-
|
|
127
|
+
return <nav>
|
|
128
|
+
<button onClick={nav.press(appScreens.project.dashboard, { params: { projectId } })}>Dashboard</button>
|
|
129
|
+
<button onClick={nav.press(appScreens.project.settings, { params: { projectId }, query: { tab: 'members' } })}>
|
|
130
|
+
Members
|
|
131
|
+
</button>
|
|
132
|
+
<button onClick={nav.pressBack()}>Back</button>
|
|
133
|
+
</nav>
|
|
134
|
+
}
|
|
68
135
|
|
|
69
|
-
|
|
136
|
+
// imperatively, replacing the history entry
|
|
137
|
+
await nav.go(appScreens.project.dashboard, { params: { projectId }, replace: true })
|
|
138
|
+
```
|
|
70
139
|
|
|
71
|
-
|
|
140
|
+
A URL that resolves to another service (`http…`) is assigned to `location.href` instead of being
|
|
141
|
+
pushed onto the history.
|
|
72
142
|
|
|
73
|
-
|
|
74
|
-
- `navigate(module, request?)` — navigate to a `ClientModule`
|
|
75
|
-
- `go(alias, request?)` — navigate by module alias
|
|
143
|
+
### A modal request
|
|
76
144
|
|
|
77
|
-
|
|
145
|
+
```tsx
|
|
146
|
+
import type { ModalBodyProps } from '@owlmeans/client'
|
|
147
|
+
import { createElement } from 'react'
|
|
78
148
|
|
|
79
|
-
|
|
149
|
+
const ConfirmDelete: FC<ModalBodyProps & { storyId: string }> = ({ modal, storyId }) =>
|
|
150
|
+
<Dialog.Body>
|
|
151
|
+
<Button onClick={() => modal?.response(true)}>Delete {storyId}</Button>
|
|
152
|
+
<Button onClick={() => modal?.cancel()}>Cancel</Button>
|
|
153
|
+
</Dialog.Body>
|
|
80
154
|
|
|
81
|
-
|
|
155
|
+
const onDelete = async () => {
|
|
156
|
+
const confirmed = await context.modal().request<boolean>(
|
|
157
|
+
({ modal }) => createElement(ConfirmDelete, { modal, storyId })
|
|
158
|
+
)
|
|
159
|
+
if (confirmed === true) { // null when cancelled
|
|
160
|
+
await context.entrypoint(appProtocols.story.delete).call({ params: { id: storyId } })
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
```
|
|
82
164
|
|
|
83
|
-
|
|
165
|
+
The surface is mounted once. It calls `useSetupModalNavigator()`, links a `useToggle()` to
|
|
166
|
+
`context.modal().link(toggle)` after `waitForInitialized()`, and renders
|
|
167
|
+
`context.modal().layer()?.Com` with `modal={context.modal()}`.
|
|
84
168
|
|
|
85
|
-
##
|
|
169
|
+
## API
|
|
86
170
|
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
171
|
+
### Context and mounting
|
|
172
|
+
|
|
173
|
+
| Symbol | Kind | Purpose |
|
|
174
|
+
|---|---|---|
|
|
175
|
+
| `makeClientContext<C, T>(cfg)` | function | Build the React client context (state, config/plugin resources, modal, debug, router accessor) |
|
|
176
|
+
| `ClientContext<C>` | type | Adds `router()`, `registerRerenderer(fn)`, `rerender()`, `modal()`, `debug()`, `getStateResource` |
|
|
177
|
+
| `App` / `AppProps` | component / type | Provide the context and, unless `noRouter`, mount the router; `children` render first |
|
|
178
|
+
| `Context`, `ClientContextContainer` | React context | The provider and the container behind it |
|
|
179
|
+
| `useContext<C, T>()` | hook | Read the current client context |
|
|
180
|
+
| `Router` / `RouterProps` | component / type | Resolve frontend entrypoints into routes; `provide` is optional |
|
|
181
|
+
| `makeRouterModel()`, `RouterModel`, `RouterProvider` | function / type | The route model and the router-provider signature |
|
|
182
|
+
| `handler(Component, preprender?)` | function | Wrap a component as an entrypoint handler for `bindScreen` |
|
|
183
|
+
|
|
184
|
+
### Screens and navigation
|
|
185
|
+
|
|
186
|
+
| Symbol | Kind | Purpose |
|
|
187
|
+
|---|---|---|
|
|
188
|
+
| `RoutedComponent<Extra>` | type | A component bound to a frontend protocol |
|
|
189
|
+
| `EntrypointContextParams<T>` | type | `{ alias, params, path, context }` |
|
|
190
|
+
| `useEntrypoint<T>()` | hook | The params of the screen currently rendering |
|
|
191
|
+
| `useNavigate()` | hook | The `Navigator` |
|
|
192
|
+
| `Navigator` | type | `navigate(entrypoint, req?)`, `go(target, req?)`, `press(target, req?)`, `back()`, `pressBack()`, `location()` |
|
|
193
|
+
| `NavRequest<T>` | type | A partial `AbstractRequest` plus `replace` and `silent` |
|
|
194
|
+
| `EntrypointTarget` | type | `EntrypointReference \| string`; application code passes protocol objects |
|
|
195
|
+
|
|
196
|
+
### State and values
|
|
197
|
+
|
|
198
|
+
| Symbol | Kind | Purpose |
|
|
199
|
+
|---|---|---|
|
|
200
|
+
| `useStoreModel<T>(id?, alias?)` | hook | One record from a state resource, live; never throws for missing data |
|
|
201
|
+
| `useStoreList<T>(opts?)` | hook | A live query `{ query?, sort?, resource? }` returning `StateModel<T>[]` |
|
|
202
|
+
| `UseStoreListOptions<T>` | type | The `useStoreList` options |
|
|
203
|
+
| `useValue<T>(loader, deps?, forceDefault?)` | hook | Render an async result; `null` (or the default) until it resolves |
|
|
204
|
+
| `UseValueParams<T>` | type | `{ default?, deps? }` |
|
|
205
|
+
| `useToggle(opened?)`, `Toggleable` | hook / type | `{ opened, open, close, set, toggle }` |
|
|
206
|
+
|
|
207
|
+
### Modal and debug services
|
|
208
|
+
|
|
209
|
+
| Symbol | Kind | Purpose |
|
|
210
|
+
|---|---|---|
|
|
211
|
+
| `appendModalService(ctx, alias?)`, `createModalService(alias?)` | function | Register or create the modal stack (`context.modal()`) |
|
|
212
|
+
| `ModalService`, `ModalStackLayer`, `ModalBodyProps`, `ModalServiceAppend` | type | `request`, `response`, `cancel`, `error`, `layer`, `link`, `stack`, `toggle` |
|
|
213
|
+
| `useSetupModalNavigator()` | hook | Give modal bodies a navigator; call once in the surface |
|
|
214
|
+
| `appendDebugService(ctx, alias?)`, `createDebugService(alias?)` | function | The debug menu, registered only when `cfg.debug.all` or `cfg.debug.debugger` is set |
|
|
215
|
+
| `appendStateDebug(ctx, alias)` | function | List a client resource under "Reset states" in the debug menu |
|
|
216
|
+
| `DebugService`, `DebugMenuItem`, `DebugServiceAppend`, `DebugConfigRecord` | type | Debug menu contracts; `context.debug()` may be `undefined` |
|
|
217
|
+
|
|
218
|
+
### Errors and constants
|
|
219
|
+
|
|
220
|
+
| Symbol | Kind | Purpose |
|
|
221
|
+
|---|---|---|
|
|
222
|
+
| `ClientError`, `ComponentError`, `ComponentPropError`, `ComponentPropUndefined` | class | The client error family, registered with `ResilientError` |
|
|
223
|
+
| `DEF_MODAL_ALIAS`, `DEF_DEBUG_ALIAS` | const | `'modal'`, `'debug'` |
|
|
224
|
+
| `DEBUGGER_FLAG`, `DEBUG_CONFIG_KEY` | const | `'debugger'` |
|
|
225
|
+
|
|
226
|
+
### Subpath `@owlmeans/client/utils`
|
|
227
|
+
|
|
228
|
+
| Symbol | Kind | Purpose |
|
|
229
|
+
|---|---|---|
|
|
230
|
+
| `buildEntrypointTree`, `visitEntrypointTree`, `EntrypointTreeVisitor` | function / type | Build and walk the frontend entrypoint tree |
|
|
231
|
+
| `initializeRouter(context)` | function | Initialize the router for a context |
|
|
232
|
+
| `createRouteRenderer`, `HandledRenderer` | function / type | Render one route with guards applied |
|
|
233
|
+
| `EntrypointContext` | React context | What `useEntrypoint` reads |
|
|
234
|
+
|
|
235
|
+
These are the pieces the router is assembled from. A package building its own routing surface
|
|
236
|
+
uses them; an application does not.
|
|
237
|
+
|
|
238
|
+
## Common pitfalls
|
|
239
|
+
|
|
240
|
+
- **Building URLs or passing alias strings in components.** Navigate with protocol objects
|
|
241
|
+
(`nav.go(protocol, { params })`) and let the entrypoint build the URL.
|
|
242
|
+
- **Resolving route params in nested components.** Read `params` from the screen props or
|
|
243
|
+
`useEntrypoint()` and pass them down.
|
|
244
|
+
- **Reading `useValue`'s second argument as a default.** An array is the dependency list, and an
|
|
245
|
+
object uses `{ default, deps }`. A bare non-array value is the default and gives no deps.
|
|
246
|
+
- **Committing after unmount in a multi-await loader.** Check `cancel.current` before writing.
|
|
247
|
+
- **Assigning into `model.record`.** Nothing re-renders. Use `model.update({ ... })`.
|
|
248
|
+
- **Importing `useNavigate`, `useEntrypoint`, `useStoreModel`, `useStoreList` or `useValue` from
|
|
249
|
+
`@owlmeans/web-client`.** It does not re-export them; import them from this package.
|
|
250
|
+
- **Requesting a modal from inside another modal body.** Closing the child also pops the parent,
|
|
251
|
+
and the parent's request never resolves. Await the first request, then issue the next.
|
|
252
|
+
- **Mounting global overlays inside a route.** They are torn down on every navigation. Pass them
|
|
253
|
+
as `App`/`renderApp` children.
|
|
254
|
+
- **Assuming `context.debug()` exists.** It is `undefined` unless the debug flags are set.
|
|
255
|
+
- **A screen whose guards all fail.** The renderer throws `AuthorizationError('frontend-guard')`, so
|
|
256
|
+
bind a login flow for guarded screens.
|
|
257
|
+
|
|
258
|
+
## Related packages
|
|
259
|
+
|
|
260
|
+
- [`@owlmeans/web-client`](../web-client): the browser layer (`renderApp`, `WebApp`, `makeContext`)
|
|
261
|
+
- [`@owlmeans/web-panel`](../web-panel): the shadcn UI context factory and navigation shell most web apps start from
|
|
262
|
+
- [`@owlmeans/state`](../state): the store `useStoreModel` / `useStoreList` read
|
|
263
|
+
- [`@owlmeans/client-entrypoint`](../client-entrypoint): `bind`, `bindAll`, `bindScreen`, typed `call`/`invoke`/`url`
|
|
264
|
+
- [`@owlmeans/client-context`](../client-context): the base client context and config
|
|
265
|
+
- [`@owlmeans/router`](../router): the router plugin `context.router()` resolves
|
|
266
|
+
- [`@owlmeans/route`](../route): `route()` and `frontend()` for screen declarations
|
|
90
267
|
|
|
91
268
|
<!-- owlmeans:agent-guidance:start -->
|
|
92
269
|
## Agent guidance
|
|
@@ -96,7 +273,7 @@ This package ships embedded agent skills under `agent-meta/`. After installing y
|
|
|
96
273
|
your project's skill store (`.agents/skills/`):
|
|
97
274
|
|
|
98
275
|
```sh
|
|
99
|
-
npx @owlmeans/agent-skills
|
|
276
|
+
npx @owlmeans/agent-skills@^0.1.18-rc.38
|
|
100
277
|
```
|
|
101
278
|
|
|
102
279
|
The embedded files are version-matched to this package release. Do not edit them
|
package/agent-meta/manifest.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 2,
|
|
3
3
|
"package": "@owlmeans/client",
|
|
4
|
-
"version": "0.1.18-rc.
|
|
5
|
-
"generatedAt": "2026-
|
|
4
|
+
"version": "0.1.18-rc.40",
|
|
5
|
+
"generatedAt": "2026-09-23T19:57:40.682Z",
|
|
6
6
|
"canonicalRepo": "https://github.com/owlmeans/common",
|
|
7
7
|
"entries": [
|
|
8
8
|
{
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: client
|
|
3
|
-
description: How to use @owlmeans/client — platform-agnostic React client framework (
|
|
3
|
+
description: How to use @owlmeans/client — the platform-agnostic React client framework (web and native) — makeClientContext, App/Router, useNavigate/Navigator, useEntrypoint/RoutedComponent, useStoreModel/useStoreList, useValue, the modal and debug services. Auto-invoked when importing client framework primitives, navigating between screens, or reading client state from React.
|
|
4
4
|
user-invocable: false
|
|
5
5
|
---
|
|
6
6
|
<!-- AUTO-GENERATED — do not edit. Regenerate via sync-agent-meta. -->
|
|
@@ -8,37 +8,212 @@ user-invocable: false
|
|
|
8
8
|
# @owlmeans/client
|
|
9
9
|
|
|
10
10
|
**Layer:** Client
|
|
11
|
-
**Install:** `"@owlmeans/client": "^0.1.18-rc.
|
|
11
|
+
**Install:** `"@owlmeans/client": "^0.1.18-rc.40"` in `dependencies`
|
|
12
|
+
|
|
13
|
+
The React substrate `@owlmeans/web-client` (browser) and the native equivalent are built on. A
|
|
14
|
+
cross-platform package imports from here; an application normally imports from the platform
|
|
15
|
+
package, which re-exports what it needs — **except the hooks below, which are only here**.
|
|
16
|
+
|
|
17
|
+
## What lives where
|
|
18
|
+
|
|
19
|
+
| Import from `@owlmeans/client` | Import from `@owlmeans/web-client` |
|
|
20
|
+
|---|---|
|
|
21
|
+
| `useNavigate`, `useEntrypoint`, `useStoreModel`, `useStoreList`, `useValue`, `useToggle`, `useSetupModalNavigator` — none of these are re-exported | `renderApp`, `makeContext`, `useAuthenticated`, and protocol binding helpers from `@owlmeans/client-entrypoint` |
|
|
22
|
+
| `RoutedComponent`, `EntrypointContextParams`, `Navigator`, `NavRequest`, `ClientContext` | `AppConfig`, `AppContext` |
|
|
23
|
+
| `App`, `Router`, `makeClientContext` — the platform-agnostic mounts | `WebApp`, `renderApp` — the browser mounts that wrap them |
|
|
12
24
|
|
|
13
25
|
## Key Exports
|
|
14
26
|
|
|
15
27
|
| Export | Description |
|
|
16
28
|
|--------|-------------|
|
|
17
|
-
| `
|
|
18
|
-
| `
|
|
19
|
-
| `
|
|
20
|
-
| `
|
|
21
|
-
| `
|
|
22
|
-
| `
|
|
23
|
-
|
|
|
24
|
-
|
|
|
29
|
+
| `makeClientContext(cfg)` | The React client context: `@owlmeans/client-context` plus the state resource, both config resources, the modal and debug services, the rerender hook and `context.router()` |
|
|
30
|
+
| `ClientContext<C>` | That context's interface — adds `router()`, `registerRerenderer(fn)`, `rerender()`, `modal()`, `debug()` |
|
|
31
|
+
| `App` / `AppProps` | Mount: provides the context and, unless `noRouter`, the router. `children` render inside the provider and before the router |
|
|
32
|
+
| `Context` / `ClientContextContainer` / `useContext()` | The React context container and the hook that reads it |
|
|
33
|
+
| `Router` / `RouterProps` / `RouterProvider` / `makeRouterModel()` | Route rendering. `provide` is optional — omitted, the active router plugin's `compile` is used |
|
|
34
|
+
| `useNavigate()` | The `Navigator` — programmatic navigation by entrypoint alias |
|
|
35
|
+
| `Navigator` / `NavRequest` | `navigate` `go` `press` `back` `pressBack` `location`; a request adds `replace` and `silent` to an `AbstractRequest` |
|
|
36
|
+
| `useEntrypoint<T>()` | The `EntrypointContextParams` of the screen currently rendering — `{ alias, path, params, context }` |
|
|
37
|
+
| `RoutedComponent<Extra>` | Type of a component bound to a frontend protocol |
|
|
38
|
+
| `handler(Component, preprender?)` | Wrap a React component as an entrypoint handler |
|
|
39
|
+
| `useStoreModel` / `useStoreList` | React hooks over a `@owlmeans/state` resource — one record by id, or a live query |
|
|
40
|
+
| `useValue(loader, deps?, forceDefault?)` / `UseValueParams<T>` | Render an async result. The second argument is the **dependency list**, not a default — see Async values |
|
|
41
|
+
| `useToggle(opened?)` / `Toggleable` | An open/close/toggle handle, which is what a modal surface binds to |
|
|
42
|
+
| `appendModalService` / `createModalService` / `ModalService` / `ModalStackLayer` | The modal stack — `context.modal()`: `request` `response` `cancel` `error` `layer()` `link(toggle)` |
|
|
43
|
+
| `ModalBodyProps` / `useSetupModalNavigator()` | `{ modal?: ModalService }` — the props a modal body is rendered with; and the hook that lets a body navigate |
|
|
44
|
+
| `appendDebugService` / `createDebugService` / `appendStateDebug(ctx, alias)` / `DebugService` | The debug menu — `context.debug()` |
|
|
45
|
+
| `ClientError`, `ComponentError`, `ComponentPropError`, `ComponentPropUndefined` | The client error family, registered with `ResilientError` |
|
|
46
|
+
| `DEF_MODAL_ALIAS` (`modal`), `DEF_DEBUG_ALIAS` (`debug`), `DEBUGGER_FLAG` / `DEBUG_CONFIG_KEY` (`debugger`) | Constants |
|
|
25
47
|
|
|
26
48
|
## Subpath Exports
|
|
27
49
|
|
|
28
|
-
- `./utils` —
|
|
50
|
+
- `./utils` — `buildEntrypointTree`, `visitEntrypointTree`, `initializeRouter`, `createRouteRenderer`,
|
|
51
|
+
`EntrypointContext`. What the router is assembled from; a package building its own routing surface
|
|
52
|
+
uses these, an application does not.
|
|
53
|
+
|
|
54
|
+
## Navigation
|
|
55
|
+
|
|
56
|
+
Navigation addresses an ALIAS, never a URL — the path lives in the entrypoint declaration, so a
|
|
57
|
+
component never builds one. `useNavigate()` returns the `Navigator`, which asks the target
|
|
58
|
+
entrypoint for its `url(request)` and hands that to the active router plugin:
|
|
59
|
+
|
|
60
|
+
```typescript
|
|
61
|
+
import { useNavigate } from '@owlmeans/client'
|
|
62
|
+
import type { RoutedComponent } from '@owlmeans/client'
|
|
63
|
+
|
|
64
|
+
export const ProjectScreen: RoutedComponent = ({ params }) => {
|
|
65
|
+
const nav = useNavigate()
|
|
66
|
+
|
|
67
|
+
// `go` navigates; `press` returns the handler for an onClick. `params` fills the path
|
|
68
|
+
// parameters of the target entrypoint, `query` the query string, `replace` swaps the
|
|
69
|
+
// history entry instead of pushing one.
|
|
70
|
+
void nav.go(PROJECT_ITEM, { params: { id: params.id }, query: { tab: 'files' } })
|
|
71
|
+
|
|
72
|
+
return <a onClick={nav.press(PROJECT_LIST)}>Back to the list</a>
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
A URL that comes back starting with `http` belongs to another service, and the navigator assigns
|
|
77
|
+
`location.href` rather than pushing a history entry. `nav.navigate(entrypoint, request)` takes the
|
|
78
|
+
entrypoint itself when you already hold it; `nav.back()` / `nav.pressBack()` go one entry back, and
|
|
79
|
+
`nav.location()` reads the current one.
|
|
80
|
+
|
|
81
|
+
A bound screen receives `{ alias, path, params, context }` as props, and `useEntrypoint()`
|
|
82
|
+
reads the same values from anywhere below it — read path parameters from `params` and pass them
|
|
83
|
+
down; a nested component never resolves route parameters itself.
|
|
84
|
+
|
|
85
|
+
## Routing and guards
|
|
86
|
+
|
|
87
|
+
`App` mounts `Router`, which resolves the frontend entrypoints the context holds into a nested
|
|
88
|
+
route tree. Only entrypoints whose route is `AppType.Frontend` are mounted, and among those only
|
|
89
|
+
the ones that name no service at all, name this app's service, or are `sticky`. Each node
|
|
90
|
+
contributes **only its own segment** — its ancestors already carry theirs, so a declaration nests
|
|
91
|
+
by naming a `parent`.
|
|
92
|
+
|
|
93
|
+
A screen's guards are its own plus every ancestor's, taken from `getGuards()`. An empty list is an
|
|
94
|
+
open screen; when the list is non-empty and no guard matches, the renderer throws
|
|
95
|
+
`AuthorizationError('frontend-guard')`.
|
|
96
|
+
|
|
97
|
+
## Client state
|
|
98
|
+
|
|
99
|
+
State lives on the context as a `@owlmeans/state` resource; these hooks subscribe to it.
|
|
100
|
+
|
|
101
|
+
```typescript
|
|
102
|
+
import { useStoreList, useStoreModel } from '@owlmeans/client'
|
|
103
|
+
|
|
104
|
+
const task = useStoreModel<Task>(id, TASKS) // one record
|
|
105
|
+
const open = useStoreList<Task>({ query: { status: 'open' }, resource: TASKS }) // live query
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
`useStoreModel` returns a `StateModel` — read `model.record`, write with `model.update({ ... })`.
|
|
109
|
+
Never assign into `model.record` — it is not a snapshot. On a model the store backs, it IS the
|
|
110
|
+
object the store holds: a field assignment mutates what every other holder of that key reads, and
|
|
111
|
+
the next `update()`/`commit()` carries the mutation through, while nothing notifies and nothing
|
|
112
|
+
re-renders. The hook never throws for missing data either — an id the store knows nothing about
|
|
113
|
+
yields a model whose `empty` is true, and nothing is written into the store on the way.
|
|
114
|
+
`useStoreList` takes `{ query?, sort?, resource? }` and matches everything when `query` is omitted.
|
|
115
|
+
Full contract: [[state]].
|
|
116
|
+
|
|
117
|
+
Both hooks go through `useSyncExternalStore`, and the live subscription React installs is torn down
|
|
118
|
+
with the component. The FIRST snapshot is taken during render, by subscribing and unsubscribing
|
|
119
|
+
again in one statement — a state resource seeds its listener synchronously, so no render runs
|
|
120
|
+
without a value and that momentary subscription never outlives the call. The value is then cached
|
|
121
|
+
and the same reference is returned until something actually changes, which is what keeps React from
|
|
122
|
+
re-rendering forever.
|
|
123
|
+
|
|
124
|
+
## Async values
|
|
125
|
+
|
|
126
|
+
`useValue(loader, deps?, forceDefault?)` runs an async loader in an effect and answers with the
|
|
127
|
+
default — `null` when there is none — until it resolves. Its second argument is overloaded, and
|
|
128
|
+
reading it as "a default" is the standard mistake:
|
|
129
|
+
|
|
130
|
+
```typescript
|
|
131
|
+
useValue(async () => api.load(id), [id]) // a DependencyList — re-runs on id
|
|
132
|
+
useValue(async () => api.load(id), { default: EMPTY, deps: [id] }) // both, via UseValueParams
|
|
133
|
+
useValue(async () => api.load(id)) // no deps — the loader runs once
|
|
134
|
+
useValue(async () => api.count(), 0) // a bare non-array value IS the default
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
The deps always come from the argument's SHAPE: an array is the dependency list itself, an object
|
|
138
|
+
with a `deps` key gives `deps ?? []`, and anything else gives `[]`. The default is read from the
|
|
139
|
+
same argument: `default` off a `UseValueParams` object, `null` when an array was passed, the value
|
|
140
|
+
itself otherwise. `forceDefault: true` changes only the second half — the argument is then taken as
|
|
141
|
+
the default whatever its shape, while still deciding the deps.
|
|
142
|
+
|
|
143
|
+
The loader is handed a `MutableRefObject<boolean>` cancel ref, which the effect's cleanup sets to
|
|
144
|
+
`true`, so a loader that awaits more than once checks `cancel.current` before it commits. A loader that resolves to a **function** is kept aside and returned as it is, rather than
|
|
145
|
+
being run as a state updater — which is what lets a component be an async value.
|
|
146
|
+
|
|
147
|
+
## Modals
|
|
148
|
+
|
|
149
|
+
`context.modal()` owns a STACK of body components and one surface. The surface is a component the
|
|
150
|
+
app mounts once: it links a toggle to the service, reads the top layer through `layer()`, and
|
|
151
|
+
renders it with the service as a prop.
|
|
29
152
|
|
|
30
|
-
|
|
153
|
+
```tsx
|
|
154
|
+
import { useContext, useSetupModalNavigator, useToggle, useValue } from '@owlmeans/client'
|
|
155
|
+
import type { ModalBodyProps } from '@owlmeans/client'
|
|
156
|
+
import { useEffect } from 'react'
|
|
157
|
+
import type { FC } from 'react'
|
|
31
158
|
|
|
32
|
-
|
|
159
|
+
export const Modal: FC = () => {
|
|
160
|
+
useSetupModalNavigator() // lets a body navigate; call it once
|
|
161
|
+
const context = useContext()
|
|
162
|
+
const toggle = useToggle(false)
|
|
163
|
+
|
|
164
|
+
useEffect(() => {
|
|
165
|
+
void context.waitForInitialized().then(() => context.modal().link(toggle))
|
|
166
|
+
}, [])
|
|
167
|
+
|
|
168
|
+
const Com = useValue<FC<ModalBodyProps> | undefined>(
|
|
169
|
+
async () => toggle.opened ? context.modal().layer()?.Com : undefined,
|
|
170
|
+
[toggle.opened]
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
return <Dialog open={toggle.opened} onOpenChange={toggle.set}>
|
|
174
|
+
{Com != null ? <Com modal={context.modal()} /> : undefined}
|
|
175
|
+
</Dialog>
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
A **body is an `FC<ModalBodyProps>`** — it receives the service as an optional `modal` prop, and
|
|
180
|
+
that prop is how it answers. Nothing else reaches it, so whatever a body needs travels in the
|
|
181
|
+
closure of the component that requested it.
|
|
33
182
|
|
|
34
183
|
```typescript
|
|
35
|
-
|
|
36
|
-
const navigateTo = navigate(context)
|
|
37
|
-
navigateTo('/projects')
|
|
184
|
+
const result = await context.modal().request<Answer>(ConfirmBody) // null when cancelled
|
|
38
185
|
```
|
|
39
186
|
|
|
187
|
+
`request` pushes the body onto the stack, opens the linked toggle, and resolves when the body calls
|
|
188
|
+
`modal.response(value)`, `modal.cancel()` (which resolves `null`) or `modal.error(e)` (which
|
|
189
|
+
rejects). All three settle the promise first, then pop the layer and close the surface — and
|
|
190
|
+
`request` pops a SECOND time when its own `await` resumes. One completed request therefore removes
|
|
191
|
+
two layers.
|
|
192
|
+
|
|
193
|
+
**Keep the stack one deep.** A lone body ends on an empty stack and the second pop costs nothing.
|
|
194
|
+
A body requested from inside another body takes its parent down with it: closing the child pops the
|
|
195
|
+
child, sees a layer still there and schedules the surface to reopen 500 ms later, and then the
|
|
196
|
+
child's continuation pops the parent in the microtask before that timer fires. The surface reopens
|
|
197
|
+
with `layer()` answering `undefined` and nothing to render, and the parent's own `request` — whose
|
|
198
|
+
deferred no one is left to settle — never resolves. Chain from the caller instead: await the first
|
|
199
|
+
request, then issue the next.
|
|
200
|
+
|
|
201
|
+
## Debug menu
|
|
202
|
+
|
|
203
|
+
`appendDebugService` registers the menu only when `cfg.debug.all` or `cfg.debug.debugger` is set,
|
|
204
|
+
so `context.debug()` answers `undefined` in a normal build and a caller must handle that. A package
|
|
205
|
+
that owns a client resource calls `appendStateDebug(context, alias)` at wiring time to have it
|
|
206
|
+
listed under "Reset states"; "Reset app" erases the whole client DB.
|
|
207
|
+
|
|
40
208
|
## Depends On
|
|
41
209
|
|
|
42
|
-
- `@owlmeans/client-context`, `@owlmeans/client-entrypoint`, `@owlmeans/client-
|
|
43
|
-
- `@owlmeans/router`, `@owlmeans/
|
|
44
|
-
|
|
210
|
+
- `@owlmeans/client-context`, `@owlmeans/client-entrypoint`, `@owlmeans/client-resource`
|
|
211
|
+
- `@owlmeans/router` (the routing plugin surface), `@owlmeans/state`, `@owlmeans/entrypoint`,
|
|
212
|
+
`@owlmeans/resource`, `@owlmeans/config`, `@owlmeans/context`, `@owlmeans/auth`, `@owlmeans/error`
|
|
213
|
+
- `react` and `@remix-run/router` (peer)
|
|
214
|
+
|
|
215
|
+
## Related
|
|
216
|
+
|
|
217
|
+
- [[web-client]] — the browser layer built on this
|
|
218
|
+
- [[state]] — the store the two state hooks read
|
|
219
|
+
- [[router]] — the routing plugin `context.router()` resolves
|
package/build/context.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,OAAO,CAAA;AAEpD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAA;AAE5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAA;AAmB/C,eAAO,MAAM,iBAAiB,GAAI,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC,CAAC,CAAC,OAAO,CAAC,KAAG,CA4BjH,CAAA;AAED,eAAO,MAAM,sBAAsB,2CAA+C,CAAA;AAElF,eAAO,MAAM,OAAO,uDAAkC,CAAA;AAEtD,eAAO,MAAM,UAAU,GAAI,CAAC,SAAS,YAAY,EAAE,CAAC,SAAS,aAAa,CAAC,CAAC,CAAC,QAE5E,CAAA"}
|
package/build/context.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createContext, useContext as useCtx } from 'react';
|
|
2
2
|
import { makeClientContext as makeBasicContext, PLUGINS } from '@owlmeans/client-context';
|
|
3
|
-
import { AppType, CONFIG_RECORD
|
|
3
|
+
import { AppType, CONFIG_RECORD } from '@owlmeans/context';
|
|
4
4
|
import { appendStateResource } from '@owlmeans/state';
|
|
5
5
|
import { appendModalService } from './components/modal.js';
|
|
6
6
|
import { appendDebugService } from './services/debug.js';
|
|
@@ -9,7 +9,6 @@ import { ROUTER_SERVICE } from '@owlmeans/router';
|
|
|
9
9
|
const defaultCfg = {
|
|
10
10
|
services: {},
|
|
11
11
|
brand: {},
|
|
12
|
-
layer: Layer.Service,
|
|
13
12
|
trusted: [],
|
|
14
13
|
[CONFIG_RECORD]: [],
|
|
15
14
|
ready: false,
|
|
@@ -40,7 +39,6 @@ export const makeClientContext = (cfg) => {
|
|
|
40
39
|
};
|
|
41
40
|
}
|
|
42
41
|
context.router = () => context.service(ROUTER_SERVICE);
|
|
43
|
-
context.makeContext = makeClientContext;
|
|
44
42
|
return context;
|
|
45
43
|
};
|
|
46
44
|
export const ClientContextContainer = createContext(makeClientContext(defaultCfg));
|
package/build/context.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,UAAU,IAAI,MAAM,EAAE,MAAM,OAAO,CAAA;AAE3D,OAAO,EAAE,iBAAiB,IAAI,gBAAgB,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAEzF,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,UAAU,IAAI,MAAM,EAAE,MAAM,OAAO,CAAA;AAE3D,OAAO,EAAE,iBAAiB,IAAI,gBAAgB,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAA;AAEzF,OAAO,EAAE,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAA;AAE1D,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAA;AACrD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAA;AAC1D,OAAO,EAAE,kBAAkB,EAAE,MAAM,qBAAqB,CAAA;AACxD,OAAO,EAAE,oBAAoB,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAA;AAEtE,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAA;AAEjD,MAAM,UAAU,GAAiB;IAC/B,QAAQ,EAAE,EAAE;IACZ,KAAK,EAAE,EAAE;IACT,OAAO,EAAE,EAAE;IACX,CAAC,aAAa,CAAC,EAAE,EAAE;IACnB,KAAK,EAAE,KAAK;IACZ,OAAO,EAAE,EAAE;IACX,KAAK,EAAE,EAAE;IACT,IAAI,EAAE,OAAO,CAAC,QAAQ;CACvB,CAAA;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAwE,GAAM,EAAK,EAAE;IACpH,MAAM,OAAO,GAAG,gBAAgB,CAAC,GAAG,CAAM,CAAA;IAC1C,mBAAmB,CAAO,OAAO,CAAC,CAAA;IAClC,kBAAkB,CAAO,OAAO,CAAC,CAAA;IACjC,oBAAoB,CAAO,OAAO,CAAC,CAAA;IACnC,oBAAoB,CAAO,OAAO,EAAE,OAAO,EAAE,aAAa,CAAC,CAAA;IAC3D,kBAAkB,CAAO,OAAO,CAAC,CAAA;IAEjC,IAAI,OAAO,CAAC,kBAAkB,IAAI,IAAI,EAAE,CAAC;QACvC,MAAM,WAAW,GAAuB,EAAE,CAAA;QAE1C,OAAO,CAAC,kBAAkB,GAAG,QAAQ,CAAC,EAAE;YACtC,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAA;YAC1B,OAAO,GAAG,EAAE;gBACV,MAAM,KAAK,GAAG,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;gBAC3C,IAAI,KAAK,IAAI,CAAC,EAAE,CAAC;oBACf,WAAW,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,CAAA;gBAC9B,CAAC;YACH,CAAC,CAAA;QACH,CAAC,CAAA;QACD,OAAO,CAAC,QAAQ,GAAG,GAAG,EAAE;YACtB,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,QAAQ,EAAE,CAAC,CAAA;QAC7C,CAAC,CAAA;IACH,CAAC;IAED,OAAO,CAAC,MAAM,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,OAAO,CAAgB,cAAc,CAAC,CAAA;IAErE,OAAO,OAAO,CAAA;AAChB,CAAC,CAAA;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,aAAa,CAAC,iBAAiB,CAAC,UAAU,CAAC,CAAC,CAAA;AAElF,MAAM,CAAC,MAAM,OAAO,GAAG,sBAAsB,CAAC,QAAQ,CAAA;AAEtD,MAAM,CAAC,MAAM,UAAU,GAAG,GAAuD,EAAE,CAAC,MAAM,CACxF,sBAAoD,CACrD,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"entrypoint.d.ts","sourceRoot":"","sources":["../src/entrypoint.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAEzD,eAAO,MAAM,aAAa,GAAI,CAAC,SAAS,EAAE,GAAG,EAAE,OAAwC,uBAAuB,CAAC,CAAC,CAAC,CAAA"}
|