@lowdefy/docs-content 0.0.0-experimental-20260928120643 → 6.1.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.
Files changed (226) hide show
  1. package/README.md +0 -1
  2. package/content/actions/link.md +0 -17
  3. package/content/actions/login.md +5 -23
  4. package/content/actions/logout.md +5 -5
  5. package/content/actions/pdfmake.md +2 -2
  6. package/content/actions/setdarkmode.md +2 -2
  7. package/content/agents/agent-properties.md +2 -4
  8. package/content/agents/agentchat.md +6 -21
  9. package/content/agents/agentconversations.md +2 -2
  10. package/content/concepts/ai-agent-docs.md +101 -313
  11. package/content/concepts/cli.md +3 -34
  12. package/content/concepts/connections-and-requests.md +0 -402
  13. package/content/concepts/custom-html.md +0 -40
  14. package/content/concepts/custom-styling.md +5 -50
  15. package/content/concepts/events-and-actions.md +2 -64
  16. package/content/concepts/i18n.md +2 -7
  17. package/content/concepts/keyboard-shortcuts.md +2 -2
  18. package/content/concepts/layout-overview.md +1 -1
  19. package/content/concepts/logger.md +0 -81
  20. package/content/concepts/lowdefy-schema.md +1 -4
  21. package/content/concepts/menus.md +7 -7
  22. package/content/concepts/module-authoring.md +2 -2
  23. package/content/connections/anthropic.md +2 -162
  24. package/content/connections/awss3.md +0 -54
  25. package/content/connections/google.md +2 -162
  26. package/content/connections/mongodb.md +3 -121
  27. package/content/connections/openai-connection.md +2 -162
  28. package/content/container-blocks/affix.md +7 -47
  29. package/content/container-blocks/alert.md +24 -76
  30. package/content/container-blocks/badge.md +24 -100
  31. package/content/container-blocks/box.md +9 -9
  32. package/content/container-blocks/card.md +25 -80
  33. package/content/container-blocks/carousel.md +7 -60
  34. package/content/container-blocks/collapse.md +9 -87
  35. package/content/container-blocks/configprovider.md +13 -35
  36. package/content/container-blocks/confirmmodal.md +23 -69
  37. package/content/container-blocks/content.md +98 -62
  38. package/content/container-blocks/descriptions.md +4 -45
  39. package/content/container-blocks/drawer.md +28 -92
  40. package/content/container-blocks/dropdownmenu.md +31 -119
  41. package/content/container-blocks/flex.md +62 -40
  42. package/content/container-blocks/footer.md +11 -15
  43. package/content/container-blocks/googlemapsheatmap.md +1 -1
  44. package/content/container-blocks/googlemapsscript.md +2 -2
  45. package/content/container-blocks/header.md +36 -71
  46. package/content/container-blocks/label.md +7 -34
  47. package/content/container-blocks/layout.md +34 -52
  48. package/content/container-blocks/masonry.md +71 -17
  49. package/content/container-blocks/mobilemenu.md +88 -131
  50. package/content/container-blocks/modal.md +26 -114
  51. package/content/container-blocks/pageheadermenu.md +31 -81
  52. package/content/container-blocks/pagesidebarlayout.md +26 -169
  53. package/content/container-blocks/pagesidermenu.md +42 -95
  54. package/content/container-blocks/popover.md +31 -34
  55. package/content/container-blocks/result.md +21 -32
  56. package/content/container-blocks/sider.md +122 -85
  57. package/content/container-blocks/span.md +7 -7
  58. package/content/container-blocks/spinner.md +3 -3
  59. package/content/container-blocks/splitter.md +68 -150
  60. package/content/container-blocks/tabs.md +12 -64
  61. package/content/container-blocks/tooltip.md +46 -22
  62. package/content/container-blocks/watermark.md +4 -22
  63. package/content/controls/reject.md +2 -4
  64. package/content/controls/throw.md +0 -1
  65. package/content/controls/try.md +2 -3
  66. package/content/deployment/deployment-environments.md +6 -8
  67. package/content/deployment/docker.md +7 -22
  68. package/content/deployment/node-server.md +0 -4
  69. package/content/deployment/vercel.md +6 -13
  70. package/content/display-blocks/aggrid.md +11 -26
  71. package/content/display-blocks/anchor.md +15 -15
  72. package/content/display-blocks/avatar.md +37 -57
  73. package/content/display-blocks/breadcrumb.md +21 -70
  74. package/content/display-blocks/button.md +18 -92
  75. package/content/display-blocks/calendar.md +0 -12
  76. package/content/display-blocks/dangeroushtml.md +1 -1
  77. package/content/display-blocks/difflist.md +1 -1
  78. package/content/display-blocks/difftimeline.md +1 -1
  79. package/content/display-blocks/divider.md +3 -64
  80. package/content/display-blocks/dropdownbutton.md +28 -79
  81. package/content/display-blocks/echart.md +1 -35
  82. package/content/display-blocks/floatbutton.md +42 -129
  83. package/content/display-blocks/html.md +1 -61
  84. package/content/display-blocks/icon.md +67 -250
  85. package/content/display-blocks/menu.md +73 -145
  86. package/content/display-blocks/message.md +124 -38
  87. package/content/display-blocks/notification.md +222 -94
  88. package/content/display-blocks/paragraph.md +9 -59
  89. package/content/display-blocks/progress.md +17 -96
  90. package/content/display-blocks/qrcode.md +4 -19
  91. package/content/display-blocks/s3download.md +1 -1
  92. package/content/display-blocks/search.md +7 -17
  93. package/content/display-blocks/skeletonbutton.md +0 -1
  94. package/content/display-blocks/skeletoninput.md +0 -1
  95. package/content/display-blocks/statistic.md +17 -75
  96. package/content/display-blocks/steps.md +25 -58
  97. package/content/display-blocks/tag.md +17 -102
  98. package/content/display-blocks/title.md +11 -50
  99. package/content/display-blocks/tour.md +23 -33
  100. package/content/input-blocks/autocomplete.md +9 -81
  101. package/content/input-blocks/buttonselector.md +8 -45
  102. package/content/input-blocks/checkboxselector.md +7 -97
  103. package/content/input-blocks/checkboxswitch.md +3 -33
  104. package/content/input-blocks/colorselector.md +14 -63
  105. package/content/input-blocks/daterangeselector.md +45 -165
  106. package/content/input-blocks/dateselector.md +41 -139
  107. package/content/input-blocks/datetimeselector.md +49 -158
  108. package/content/input-blocks/inputgallery.md +3 -3
  109. package/content/input-blocks/monthselector.md +52 -120
  110. package/content/input-blocks/multipleselector.md +39 -150
  111. package/content/input-blocks/numberinput.md +12 -98
  112. package/content/input-blocks/pagination.md +14 -70
  113. package/content/input-blocks/paragraphinput.md +37 -51
  114. package/content/input-blocks/passwordinput.md +6 -60
  115. package/content/input-blocks/phonenumberinput.md +26 -59
  116. package/content/input-blocks/radioselector.md +7 -83
  117. package/content/input-blocks/ratingslider.md +26 -57
  118. package/content/input-blocks/s3uploadbutton.md +24 -24
  119. package/content/input-blocks/s3uploaddragger.md +3 -3
  120. package/content/input-blocks/s3uploadphoto.md +5 -5
  121. package/content/input-blocks/segmentedselector.md +32 -72
  122. package/content/input-blocks/selector.md +21 -109
  123. package/content/input-blocks/switch.md +17 -65
  124. package/content/input-blocks/textarea.md +3 -32
  125. package/content/input-blocks/textinput.md +28 -69
  126. package/content/input-blocks/tiptapmentioninput.md +1 -1
  127. package/content/input-blocks/titleinput.md +12 -39
  128. package/content/input-blocks/treeinput.md +25 -49
  129. package/content/input-blocks/treemultipleselector.md +10 -127
  130. package/content/input-blocks/treeselector.md +9 -97
  131. package/content/input-blocks/upload.md +15 -64
  132. package/content/input-blocks/uploaddragger.md +1 -17
  133. package/content/input-blocks/uploadphoto.md +1 -18
  134. package/content/input-blocks/weekselector.md +55 -120
  135. package/content/list-blocks/controlledlist.md +15 -24
  136. package/content/list-blocks/list.md +11 -11
  137. package/content/list-blocks/masonrylist.md +34 -7
  138. package/content/migration/upgrade-guide.md +0 -1
  139. package/content/operators/_app.md +1 -2
  140. package/content/operators/_error.md +1 -23
  141. package/content/operators/_get.md +6 -6
  142. package/content/operators/_operator.md +3 -17
  143. package/content/operators/_ref.md +0 -258
  144. package/content/operators/_type.md +3 -14
  145. package/content/operators/_user.md +3 -3
  146. package/content/other/introduction.md +1 -1
  147. package/content/plugins/plugins-dev.md +0 -66
  148. package/content/plugins/plugins-introduction.md +1 -27
  149. package/content/testing/e2e-configuration.md +1 -8
  150. package/content/testing/e2e-getting-started.md +1 -1
  151. package/content/testing/e2e-introduction.md +1 -1
  152. package/content/tutorial/tutorial-actions-operators.md +2 -2
  153. package/content/tutorial/tutorial-add-blocks.md +2 -2
  154. package/content/tutorial/tutorial-create-page.md +2 -48
  155. package/content/tutorial/tutorial-display-data-page.md +3 -3
  156. package/content/tutorial/tutorial-requests-sql.md +0 -153
  157. package/content/tutorial/tutorial-start.md +1 -66
  158. package/content/user-authentication/login-and-logout.md +8 -158
  159. package/content/user-authentication/users-introduction.md +0 -8
  160. package/index.json +2 -6065
  161. package/package.json +1 -7
  162. package/scripts/extractAgentDocs.js +4 -36
  163. package/content/actions/emailotpsend.md +0 -58
  164. package/content/actions/emailotpverify.md +0 -77
  165. package/content/actions/getlocalstorage.md +0 -41
  166. package/content/actions/magiclinkverify.md +0 -113
  167. package/content/actions/posthogalias.md +0 -29
  168. package/content/actions/posthogcapture.md +0 -49
  169. package/content/actions/posthogcapturepageleave.md +0 -38
  170. package/content/actions/posthogfeatureflag.md +0 -50
  171. package/content/actions/posthoggroup.md +0 -37
  172. package/content/actions/posthogidentify.md +0 -54
  173. package/content/actions/posthoginit.md +0 -66
  174. package/content/actions/posthogoptin.md +0 -29
  175. package/content/actions/posthogoptout.md +0 -29
  176. package/content/actions/posthogpageview.md +0 -37
  177. package/content/actions/posthogreloadfeatureflags.md +0 -47
  178. package/content/actions/posthogreset.md +0 -28
  179. package/content/actions/posthogsetpersonproperties.md +0 -36
  180. package/content/actions/removelocalstorage.md +0 -26
  181. package/content/actions/setlocalstorage.md +0 -32
  182. package/content/adapter-reference/mongodbauthadapter.md +0 -46
  183. package/content/agents/agents-introduction.md +0 -107
  184. package/content/callback-reference/auth0logoutcallback.md +0 -54
  185. package/content/concepts/blocks.md +0 -150
  186. package/content/concepts/dynamic-page-content.md +0 -304
  187. package/content/concepts/html-attributes.md +0 -285
  188. package/content/concepts/lowdefy-api.md +0 -1110
  189. package/content/concepts/notifications.md +0 -155
  190. package/content/concepts/page-and-app-state.md +0 -244
  191. package/content/concepts/theming.md +0 -582
  192. package/content/connections/aigateway.md +0 -368
  193. package/content/connections/axioshttp.md +0 -181
  194. package/content/controls/while.md +0 -46
  195. package/content/display-blocks/clickablehtml.md +0 -239
  196. package/content/display-blocks/eventlog.md +0 -363
  197. package/content/display-blocks/pollingtimer.md +0 -263
  198. package/content/input-blocks/captcha.md +0 -40
  199. package/content/input-blocks/placesautocomplete.md +0 -319
  200. package/content/input-blocks/tagmultipleselector.md +0 -114
  201. package/content/input-blocks/tagselector.md +0 -114
  202. package/content/migration/auth-upgrade.md +0 -327
  203. package/content/migration/v3-to-v4.md +0 -417
  204. package/content/migration/v6-to-v7.md +0 -222
  205. package/content/operators/_cron.md +0 -292
  206. package/content/other/mongodbadapter.md +0 -3
  207. package/content/plugins/plugins-icon-sets.md +0 -267
  208. package/content/plugins/posthog.md +0 -275
  209. package/content/provider-reference/auth-js-providers.md +0 -107
  210. package/content/provider-reference/openidconnectprovider.md +0 -44
  211. package/content/testing/config-tests.md +0 -278
  212. package/content/tutorial/tutorial-requests-api.md +0 -155
  213. package/content/user-authentication/auth-configuration.md +0 -266
  214. package/content/user-authentication/auth-steps.md +0 -138
  215. package/content/user-authentication/mcp-oauth.md +0 -292
  216. package/content/user-authentication/organizations.md +0 -221
  217. package/content/user-authentication/protected-pages-apis.md +0 -97
  218. package/content/user-authentication/roles.md +0 -49
  219. package/content/user-authentication/two-factor.md +0 -229
  220. package/content/user-authentication/user-object.md +0 -58
  221. package/content/websockets/websocket-publish.md +0 -108
  222. package/content/websockets/websocket-subscriptions.md +0 -100
  223. package/content/websockets/websockets-introduction.md +0 -97
  224. package/hazards.json +0 -44
  225. package/scripts/hashDocSources.js +0 -38
  226. package/scripts/recordSourceHashes.js +0 -88
@@ -1,150 +0,0 @@
1
- # Blocks
2
-
3
- A Lowdefy page is compiled out of an arrangement of blocks. Every HTML element of this page is rendered as a result of a block placed and configured on the page. A Lowdefy Block is just a React component. A large number of default blocks make it easy to build apps with Lowdefy, and for more specific requirements, custom blocks can be added to apps as [plugins](/plugins).
4
-
5
- Blocks make it simple for Lowdefy developers to create apps since they only have to decide which block type to use, where in the layout the block should render, and what the block should do by defining the block's `properties` and `events`. How a block implements these `properties` and `events` is up to the specific block type.
6
-
7
- All Lowdefy blocks are categorized according to their primary function:
8
- - `display` - Display page elements.
9
- - `input` - Modify a value in [`state`](/page-and-app-state).
10
- - `container` - Render other blocks into [`content slots`](/layout).
11
- - `list` - Render `content slots` and blocks for each element in the data array represented in [`state`](/page-and-app-state).
12
-
13
- When `state` updates or a requests call completes, the Lowdefy engine re-evaluates all operators and re-renders blocks for which the operator evaluation is different from the previous render result. The result is _live updates_ to all blocks on a page. Operators can be used to build _live update_ logic into all block fields, except for the `id`, `type`, `slots` and `blocks` fields.
14
-
15
- The schema for a Lowdefy block is:
16
-
17
- - `id: string`: An identifier for a block. For `Input` blocks the block `id` sets the field key which the block will modify in `state`. Field _dot-notation_ can be used to express fields which are nested in objects or arrays.
18
- - `type: string`: __Required__ - This is the block type identifier and defines what block to use. The block type used must either be a default block type or can defined in the app's [`plugins`](/plugins) configuration.
19
- - `properties: object`: All the settings passed to a block component. __Operators are evaluated__.
20
- - `blocks: array`: An array of blocks to render to the default `content` slot for `container` and `list` blocks. See [layout](/layout-overview) for more details on how to use the `blocks` array.
21
- - `slots: object`: Used to set the content slots and content layout settings for `container` and `list` blocks. See [layout](/layout-overview) for more details on how to use `slots`.
22
- - `events: object`: Used to define [`actions`](/events-and-actions) that run when the block triggers an [`event`](/events-and-actions).
23
- - `layout: object`: Used to define the [layout](/layout-overview) settings for a block. __Operators are evaluated__.
24
- - `skeleton: object`: Used to overwrite a block's default loading behavior by rendering a skeleton. Any block types from [`@lowdefy/blocks-basic`](https://github.com/lowdefy/lowdefy/tree/main/packages/plugins/blocks/blocks-basic/src/blocks) and [`@lowdefy/blocks-loaders`](https://github.com/lowdefy/lowdefy/tree/main/packages/plugins/blocks/blocks-loaders/src/blocks) can be used in the skeleton definition, including sub-blocks. __Operators are evaluated__.
25
- - `loading: boolean`: When true, renders the block in loading. If a `skeleton` is defined, it will be rendered, else the block's default loading behavior will be rendered. __Operators are evaluated__.
26
- - `required: boolean | string`: For `input` blocks, whether or not a value is required in `state` when the [`Validate`](/Validate) action is called. Can be either a boolean or a string that is used as the validation error message . __Operators are evaluated__.
27
- - `class: string | array | object`: CSS class names to apply to the block. Supports Tailwind CSS utility classes. __Operators are evaluated__.
28
- - `style: css object`: Inline CSS styles. Flat CSS targets the layout wrapper. Use `.`-prefixed keys (e.g. `.element`, `.header`, `.body`) to target specific block parts. __Operators are evaluated__.
29
- - `validate: array`: A list of validation tests to pass when the [`Validate`](/Validate) action is called. __Operators are evaluated__.
30
- - `visible: boolean`: Controls whether or not to render a block. Operators are generally used here, and must evaluate to `false` to make the block invisible. Blocks with `visible: false` are excluded from `state`. __Operators are evaluated__.
31
-
32
- ## Block types
33
-
34
- Lowdefy has a set of default block types as defined in the Lowdefy docs. Most of the default Lowdefy blocks aim to cover a very generic implementation of the [Ant Design](https://ant.design/components/overview) React component library, but some addition component libraries are also included. To use all the default block types, you can simply use the block `type` key, such as [`Button`](/Button), [`TextInput`](/TextInput), or [`Box`](/Box).
35
-
36
- ###### Default block type config example:
37
- ```yaml
38
- lowdefy: 6.0.0
39
- pages:
40
- - id: example_dashboard
41
- type: PageHeaderMenu
42
- blocks:
43
- - id: basic_chart
44
- type: EChart
45
- properties:
46
- # ... EChart properties
47
- ```
48
-
49
- However, the default types can be overwritten or additional types can be defined as required. This is done by defining additional [`plugins`](/plugins).
50
-
51
- ## Input block validation
52
-
53
- All `input` block types maintain a value in the page [`state`](/page-and-app-state). This value is set to the field name matching the block `id`. Nested fields can be created by using _dot notation_ in the `id` to specify the field path, for example, `id: "a.b.c"` will produce a value `{"a": {"b": {"c": null }}}` in the page `state`.
54
-
55
- Client side field validation can be applied by setting the `required` and / or `validate` block fields. Field validation is first evaluated when the [`Validate`](/Validate) action is invoked on a page.
56
-
57
- ##### required schema:
58
-
59
- `required` can be a `boolean` or `string` type. When `required: true` the field label will indicate this with a red asterisk for user feedback, and a value will have to be supplied to the field in order to pass validation. If `required` is set to a `string`, this string will be used as the feedback message when the validation fails.
60
-
61
- ```yaml
62
- - id: name
63
- type: TextInput
64
- required: Please provide your name.
65
- properties:
66
- title: Name
67
- ```
68
-
69
- ##### validate schema:
70
-
71
- The `validate` field takes an `array` of test `objects` to evaluate before passing the field validation. This list of tests are evaluated sequentially, so the first test that fails will be used as the feedback message to the user.
72
-
73
- The schema for the validation test `objects`:
74
- - `pass: boolean`: __Required__ - The test that validates if this item passes or not. This is usually written with operators which evaluate to `true` or `false`. __Operators are evaluated__.
75
- - `message: string`: __Required__ - The feedback message to the user if this validation tests fails. __Operators are evaluated__.
76
- - `status: enum`: The feedback type to present to the user. Option are `error` and `warning`. Default is `error`. __Operators are evaluated__.
77
-
78
- The following `validate` example first verifies that something was entered into the `email` field, then checks that the field passes a email regex validation using the [`_regex`](/_regex) operator:
79
-
80
- ```yaml
81
- - id: email
82
- type: TextInput
83
- validate:
84
- - message: Please enter a email address.
85
- status: error
86
- pass:
87
- _ne:
88
- - _state: email
89
- - null
90
- - message: Please provide a valid email address.
91
- status: error
92
- pass:
93
- _regex: '^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$'
94
- properties:
95
- title: Email
96
- ```
97
-
98
- ## Block events
99
-
100
- By default all blocks implement `onMount` and `onMountAsync` events. Both the `onMount` and `onMountAsync` events are triggered when the block is mounted. For the `onMount` event, the block only mounts when the event action chain is completed, however, for the `onMountAsync` event, the block will mount as soon as possible while the event actions complete execution.
101
-
102
- Apart from the `onMount` and `onMountAsync` events, most blocks also implement their own block specific events such as `onOpen` for [Modal](/Modal) or `onClick` for [Button](/Button). See the events tab on each block's documentation for more details.
103
-
104
- See [the events and actions page](/events-and-actions) for more details.
105
-
106
- ## Block loading
107
-
108
- Blocks will only start rendering when the `onInit` event has completed its actions. The `onMount` event on blocks will render blocks with loading active. By default, some blocks will change behavior while they are loading. For example, input blocks will be disabled during loading. The loading behavior of blocks can be controlled using the `loading` block property. Setting `loading` to `true` on a container or list block, will result in rendering all child blocks with loading active.
109
-
110
- Often it is useful to render a skeleton of blocks instead of the blocks' default loading behavior. When block definitions are provided to the `skeleton` property on a block, this `skeleton` definition will be rendered when loading is active. Any block types from [`@lowdefy/blocks-basic`](https://github.com/lowdefy/lowdefy/tree/main/packages/plugins/blocks/blocks-basic/src/blocks) and [`@lowdefy/blocks-loaders`](https://github.com/lowdefy/lowdefy/tree/main/packages/plugins/blocks/blocks-loaders/src/blocks) can be used as the skeleton definition. Skeleton blocks are not real blocks, they do not have values in state or events, but they can contain other skeleton blocks as children.
111
-
112
- ##### Block `loading` and `skeleton` example:
113
-
114
- ```yaml
115
- pages:
116
- - id: page_one
117
- type: Box
118
- blocks:
119
- # ...
120
- - id: paragraph_one
121
- type: Paragraph
122
- loading:
123
- _eq:
124
- - _state: done
125
- - false
126
- skeleton:
127
- type: SkeletonParagraph
128
- properties:
129
- lines: 1
130
- properties:
131
- content: Lorem ipsum dolor sit amet.
132
- # ...
133
- ```
134
-
135
- ## TLDR
136
- - All user interfaces in Lowdefy are assembled out of blocks, which are React components.
137
- #### Block types
138
- - There are four block categories: `display`, `input`, `container` and `list`.
139
- - Operators re-evaluate on every [`state`](/page-and-app-state) update or when request calls complete. This allows blocks to _live update_.
140
- - Lowdefy has built in default block types, however this can be overwritten or extended with custom blocks by defining [`plugins`](/plugins) on the Lowdefy config root.
141
- - `input` blocks maintain a value in `state` matching the block `id` key. _Dot notation_ applies to specify nested fields.
142
- #### Block validation
143
- - Field level input validation can be achieved by marking an `input` block as `required` or by specifying a list of `validate` tests.
144
- - Validation is invoked using the [`Validate`](/Validate) action.
145
- #### Block events
146
- - All blocks have`onMount` and `onMountAsync` events.
147
- - Each block implements it's own additional events such as `onClick` etc.
148
- #### Block loading
149
- - Some blocks gracefully handle a loading state while `onMount` events are being executed.
150
- - A block's default loading can be overwritten by defining custom `skeleton` settings on a block.
@@ -1,304 +0,0 @@
1
- # Dynamic Page Content
2
-
3
- Dynamic page content lets parts of a page — or a whole page — be resolved on the server at page load. You place a `Dynamic` block on a page and point it at an [API endpoint](/lowdefy-api). When the page is requested, the server calls the endpoint's routine in-process, the routine returns block config, and the server validates that config and splices it into the page before responding. The client renders the result like any other page.
4
-
5
- Dynamic page content is useful when the structure of a page depends on runtime data:
6
-
7
- - A dashboard whose sections depend on the user's role, plan, or feature flags.
8
- - A form generated from a workflow definition stored in a database.
9
- - A product page whose layout comes from a CMS record.
10
- - Table views, kanban columns, or navigation derived from tenant configuration.
11
-
12
- For content where only the _data_ changes, use [requests](/connections-and-requests) — they are cached, re-fetchable, and don't reset page state. Reach for dynamic page content when the _blocks themselves_ need to change per request.
13
-
14
- ## How It Works
15
-
16
- 1. A user requests a page containing a `Dynamic` block.
17
- 2. The server checks page authorization as usual, then calls the endpoint configured on each `Dynamic` block — in-process, no HTTP. The endpoint's own auth is also checked against the user's session.
18
- 3. The routine executes with a payload containing the block's `params`, the `pageId`, the `blockId`, and the page request's `urlQuery`.
19
- 4. The routine returns `{ blocks: [...] }` — ordinary Lowdefy block config.
20
- 5. The server builds and validates the returned blocks: block, action and operator types must be in the app's client bundle, block properties are validated against each block type's schema, and `Request` actions must reference requests defined statically on the page.
21
- 6. The validated blocks become the `Dynamic` block's content, and the page is sent to the client.
22
-
23
- If resolution fails, the `Dynamic` block renders its `fallback` slot (or nothing) and the error is logged on the server — the page still loads. Set `required: true` to fail the whole page request instead.
24
-
25
- ## The Dynamic Block
26
-
27
- ```yaml
28
- - id: insights
29
- type: Dynamic
30
- properties:
31
- endpointId: resolve_insights # Required. The endpoint that resolves this content.
32
- params: # Optional. Static values passed to the endpoint.
33
- area: insights
34
- required: false # Optional. true fails the page load on resolution failure.
35
- types: # Optional. Extra types the endpoint may return.
36
- blocks:
37
- - Statistic
38
- slots:
39
- fallback: # Optional. Rendered when resolution fails.
40
- blocks:
41
- - id: insights_unavailable
42
- type: Html
43
- properties:
44
- html: Insights are unavailable right now.
45
- ```
46
-
47
- `params` must not contain operators — the page config is static. Runtime values belong in the endpoint routine, which reads the payload with `_payload` and the session with `_user`.
48
-
49
- A page that should be entirely dynamic is just a page whose body is a single `Dynamic` block.
50
-
51
- ## The Resolver Endpoint
52
-
53
- The endpoint is a normal API endpoint. Use `type: InternalApi` so it has no HTTP route — it is then only callable by the server itself.
54
-
55
- The endpoint receives this payload:
56
-
57
- - `params: object` - The `Dynamic` block's `params`, verbatim.
58
- - `pageId: string` - The page being resolved.
59
- - `blockId: string` - The `Dynamic` block's id.
60
- - `urlQuery: object` - The query parameters of the page request.
61
-
62
- The routine must return an object with a `blocks` array:
63
-
64
- ```yaml
65
- api:
66
- - id: resolve_insights
67
- type: InternalApi
68
- auth:
69
- public: false
70
- routine:
71
- - id: get_sections
72
- type: MongoDBFind
73
- connectionId: mongodb
74
- properties:
75
- query:
76
- roles:
77
- $in:
78
- _user: roles
79
- area:
80
- _payload: params.area
81
- - :return:
82
- blocks:
83
- _array.map:
84
- on:
85
- _step: get_sections
86
- callback:
87
- _function:
88
- __object.assign:
89
- - id:
90
- __args: 0.section_id
91
- type: Statistic
92
- properties:
93
- title:
94
- __args: 0.title
95
- value:
96
- __args: 0.value
97
- ```
98
-
99
- All operators registered on the server — including shared operators like `_state`, `_if` and `_string` — are evaluated during `:return` (`_state` reads the routine's own `:set_state` state). To defer an operator to the client instead, prefix it with one extra underscore, the same convention `_function` bodies use for `__args`:
100
-
101
- ```yaml
102
- - :return:
103
- blocks:
104
- - id: greeting
105
- type: Html
106
- properties:
107
- html:
108
- __state: name_input # unescaped to `_state` — evaluates on the client
109
- ```
110
-
111
- The server strips one leading underscore from `__`-prefixed keys in the returned config, so `__state` reaches the client as `_state` and binds to page state like any static block. Client-only operators (`_request`, `_global`, ...) have no server implementation and need no escaping, but the `__` form works for them too and is the consistent style.
112
-
113
- > **Never place `_secret` in returned block config.** It evaluates during `:return` and the resulting value ships to the browser.
114
-
115
- ### Data in the returned config is literal
116
-
117
- While a Dynamic block's endpoint evaluates its `:return`, data read at runtime stays data. That covers step results, the payload, routine state, `:for` items, and values built from data, such as `_json.parse` of a stored string. Three rules apply:
118
-
119
- - **Data cannot carry operators.** No operator may return a value that contains operators. A record holding `{ _request: ... }` or `{ __state: ... }` fails resolution, and the block renders its fallback. The error names the operator and where in its result the operator was found.
120
- - **Data cannot be a block or an action.** Without a [dynamic blocks policy](#dynamic-blocks-policies), every block and action in the returned content must be written in the `:return` config. Data may fill values inside those blocks (an id, a title, a type, a list of options), but a block or action that is itself data an operator returned, or a copy of it, fails resolution. To render stored block config, check it with a `ValidateDynamic` step under a policy.
121
- - **Data cannot become an operator by merging.** An object from data that `_object.assign` merges with other config must not be left with an operator key alone, for example next to a key whose value is a function or evaluates to undefined on the client.
122
-
123
- Data may nest at most 200 levels deep; deeper data fails resolution with an error saying so. Only keys that name one of the app's operators count as operators. Data such as a search hit's `{ _score: 0.5 }` or `{ _source: { ... } }` stays data.
124
-
125
- Write client operators in the `:return` config itself. Only operators that pass their own already-checked params through — `_if`, `_switch`, `_if_none`, `_get`, `_args`, `_function`, `_log`, `_array` and `_object` (except `_object.fromEntries` and `_object.defineProperty`) — may return them, so mapping data rows into blocks with `_array.map` and `_function` works as shown above.
126
-
127
- These patterns return config through data and fail resolution:
128
-
129
- - **Blocks built up in routine state** (`:set_state` in a loop, then `_state` in `:return`). Build the list inside `:return` with `_array.map` or `_array.concat`.
130
- - **Blocks returned by a nested endpoint** and read with `_step`. Share block config with `_ref` instead.
131
- - **A `:for` over a literal list of block configs**, read with `_item`. Map the list inside `:return`.
132
- - **Blocks built by `_js` or `_jsonata`.** Return the data from them and map it into blocks inside `:return`.
133
- - **Stored block config returned as it is**, whether read directly, picked out with `_get`, or copied or extended by an `_array.map` callback (`__args: 0`, `__object.assign`). Put the Dynamic block under a policy and return the content through `ValidateDynamic` (see [Rendering stored content under a policy](#rendering-stored-content-under-a-policy)).
134
-
135
- ## Using urlQuery in the Routine
136
-
137
- The page request's query string is forwarded to the resolver as `urlQuery` in the payload. A page loaded as `/products?category=shoes&sort=price` resolves with `urlQuery: { category: 'shoes', sort: 'price' }`:
138
-
139
- ```yaml
140
- api:
141
- - id: resolve_products
142
- type: InternalApi
143
- routine:
144
- - id: get_products
145
- type: MongoDBFind
146
- connectionId: mongodb
147
- properties:
148
- query:
149
- category:
150
- _payload: urlQuery.category
151
- options:
152
- sort:
153
- - - _payload: urlQuery.sort
154
- - 1
155
- - :return:
156
- blocks:
157
- - id: product_count
158
- type: Html
159
- properties:
160
- html:
161
- _string.concat:
162
- - 'Found '
163
- - _array.length:
164
- _step: get_products
165
- - ' products in "'
166
- - _payload: urlQuery.category
167
- - '"'
168
- ```
169
-
170
- The resolver executes on every navigation to the page — a menu link, a `Link` action (including to the same page), or the browser back and forward buttons all re-resolve the content on the server. Dynamic page config is never served from a client cache.
171
-
172
- ## Client Bundle Types
173
-
174
- The client bundle is fixed at build time — resolved content can only use block, action and operator types the build included. Types used on static pages are always available. To use a type that appears _only_ in dynamic content, declare it on the `Dynamic` block:
175
-
176
- ```yaml
177
- - id: insights
178
- type: Dynamic
179
- properties:
180
- endpointId: resolve_insights
181
- types:
182
- blocks:
183
- - Statistic
184
- - EChart
185
- actions:
186
- - CopyToClipboard
187
- operators:
188
- - _number
189
- ```
190
-
191
- The build bundles declared types into the client. If a routine returns a type that is not in the bundle, resolution fails with a clear error instead of a silently broken page.
192
-
193
- ## Dynamic Blocks Policies
194
-
195
- A dynamic blocks policy, declared under `policies.dynamicBlocks` in `lowdefy.yaml`, lets a Dynamic block render block config that is stored as data — a form built by a form builder, or config a model generated — within limits the app declares. The policy lists what the content may use. Anything unlisted fails, and the policy is checked twice with the same function: by a `ValidateDynamic` step before the content is stored, and on every page get before the content renders.
196
-
197
- ```yaml
198
- policies:
199
- dynamicBlocks:
200
- - id: generated_form
201
- blocks:
202
- - Title
203
- - Paragraph
204
- - TextInput
205
- - Selector
206
- actions:
207
- - SetState
208
- - CallAPI
209
- operators:
210
- - _state
211
- - _eq
212
- - _if
213
- endpoints:
214
- - submit_form_response
215
- links:
216
- pages:
217
- - form_submitted
218
- origins:
219
- - https://example.com
220
- state: form
221
- ```
222
-
223
- | Key | Default | Meaning |
224
- | --------------- | --------- | ----------------------------------------------------------------------------------------------------------- |
225
- | `id` | required | Policy id, referenced by Dynamic blocks and steps. |
226
- | `blocks` | required | Block types the content may use. `Dynamic` cannot be listed. |
227
- | `actions` | `[]` | Action types the content may use. |
228
- | `operators` | `[]` | Client operator names. `_string` allows every `_string` method. `_operator` cannot be listed. |
229
- | `endpoints` | `[]` | Endpoints a `CallAPI` action in the content may call. |
230
- | `requests` | `[]` | Page requests a `Request` action may call. The build checks every page that hosts the policy defines them. |
231
- | `links.pages` | `[]` | Pages the content may navigate to, by `pageId` or by an app path such as `/form_submitted`. |
232
- | `links.origins` | `[]` | Exact origins (`https://example.com`) the content may link to or load from. |
233
- | `state` | none | When set, input block ids, `SetState` keys and `_state` reads must sit under this state path. |
234
- | `html` | `false` | When `false`, no string in the content may contain HTML tag syntax. |
235
- | `limits` | see below | `depth` (10), `blocks` (500), `bytes` (262144) and `actionsPerEvent` (20). They can be raised, not removed. |
236
-
237
- Besides the lists, a policy requires literal values wherever the content names a target: `properties`, `style`, events and action lists; the params of `Link`, `CallAPI`, `Request` and `SetState`; every `_state` key; and every `pageId` and URL. URLs must be app paths or use a listed origin — including image sources, markdown links and CSS `url()`. A block's properties schema marks which properties hold a URL (see [Plugins](/plugins-introduction)), so a URL property is checked whatever it is called, such as `Search` `indexUrl` or `QRCode` `icon`; every value no schema marks, including action params and the properties of blocks that mark none, is checked by its key (`url`, `href`, `src`, ...). URLs are read as the browser reads them, so surrounding spaces and embedded tabs or newlines do not hide one.
238
-
239
- > With `html: false`, an operator that builds strings (`_string`, `_uri`, `_base64`, `_json`) can still assemble HTML at render time from content that passed the check. The build warns when a policy lists one. Leave them out of policies for generated content.
240
-
241
- ### Rendering stored content under a policy
242
-
243
- Put the policy on the Dynamic block, and return the content through a `ValidateDynamic` step with the same policy. Data stays literal in a Dynamic endpoint (see [Data in the returned config is literal](#data-in-the-returned-config-is-literal)); the blocks of a `ValidateDynamic` step that passed with the block's policy are the one exception.
244
-
245
- ```yaml
246
- pages:
247
- - id: form
248
- type: PageHeaderMenu
249
- blocks:
250
- - id: generated
251
- type: Dynamic
252
- properties:
253
- endpointId: get_form_blocks
254
- policy: generated_form
255
- - id: submit
256
- type: Button
257
- properties:
258
- title: Submit
259
- events:
260
- onClick:
261
- - id: save
262
- type: CallAPI
263
- params:
264
- endpointId: submit_form_response
265
- payload:
266
- answers:
267
- _state: form
268
-
269
- api:
270
- - id: get_form_blocks
271
- type: InternalApi
272
- routine:
273
- - id: get_form
274
- type: MongoDBFindOne
275
- connectionId: forms
276
- properties:
277
- query:
278
- _id:
279
- _payload: urlQuery.formId
280
- - id: check
281
- type: ValidateDynamic
282
- properties:
283
- policy: generated_form
284
- blocks:
285
- _step: get_form.blocks
286
- - :return:
287
- blocks:
288
- _step: check.blocks
289
- ```
290
-
291
- The policy's types are bundled into the page, so a Dynamic block with `policy` does not declare `properties.types`. Content that breaks the policy at page get renders the fallback, and the log lists each violation.
292
-
293
- ### Checking generated content
294
-
295
- A generator calls `ValidateDynamic` with `throwOnInvalid: false` and feeds the errors back to the model. Each error has a `path` into the submitted content, a `rule` and a `message`. `DescribeDynamicPolicy` returns what the policy allows, with the properties schema of each block and the params schema of each action and operator, to build the prompt from. See [Validating Dynamic Content As A Routine Step](/lowdefy-api#validating-dynamic-content-as-a-routine-step).
296
-
297
- ## Rules and Limitations
298
-
299
- - **No `requests` in resolved content.** Request artifacts are written at build time. Resolved blocks reference requests defined statically on the page via `Request` actions, or call endpoints with `CallAPI`.
300
- - **Nesting is allowed** — resolved content may contain further `Dynamic` blocks, up to 5 levels deep.
301
- - **Page state resets per visit.** Dynamic pages build a fresh context on every navigation, since the server may resolve different content each time. Keep cross-navigation state in `_global` or `_url_query`.
302
- - **Endpoint auth always applies.** A public page pointing at a role-protected endpoint renders the fallback for users without the role — useful for role-gated sections.
303
- - **Data cannot carry operators or be blocks.** Operators in step results, payload or state returned into `:return` fail resolution, and so do blocks and actions that are data, except the blocks of a `ValidateDynamic` step under the block's policy. See [Data in the returned config is literal](#data-in-the-returned-config-is-literal) and [Dynamic Blocks Policies](#dynamic-blocks-policies).
304
- - **`blockId` namespace is shared.** Resolved blocks share the page's state namespace, so `_state` binds across static and dynamic blocks. Keep blockIds unique, as on any page.