@sonata-innovations/fiber-fbre 3.3.0 → 3.4.0

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.
@@ -0,0 +1,387 @@
1
+ ---
2
+ title: FBRE Integration Guide
3
+ applies-to:
4
+ - "@sonata-innovations/fiber-fbre@^3.3"
5
+ read-when: "Embedding the render engine in a parent app: props and modes, onFlowComplete contract, confirmation screen, store access, events, theming, pre-populating data."
6
+ ---
7
+
8
+ <!-- Generated from the Fiber repo's docs/ tree by project/scripts/sync-package-docs.mjs. Do not edit here. -->
9
+ # FBRE — Render Engine
10
+
11
+ FBRE consumes Flow JSON, renders the form (conditions, validation, screen transitions), and returns collected data (`FlowData`) to the parent application.
12
+
13
+ For the Flow JSON format itself, see the [Flow JSON Quick Reference](@sonata-innovations/fiber-types/docs/schema/flow-quick-reference.md). For theming in depth, see the [FBRE Theming Guide](../features/fbre-theming.md).
14
+
15
+ ## Minimal Setup
16
+
17
+ ```tsx
18
+ import { FBRE } from "@sonata-innovations/fiber-fbre";
19
+ import "@sonata-innovations/fiber-fbre/styles"; // MUST import separately
20
+
21
+ function App() {
22
+ const handleComplete = (data: FlowData) => {
23
+ console.log("Collected data:", data);
24
+ };
25
+
26
+ return (
27
+ <FBRE
28
+ flow={myFlow}
29
+ onFlowComplete={handleComplete}
30
+ />
31
+ );
32
+ }
33
+ ```
34
+
35
+ ## Props Reference (Local Mode)
36
+
37
+ | Prop | Type | Required | Default | Description |
38
+ |------|------|----------|---------|-------------|
39
+ | `flow` | `Flow` | Yes | — | Flow JSON object to render |
40
+ | `onFlowComplete` | `(data: FlowData) => void \| ConfirmationResult \| Promise<void \| ConfirmationResult>` | Yes | — | Called when user completes the last screen. See [Confirmation Screen](#confirmation-screen) |
41
+ | `data` | `FlowData` | No | `undefined` | Pre-populated form data. **Not reactive** — applied only when the flow loads; changing `data` alone does nothing (see Pitfalls) |
42
+ | `screenIndex` | `number` | No | `0` | Controlled screen index |
43
+ | `mode` | `FlowModeType` | No | — | `"standard"` or `"conversational"` — overrides `flow.config.mode` |
44
+ | `theme` | `ThemeConfig` | No | — | Override theme settings (merged over `flow.config.theme`) |
45
+ | `navigation` | `NavigationConfig` | No | — | Override navigation settings (merged over `flow.config.navigation`) |
46
+ | `controls` | `ControlsConfig` | No | — | Override controls settings (merged over `flow.config.controls`) |
47
+ | `context` | `Record<string, string \| boolean \| number>` | No | — | External context for context conditions (reactive — updates trigger re-evaluation) |
48
+ | `storeRef` | `MutableRefObject<StoreApi<FBREStoreState> \| null>` | No | — | Exposes Zustand store for imperative access |
49
+ | `onScreenChange` | `(index: number, data: any) => void` | No | — | Called on screen navigation; at runtime `data` is the current `FlowData` (declared `any`) |
50
+
51
+ > **Watching screen validity.** There is no validity callback prop. Subscribe through `storeRef` instead — `storeRef.current.subscribe(...)` and read `getScreenValidity(index)`, or select `screenValidity` directly. (An `onScreenValidationChange` prop was accepted but never invoked in any released version; it has been removed.)
52
+
53
+ Config group props (`theme`, `navigation`, `controls`) are shallow-merged over the corresponding `flow.config` group. JSX prop values take precedence.
54
+
55
+ The props above apply to **local mode** (passing a `flow` object directly). FBRE also supports two additional modes:
56
+
57
+ ## Remote Mode
58
+
59
+ Remote mode fetches the flow from a Fiber API server. Pass `flowId` and `apiEndpoint` instead of `flow`:
60
+
61
+ ```tsx
62
+ <FBRE
63
+ flowId="your-flow-id"
64
+ apiEndpoint="https://your-fiber-server.com/api/v1"
65
+ apiKey="optional-api-key"
66
+ onFlowComplete={(data) => console.log(data)}
67
+ />
68
+ ```
69
+
70
+ | Prop | Type | Required | Default | Description |
71
+ |------|------|----------|---------|-------------|
72
+ | `flowId` | `string` | Yes | — | Flow ID to fetch from the API |
73
+ | `apiEndpoint` | `string` | Yes | — | Fiber API base URL |
74
+ | `apiKey` | `string` | No | — | API key for authentication |
75
+ | `data` | `FlowData` | No | `undefined` | Pre-populated form data (not reactive — see Pitfalls) |
76
+ | `screenIndex` | `number` | No | `0` | Controlled screen index |
77
+ | `mode` | `FlowModeType` | No | — | `"standard"` or `"conversational"` — overrides the fetched flow's `config.mode` |
78
+ | `theme` | `ThemeConfig` | No | — | Override theme settings |
79
+ | `navigation` | `NavigationConfig` | No | — | Override navigation settings |
80
+ | `controls` | `ControlsConfig` | No | — | Override controls settings |
81
+ | `storeRef` | `MutableRefObject<StoreApi<FBREStoreState> \| null>` | No | — | Exposes Zustand store |
82
+ | `onFlowComplete` | `(data: FlowData) => void \| ConfirmationResult \| Promise<void \| ConfirmationResult>` | Yes | — | Called on completion. See [Confirmation Screen](#confirmation-screen) |
83
+ | `context` | `Record<string, string \| boolean \| number>` | No | — | External context for context conditions (reactive) |
84
+ | `onScreenChange` | `(index: number, data: any) => void` | No | — | Called on screen navigation; `data` is the current `FlowData` at runtime |
85
+
86
+ ## Server-Driven Mode
87
+
88
+ Server-driven mode delegates all logic (conditions, validation, screen transitions) to the server. The client renders one screen at a time:
89
+
90
+ ```tsx
91
+ <FBRE
92
+ sessionEndpoint="https://your-fiber-server.com/public/sessions"
93
+ flowId="your-flow-id"
94
+ apiKey="optional-api-key"
95
+ onFlowComplete={(data) => console.log(data)}
96
+ />
97
+ ```
98
+
99
+ | Prop | Type | Required | Default | Description |
100
+ |------|------|----------|---------|-------------|
101
+ | `sessionEndpoint` | `string` | Yes | — | Session API endpoint |
102
+ | `flowId` | `string` | Yes | — | Flow ID to start a session with |
103
+ | `apiKey` | `string` | No | — | API key for authentication |
104
+ | `theme` | `ThemeConfig` | No | — | Override theme settings |
105
+ | `context` | `Record<string, string \| boolean \| number>` | No | — | External context sent to the server at session start |
106
+ | `onFlowComplete` | `(data: any) => void` | Yes | — | Called on session completion |
107
+ | `onScreenChange` | `(screenNumber: number) => void` | No | — | Called on screen navigation (note: receives screen number, not index + data) |
108
+
109
+ > **Note:** Server-driven mode has a different `onScreenChange` signature — `(screenNumber: number) => void` — compared to local/remote mode's `(index: number, data: FlowData) => void`.
110
+
111
+ In server-driven mode, the `context` is sent to the server in the `POST /public/sessions` request body and stored on the session. The server uses it to evaluate cross-screen context conditions, and it is returned in each screen payload so the client can evaluate intra-screen context conditions locally.
112
+
113
+ On a successful completion, server-driven mode resets the submit button and renders a terminal [confirmation screen](#confirmation-screen) — the flow's configured `config.confirmation` message when present, otherwise a generic "Thank you". `onFlowComplete` still fires with the server result, so a parent that wants its own post-completion UI can unmount or replace the component from that handler.
114
+
115
+ ## Conversational Mode
116
+
117
+ Optimized one-question-per-screen experience. Set via JSX prop or flow config:
118
+
119
+ ```tsx
120
+ // Via JSX prop (overrides flow config)
121
+ <FBRE flow={myFlow} mode="conversational" onFlowComplete={handleComplete} />
122
+
123
+ // Via flow config
124
+ const flow = {
125
+ ...myFlow,
126
+ config: { ...myFlow.config, mode: "conversational" }
127
+ };
128
+ <FBRE flow={flow} onFlowComplete={handleComplete} />
129
+
130
+ // Server-driven mode
131
+ <FBRE
132
+ sessionEndpoint="https://api.example.com/api/v1/public/sessions"
133
+ flowId="flow-id"
134
+ mode="conversational"
135
+ onFlowComplete={handleComplete}
136
+ />
137
+ ```
138
+
139
+ Conversational mode vertically centers content, auto-advances after single-select choices (~500ms), advances on Enter for text inputs, and animates component entry. Styles partition by mode: standard mode uses `clean`, `outlined`, `refined-clean`, `airy-clean`, `soft-outlined`, `defined-outlined`; conversational mode has four dedicated styles — `centered-minimal`, `stacked-cards`, `soft-float`, `bold-statement`. FlowData output is unchanged by mode.
140
+
141
+ ## Confirmation Screen
142
+
143
+ A terminal "thank you" screen shown after the flow is submitted. It is a flow-level setting (`config.confirmation`), not a `Screen`, so it is never edited in the builder's stage editor. The config-driven screen renders only when `show` is not `false` **and** `title` or `body` has content; when shown, it replaces the final screen and hides the navigation controls/stepper. Note two edge cases: a non-empty `ConfirmationResult` returned from `onFlowComplete` forces the confirmation to render **even when `config.confirmation.show` is `false`**. Server-driven mode renders a terminal confirmation too, but drives it from `config.confirmation` only (it does not honor a `ConfirmationResult` return, since `onFlowComplete` there receives the raw server result); when no confirmation is configured it falls back to a generic "Thank you".
144
+
145
+ ```tsx
146
+ const flow = {
147
+ ...myFlow,
148
+ config: {
149
+ ...myFlow.config,
150
+ confirmation: {
151
+ show: true,
152
+ title: "Thank you!",
153
+ // ${...} references resolve against collected fields, calculations, and context
154
+ body: "We received your submission, ${email}.",
155
+ },
156
+ },
157
+ };
158
+
159
+ <FBRE flow={flow} onFlowComplete={handleComplete} />
160
+ ```
161
+
162
+ **Deciding when to show it — the `onFlowComplete` contract.** The confirmation appears once `onFlowComplete` settles. The return value controls the behavior:
163
+
164
+ | Return | Behavior |
165
+ |--------|----------|
166
+ | `void` | Confirmation shows immediately (optimistic). |
167
+ | `Promise<void>` | Submit button stays in its in-flight (loading) state until the promise settles. On resolve → confirmation shows; on **reject** → a completion error renders and the confirmation is **not** shown. |
168
+ | `ConfirmationResult` (`{ title?, body? }`), sync or as the resolved value of a Promise | Overrides the configured message — use for content only known after submit, e.g. a server reference number. |
169
+
170
+ ```tsx
171
+ // Wait for the server, then show a confirmation carrying the server's reference number
172
+ const handleComplete = async (data: FlowData): Promise<ConfirmationResult> => {
173
+ const { referenceId } = await saveToBackend(data); // rejects → FBRE shows the error, no confirmation
174
+ return { title: "All done!", body: `Your reference number is ${referenceId}.` };
175
+ };
176
+
177
+ <FBRE flow={flow} onFlowComplete={handleComplete} />
178
+ ```
179
+
180
+ `ConfirmationConfig` and `ConfirmationResult` are exported from `@sonata-innovations/fiber-fbre`. See [FlowConfiguration → ConfirmationConfig](@sonata-innovations/fiber-types/docs/schema/flow-schema.md#confirmationconfig) for the schema.
181
+
182
+ ## Store Access Patterns
183
+
184
+ **Option A: `storeRef` prop (from outside FBRE)**
185
+ ```tsx
186
+ import { useRef } from "react";
187
+ import { FBRE, type FBREStoreState } from "@sonata-innovations/fiber-fbre";
188
+ import type { StoreApi } from "zustand";
189
+
190
+ function App() {
191
+ const storeRef = useRef<StoreApi<FBREStoreState> | null>(null);
192
+
193
+ const readData = () => {
194
+ const data = storeRef.current?.getState().getFlowData();
195
+ console.log(data);
196
+ };
197
+
198
+ return <FBRE flow={myFlow} storeRef={storeRef} onFlowComplete={handleComplete} />;
199
+ }
200
+ ```
201
+
202
+ **Option B: `useFBREStore` / `useFBREStoreApi` hooks (from inside FBRE children)**
203
+ ```tsx
204
+ import { useFBREStore, useFBREStoreApi } from "@sonata-innovations/fiber-fbre";
205
+
206
+ // Reactive (re-renders on change):
207
+ const isValid = useFBREStore((s) => s.getScreenValidity(0));
208
+
209
+ // Non-reactive (read on demand):
210
+ const storeApi = useFBREStoreApi();
211
+ const data = storeApi.getState().getFlowData();
212
+ ```
213
+
214
+ **Option C: `useFBREApi` hook (remote mode only)**
215
+ ```tsx
216
+ import { useFBREApi } from "@sonata-innovations/fiber-fbre";
217
+
218
+ // Returns FBREApiContextValue | null (null outside remote mode)
219
+ const api = useFBREApi();
220
+ if (api) {
221
+ console.log(api.config); // { apiEndpoint, apiKey?, timeout? }
222
+ console.log(api.flowId); // string
223
+ console.log(api.flowVersionId); // string
224
+ console.log(api.tenantId); // string
225
+ }
226
+ ```
227
+
228
+ ## Consumer-Relevant Store Actions
229
+
230
+ | Action | Signature | Description |
231
+ |--------|-----------|-------------|
232
+ | `getFlowData` | `() => FlowData` | Returns all collected form data |
233
+ | `getScreenValidity` | `(index: number) => boolean` | Check if a screen passes validation |
234
+ | `evaluateFlowValidation` | `() => boolean` | Validate entire flow, returns `true` if all valid |
235
+ | `getScreenByIndex` | `(index: number) => FlowScreen \| null` | Get screen by position |
236
+ | `getMaxScreenIndex` | `() => number` | Returns the maximum screen **index** (`screen count − 1`); does not filter condition-hidden screens. The last screen is index `getMaxScreenIndex()` |
237
+ | `getValidationErrors` | `(uuid: string) => string[]` | Get validation errors for a component |
238
+ | `getCalculationResult` | `(uuid: string) => number \| null` | Result of a flow calculation by uuid |
239
+ | `updateComponentValue` | `(uuid: string, value: any) => void` | Programmatically set a component's value |
240
+ | `updateContext` | `(context: Record<string, string \| boolean \| number>) => void` | Replace the external context (normally driven by the `context` prop) |
241
+ | `loadFlow` | `(flow: Flow, data?: FlowData, context?: Record<string, string \| boolean \| number>) => void` | Load a new flow (usually handled by prop change) |
242
+
243
+ ## Events
244
+
245
+ ```tsx
246
+ import { addFBREEventListener, removeFBREEventListener } from "@sonata-innovations/fiber-fbre";
247
+
248
+ // File upload listener
249
+ const handler = (componentUuid: string, fileData: FileUploadData) => {
250
+ console.log("File uploaded for component:", componentUuid, fileData);
251
+ };
252
+ addFBREEventListener("file-upload", handler);
253
+
254
+ // Cleanup
255
+ removeFBREEventListener("file-upload", handler);
256
+ ```
257
+
258
+ `"file-upload"` is currently the only event type. The event bus is **module-global, not per-instance**: with multiple `<FBRE />` instances mounted, one listener receives file-upload events from all of them, distinguishable only by component UUID.
259
+
260
+ ## Theming
261
+
262
+ Three ways to theme, from least to most control: pick a **color scheme** preset, set **palette knobs** on `theme`, or override the raw `--fbre-*` CSS custom properties. They layer — preset seeds the tokens, knobs override a subset inline, raw CSS wins last. The **[FBRE Theming Guide](../features/fbre-theming.md)** is the full reference (precedence model, derivation mechanics, complete token catalog); the most common tokens:
263
+
264
+ | Variable | Default (Light) | Default (Dark) | Knob | Description |
265
+ |----------|----------------|----------------|------|-------------|
266
+ | `--fbre-theme-color` | `#1976d2` | `#42a5f5` | `color` | Primary accent |
267
+ | `--fbre-bg` | `#fff` | `#121212` | `background` | Form ground |
268
+ | `--fbre-surface` | `#fff` | `#1e1e1e` | `surface` | Surfaces / input fills |
269
+ | `--fbre-input-bg` | `var(--fbre-surface)` | `var(--fbre-surface)` | (derived) | Input fill (resting) |
270
+ | `--fbre-text` | `#212121` | `#e0e0e0` | `text` | Primary text |
271
+ | `--fbre-text-secondary` | `#666` | `#9e9e9e` | (derived) | Secondary text |
272
+ | `--fbre-label` | `var(--fbre-text-secondary)` | (same) | (derived) | Field label |
273
+ | `--fbre-border` | `#ccc` | `#444` | `border` | Border color |
274
+ | `--fbre-error` | `#d32f2f` | `#ef5350` | `error` | Error color |
275
+ | `--fbre-success` | `#2d6a28` | `#a8e6a0` | `success` | Success color |
276
+ | `--fbre-warning` | `#7a5900` | `#ffe082` | `warning` | Warning color |
277
+ | `--fbre-radius` | `4px` | `4px` | `radius` | Border radius |
278
+ | `--fbre-font` | `"Segoe UI", system-ui, -apple-system, sans-serif` | (same) | `fontFamily` | Font family |
279
+ | `--fbre-transition-duration` | `250ms` | `250ms` | — | Screen transition timing |
280
+ | `--fbre-transition-easing` | `cubic-bezier(0.4, 0, 0.2, 1)` | (same) | — | Screen transition curve |
281
+
282
+ The color scheme is selected via the `theme` prop (`{ colorScheme: "dark" }`) or `flow.config.theme.colorScheme` (default `"light"`). The prop takes precedence. `colorScheme` seeds the built-in light/dark palette preset; it replaces the former `darkMode` boolean.
283
+
284
+ Palette knobs on `theme` (`color`, `background`, `surface`, `text`, `border`, `radius`, `fontFamily`, and the semantic `error`/`success`/`warning`) are applied automatically via inline style and override the corresponding `--fbre-*` CSS variables on top of the preset. Each derives its related tokens (e.g. `surface` also sets the input fills and hover/alt surfaces). Any subset may be set; unset knobs fall through to the preset. Example: `<FBRE theme={{ colorScheme: "dark", surface: "#243244", text: "#e8ede9" }} ... />`. For finer control you can still override the raw `--fbre-*` variables in your own CSS.
285
+
286
+ ## Pre-populating Data
287
+
288
+ Pass the `data` prop with a `FlowData` object. UUIDs must match components in the flow.
289
+
290
+ ```tsx
291
+ const prefilled: FlowData = {
292
+ uuid: "flow-uuid-here",
293
+ metadata: { name: "My Flow" },
294
+ screens: [
295
+ {
296
+ uuid: "screen-1-uuid",
297
+ label: "Screen 1",
298
+ components: [
299
+ { uuid: "comp-uuid-1", type: "inputText", value: "Pre-filled text" },
300
+ { uuid: "comp-uuid-2", type: "checkbox", value: ["option1", "option3"] },
301
+ ],
302
+ },
303
+ ],
304
+ };
305
+
306
+ <FBRE flow={myFlow} data={prefilled} onFlowComplete={handleComplete} />
307
+ ```
308
+
309
+ ## Integration Patterns
310
+
311
+ ### External Navigation (Hiding Built-In Buttons)
312
+
313
+ Hide FBRE's built-in navigation with `controls={{ show: false }}` and drive `screenIndex` yourself:
314
+
315
+ ```tsx
316
+ import { useRef, useState } from "react";
317
+ import { FBRE, type FBREStoreState } from "@sonata-innovations/fiber-fbre";
318
+ import type { StoreApi } from "zustand";
319
+
320
+ function ExternalNav() {
321
+ const storeRef = useRef<StoreApi<FBREStoreState> | null>(null);
322
+ const [screen, setScreen] = useState(0);
323
+
324
+ const goNext = () => {
325
+ const store = storeRef.current?.getState();
326
+ if (!store) return;
327
+ if (store.getScreenValidity(screen)) {
328
+ // getMaxScreenIndex() returns the last screen's index (count - 1)
329
+ setScreen((s) => Math.min(s + 1, store.getMaxScreenIndex()));
330
+ }
331
+ };
332
+
333
+ return (
334
+ <>
335
+ <FBRE
336
+ flow={myFlow}
337
+ controls={{ show: false }}
338
+ screenIndex={screen}
339
+ storeRef={storeRef}
340
+ onFlowComplete={handleComplete}
341
+ />
342
+ <button onClick={() => setScreen((s) => Math.max(0, s - 1))}>Back</button>
343
+ <button onClick={goNext}>Next</button>
344
+ </>
345
+ );
346
+ }
347
+ ```
348
+
349
+ ### Multiple FBRE Instances
350
+
351
+ Each `<FBRE />` creates its own isolated store. No conflicts:
352
+
353
+ ```tsx
354
+ <FBRE flow={flowA} onFlowComplete={handleA} />
355
+ <FBRE flow={flowB} onFlowComplete={handleB} />
356
+ ```
357
+
358
+ ### Reading Flow Data Mid-Flow
359
+
360
+ ```tsx
361
+ const storeRef = useRef<StoreApi<FBREStoreState> | null>(null);
362
+
363
+ const checkProgress = () => {
364
+ const data = storeRef.current?.getState().getFlowData();
365
+ const isScreenValid = storeRef.current?.getState().getScreenValidity(0);
366
+ console.log("Current data:", data, "Screen 0 valid:", isScreenValid);
367
+ };
368
+
369
+ <FBRE flow={myFlow} storeRef={storeRef} onFlowComplete={handleComplete} />
370
+ ```
371
+
372
+ ## Pitfalls
373
+
374
+ **MUST:**
375
+ - Import styles separately (`import "@sonata-innovations/fiber-fbre/styles"`) — styles are not bundled with the JS
376
+ - Match UUIDs exactly when pre-populating `FlowData`
377
+
378
+ **DO NOT:**
379
+ - Change `flow.uuid` unless you want a full re-load (triggers `loadFlow` via `useEffect` dependency)
380
+ - Expect a changed `data` prop to re-populate the form — `data` is applied only when the flow loads. To re-prefill, reload the flow (new `flow.uuid`) or call `loadFlow(flow, data)` via `storeRef`
381
+ - Set runtime-only fields (`value`, `valid`, `addedComponents`) in Flow JSON — these are managed by FBRE at runtime
382
+ - Expect display components (`header`, `text`, `divider`, `callout`, `table`) in FlowData output — they are excluded. `computed` **is** included (it carries a derived value), and flows with calculations also emit a top-level `calculations` array
383
+ - Expect hidden components or hidden screens (via conditions) in FlowData output — they are excluded
384
+ - Access `storeRef.current` before the provider has mounted — it will be `null`
385
+ - Use the `useFBREStore` hook outside the FBRE provider — it requires context
386
+
387
+ **Type imports:** `Flow`, `FlowData`, `ScreenData`, `ComponentData`, `FileUploadData`, `ThemeConfig`, and the condition/validation types are all re-exported from `@sonata-innovations/fiber-fbre` — no direct dependency on `fiber-types` is needed.
package/package.json CHANGED
@@ -1,16 +1,20 @@
1
1
  {
2
2
  "name": "@sonata-innovations/fiber-fbre",
3
- "version": "3.3.0",
3
+ "version": "3.4.0",
4
4
  "description": "Fiber Render Engine — renders Flow JSON forms with conditional logic, validation, and screen transitions",
5
- "keywords": ["fiber", "form-builder", "form-renderer", "react", "flow-json", "data-collection"],
5
+ "keywords": [
6
+ "fiber",
7
+ "form-builder",
8
+ "form-renderer",
9
+ "react",
10
+ "flow-json",
11
+ "data-collection"
12
+ ],
6
13
  "license": "MIT",
7
- "repository": {
8
- "type": "git",
9
- "url": "git+https://github.com/sonata-innovations/fiber.git",
10
- "directory": "fbre"
14
+ "bugs": {
15
+ "url": "https://github.com/sonata-innovations/fiber-docs/issues"
11
16
  },
12
- "bugs": { "url": "https://github.com/sonata-innovations/fiber/issues" },
13
- "homepage": "https://github.com/sonata-innovations/fiber",
17
+ "homepage": "https://github.com/sonata-innovations/fiber-docs",
14
18
  "type": "module",
15
19
  "main": "dist/fiber-fbre.cjs",
16
20
  "module": "dist/fiber-fbre.js",
@@ -24,17 +28,22 @@
24
28
  "./styles": "./dist/fiber-fbre.css"
25
29
  },
26
30
  "files": [
27
- "dist"
31
+ "dist",
32
+ "AGENTS.md",
33
+ "CHANGELOG.md",
34
+ "docs"
28
35
  ],
29
36
  "sideEffects": true,
30
37
  "scripts": {
38
+ "typecheck": "tsc --noEmit",
31
39
  "dev": "vite",
32
40
  "dev:playground": "vite --config vite.config.dev.ts",
33
41
  "check:parity": "node scripts/check-manifest-parity.mjs",
34
42
  "prebuild": "npm run check:parity",
35
43
  "build": "tsc --noEmit && vite build",
36
44
  "build:playground": "vite build --config vite.config.dev.ts",
37
- "preview": "vite preview"
45
+ "preview": "vite preview",
46
+ "prepack": "node ../project/scripts/sync-package-docs.mjs fbre"
38
47
  },
39
48
  "publishConfig": {
40
49
  "access": "public"