@swarm.ing/pieui 2.1.4 → 2.1.6

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.
Files changed (72) hide show
  1. package/README.md +595 -124
  2. package/dist/cli.js +2208 -14
  3. package/dist/code/commands/listEvents.d.ts.map +1 -1
  4. package/dist/code/commands/registry.d.ts.map +1 -1
  5. package/dist/components/PieCard/index.d.ts +1 -1
  6. package/dist/components/PieCard/index.d.ts.map +1 -1
  7. package/dist/components/PieCard/types/index.d.ts +11 -0
  8. package/dist/components/PieCard/types/index.d.ts.map +1 -1
  9. package/dist/components/index.esm.js +1 -1
  10. package/dist/components/index.js +1 -1
  11. package/dist/index.esm.js +2 -2
  12. package/dist/index.js +2 -2
  13. package/dist/max/index.esm.js +1 -1
  14. package/dist/max/index.js +1 -1
  15. package/dist/native/PieNativeRoot.d.ts +15 -0
  16. package/dist/native/PieNativeRoot.d.ts.map +1 -0
  17. package/dist/native/components/AutoRedirectCard.d.ts +10 -0
  18. package/dist/native/components/AutoRedirectCard.d.ts.map +1 -0
  19. package/dist/native/components/BoxCard.d.ts +13 -0
  20. package/dist/native/components/BoxCard.d.ts.map +1 -0
  21. package/dist/native/components/DeviceStorageCard.d.ts +12 -0
  22. package/dist/native/components/DeviceStorageCard.d.ts.map +1 -0
  23. package/dist/native/components/HTMLEmbedCard.d.ts +11 -0
  24. package/dist/native/components/HTMLEmbedCard.d.ts.map +1 -0
  25. package/dist/native/components/HiddenCard.d.ts +11 -0
  26. package/dist/native/components/HiddenCard.d.ts.map +1 -0
  27. package/dist/native/components/IOEventsCard.d.ts +11 -0
  28. package/dist/native/components/IOEventsCard.d.ts.map +1 -0
  29. package/dist/native/components/OneOfCard.d.ts +12 -0
  30. package/dist/native/components/OneOfCard.d.ts.map +1 -0
  31. package/dist/native/components/SequenceCard.d.ts +12 -0
  32. package/dist/native/components/SequenceCard.d.ts.map +1 -0
  33. package/dist/native/components/SessionStorageCard.d.ts +9 -0
  34. package/dist/native/components/SessionStorageCard.d.ts.map +1 -0
  35. package/dist/native/components/index.d.ts +13 -0
  36. package/dist/native/components/index.d.ts.map +1 -0
  37. package/dist/native/index.d.ts +41 -0
  38. package/dist/native/index.d.ts.map +1 -0
  39. package/dist/native/index.esm.js +3 -0
  40. package/dist/native/index.js +3 -0
  41. package/dist/platform/clientSources.d.ts +4 -0
  42. package/dist/platform/clientSources.d.ts.map +1 -0
  43. package/dist/platform/clientSources.native.d.ts +4 -0
  44. package/dist/platform/clientSources.native.d.ts.map +1 -0
  45. package/dist/platform/clientSources.web.d.ts +10 -0
  46. package/dist/platform/clientSources.web.d.ts.map +1 -0
  47. package/dist/platform/nativeConfig.d.ts +63 -0
  48. package/dist/platform/nativeConfig.d.ts.map +1 -0
  49. package/dist/platform/nativeFormStore.d.ts +12 -0
  50. package/dist/platform/nativeFormStore.d.ts.map +1 -0
  51. package/dist/platform/types.d.ts +39 -0
  52. package/dist/platform/types.d.ts.map +1 -0
  53. package/dist/providers/SocketIOInitProvider.d.ts.map +1 -1
  54. package/dist/telegram/index.esm.js +1 -1
  55. package/dist/telegram/index.js +1 -1
  56. package/dist/tests/centrifugeRecovery.test.d.ts +2 -0
  57. package/dist/tests/centrifugeRecovery.test.d.ts.map +1 -0
  58. package/dist/tests/clientSources.test.d.ts +2 -0
  59. package/dist/tests/clientSources.test.d.ts.map +1 -0
  60. package/dist/tests/clientSourcesNative.test.d.ts +12 -0
  61. package/dist/tests/clientSourcesNative.test.d.ts.map +1 -0
  62. package/dist/tests/piecardRecovery.test.d.ts +2 -0
  63. package/dist/tests/piecardRecovery.test.d.ts.map +1 -0
  64. package/dist/util/ajaxCommonUtils.d.ts.map +1 -1
  65. package/dist/util/centrifuge.d.ts +5 -0
  66. package/dist/util/centrifuge.d.ts.map +1 -1
  67. package/dist/util/centrifugeRecovery.d.ts +26 -0
  68. package/dist/util/centrifugeRecovery.d.ts.map +1 -0
  69. package/dist/util/globalForm.d.ts +4 -5
  70. package/dist/util/globalForm.d.ts.map +1 -1
  71. package/dist/util/waitForSidAvailable.d.ts.map +1 -1
  72. package/package.json +17 -4
package/README.md CHANGED
@@ -1,22 +1,93 @@
1
1
  # PieUI
2
2
 
3
- PieUI is a React component library for rendering server-driven UI "cards" with optional real-time and AJAX updates. It provides a component registry, root wrappers that set up providers, and helpers for styling and class name management.
4
-
5
- **Install**
3
+ **PieUI** (`@swarm.ing/pieui`) is a React library for rendering **server-driven UIs**. A backend returns a JSON description of a screen, and PieUI turns it into a React tree by looking up each node in a component **registry**. On top of rendering it ships real-time messaging (Socket.IO, Centrifuge, Mitt), server-driven AJAX updates, host integrations (Telegram Mini Apps, MAX, React Native), an OpenAI voice-agent bridge, a Storybook addon, and a `pieui` CLI for scaffolding apps, pages, and cards.
4
+
5
+ - **Server-driven** — screens are described by data (`UIConfigType`), not code.
6
+ - **Registry-based** — register components by name; the backend references them by that name.
7
+ - **Real-time** — cards can subscribe to Socket.IO, Centrifuge, or in-process Mitt events.
8
+ - **Multi-platform** — web, Telegram Mini Apps, MAX (VK), and React Native from one core.
9
+ - **Tooling** — a CLI that scaffolds Next.js apps, generates cards/pages, and syncs a component registry.
10
+
11
+ > React and React DOM `>=19` are peer dependencies. React Native `>=0.74` and `@openai/agents` are **optional** peers (only needed for the `/native` and `/agent` entries).
12
+
13
+ ---
14
+
15
+ ## Table of contents
16
+
17
+ - [Installation](#installation)
18
+ - [Core concepts](#core-concepts)
19
+ - [Quick start](#quick-start)
20
+ - [Package entry points](#package-entry-points)
21
+ - [Root components](#root-components)
22
+ - [Registering components](#registering-components)
23
+ - [Component prop shapes](#component-prop-shapes)
24
+ - [Built-in cards](#built-in-cards)
25
+ - [Real-time messaging](#real-time-messaging)
26
+ - [Server-driven AJAX updates](#server-driven-ajax-updates)
27
+ - [`depsNames` — client-side submit sources](#depsnames--client-side-submit-sources)
28
+ - [Configuration & environment](#configuration--environment)
29
+ - [Registry API](#registry-api)
30
+ - [Styling helpers](#styling-helpers)
31
+ - [Platform integrations](#platform-integrations)
32
+ - [Telegram Mini Apps](#telegram-mini-apps)
33
+ - [MAX (VK Messenger)](#max-vk-messenger)
34
+ - [React Native](#react-native)
35
+ - [OpenAI agent integration](#openai-agent-integration)
36
+ - [Storybook integration](#storybook-integration)
37
+ - [CLI reference](#cli-reference)
38
+ - [API reference](#api-reference)
39
+ - [License](#license)
40
+
41
+ ---
42
+
43
+ ## Installation
6
44
 
7
45
  ```sh
8
46
  bun add @swarm.ing/pieui
47
+ # or
9
48
  npm install @swarm.ing/pieui
49
+ # or
50
+ pnpm add @swarm.ing/pieui
51
+ ```
52
+
53
+ ```jsonc
54
+ // peerDependencies
55
+ "react": ">=19",
56
+ "react-dom": ">=19",
57
+ "react-native": ">=0.74", // optional — only for @swarm.ing/pieui/native
58
+ "@openai/agents": "^0.4.5" // optional — only for @swarm.ing/pieui/agent
10
59
  ```
11
60
 
12
- React and React DOM `>=19` are peer dependencies.
61
+ ---
62
+
63
+ ## Core concepts
64
+
65
+ **Server-driven UI.** The backend describes a screen as a tree of `UIConfigType` nodes:
66
+
67
+ ```ts
68
+ interface UIConfigType {
69
+ card: string // registry name of the component to render
70
+ data: any // props bag passed to the component as `data`
71
+ content: UIConfigType | UIConfigType[] // nested child config(s), if any
72
+ }
73
+ ```
74
+
75
+ **The registry.** Every renderable component is registered under a `name`. The renderer (`UI`) reads `config.card`, looks it up in the registry, and renders it — passing `data`, `content`, and `setUiAjaxConfiguration` as appropriate.
76
+
77
+ **Cards.** A "card" is just a registered React component. PieUI ships a handful of built-in container/leaf cards (`SequenceCard`, `BoxCard`, `HTMLEmbedCard`, …) and you register your own for everything app-specific.
78
+
79
+ **Side-effect registration.** Importing from `@swarm.ing/pieui` (or `@swarm.ing/pieui/components`) registers the built-in cards automatically as a side effect — there is **no `initializePieComponents()` call to make** anymore. Your own cards register themselves when their module is imported (see [Registering components](#registering-components)).
80
+
81
+ ---
13
82
 
14
- **Quick Start**
83
+ ## Quick start
15
84
 
16
85
  ```tsx
17
- import { PieRoot, initializePieComponents } from '@swarm.ing/pieui'
86
+ 'use client'
18
87
 
19
- initializePieComponents()
88
+ import { PieRoot } from '@swarm.ing/pieui'
89
+ // Importing your registry module triggers side-effect registration of your cards.
90
+ import './piecomponents/registry'
20
91
 
21
92
  export function App() {
22
93
  return (
@@ -25,8 +96,8 @@ export function App() {
25
96
  pathname: window.location.pathname,
26
97
  search: window.location.search,
27
98
  }}
28
- fallback={<>Loading...</>}
29
- onError={() => console.error('Failed to load UI')}
99
+ fallback={<>Loading…</>}
100
+ onError={() => window.location.reload()}
30
101
  onNavigate={(url) => {
31
102
  window.location.href = url
32
103
  }}
@@ -36,17 +107,77 @@ export function App() {
36
107
  'wss://realtime.example.com/connection/websocket',
37
108
  enableRenderingLog: false,
38
109
  }}
39
- initializePie={() => {
40
- // Register custom components here if needed.
41
- }}
42
110
  />
43
111
  )
44
112
  }
45
113
  ```
46
114
 
47
- If you are embedding PieUI inside a Telegram WebApp, use `PieTelegramRoot` instead of `PieRoot`.
115
+ `PieRoot` fetches the screen config from `` `${config.apiServer}/api/content${pathname}?${search}` `` with React Query + Axios, sets up every provider PieUI needs, and renders the resulting tree.
116
+
117
+ - **Telegram Mini App?** Use `PieTelegramRoot` from `@swarm.ing/pieui/telegram`.
118
+ - **MAX mini-app?** Use `PieMaxRoot` from `@swarm.ing/pieui/max`.
119
+ - **React Native?** Use `PieRoot`/`PieNativeRoot` from `@swarm.ing/pieui/native`.
120
+
121
+ ---
122
+
123
+ ## Package entry points
124
+
125
+ PieUI is split into focused entry points so apps only ship what they use:
126
+
127
+ | Import path | Contents |
128
+ | ---------------------------------- | ----------------------------------------------------------------------------------------- |
129
+ | `@swarm.ing/pieui` | Main barrel: roots, `UI`, `PieCard`, registry API, hooks, types, built-in card side-effect |
130
+ | `@swarm.ing/pieui/components` | Just the built-in cards + `UI`/`PieCard` (registers built-ins on import) |
131
+ | `@swarm.ing/pieui/telegram` | `PieTelegramRoot`, Telegram WebApp hooks, `CloudStorageCard`/`SecureStorageCard` |
132
+ | `@swarm.ing/pieui/max` | `PieMaxRoot` and MAX (VK) WebApp hooks |
133
+ | `@swarm.ing/pieui/native` | React Native core + native card variants + native source wiring |
134
+ | `@swarm.ing/pieui/agent` | OpenAI agent tools (`getMittAgentTools`, `useOpenAIWebRTC`) — pulls in `@openai/agents` |
135
+ | `@swarm.ing/pieui/storybook` | Storybook providers/decorators for testing cards in isolation |
136
+ | `@swarm.ing/pieui/storybook/addon` | Storybook addon (panel + manager) for firing PieCard methods from the Storybook UI |
137
+
138
+ The Telegram, MAX, and agent integrations are deliberately split out so apps that don't target those hosts never bundle their code.
139
+
140
+ ---
141
+
142
+ ## Root components
143
+
144
+ All roots wrap children in the PieUI provider stack (React Query, Mitt, Socket.IO, Centrifuge, config, navigation, and — unless disabled — a global `<form>`).
145
+
146
+ ### `PieRoot`
48
147
 
49
- **Register Custom Components**
148
+ Fetches a `UIConfigType` from `api/content{pathname}{search}` and renders it.
149
+
150
+ | Prop | Type | Description |
151
+ | ------------------- | --------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
152
+ | `location` | `{ pathname: string; search: string }` | Current route. Used to build the request URL and as part of the React Query key. |
153
+ | `config` | `PieConfig` | Runtime configuration (API URLs, logging, page processor). **Required.** |
154
+ | `fallback` | `ReactNode` | Rendered while loading or on fetch failure. |
155
+ | `piecache` | `Record<string, UIConfigType>` | Optional per-pathname snapshot; a cached shell is shown via `UILoading` instead of the plain `fallback`. |
156
+ | `onError` | `(error?: unknown) => void` | Called on a render-blocking error (config fetch throws, or a lazy card chunk fails after retries). |
157
+ | `onNavigate` | `(url: string) => void` | Navigation handler forwarded through `NavigateContext` so cards route via the host router, not a full reload. |
158
+ | `queryOptions` | `PieQueryOptions` | React Query overrides (everything except `queryKey`/`queryFn`/`enabled`, which PieRoot manages). |
159
+ | `queryClient` | `QueryClient` | Supply a stable (module-singleton) client so the config cache survives remounts. Otherwise one is made per mount. |
160
+ | `disableGlobalForm` | `boolean` | When `true`, the implicit `<form id="piedata_global_form">` wrapper is not rendered. |
161
+
162
+ ### `PieBaseRoot`
163
+
164
+ The provider stack **without** any fetch. Renders `children` inside the same providers and (optional) form shell. Use it when you already have a `UIConfigType` (render it with `UI`) or want PieUI context without a network round-trip.
165
+
166
+ ### `PiePreviewRoot`
167
+
168
+ A root tailored to the CLI preview harness (`pieui registry dev`/`build`) for previewing a single card.
169
+
170
+ ### Platform roots
171
+
172
+ - **`PieTelegramRoot`** (`/telegram`) — like `PieRoot`, but appends Telegram WebApp `initData` to the request query string via `useWebApp`. Throws if `apiServer` is missing.
173
+ - **`PieMaxRoot`** (`/max`) — MAX (VK) equivalent.
174
+ - **`PieNativeRoot`** (`/native`) — `PieBaseRoot` for React Native (no HTML form).
175
+
176
+ ---
177
+
178
+ ## Registering components
179
+
180
+ A card is any React component registered under a name. The CLI generates a per-card `index.ts` that calls `registerPieComponent`, and a `piecomponents/registry.ts` that side-effect-imports each card. Registering manually:
50
181
 
51
182
  ```tsx
52
183
  import { registerPieComponent } from '@swarm.ing/pieui'
@@ -55,167 +186,507 @@ import MyCard from './MyCard'
55
186
  registerPieComponent({
56
187
  name: 'MyCard',
57
188
  component: MyCard,
58
- metadata: {
59
- author: 'You',
60
- description: 'Custom card',
189
+ metadata: { author: 'You', version: '1.0.0', description: 'A custom card' },
190
+ })
191
+ ```
192
+
193
+ **Lazy / code-split cards** — pass a `loader` instead of `component`; PieUI wraps it in `React.lazy` and renders it inside `Suspense` (with an optional `fallback`):
194
+
195
+ ```tsx
196
+ registerPieComponent({
197
+ name: 'HeavyChart',
198
+ loader: () => import('./HeavyChart'),
199
+ fallback: <Spinner />,
200
+ })
201
+ ```
202
+
203
+ `ComponentRegistration` shape:
204
+
205
+ ```ts
206
+ interface ComponentRegistration<TProps> {
207
+ name: string
208
+ component?: ComponentType<TProps>
209
+ loader?: () => Promise<{ default: ComponentType<TProps> }>
210
+ fallback?: ComponentType<{}>
211
+ metadata?: { author?: string; version?: string; description?: string; tags?: string[] }
212
+ }
213
+ ```
214
+
215
+ > A registration must provide a `name` **and** either `component` or `loader`, otherwise `registerPieComponent` throws.
216
+
217
+ ---
218
+
219
+ ## Component prop shapes
220
+
221
+ The renderer passes different props depending on a card's "kind". Pick the matching prop type for your component:
222
+
223
+ | Kind | Prop type | Props received | `card add` type |
224
+ | ------------------- | -------------------------------------- | -------------------------------------------------------- | ------------------- |
225
+ | Simple | `PieSimpleComponentProps<T>` | `{ data }` | `simple` |
226
+ | Complex | `PieComplexComponentProps<T>` | `{ data, setUiAjaxConfiguration? }` | `complex` |
227
+ | Container | `PieContainerComponentProps<T>` | `{ data, content: UIConfigType, setUiAjaxConfiguration? }` | `simple-container` |
228
+ | Complex container | `PieComplexContainerComponentProps<T>` | `{ data, content: UIConfigType[], setUiAjaxConfiguration? }` | `complex-container` |
229
+
230
+ Each has an `InputPie…ComponentProps<T, TStored>` variant that adds a typed `stored` prop (used when a card needs locally stored state — wired through `<PieCard stored={…} />`).
231
+
232
+ ```tsx
233
+ import type { PieContainerComponentProps } from '@swarm.ing/pieui'
234
+
235
+ interface MyData { title: string }
236
+
237
+ export default function Panel({
238
+ data,
239
+ content,
240
+ }: PieContainerComponentProps<MyData>) {
241
+ return (
242
+ <section>
243
+ <h2>{data.title}</h2>
244
+ <UI uiConfig={content} />
245
+ </section>
246
+ )
247
+ }
248
+ ```
249
+
250
+ ---
251
+
252
+ ## Built-in cards
253
+
254
+ These register automatically when you import `@swarm.ing/pieui` (or `/components`).
255
+
256
+ ### Containers
257
+
258
+ | Card | Kind | Description |
259
+ | --------------- | ----------------- | ----------------------------------------------------------------------------- |
260
+ | `SequenceCard` | complex-container | Renders an array of children sequentially inside a styled wrapper. |
261
+ | `UnionCard` | complex-container | Renders an array of children with no wrapping element. |
262
+ | `OneOfCard` | complex-container | Renders children in a styled wrapper (typically for conditional selection). |
263
+ | `BoxCard` | container | Single-child wrapper with optional click-to-navigate and inline styling. |
264
+ | `AjaxGroupCard` | container | Single-child group that loads/replaces its content via AJAX and emits events. |
265
+
266
+ ### Common (leaf)
267
+
268
+ | Card | Kind | Description |
269
+ | -------------------- | ------ | ----------------------------------------------------------------------------------- |
270
+ | `HiddenCard` | simple | Renders a hidden input with state management and real-time value sync. |
271
+ | `HTMLEmbedCard` | simple | Parses and renders arbitrary HTML (optionally driven by OpenAI WebRTC generation). |
272
+ | `AutoRedirectCard` | simple | Redirects on mount (internal route or external URL). |
273
+ | `IOEventsCard` | simple | Handles toast notifications, alerts, push notifications, and redirect/reload events. |
274
+ | `DeviceStorageCard` | simple | Persists data to `localStorage`, mirrored into a hidden input for form submission. |
275
+ | `SessionStorageCard` | simple | Persists data to `sessionStorage`, mirrored into a hidden input. |
276
+
277
+ ### Telegram-only (register via `@swarm.ing/pieui/telegram`)
278
+
279
+ | Card | Kind | Description |
280
+ | ------------------- | ------ | ----------------------------------------------------------------- |
281
+ | `CloudStorageCard` | simple | Persists data to Telegram `CloudStorage` (async), hidden-input mirror. |
282
+ | `SecureStorageCard` | simple | Persists data to Telegram `SecureStorage` (async), hidden-input mirror. |
283
+
284
+ The storage cards pair with the AJAX `depsNames` prefixes: `localStorage:` ↔ `DeviceStorageCard`, `sessionStorage:` ↔ `SessionStorageCard`, `telegram:cloud:` ↔ `CloudStorageCard`, `telegram:secure:` ↔ `SecureStorageCard` (see [`depsNames`](#depsnames--client-side-submit-sources)).
285
+
286
+ ---
287
+
288
+ ## Real-time messaging
289
+
290
+ `PieCard` wires a card into PieUI's real-time transports. It renders no UI of its own — it returns its `children` and, on mount, subscribes the supplied `methods` map to whichever transports are enabled:
291
+
292
+ | Transport | Event / channel format | Enable with |
293
+ | ------------- | --------------------------------------------------- | ----------------------- |
294
+ | **Socket.IO** | `pie{methodName}_{data.name}` | `useSocketioSupport` |
295
+ | **Centrifuge**| `pie{methodName}_{data.name}_{centrifugeChannel}` | `useCentrifugeSupport` + `centrifugeChannel` |
296
+ | **Mitt** | `pie{methodName}_{data.name}` | `useMittSupport` |
297
+
298
+ ```tsx
299
+ import { PieCard } from '@swarm.ing/pieui'
300
+
301
+ function LiveCounter({ data }) {
302
+ const [count, setCount] = useState(0)
303
+ return (
304
+ <PieCard
305
+ card="LiveCounter"
306
+ data={data}
307
+ useMittSupport
308
+ useSocketioSupport
309
+ methods={{
310
+ increment: (payload) => setCount((c) => c + (payload?.by ?? 1)),
311
+ reset: () => setCount(0),
312
+ }}
313
+ >
314
+ <span>{count}</span>
315
+ </PieCard>
316
+ )
317
+ }
318
+ ```
319
+
320
+ The `methods` map is held in a ref, so you can pass freshly-created closures every render without re-subscribing. Cleanup runs on unmount or when `data.name`/the support flags change.
321
+
322
+ ### Emitting Mitt events — `usePieEmit`
323
+
324
+ Trigger a card's Mitt-subscribed method from anywhere in the tree:
325
+
326
+ ```tsx
327
+ import { usePieEmit } from '@swarm.ing/pieui'
328
+
329
+ function Controls() {
330
+ const emit = usePieEmit('LiveCounter') // card name
331
+ return <button onClick={() => emit('increment', { by: 5 })}>+5</button>
332
+ }
333
+ ```
334
+
335
+ `getEmitter()` returns the shared emitter for imperative use outside React.
336
+
337
+ ---
338
+
339
+ ## Server-driven AJAX updates
340
+
341
+ Cards that trigger updates receive a `setUiAjaxConfiguration` callback. Combined with `useAjaxSubmit`, a card can POST to the backend and swap part of the UI — or stream UI events — without a full reload.
342
+
343
+ ```tsx
344
+ import { useAjaxSubmit } from '@swarm.ing/pieui'
345
+
346
+ function SubmitButton({ data, setUiAjaxConfiguration }) {
347
+ const submit = useAjaxSubmit(
348
+ setUiAjaxConfiguration,
349
+ data.kwargs, // static key/values from the card config
350
+ data.deps_names, // client-side values resolved at submit time
351
+ data.pathname, // backend handler path
352
+ { timeout: 10_000, retryPolicy: { maxRetries: 2, baseDelay: 1000 } }
353
+ )
354
+ return <button onClick={() => submit({ extra: 'value' })}>Submit</button>
355
+ }
356
+ ```
357
+
358
+ The request is `POST {apiServer}/api/ajax_content{pathname}`, and the response either replaces the `UIConfigType` subtree or streams JSON-line UI events through `setUiAjaxConfiguration`. The body is assembled from three sources:
359
+
360
+ 1. **`kwargs`** — static key/value pairs from the card config.
361
+ 2. **`extraKwargs`** — values passed to the returned submit function at call time.
362
+ 3. **`depsNames`** — names whose **current client-side value** is read at submit time (see below).
363
+
364
+ ### `RetryPolicy`
365
+
366
+ ```ts
367
+ type RetryPolicy = {
368
+ maxRetries?: number // default 0 (no retries)
369
+ baseDelay?: number // default 1000 ms; doubled each attempt
370
+ retryOn?: number[] // default [502, 503, 504]; timeouts/network errors always retry
371
+ }
372
+ ```
373
+
374
+ ---
375
+
376
+ ## `depsNames` — client-side submit sources
377
+
378
+ Each entry in `depsNames` is a "magic name": an optional **source prefix** plus a key. The value is submitted under the **bare key** (the part after the prefix), so `localStorage:token` is sent as the field `token`.
379
+
380
+ | `depsNames` entry | Read from |
381
+ | ------------------------ | ------------------------------------------------------------- |
382
+ | `email` *(no prefix)* | DOM input named `email` (`document.getElementsByName`) |
383
+ | `sid` | `window.sid` — Socket.IO session id (awaits the socket) |
384
+ | `localStorage:<key>` | `localStorage.getItem(key)` |
385
+ | `sessionStorage:<key>` | `sessionStorage.getItem(key)` |
386
+ | `cookie:<name>` | matching cookie from `document.cookie` (URL-decoded) |
387
+ | `url:<param>` | `?<param>` query params (repeated → multiple values) |
388
+ | `telegram:cloud:<key>` | `Telegram.WebApp.CloudStorage.getItem` *(async)* |
389
+ | `telegram:secure:<key>` | `Telegram.WebApp.SecureStorage.getItem` *(async)* |
390
+
391
+ ```ts
392
+ depsNames: ['email', 'localStorage:token', 'url:ref', 'sid']
393
+ // POST body fields: email, token, ref, sid
394
+ ```
395
+
396
+ Notes:
397
+
398
+ - A **missing value contributes nothing** — the field is simply omitted (same as an absent DOM input).
399
+ - A single entry can yield **multiple values** (a multi-file `<input>`, repeated `url:` params); each is appended under the same bare key.
400
+ - `telegram:cloud:` / `telegram:secure:` are **async**. The submit flow awaits them; the sync `readAjaxKey` returns `[]` for them, so use `readAjaxKeyAsync` to read directly. `parseDepName(name)` returns `{ source, key }`.
401
+ - `depsNames` is normally supplied by the backend `UIConfig` at runtime — it is data interpreted by the frontend, not a CLI surface.
402
+
403
+ ---
404
+
405
+ ## Configuration & environment
406
+
407
+ `PieConfig` (passed to roots as `config`):
408
+
409
+ ```ts
410
+ interface PieConfig {
411
+ apiServer: string // base URL of the PieUI API (build endpoints from it)
412
+ centrifugeServer?: string // Centrifuge websocket URL
413
+ enableRenderingLog?: boolean // verbose render/AJAX/realtime logging
414
+ pageProcessor?: string // page-processing configuration
415
+ }
416
+ ```
417
+
418
+ When PieUI is wired through the CLI scaffold, these are read from environment variables (multiple framework prefixes supported):
419
+
420
+ - `PIE_API_SERVER` / `VITE_PIE_API_SERVER` / `NEXT_PUBLIC_PIE_API_SERVER`
421
+ - `PIE_CENTRIFUGE_SERVER` / `VITE_PIE_CENTRIFUGE_SERVER` / `NEXT_PUBLIC_PIE_CENTRIFUGE_SERVER`
422
+ - `PIE_ENABLE_RENDERING_LOG` (optional)
423
+ - `PIE_PAGE_PROCESSOR` (optional)
424
+
425
+ Use the literal value `auto-api` for a server URL to derive it automatically from the current hostname.
426
+
427
+ ---
428
+
429
+ ## Registry API
430
+
431
+ All exported from `@swarm.ing/pieui` (and `/native`):
432
+
433
+ | Function | Description |
434
+ | --------------------------------- | ---------------------------------------------------------------------------- |
435
+ | `registerPieComponent(reg)` | Register a component or lazy loader. Returns the (possibly lazy) component. |
436
+ | `registerMultipleComponents([…])` | Register an array of registrations at once. |
437
+ | `unregisterComponent(name)` | Remove a component from the registry. |
438
+ | `hasComponent(name)` | `true` if a name is registered. |
439
+ | `getRegistryEntry(name)` | Full `ComponentRegistration` (incl. `fallback` / `isLazy`). |
440
+ | `getComponentMeta(name)` | The `metadata` supplied at registration, if any. |
441
+ | `getAllRegisteredComponents()` | Array of all registered names. |
442
+ | `getRegistrySize()` | Number of registered components. |
443
+ | `getLazyComponentNames()` | Names of code-split (lazy) components. |
444
+ | `preloadComponent(name)` | Warm a single lazy chunk so the next render resolves without a fallback flash. |
445
+ | `prefetchLazyComponents()` | Idle-time, connection-aware background warm-up of every lazy chunk (idempotent). |
446
+ | `registry` | The underlying `Map` (shared singleton across all entry points). |
447
+ | `trackLazy(loader, name)` | Low-level `React.lazy` wrapper with named tracking. |
448
+
449
+ > The registry is stored on `globalThis` under a shared `Symbol.for` key, so a card registered through one entry point (`/components`) is visible to a renderer loaded from another (`/telegram`). This avoids "[UI] Component not found in registry" across bundles.
450
+
451
+ ---
452
+
453
+ ## Styling helpers
454
+
455
+ - **`cn(...classes)`** — class-name merge built on `clsx` + `tailwind-merge` (dedupes conflicting Tailwind utilities).
456
+ - **`sx2radium(style)`** — converts a style object into Radium-friendly `CSSProperties`, including turning an object `animationName` into Radium keyframes.
457
+ - **`PIEBREAK`** — the `__piedemo__` delimiter used internally to build form field names.
458
+ - **`pieName(...)`** — helper for composing Pie event/field names.
459
+ - **`submitGlobalForm()`** — programmatically submits the implicit global `<form>`.
460
+
461
+ ---
462
+
463
+ ## Platform integrations
464
+
465
+ ### Telegram Mini Apps
466
+
467
+ ```tsx
468
+ import { PieTelegramRoot, useWebApp, useInitData } from '@swarm.ing/pieui/telegram'
469
+
470
+ function App() {
471
+ return <PieTelegramRoot location={location} config={config} />
472
+ }
473
+ ```
474
+
475
+ - `useWebApp()` — the full `Telegram.WebApp` object (typed: `MainButton`, `BackButton`, `HapticFeedback`, `CloudStorage`, `BiometricManager`, theme params, safe-area insets, fullscreen/orientation, and the Bot API methods).
476
+ - `useInitData()` — the parsed init data.
477
+ - Importing this entry also registers `CloudStorageCard` and `SecureStorageCard`.
478
+
479
+ ### MAX (VK Messenger)
480
+
481
+ ```tsx
482
+ import {
483
+ PieMaxRoot,
484
+ useMaxWebApp,
485
+ useMaxInitData,
486
+ useMaxBackButton,
487
+ useMaxHapticFeedback,
488
+ } from '@swarm.ing/pieui/max'
489
+ ```
490
+
491
+ Typed access to the MAX bridge (`BackButton`, `HapticFeedback`, `DeviceStorage`/`SecureStorage`, `BiometricManager`, share/download helpers, screen capture, etc.).
492
+
493
+ ### React Native
494
+
495
+ The `/native` entry exposes the platform-agnostic core (registry, `UI`, `PieCard`, real-time contexts, AJAX helpers) plus native-specific wiring. It deliberately does **not** export the DOM container/leaf cards — on native the host registers its own React Native leaf components and renders them through `UI`/`PieCard`. Metro resolves the `.native` platform layer automatically.
496
+
497
+ Wire the host's storage / route / form sources once at startup:
498
+
499
+ ```ts
500
+ import { configureNativeClientSources } from '@swarm.ing/pieui/native'
501
+ import { MMKV } from 'react-native-mmkv'
502
+
503
+ const mmkv = new MMKV()
504
+
505
+ configureNativeClientSources({
506
+ storage: {
507
+ getItem: (k) => mmkv.getString(k) ?? null,
508
+ setItem: (k, v) => mmkv.set(k, v),
509
+ removeItem: (k) => mmkv.delete(k),
61
510
  },
511
+ getRouteParams: (key) => getCurrentRoute().params[key] ?? [],
512
+ getInput: (name) => readNativeField(name),
513
+ submitForm: () => {/* host submit */},
62
514
  })
63
515
  ```
64
516
 
65
- **Exports**
66
- Runtime exports:
517
+ `NativeClientConfig` supports sync (`storage`, `sessionStorage`) and async (`asyncStorage`, `asyncSessionStorage`) adapters, `getCookie`, `getRouteParams`, `getInput`, and `submitForm`. Unconfigured sources degrade to the same "missing value" semantics as web (`null` / `[]`). Render with `PieRoot`/`PieNativeRoot` and pass `disableGlobalForm` (there is no HTML form on native). A small native form store is exposed via `setNativeField` / `clearNativeField` / `readNativeField`.
518
+
519
+ ---
520
+
521
+ ## OpenAI agent integration
67
522
 
68
- - `UI`: Renders a `UIConfigType` by looking up `uiConfig.card` in the registry. Supports lazy components via `Suspense` and passes `data`, `content`, and `setUiAjaxConfiguration` into the rendered component.
69
- - `PieRoot`: Fetches UI configuration from `config.apiServer + "/api/content"` using the current `location` and renders `UI` inside PieUI providers (React Query, Socket.IO, Centrifuge, Mitt, Radium). Calls `initializePieComponents()` and your `initializePie` callback once.
70
- - `PieTelegramRoot`: Same as `PieRoot`, but adds Telegram WebApp `initData` to the request query string via `useWebApp`. Throws if `apiServer` is missing.
71
- - `PieBaseRoot`: Provider wrapper without fetching UI configuration. Renders `children` inside the same PieUI provider stack and form shell.
72
- - `PieCard`: Wrapper for card components that wires optional Socket.IO, Centrifuge, or Mitt event handlers based on `methods` and `data.name`. Returns `children` unchanged.
73
- - `registerPieComponent`: Registers a component (or lazy loader) into the PieUI registry, with optional metadata and fallback.
74
- - `initializePieComponents`: Registers the built-in card components once (SequenceCard, BoxCard, UnionCard, AjaxGroupCard, AjaxButtonCard, RedirectButtonCard, ChatCard, HiddenCard, AutoRedirectCard, HTMLEmbedCard, IOEventsCard, OpenAIVoiceAgentCard, TableCard).
75
- - `isPieComponentsInitialized`: Returns `true` if `initializePieComponents` has already been called.
76
- - `useAjaxSubmit`: Hook that returns a function to `POST` to `api/ajax_content` and updates UI state via `setUiAjaxConfiguration`. Supports streamed JSON line events.
77
- - `sx2radium`: Converts a style object to Radium-friendly `CSSProperties`, including converting object `animationName` into Radium keyframes.
78
- - `cn`: Class name merge helper using `clsx` and `tailwind-merge`.
79
- - `PIEBREAK`: String delimiter (`__piedemo__`) used internally to build form field names.
523
+ The `/agent` entry exposes PieCard methods as OpenAI function tools and provides a WebRTC voice hook. It pulls in `@openai/agents`, so it's a separate entry to keep it out of apps that don't need it.
80
524
 
81
- Type exports:
525
+ ```tsx
526
+ import {
527
+ usePieMittAgentTools, // hook: build tools from the active Mitt emitter
528
+ getMittAgentTools, // imperative variant
529
+ useOpenAIWebRTC, // WebRTC voice session hook
530
+ } from '@swarm.ing/pieui/agent'
531
+ ```
82
532
 
83
- - `PieComponentProps`: Union type of the supported Pie component prop shapes.
84
- - `PieSimpleComponentProps`: `{ data }` props for simple components.
85
- - `PieComplexComponentProps`: `{ data, setUiAjaxConfiguration? }` props for components that trigger AJAX or updates.
86
- - `PieContainerComponentProps`: `{ data, content, setUiAjaxConfiguration? }` props for components that render a single nested `UIConfigType`.
87
- - `PieComplexContainerComponentProps`: `{ data, content: UIConfigType[], setUiAjaxConfiguration? }` props for components that render an array of nested configs.
88
- - `PieConfig`: Configuration object for Pie roots. Includes `apiServer` and optional `centrifugeServer`, `enableRenderingLog`, `pageProcessor`.
89
- - `UIConfigType`: Server-driven UI configuration with `card`, `data`, and `content` (nested `UIConfigType` or array).
90
- - `SetUiAjaxConfigurationType`: Setter type for updating the UI configuration or streaming UI events.
533
+ - `getMittAgentTools(descriptors, options)` / `usePieMittAgentTools(...)` turn PieCard methods into agent tools. Options: `filter`, `describe`, and `nameFor` to control which descriptors become tools, their descriptions, and tool names.
534
+ - `useOpenAIWebRTC(audioElement?, onEvent?)` — returns `{ isSessionActive, startSession(ephemeralKey, useMicrophone?), stopSession(), sendTextMessage(text) }` for an OpenAI Realtime WebRTC session (pass an `<audio>` element to play remote audio). Pairs with `HTMLEmbedCard`'s AI-generation support.
91
535
 
92
- ## CLI Template Scaffolding
536
+ ---
93
537
 
94
- Create a fresh Next.js app and initialize PieUI in it:
538
+ ## Storybook integration
95
539
 
96
- ```sh
97
- bunx pieui create my-app-name
540
+ Test cards in isolation with the PieUI providers and fire their real-time methods from the Storybook UI.
541
+
542
+ ```tsx
543
+ // .storybook/preview.tsx
544
+ import { withPieCard } from '@swarm.ing/pieui/storybook'
545
+ export const decorators = [withPieCard]
546
+ ```
547
+
548
+ ```tsx
549
+ // MyCard.stories.tsx
550
+ import { PieStorybookProviders, PieMethodTrigger } from '@swarm.ing/pieui/storybook'
551
+
552
+ export const Live = () => (
553
+ <PieStorybookProviders>
554
+ <MyCard data={{ name: 'MyCard' }} />
555
+ <PieMethodTrigger card="MyCard" method="increment" payload={{ by: 1 }} />
556
+ </PieStorybookProviders>
557
+ )
98
558
  ```
99
559
 
100
- This command:
560
+ - `PieStorybookProviders` — mounts the full provider stack with a stubbed config and a local Mitt emitter.
561
+ - `withPieCard` — decorator wrapping a story in those providers + a channel bridge.
562
+ - `PieMethodTrigger` — a button that fires a `pie{method}_{card}` Mitt event.
563
+ - `firePieMethod(emitter, card, method, payload)` / `usePieStorybookEmitter()` — imperative helpers.
564
+ - The **addon** (`@swarm.ing/pieui/storybook/addon`) adds a Storybook panel to fire methods interactively; register it in `.storybook/main` (the CLI's `card add-story` does this automatically).
565
+
566
+ ---
101
567
 
102
- - runs `bun create next-app@latest my-app-name --yes`
103
- - initializes `piecomponents/registry.ts` and PieUI config in the new app
104
- - prepares the app for `bunx pieui card add ...`
568
+ ## CLI reference
105
569
 
106
- Create a blank Next.js web app template with PieUI CLI:
570
+ The CLI ships as `pieui` (run via `bunx pieui …` or the installed bin). It mirrors the backend `pie` Python CLI — subcommand names, positionals, and flags are kept in sync.
571
+
572
+ ### Scaffolding
107
573
 
108
574
  ```sh
109
- bunx pieui create-pie-app my-pie-app
110
- # or alias:
111
- bunx pieui create-pieui my-pie-app
575
+ pieui create <AppName> # create a Next.js app and run `pieui init` inside it
576
+ pieui create-pie-app <AppName> # create a blank PieUI Next.js template (alias: create-pieui)
577
+ pieui init [--out-dir <dir>] # add piecomponents/, registry.ts, Tailwind & Next config to an existing app
112
578
  ```
113
579
 
114
- This command:
580
+ `create` scaffolds Next.js (`next-app@latest`), installs `@swarm.ing/pieui`, runs `init`, installs Storybook, then `bun run dev`. `init` also searches your home directory (depth ≤ 2) for a backend project with `pages/` and `components/` dirs and, in a TTY, offers to link them (saved to `.pie/config.json`).
115
581
 
116
- - runs `bun create next-app@latest my-pie-app --yes`
117
- - copies a standard `_shared` folder into the new app (sourced from `ai-exchange-bot` when found)
118
- - rewrites `dev/build/start` scripts to `bun --bun next ...`
119
- - appends a TODO marker in `app/page.tsx` for future backend (Python Unicorn) linking
582
+ ### Build
120
583
 
121
- If the `_shared` source cannot be found automatically, PieUI now creates a fallback `_shared/simple.tsx` scaffold and continues.
584
+ ```sh
585
+ pieui postbuild [--src-dir <dir>] [--out-dir <dir>] [--append]
586
+ ```
122
587
 
123
- To force a specific shared source, set:
588
+ Scans for `registerPieComponent()` calls, generates a JSON Schema per card data type, and writes `pieui.components.json`. Defaults: `--src-dir src`, `--out-dir public`. `--append` merges with the library manifest in `node_modules`.
124
589
 
125
590
  ```sh
126
- PIEUI_SHARED_TEMPLATE_DIR=/absolute/path/to/_shared bunx pieui create-pie-app my-pie-app
591
+ pieui self-upgrade [--pm <bun|pnpm|yarn|npm>] # upgrade the global CLI
127
592
  ```
128
593
 
129
- Planned create flow target:
594
+ ### Auth
130
595
 
131
596
  ```sh
132
- bun create pieui@latest my-pie-app
597
+ pieui login # browser auth; writes .pie/config.json and PIE_* keys into .env
133
598
  ```
134
599
 
135
- Create a page scaffold inside an existing Next app:
600
+ ### Pages (`pieui page …`)
136
601
 
137
602
  ```sh
138
- bunx pieui page add chat
603
+ pieui page add <path> # create app/<path>/page.tsx from the Pie page template
604
+ pieui page view <path> # print the page source
605
+ pieui page ajax <path> <add|remove> <handler> # add/remove an AJAX handler (delegates to the backend)
139
606
  ```
140
607
 
141
- This command writes `app/chat/page.tsx` with the standard Suspense-wrapped Pie page shell:
608
+ `add` normalizes the path under `app/`, derives a `PascalCasePage` component name, and rejects traversal outside `app/`.
142
609
 
143
- ```tsx
144
- 'use client'
610
+ ### Cards (`pieui card …`)
611
+
612
+ ```sh
613
+ pieui card add [<type>] <Name> [--io] [--ajax] [--input] [--from <ref>]
614
+ ```
145
615
 
146
- import PiePage from '@/app/_shared/simple'
147
- import { Suspense } from 'react'
148
- import LoadingScreen from '@/components/LoadingScreen'
616
+ Creates `piecomponents/<Name>/` (`index.ts`, `types/index.ts`, `ui/<Name>.tsx`) and registers it in `registry.ts`. `<type>` is one of `simple`, `complex`, `simple-container`, `complex-container` (default). Flags:
149
617
 
150
- export default function ChatPage() {
151
- return (
152
- <Suspense fallback={<LoadingScreen />}>
153
- <PiePage />
154
- </Suspense>
155
- )
156
- }
618
+ - `--io` add real-time support fields (`use_*_support`) to the data interface.
619
+ - `--ajax` — add AJAX fields (`pathname`, `deps_names`, `kwargs`).
620
+ - `--input` — generate the `InputPie…ComponentProps` variant with a typed `stored` prop.
621
+ - `--from <ref>` — port from backend Python metadata (a `.py`/JSON path, a card name, or auto-detected from the configured `backendComponentsDir`).
622
+
623
+ ```sh
624
+ pieui card list [<filter>] [--src-dir <dir>] # list cards (filter: all|simple|complex|simple-container|complex-container)
625
+ pieui card view <Name> # print a card's props, ajax, io, and events
626
+ pieui card remove <Name> # delete a card directory
627
+ pieui card list-events <Name> # list a card's methods (event handlers)
628
+ pieui card add-event <Name> <EventName> # add a method to a card
629
+ pieui card pull <ref> # restore a card from a URL, local JSON file, or remote name
157
630
  ```
158
631
 
159
- Create a component scaffold inside `piecomponents/`:
632
+ Metadata & Storybook:
160
633
 
161
634
  ```sh
162
- bunx pieui card add simple StatusCard
635
+ pieui card dump-metadata <Name> [--out <file.json>] # emit full PieMetadata JSON (props/events/imports/ajax/io)
636
+ pieui card check-sync <Name> # compare TypeScript ↔ Python metadata, report mismatches
637
+ pieui card add-story <Name> [--force] # generate <Name>.stories.tsx wired to PieCard methods
638
+ pieui card generate-preview <Name> [--out <file.png>] # render the story via storycap to a PNG
163
639
  ```
164
640
 
165
- Add optional realtime and AJAX fields to the generated `types/index.ts`:
641
+ ### Remote card storage (`pieui card remote …`)
166
642
 
167
643
  ```sh
168
- bunx pieui card add simple LiveCard --io --ajax
644
+ pieui card remote list [--user <id>] [--project <slug>]
645
+ pieui card remote push <Name>
646
+ pieui card remote pull <Name>[@rev]
647
+ pieui card remote remove <Name>
648
+ pieui card remote history <Name> [--page <n>] [--per-page <n>] [--from <r>] [--to <r>]
649
+ pieui card remote public <Name> # make readable as r/<user>/<Name>
650
+ pieui card remote private <Name> # revert to private
169
651
  ```
170
652
 
171
- ## AJAX `depsNames` sources
653
+ ### Registry preview harness (`pieui registry …`)
172
654
 
173
- An Ajax card (`AjaxGroupCard`, `AjaxButtonCard`, …) submits to
174
- `api/ajax_content{pathname}` via `useAjaxSubmit`. The request body is built from
175
- three places:
655
+ ```sh
656
+ pieui registry dev [--port <n>] [--api-server <url>] # run the PiePreviewRoot harness (default port 3210)
657
+ pieui registry build [--out <dir>] # static-export the harness (default .pie/registry/out)
658
+ ```
176
659
 
177
- 1. `kwargs` static key/value pairs from the card config.
178
- 2. `extraKwargs` — values passed at call time.
179
- 3. `depsNames` — names whose **current client-side value** is read and appended
180
- at submit time.
660
+ ### Configuration & environment
181
661
 
182
- Each entry in `depsNames` is a "magic name": an optional source prefix plus a
183
- key. The value is always submitted under the **bare key** (the part after the
184
- prefix), so `localStorage:token` is sent as the field `token`.
662
+ `.pie/config.json` (written by `login` / `init`) holds `user_id`, `project`, `api_key`, and optional `backendPagesDir` / `backendComponentsDir`. Notable env vars: `PIE_USER_ID`, `PIE_PROJECT`/`PIE_PROJECT_SLUG`, `PIE_API_KEY`; `PIEUI_CREATE_NEXT_APP_SPEC`, `PIEUI_CREATE_PACKAGE_SPEC`, `PIEUI_CREATE_BUN_BIN`, `PIEUI_CREATE_SKIP_STORYBOOK`; `PIEUI_LOGIN_CONNECT_BASE`, `PIEUI_LOGIN_CREDENTIALS_API`. Add `--help`/`-h` to any command for scoped help.
185
663
 
186
- | `depsNames` entry | Read from |
187
- | ------------------------- | ------------------------------------------------------------- |
188
- | `email` _(no prefix)_ | DOM input named `email` (`document.getElementsByName`) |
189
- | `sid` | `window.sid` — SocketIO session id (awaits the socket) |
190
- | `localStorage:<key>` | `localStorage.getItem(key)` |
191
- | `sessionStorage:<key>` | `sessionStorage.getItem(key)` |
192
- | `cookie:<name>` | matching cookie from `document.cookie` (URL-decoded) |
193
- | `url:<param>` | `?<param>` query params (repeated params → multiple values) |
194
- | `telegram:cloud:<key>` | `Telegram.WebApp.CloudStorage.getItem` _(async)_ |
195
- | `telegram:secure:<key>` | `Telegram.WebApp.SecureStorage.getItem` _(async)_ |
664
+ ---
196
665
 
197
- Notes:
666
+ ## API reference
198
667
 
199
- - A **missing value contributes nothing** — same as an absent DOM input. The
200
- field is simply omitted from the request.
201
- - A single entry can yield **multiple values** (a multi-file `<input>`, repeated
202
- `url:` params); each is appended under the same bare key.
203
- - `telegram:cloud:` / `telegram:secure:` are **asynchronous**. The submit flow
204
- awaits them automatically; the sync `readAjaxKey` returns `[]` for them, so use
205
- `readAjaxKeyAsync` if reading directly.
206
- - The storage prefixes mirror the storage cards: `localStorage:` ↔
207
- `DeviceStorageCard`, `sessionStorage:` ↔ `SessionStorageCard`,
208
- `telegram:cloud:` ↔ `CloudStorageCard`, `telegram:secure:` ↔
209
- `SecureStorageCard`. The Telegram cards live under the
210
- `@swarm.ing/pieui/telegram` entry.
211
-
212
- Example — submit a DOM field, a localStorage token, a URL param and the socket
213
- id together:
668
+ ### Runtime exports (`@swarm.ing/pieui`)
214
669
 
215
- ```ts
216
- depsNames: ['email', 'localStorage:token', 'url:ref', 'sid']
217
- // POST body fields: email, token, ref, sid
218
- ```
670
+ | Export | Description |
671
+ | ------ | ----------- |
672
+ | `UI` | Renders a `UIConfigType` by resolving `uiConfig.card` from the registry (Suspense for lazy cards; passes `data`, `content`, `setUiAjaxConfiguration`). |
673
+ | `UILoading` | Renders a cached/placeholder shell while a screen loads. |
674
+ | `UIRendererContext` | Context carrying renderer props (`UIRendererProps`). |
675
+ | `PieRoot` / `PieBaseRoot` / `PiePreviewRoot` | Root components (see [Root components](#root-components)). |
676
+ | `PieCard` | Wires a card into Socket.IO / Centrifuge / Mitt messaging. |
677
+ | `registerPieComponent` & registry helpers | See [Registry API](#registry-api). |
678
+ | `trackLazy` | Named `React.lazy` wrapper. |
679
+ | `useAjaxSubmit` / `readAjaxKey` / `readAjaxKeyAsync` / `parseDepName` | AJAX submit + dep-name resolution. |
680
+ | `usePieEmit` / `getEmitter` / `MittContext` | Mitt event emission. |
681
+ | `SocketIOContext` / `CentrifugeIOContext` / `FallbackContext` / `PieConfigContext` | PieUI contexts. |
682
+ | `cn` / `sx2radium` / `pieName` / `submitGlobalForm` / `PIEBREAK` | Utilities. |
683
+
684
+ ### Type exports
685
+
686
+ `PieComponentProps`, `PieSimpleComponentProps`, `PieComplexComponentProps`, `PieContainerComponentProps`, `PieComplexContainerComponentProps`, and their `InputPie…` variants; `PieConfig`, `UIConfigType`, `SetUiAjaxConfigurationType`, `PieQueryOptions`, `RetryPolicy`, `DepSource`. Telegram/MAX entries export their respective `WebApp`/init-data types; the `/native` entry adds `PieRootProps`, `PieBaseRootProps`, and the `NativeClientConfig`/adapter types.
687
+
688
+ ---
689
+
690
+ ## License
219
691
 
220
- `depsNames` is normally supplied by the backend `UIConfig` at runtime — for the
221
- Python card field that produces it, see the `pie` repo (`deps_names`).
692
+ MIT