@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
@@ -341,39 +341,6 @@ Free standard shipping (3-5 business days). Express shipping available for $9.99
341
341
  for $9.99 (1-2 business days).
342
342
  ```
343
343
 
344
- Billed every month. Cancel any time.
345
-
346
- Billed once a year with two months free.
347
-
348
- ```yaml
349
- - id: centered_tabs
350
- type: Tabs
351
- properties:
352
- centered: true
353
- tabBarGutter: 40
354
- indicator:
355
- size: 24
356
- align: center
357
- tabs:
358
- - key: centered_monthly
359
- title: Monthly
360
- - key: centered_yearly
361
- title: Yearly
362
- slots:
363
- centered_monthly:
364
- blocks:
365
- - id: centered_monthly_content
366
- type: Paragraph
367
- properties:
368
- content: Billed every month. Cancel any time.
369
- centered_yearly:
370
- blocks:
371
- - id: centered_yearly_content
372
- type: Paragraph
373
- properties:
374
- content: Billed once a year with two months free.
375
- ```
376
-
377
344
  **Small:**
378
345
 
379
346
  Compact tabs for dense interfaces where screen space is at a premium. Ideal for side panels and secondary navigation.
@@ -654,16 +621,16 @@ Monthly target progress at 85%. On track for completion by end of quarter.
654
621
  tabs:
655
622
  - key: icon_home
656
623
  title: Home
657
- icon: home
624
+ icon: AiOutlineHome
658
625
  - key: icon_users
659
626
  title: Users
660
- icon: users
627
+ icon: AiOutlineTeam
661
628
  - key: icon_settings
662
629
  title: Settings
663
- icon: settings
630
+ icon: AiOutlineSetting
664
631
  - key: icon_chart
665
632
  title: Analytics
666
- icon: chart
633
+ icon: AiOutlineBarChart
667
634
  slots:
668
635
  icon_home:
669
636
  blocks:
@@ -717,17 +684,17 @@ Monthly target progress at 85%. On track for completion by end of quarter.
717
684
  - key: ci_success
718
685
  title: Passed
719
686
  icon:
720
- name: check-circle
687
+ name: AiOutlineCheckCircle
721
688
  color: "#52c41a"
722
689
  - key: ci_warning
723
690
  title: Warnings
724
691
  icon:
725
- name: warning
692
+ name: AiOutlineWarning
726
693
  color: "#faad14"
727
694
  - key: ci_error
728
695
  title: Failed
729
696
  icon:
730
- name: close-circle
697
+ name: AiOutlineCloseCircle
731
698
  color: "#ff4d4f"
732
699
  slots:
733
700
  ci_success:
@@ -885,7 +852,7 @@ Your video library. Supports MP4, WebM, and MOV formats. Maximum file size is 50
885
852
  flex: 0 0 auto
886
853
  properties:
887
854
  title: Upload
888
- icon: upload
855
+ icon: AiOutlineUpload
889
856
  color: primary
890
857
  variant: solid
891
858
  size: small
@@ -932,13 +899,13 @@ Yesterday - Alex created 3 new issues in the backlog tracker.
932
899
  tabs:
933
900
  - key: rich_dashboard
934
901
  title: Dashboard
935
- icon: Gauge
902
+ icon: AiOutlineDashboard
936
903
  - key: rich_team
937
904
  title: Team
938
- icon: users
905
+ icon: AiOutlineTeam
939
906
  - key: rich_activity
940
907
  title: Activity
941
- icon: history
908
+ icon: AiOutlineHistory
942
909
  slots:
943
910
  rich_dashboard:
944
911
  blocks:
@@ -1697,13 +1664,7 @@ Press Cmd+3 (Mac) or Ctrl+3 (Windows) to jump to this tab.
1697
1664
  | Property | Type | Default | Description |
1698
1665
  | --- | --- | --- | --- |
1699
1666
  | `animated` | boolean | `true` | Whether to change tabs with animation. Only works while tabPlacement is top or bottom. |
1700
- | `centered` | boolean | `false` | Center the tabs in the tab bar. |
1701
1667
  | `defaultActiveKey` | string | - | Initial active TabPane's key, if activeKey is not set. |
1702
- | `destroyOnHidden` | boolean | `false` | Unmount the content of inactive tabs. Blocks in a hidden tab keep their state values. |
1703
- | `indicator` | object | - | Size and alignment of the active tab indicator (ink bar). |
1704
- | `indicator.size` | number | - | Length of the indicator in pixels. Defaults to the width of the tab. |
1705
- | `indicator.align` | string | `"center"` | Alignment of the indicator along the tab when size is set. Enum: `start`, `center`, `end`. |
1706
- | `tabBarGutter` | number | - | Gap between tabs in pixels. |
1707
1668
  | `size` | string | `"default"` | Size of the tabs. Enum: `default`, `small`, `large`. |
1708
1669
  | `tabPlacement` | string | `"top"` | Position of the tabs. Enum: `top`, `end`, `bottom`, `start`. |
1709
1670
  | `tabType` | string | `"line"` | Type of tabs. Enum: `line`, `card`. |
@@ -1712,24 +1673,13 @@ Press Cmd+3 (Mac) or Ctrl+3 (Windows) to jump to this tab.
1712
1673
  | `tabs.$.key` | string | - | Area key of the tab. |
1713
1674
  | `tabs.$.eventName` | string | - | Block-level event name to trigger when this tab becomes active, in addition to onChange. Declare an event with this name under `events:`. The event receives `{ key }` of the now-active tab. |
1714
1675
  | `tabs.$.disabled` | boolean | `false` | Disable the tab if true. |
1715
- | `tabs.$.icon` | string \| object | - | Icon name (a semantic name like `edit`, a Lucide icon name like `Pencil`, or a set-qualified name like `tabler:Pencil`) or properties of an Icon block to customize icon to show in tab title. |
1716
- | `tabs.$.icon.name` | string | - | Icon name: a semantic name like `edit`, a Lucide icon name like `Pencil`, or a set-qualified name like `tabler:Pencil`. |
1717
- | `tabs.$.icon.color` | string | - | Icon color. |
1718
- | `tabs.$.icon.size` | string \| number | - | Size of the icon. Defaults to `theme.icons.size`. |
1719
- | `tabs.$.icon.rotate` | number | - | Number of degrees to rotate the icon. |
1720
- | `tabs.$.icon.spin` | boolean | - | Continuously spin the icon with animation. |
1721
- | `tabs.$.icon.strokeWidth` | number | - | Stroke width of the icon lines, in pixels of the 24px icon grid. Defaults to `theme.icons.strokeWidth` (2). |
1722
- | `tabs.$.icon.nonScalingStroke` | boolean | - | Keep the stroke width constant at any icon size. Defaults to `theme.icons.nonScalingStroke`. |
1723
- | `tabs.$.icon.title` | string | - | Icon hover title for accessibility. An empty string marks the icon as decorative. |
1724
- | `tabs.$.icon.disableLoadingIcon` | boolean | - | While loading after the icon has been clicked, don't render the loading icon. |
1676
+ | `tabs.$.icon` | string \| object | - | Name of an React-Icon (See all icons) or properties of an Icon block to customize icon to show in tab title. |
1725
1677
  | `tabs.$.shortcut` | string | - | Keyboard shortcut to switch to this tab. Use "mod" for Cmd/Ctrl. |
1726
1678
  | `extraAreaKey` | string | - | Area key for the extra area blocks. |
1727
1679
  | `theme` | object | - | Antd design token overrides for this block. See [antd design tokens](https://ant.design/components/overview#design-token). See [Ant Design tabs tokens](https://ant.design/components/tabs#design-token). |
1728
1680
  | `theme.cardBg` | string | `"rgba(0, 0, 0, 0.02)"` | Background color of card-type tab. |
1729
1681
  | `theme.cardGutter` | number | `2` | Gap between card-type tabs. |
1730
1682
  | `theme.cardHeight` | number | `40` | Height of card-type tab. |
1731
- | `theme.cardHeightSM` | number | `32` | Height of small card-type tab. |
1732
- | `theme.cardHeightLG` | number | `48` | Height of large card-type tab. |
1733
1683
  | `theme.cardPadding` | string | `"8px 16px"` | Padding of card-type tab. |
1734
1684
  | `theme.cardPaddingLG` | string | `"11px 16px"` | Padding of large card-type tab. |
1735
1685
  | `theme.cardPaddingSM` | string | `"4px 8px"` | Padding of small card-type tab. |
@@ -1764,7 +1714,5 @@ Press Cmd+3 (Mac) or Ctrl+3 (Windows) to jump to this tab.
1764
1714
  | `/tabBar` | The Tabs tab bar. |
1765
1715
  | `/tabPane` | The Tabs tab pane. |
1766
1716
  | `/inkBar` | The Tabs ink bar. |
1767
- | `/item` | Each tab in the tab bar. |
1768
- | `/popup` | The dropdown that lists tabs that overflow the tab bar. |
1769
1717
 
1770
1718
  Slot keys are user-defined in your config and resolved at build time — not generated at runtime. The block typically pairs slots with an array property (`tabs`, `panels`, `slides`) listed in the Properties table; see the examples above for the expected shape.
@@ -689,7 +689,7 @@ Hover over this text to see the tooltip.
689
689
  layout:
690
690
  flex: 0 0 auto
691
691
  properties:
692
- icon: delete
692
+ icon: AiOutlineDelete
693
693
  hideTitle: true
694
694
  color: danger
695
695
  variant: text
@@ -749,8 +749,7 @@ Hover over this text to see the tooltip.
749
749
  flex: 0 0 auto
750
750
  properties:
751
751
  title: Tooltip with custom overlay style
752
- style:
753
- .inner:
752
+ overlayStyle:
754
753
  boxShadow: 0 4px 12px rgba(0, 0, 0, 0.3)
755
754
  blocks:
756
755
  - id: tooltip_overlay_style_btn
@@ -921,7 +920,7 @@ Hover me (Tailwind element class)
921
920
  properties:
922
921
  title: Tailwind on element wrapper
923
922
  class:
924
- .element: cursor-help
923
+ element: cursor-help
925
924
  blocks:
926
925
  - id: tooltip_class_element_text
927
926
  type: Paragraph
@@ -934,7 +933,7 @@ Hover me (Tailwind element class)
934
933
  properties:
935
934
  title: Tailwind on inner popup
936
935
  class:
937
- .inner: text-lg font-bold
936
+ inner: text-lg font-bold
938
937
  blocks:
939
938
  - id: tooltip_class_inner_btn
940
939
  type: Button
@@ -1089,19 +1088,47 @@ $8,230
1089
1088
  properties:
1090
1089
  label:
1091
1090
  title: Username
1092
- tooltip:
1093
- title: Your unique username. Must be 3-20 characters, letters and numbers only.
1094
- color: "#8c8c8c"
1091
+ extra:
1092
+ - id: tooltip_form_username_help
1093
+ type: Tooltip
1094
+ layout:
1095
+ flex: 0 0 auto
1096
+ properties:
1097
+ title: Your unique username. Must be 3-20 characters, letters and numbers only.
1098
+ placement: right
1099
+ blocks:
1100
+ - id: tooltip_form_username_icon
1101
+ type: Icon
1102
+ layout:
1103
+ flex: 0 0 auto
1104
+ properties:
1105
+ name: AiOutlineQuestionCircle
1106
+ size: 14
1107
+ color: "#8c8c8c"
1095
1108
  placeholder: Enter your username
1096
1109
  - id: tooltip_form_email
1097
1110
  type: TextInput
1098
1111
  properties:
1099
1112
  label:
1100
1113
  title: Email Address
1101
- tooltip:
1102
- title: We will send account notifications to this address. You can change it at
1103
- any time.
1104
- color: "#8c8c8c"
1114
+ extra:
1115
+ - id: tooltip_form_email_help
1116
+ type: Tooltip
1117
+ layout:
1118
+ flex: 0 0 auto
1119
+ properties:
1120
+ title: We will send account notifications to this address. You can change it at
1121
+ any time.
1122
+ placement: right
1123
+ blocks:
1124
+ - id: tooltip_form_email_icon
1125
+ type: Icon
1126
+ layout:
1127
+ flex: 0 0 auto
1128
+ properties:
1129
+ name: AiOutlineQuestionCircle
1130
+ size: 14
1131
+ color: "#8c8c8c"
1105
1132
  placeholder: Enter your email
1106
1133
  ```
1107
1134
 
@@ -1148,7 +1175,7 @@ Monthly Revenue
1148
1175
  layout:
1149
1176
  flex: 0 0 auto
1150
1177
  properties:
1151
- name: info
1178
+ name: AiOutlineInfoCircle
1152
1179
  size: 14
1153
1180
  color: "#8c8c8c"
1154
1181
  - id: tooltip_dashboard_users_stat
@@ -1193,7 +1220,7 @@ Monthly Revenue
1193
1220
  layout:
1194
1221
  flex: 0 0 auto
1195
1222
  properties:
1196
- name: info
1223
+ name: AiOutlineInfoCircle
1197
1224
  size: 14
1198
1225
  color: "#8c8c8c"
1199
1226
  - id: tooltip_dashboard_revenue_stat
@@ -1210,18 +1237,15 @@ Monthly Revenue
1210
1237
 
1211
1238
  | Property | Type | Default | Description |
1212
1239
  | --- | --- | --- | --- |
1213
- | `arrow` | boolean \| object | `true` | Whether to show the arrow. Set `{ pointAtCenter: true }` to point the arrow at the center of the target. |
1214
- | `arrow.pointAtCenter` | boolean | `false` | Whether the arrow is pointed at the center of target. |
1215
- | `arrowPointAtCenter` | boolean | `false` | Whether the arrow is pointed at the center of target. Same as `arrow: { pointAtCenter: true }`. |
1240
+ | `arrowPointAtCenter` | boolean | `false` | Whether the arrow is pointed at the center of target. |
1216
1241
  | `autoAdjustOverflow` | boolean | `true` | Whether to adjust popup placement automatically when popup is off screen. |
1217
1242
  | `color` | string | - | The background color. |
1218
1243
  | `defaultOpen` | boolean | `false` | Whether the floating tooltip card is visible by default. |
1219
- | `destroyOnHidden` | boolean | `false` | Whether to destroy the tooltip DOM when hidden. |
1220
- | `destroyTooltipOnHide` | boolean | `false` | Same as destroyOnHidden, which takes precedence. |
1244
+ | `destroyTooltipOnHide` | boolean | `false` | Whether to destroy the tooltip DOM when hidden. |
1221
1245
  | `mouseEnterDelay` | number | `0.1` | Delay in seconds, before tooltip is shown on mouse enter. |
1222
- | `mouseLeaveDelay` | number | `0.1` | Delay in seconds, before tooltip is hidden on mouse leave. |
1246
+ | `mouseLeaveDelay` | number | `0.1` | Delay in seconds, before tooltip is shown on mouse enter. |
1223
1247
  | `placement` | string | `"top"` | The position of the tooltip relative to the target. Enum: `top`, `left`, `right`, `bottom`, `topLeft`, `topRight`, `bottomLeft`, `bottomRight`, `leftTop`, `leftBottom`, `rightTop`, `rightBottom`. |
1224
- | `trigger` | string | `"hover"` | Tooltip trigger mode. `contextMenu` opens the tooltip on right click. Enum: `hover`, `focus`, `click`, `contextMenu`. |
1248
+ | `trigger` | string | `"hover"` | Tooltip trigger mode. Enum: `hover`, `focus`, `click`. |
1225
1249
  | `title` | string | - | Title to show in the title area - supports html. Overwritten by blocks in the title content area. |
1226
1250
  | `zIndex` | integer | - | The z-index of the Tooltip. |
1227
1251
  | `theme` | object | - | Antd design token overrides for this block. See [antd design tokens](https://ant.design/components/overview#design-token). See [Ant Design tooltip tokens](https://ant.design/components/tooltip#design-token). |
@@ -1237,7 +1261,7 @@ Monthly Revenue
1237
1261
 
1238
1262
  | Event | Event Data | Description |
1239
1263
  | --- | --- | --- |
1240
- | `onOpenChange` | `{ open }` | Trigger action when visibility of the tooltip card is changed. |
1264
+ | `onOpenChange` | \- | Trigger action when visibility of the tooltip card is changed. |
1241
1265
 
1242
1266
  | Key | Target |
1243
1267
  | --- | --- |
@@ -91,24 +91,6 @@ Watermark overlay with text, image, and font customization.
91
91
  height: 200px
92
92
  ```
93
93
 
94
- ```yaml
95
- - id: per_line_font
96
- type: Watermark
97
- properties:
98
- text:
99
- - text: CONFIDENTIAL
100
- font:
101
- fontSize: 22
102
- fontWeight: bold
103
- color: rgba(255, 0, 0, 0.12)
104
- - Prepared for the finance team
105
- blocks:
106
- - id: per_line_font_child
107
- type: Box
108
- style:
109
- height: 200px
110
- ```
111
-
112
94
  ```yaml
113
95
  - id: align_left
114
96
  type: Watermark
@@ -296,7 +278,7 @@ Drag and drop files here or click to browse
296
278
  - id: css_gradient_bg
297
279
  type: Watermark
298
280
  class:
299
- .element: bg-gradient-to-br from-primary/10 to-primary/5 rounded-lg p-4
281
+ element: bg-gradient-to-br from-primary/10 to-primary/5 rounded-lg p-4
300
282
  properties:
301
283
  text: Preview
302
284
  font:
@@ -313,7 +295,7 @@ Drag and drop files here or click to browse
313
295
  - id: css_dark_surface
314
296
  type: Watermark
315
297
  class:
316
- .element: bg-bg-layout rounded-lg p-4
298
+ element: bg-bg-layout rounded-lg p-4
317
299
  properties:
318
300
  text: Dark Theme
319
301
  font:
@@ -338,7 +320,7 @@ Drag and drop files here or click to browse
338
320
  - id: css_bordered_area
339
321
  type: Watermark
340
322
  class:
341
- .element: border-2 border-dashed border-border rounded-xl p-6
323
+ element: border-2 border-dashed border-border rounded-xl p-6
342
324
  properties:
343
325
  text: Upload Area
344
326
  font:
@@ -513,7 +495,7 @@ Mobile app for real-time inventory tracking across multiple warehouses. Integrat
513
495
  | `inherit` | boolean | `true` | Inherit watermark config from parent Watermark block. |
514
496
  | `offset` | array | - | Offset of the watermark from the top-left as [x, y]. |
515
497
  | `rotate` | number | `-22` | Rotation angle of watermark in degrees. |
516
- | `text` | string \| array | - | Watermark text content. An array renders one line per item. A line can be a string, or `{ text, font }` to give that line its own font style. |
498
+ | `text` | string \| array | - | Watermark text content. Maps to antd "content" prop. |
517
499
  | `theme` | object | - | Antd design token overrides for this block. See [antd design tokens](https://ant.design/components/overview#design-token). See [Ant Design watermark tokens](https://ant.design/components/watermark#design-token). |
518
500
  | `theme.colorFill` | string | - | Default watermark text color when font.color is not set. Maps to the global colorFill token. |
519
501
  | `theme.fontSizeLG` | number | `16` | Default watermark font size when font.fontSize is not set. Maps to the global fontSizeLG token. |
@@ -7,11 +7,9 @@
7
7
  The `:reject` control is used to return a user-friendly error to the client when validation fails or business rules are violated.
8
8
  Unlike [`:throw`](/:throw), which indicates a system error, `:reject` represents an expected failure condition that should be communicated to the user.
9
9
  The control immediately stops routine execution and returns with a `"reject"` status.
10
- Importantly, `:reject` does not trigger `:catch` blocks in [`:try`](/:try) statements: the reject flows past every enclosing `:try`, so a `:catch` in an outer `:try` never runs either, while `:finally` still runs.
11
- This makes `:reject` ideal for handling validation and business logic errors separately from system errors.
12
- Choose [`:throw`](/:throw) when a step failed and the routine may recover; choose `:reject` when the routine decided the request cannot be fulfilled.
10
+ Importantly, `:reject` does not trigger `:catch` blocks in [`:try`](/:try) statements, making it ideal for handling validation and business logic errors separately from system errors.
13
11
 
14
- `:reject` also takes an Error as its message, such as the error a `:catch` caught: `:reject: { _error: true }`. The reject message is then "Something went wrong.", unless the error was a `UserError` or an auth refusal (`AuthenticationError`, `AuthorizationError` or `TwoFactorEnrolmentRequiredError`), whose message is kept. To reject with the caught error's real message, name it: `:reject: { _error: message }`. See [`_error`](/_error).
12
+ `:reject` also takes an Error as its message, such as the error a `:catch` caught: `:reject: { _error: true }`. The reject message is then "Something went wrong.", unless the error was a `UserError` or an authentication error, whose message is kept. To reject with the caught error's real message, name it: `:reject: { _error: message }`. See [`_error`](/_error).
15
13
 
16
14
  #### Keys
17
15
 
@@ -8,7 +8,6 @@ The `:throw` control creates a system error that immediately stops routine execu
8
8
  Unlike [`:reject`](/:reject), which handles expected user errors, `:throw` is designed for unexpected system failures, programming errors, or critical issues that require attention.
9
9
  The key difference is that `:throw` can be caught and handled by [`:try`](/:try)/`:catch` blocks, while [`:reject`](/:reject) cannot.
10
10
  This makes `:throw` ideal for recoverable system errors where you might want to implement fallback logic.
11
- Choose `:throw` when a step failed and the routine may recover; choose [`:reject`](/:reject) when the routine decided the request cannot be fulfilled.
12
11
 
13
12
  `:throw` also takes an Error as its message, such as the error a `:catch` caught: `:throw: { _error: true }`. The error is rethrown as it is, with its own class and cause, and `:cause` is ignored. The client receives it with the message "Something went wrong.", keeping its `code` and `statusCode`, unless it was a `UserError`, whose message is kept. To show the user the caught error's real message, name it: `:throw: { _error: message }`. See [`_error`](/_error).
14
13
 
@@ -7,14 +7,13 @@
7
7
  If one control in the routine chain defined in the `:try` key fails by throwing an error, the steps in the list following the failed control will not be executed.
8
8
  To handle any errors thrown by a routine element, a routine can be provided using `catch` key.
9
9
  The routine defined using the `:finally` key will be run regardless of whether or not the routine throws an error.
10
- A [`:reject`](/:reject) inside the `:try` routine is __not__ caught. `:reject` is the routine's own reply — it stops the routine, returns a `"reject"` status to the caller, and flows past every enclosing `:catch`. `:finally` still runs. Use [`:throw`](/:throw) for failures a `:catch` should handle.
11
10
  Inside the `:catch` routine, the [`_error`](/_error) operator returns the error that was caught, so the routine can branch on its `statusCode` or `code`, or read its `message`. `_error` returns the error of the innermost `:catch` that encloses it, and `null` outside a `:catch`.
12
11
 
13
12
  #### Keys
14
13
 
15
14
  - `:try: routine`: __Required__ - The routine to be run.
16
- - `:catch: routine`: The routine to execute if any step in the routine defined errors. Runs on a thrown error only — a `:reject` is not caught.
17
- - `:finally: routine`: The routine to be run regardless of the out come of the initial routine. Runs on success, error and reject.
15
+ - `:catch: routine`: The routine to execute if any step in the routine defined errors.
16
+ - `:finally: routine`: The routine to be run regardless of the out come of the initial routine.
18
17
 
19
18
  #### Examples
20
19
 
@@ -1,6 +1,6 @@
1
1
  # Deployment environments
2
2
 
3
- Most apps run as more than one deployment: production, a staging copy, a developer's machine. Everything that differs between them is declared once, under `config.environments`, and each deployment says which environment it is with the `LOWDEFY_ENVIRONMENT` environment variable. Lowdefy then takes every environment-specific default from the **current environment** — the app URL, crons, the email delivery filter, Sentry, PostHog, and the feature switches — so none of them needs its own variable or operator chain.
3
+ Most apps run as more than one deployment: production, a staging copy, a developer's machine. Everything that differs between them is declared once, under `config.environments`, and each deployment says which environment it is with the `LOWDEFY_ENVIRONMENT` environment variable. Lowdefy then takes every environment-specific default from the **current environment** — the app URL, crons, the email delivery filter, Sentry, and the feature switches — so none of them needs its own variable or operator chain.
4
4
 
5
5
  ```yaml
6
6
  # lowdefy.yaml
@@ -46,18 +46,17 @@ Every setting is optional, and every feature is **on by default**: only an expli
46
46
  | `email.filter` | none | Delivery filter (`replaceAddress`, `allowlist`, `regex`) for mail requests. |
47
47
  | `email.enabled` | `true` | `false`: mail requests send nothing. |
48
48
  | `sentry.enabled` | `true` | `false`: Sentry off, server and client. |
49
- | `posthog.enabled` | `true` | `false`: PostHog off — `PostHogInit` behaves as `enabled: false`. |
50
49
  | `guards.secrets`, `guards.env` | none | Regular expressions the named secrets and environment variables must match, or the build fails. |
51
50
 
52
51
  ## URL
53
52
 
54
53
  The current environment's `url` is the default for:
55
54
 
56
- - the auth canonical URL (`BETTER_AUTH_URL`) — password-reset, magic-link and verification links, the CSRF origin allowlist, and the MCP resource URIs;
55
+ - the auth base URL (`AUTH_URL`) — sign-in callbacks and auth links;
57
56
  - the `serverUrl` of `RenderNotification` steps — the links and logo in notification emails;
58
57
  - where crons are forwarded to, when another environment forwards to this one.
59
58
 
60
- An explicit `BETTER_AUTH_URL` or `serverUrl` still wins. The dev server (`lowdefy dev`) never uses the current environment's `url`: notification and auth links use the request origin, the local app, even when your local `.env` names a deployed environment. Production never uses the request origin, since a spoofed `Host` header would then steer the links in outgoing mail. A production server with `auth.email` configured refuses to start when neither `BETTER_AUTH_URL` nor the current environment's `url` is set.
59
+ An explicit `AUTH_URL` / `NEXTAUTH_URL` or `serverUrl` still wins. The dev server (`lowdefy dev`) never uses the current environment's `url`: auth and notification links use the request origin, the local app, even when your local `.env` names a deployed environment. Production never uses the request origin, since a spoofed `Host` header would then steer the links in outgoing mail.
61
60
 
62
61
  Every deployment that names an environment is taken to be served at its `url`. Preview deployments that should not sign users in on the staging host need their own environment, e.g. a `preview` environment with no `url` and the same `email.filter` and guards as staging.
63
62
 
@@ -81,11 +80,10 @@ Endpoint `schedules` can be keyed by environment name, with a `default` for the
81
80
 
82
81
  See the [SMTP](/SMTP) and [SendGridMail](/SendGridMail) connections for the filter fields.
83
82
 
84
- ## Logs, Sentry and PostHog
83
+ ## Logs and Sentry
85
84
 
86
85
  - Every server log line carries `environment` next to `app_name`, `app_version` and `git_sha`, so one log drain can hold every environment. Logging cannot be switched off.
87
86
  - Sentry reports under the environment name unless `logger.sentry.environment` is set, and `sentry.enabled: false` turns it off on the server and in the browser.
88
- - `PostHogInit` registers the environment name as the `environment` super property, so every PostHog event carries it. `posthog.enabled: false` switches PostHog off in that environment: `PostHogInit` behaves as `enabled: false` whatever its params say, needs no `apiKey`, and every other PostHog action is a no-op.
89
87
 
90
88
  ## Guards
91
89
 
@@ -100,7 +98,7 @@ config:
100
98
  secrets: # Lowdefy secrets, by name (LOWDEFY_SECRET_<name>)
101
99
  MONGODB_URI: 'acme-prod\.a1b2c\.mongodb\.net'
102
100
  env: # any environment variable
103
- BETTER_AUTH_URL: '^https://app\.example\.com$'
101
+ AUTH_URL: '^https://app\.example\.com$'
104
102
  ```
105
103
 
106
104
  - Patterns match anywhere in the value, so a distinctive substring is enough; add `^` and `$` to pin the whole value. A pattern is committed with your config, so never put the sensitive part of a secret in it — a host name or database name is enough.
@@ -113,7 +111,7 @@ config:
113
111
  Environment settings stay on the server. The browser only learns the current environment's **name** and the list of features it switches off, through the app metadata:
114
112
 
115
113
  - `_app: environment` — the current environment's name.
116
- - `_app: disabled` — the switched-off features, e.g. `[email, posthog]`.
114
+ - `_app: disabled` — the switched-off features, e.g. `[email, sentry]`.
117
115
 
118
116
  Other environments' settings, URLs, secret names, email filters and guards never reach the client bundle. Only the current environment's guards are kept in the build output, in the server-only `config.json`, for the startup check.
119
117
 
@@ -15,7 +15,7 @@ The generated Dockerfile:
15
15
  ```text
16
16
  # syntax=docker/dockerfile:1
17
17
 
18
- FROM node:24-slim AS builder
18
+ FROM node:22-slim AS builder
19
19
 
20
20
  WORKDIR /lowdefy
21
21
 
@@ -41,7 +41,7 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
41
41
  && npx lowdefy@"$LOWDEFY_VERSION" build \
42
42
  && npx lowdefy@"$LOWDEFY_VERSION" docker-output
43
43
 
44
- FROM node:24-slim AS runner
44
+ FROM node:22-slim AS runner
45
45
 
46
46
  ENV NODE_ENV=production
47
47
  ENV PORT=3000
@@ -93,7 +93,7 @@ Key properties of this setup:
93
93
  - **Fast rebuilds**: the pnpm store is kept in a BuildKit cache mount, so changing app config only re-downloads dependencies that actually changed.
94
94
  - **Small runtime image**: `docker-output` traces the server's real import graph and copies only what the server loads at runtime — a fraction of the installed `node_modules`, since the client-side block packages are already compiled into `dist/client` and never imported by the server.
95
95
  - **Non-root**: the server runs as the `node` user built into the official Node.js images.
96
- - For stronger supply-chain guarantees, pin the base images by digest (`node:24-slim@sha256:...`) and let a bot like Renovate or Dependabot keep the digest updated.
96
+ - For stronger supply-chain guarantees, pin the base images by digest (`node:22-slim@sha256:...`) and let a bot like Renovate or Dependabot keep the digest updated.
97
97
 
98
98
  ### Health checks
99
99
 
@@ -124,7 +124,7 @@ The server is configured entirely through environment variables at runtime — t
124
124
  | `LOWDEFY_SECRET_*` | App secrets, accessed with the [`_secret`](/_secret) operator. |
125
125
  | `AUTH_SECRET` | Required when using [Lowdefy Auth](/users-introduction). |
126
126
  | `LOWDEFY_ENVIRONMENT` | Read at build time: the environment this image is built for, one of `config.environments`. |
127
- | `BETTER_AUTH_URL` | The app's canonical origin for auth links and the MCP resource URIs. Defaults to the `url` of the current environment in `config.environments`. The server refuses to start without one of the two when `auth.email` is configured. Set it when a proxy terminates TLS in front of the container: without it, auth trusts only the origin the request reached the server on (`http://…`), and refuses sign-in from the `https://` page. |
127
+ | `AUTH_URL` | The deployed app URL, required for OAuth providers. Defaults to the `url` of the current environment in `config.environments`. |
128
128
  | `CRON_SECRET` | Bearer token protecting `/api/cron/*` and `/api/detached/*` endpoints. |
129
129
  | `LOWDEFY_LOG_LEVEL` | Server log level: `debug`, `info` (default), `warn`, `error`. |
130
130
  | `SENTRY_DSN` | Enables Sentry error reporting when set. |
@@ -148,21 +148,6 @@ RUN --mount=type=secret,id=sentry,env=SENTRY_AUTH_TOKEN \
148
148
  npx lowdefy@"$LOWDEFY_VERSION" build
149
149
  ```
150
150
 
151
- ### Behind a reverse proxy
152
-
153
- The server takes each request's client address from its connection. Auth rate limits count attempts per client address (for example 3 sign-in attempts per 10 seconds), sessions record it, and the request log writes it as `client_address`. `X-Forwarded-For` is not read by default, because any client can send it.
154
-
155
- Behind a reverse proxy, load balancer or ingress, every connection comes from the proxy, so every client would share its address and its rate limits. List the proxy addresses, or CIDR ranges, in `config.trustedProxies`:
156
-
157
- ```yaml
158
- config:
159
- trustedProxies:
160
- - 10.0.0.0/8
161
- - 172.16.0.0/12
162
- ```
163
-
164
- When a request's connection comes from a trusted proxy, the server reads `X-Forwarded-For` from the right, skips every trusted hop, and takes the first address that is not trusted. Entries further left were written by the client and are ignored. Do not list `0.0.0.0/0` or `::/0`: they trust every address, so any client could choose its own, and the build warns about them. The proxy must append to `X-Forwarded-For` (nginx: `proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;`). The server logs a warning the first time a request carries `X-Forwarded-For` while `trustedProxies` is not set.
165
-
166
151
  ### Logging
167
152
 
168
153
  The server writes structured JSON logs (one JSON object per line, via [pino](https://getpino.io)) to stdout — the format container platforms and log collectors (CloudWatch, Loki, Datadog, etc.) expect. Nothing is written to files inside the container.
@@ -203,7 +188,7 @@ The container inherits the Dockerfile `HEALTHCHECK`, so `docker compose ps` repo
203
188
  docker compose up --build
204
189
  ```
205
190
 
206
- If you set a container memory limit, Node.js 24+ sizes its heap from the container's cgroup limit automatically. To control it explicitly, set `NODE_OPTIONS=--max-old-space-size=<MiB>` a comfortable margin below the container limit.
191
+ If you set a container memory limit, Node.js 22+ sizes its heap from the container's cgroup limit automatically. To control it explicitly, set `NODE_OPTIONS=--max-old-space-size=<MiB>` a comfortable margin below the container limit.
207
192
 
208
193
  ### Config files or plugins outside the config directory
209
194
 
@@ -214,7 +199,7 @@ Sometimes files outside of the config directory need to be accessed by the Lowde
214
199
  ```text
215
200
  # syntax=docker/dockerfile:1
216
201
 
217
- FROM node:24-slim AS builder
202
+ FROM node:22-slim AS builder
218
203
 
219
204
  WORKDIR /lowdefy
220
205
 
@@ -232,7 +217,7 @@ RUN --mount=type=cache,id=pnpm,target=/pnpm/store \
232
217
  && npx lowdefy@"$LOWDEFY_VERSION" build --config-directory ./app \
233
218
  && npx lowdefy@"$LOWDEFY_VERSION" docker-output --config-directory ./app
234
219
 
235
- FROM node:24-slim AS runner
220
+ FROM node:22-slim AS runner
236
221
 
237
222
  ENV NODE_ENV=production
238
223
  ENV PORT=3000
@@ -22,10 +22,6 @@ from inside the folder, or `pnpm start`. The server listens on `PORT` (default 3
22
22
 
23
23
  Always run the build before restarting the server — the server reads the client asset manifest once at startup.
24
24
 
25
- With `auth.email` configured, the server needs the app's canonical origin — `BETTER_AUTH_URL`, or the `url` of the current environment in `config.environments` — or it refuses to start, so emailed auth links cannot take their host from a request. To test the production server locally, set `BETTER_AUTH_URL=http://localhost:3000`.
26
-
27
- Behind a reverse proxy or load balancer, list its addresses in `config.trustedProxies` so auth rate limits count each client, not the proxy. See [Behind a reverse proxy](/docker#behind-a-reverse-proxy).
28
-
29
25
  ### Alternative
30
26
 
31
27
  An alternative option would be to make use of [Docker](./docker) to deploy the app. Docker has a few advantages, including scalability, application portability, version control and deployment speed, amoung others.
@@ -27,17 +27,14 @@ In the Vercel project:
27
27
  - Eg: if `lowdefy.yaml` is at the top level of the repository, set the root directory to `deploy`; if it is in `apps/app_name`, set it to `apps/app_name/deploy`.
28
28
  - **Install Command:** `bash vercel.install.sh`. Leave the **Build Command** to `vercel.json` (do not override it in the dashboard). There is no **Output Directory** setting — the build emits `.vercel/output`, which Vercel detects automatically.
29
29
  - Enable **"Include files outside the root directory in the Build Step"** — the Lowdefy config usually lives in the parent of `deploy/`.
30
- - **Node.js Version:** `24.x` or newer. The install and build steps run the Lowdefy CLI, which requires Node.js 24; the function itself runs on the `nodejs24.x` runtime set in the generated Build Output.
31
30
 
32
31
  ###### Public files
33
32
 
34
- Files in your app's `public/` directory (favicon, icons, images, `manifest.webmanifest`, etc.) are copied into `dist/client` by Vite during the build, placed in `.vercel/output/static`, and served by the Vercel CDN — no extra configuration needed. With `config.basePath` set, they are placed and served under the base path, as are the generated cron paths below.
33
+ Files in your app's `public/` directory (favicon, icons, images, `manifest.webmanifest`, etc.) are copied into `dist/client` by Vite during the build, placed in `.vercel/output/static`, and served by the Vercel CDN — no extra configuration needed.
35
34
 
36
35
  ###### Secrets and environment variables
37
36
 
38
- Secrets can be set in the Environment Variables settings section by creating environment variables prefixed with `LOWDEFY_SECRET_`. Pin the auth canonical URL with the current environment's `url` (see [Deployment environments](/deployment-environments)) or `BETTER_AUTH_URL`; with `auth.email` configured the app refuses to start without it. Different secrets can be set for production and preview deployments.
39
-
40
- On Vercel the client address used by auth rate limits, sessions and request logs comes from the platform (`x-real-ip`), which Vercel sets on every request. `config.trustedProxies` is not used.
37
+ Secrets can be set in the Environment Variables settings section by creating environment variables prefixed with `LOWDEFY_SECRET_`. Use `AUTH_SECRET` (and `AUTH_URL` for OAuth, which defaults to the current environment's `url` — see [Deployment environments](#deployment-environments)) for authentication. Different secrets can be set for production and preview deployments.
41
38
 
42
39
  ###### Function settings
43
40
 
@@ -85,11 +82,11 @@ Each schedule becomes a cron job pointing at `/api/cron/<endpointId>`. When it f
85
82
 
86
83
  ###### Deployment environments
87
84
 
88
- Declare the app's environments once under `config.environments` and name the current one with the `LOWDEFY_ENVIRONMENT` Environment Variable — see [Deployment environments](/deployment-environments) for every setting (URL, crons, email, Sentry, PostHog, feature switches, guards). On Vercel, add `LOWDEFY_ENVIRONMENT` to each Vercel environment (for example `prod` on Production and `staging` on the staging branch's Preview environment). Vercel Environment Variables are available at build time, which is when Lowdefy reads it and checks guards.
85
+ Declare the app's environments once under `config.environments` and name the current one with the `LOWDEFY_ENVIRONMENT` Environment Variable — see [Deployment environments](/deployment-environments) for every setting (URL, crons, email, Sentry, feature switches, guards). On Vercel, add `LOWDEFY_ENVIRONMENT` to each Vercel environment (for example `prod` on Production and `staging` on the staging branch's Preview environment). Vercel Environment Variables are available at build time, which is when Lowdefy reads it and checks guards.
89
86
 
90
87
  ###### Crons for staging and other environments
91
88
 
92
- Vercel fires cron jobs only on the **production** deployment — a staging or preview deployment never runs its schedules on its own. Give an environment a `cron.secret` and the environment Vercel fires crons on registers that environment's schedules too; when one fires, production forwards it to that environment's own `/api/cron/<endpointId>` at its `url` (under `config.basePath` when one is set) and answers Vercel immediately (the ping is fire-and-forget, kept alive via the request context and bounded by `maxDuration`; its outcome is logged as `forward_scheduled_endpoint_done` / `_failed`).
89
+ Vercel fires cron jobs only on the **production** deployment — a staging or preview deployment never runs its schedules on its own. Give an environment a `cron.secret` and the environment Vercel fires crons on registers that environment's schedules too; when one fires, production forwards it to that environment's own `/api/cron/<endpointId>` at its `url` and answers Vercel immediately (the ping is fire-and-forget, kept alive via the request context and bounded by `maxDuration`; its outcome is logged as `forward_scheduled_endpoint_done` / `_failed`).
93
90
 
94
91
  - **Forwarded environments:** an environment with a `cron.secret` is forwarded to, so it must have a `url`. `cron.secret` is the **name** of the Lowdefy secret holding that environment's own `CRON_SECRET` — a plain string such as `STAGING_CRON_SECRET`, not `{ _secret: ... }`: environment settings are resolved at build time, and the forward route reads the value at runtime from `LOWDEFY_SECRET_<name>`. Set `cron.enabled: false` on an environment to register no crons for it.
95
92
  - **Secrets on production:** for each forwarded environment add an Environment Variable `LOWDEFY_SECRET_<secret name>` (for example `LOWDEFY_SECRET_STAGING_CRON_SECRET`) to the production deployment, with that environment's `CRON_SECRET` as value. The forward route `/api/cron-forward/*` itself is secured by production's own `CRON_SECRET` like every cron route, and fails closed when the environment's secret is missing.
@@ -110,13 +107,9 @@ See [Async Endpoints](/lowdefy-api) and [Detached Endpoint Calls](/lowdefy-api)
110
107
 
111
108
  Vercel Fluid bills by execution duration, so a request that hangs (a stuck database, SMTP or external API call) is a real cost risk. Two guardrails apply:
112
109
 
113
- - **`config.requestTimeout`** (in `lowdefy.yaml`, default `30000` ms) — the server returns a timeout instead of letting a request run on, and cancels the AI model calls the request was waiting on. Set to `0` to disable. Agent streaming routes are exempt.
110
+ - **`config.requestTimeout`** (in `lowdefy.yaml`, default `30000` ms) — the server returns a timeout instead of letting a request run on. Set to `0` to disable. Agent streaming routes are exempt.
114
111
  - **`config.vercel.maxDuration`** (default `60`) — a hard platform cap; Vercel stops the function at this many seconds. See Function settings above.
115
112
 
116
- Keep `config.requestTimeout` below `maxDuration`: when it is not, Vercel stops the function before the request timeout answers, so the upstream calls the request left running are not cancelled and the request ends without a logged timeout. The build warns when `config.requestTimeout` is not shorter than `maxDuration` (or than the 60-second default, when it runs on Vercel).
117
-
118
- On Vercel, only the request timeout cancels an AI model call a request is waiting on. A client that disconnects does not: the call runs until it finishes, reaches its own `timeout`, or hits the request timeout. On the Node server a disconnect cancels it too.
119
-
120
- > The function runs on Vercel's Node.js runtime. Streaming agent responses (`/api/agent/*`) are exempt from `config.requestTimeout` and are bounded only by `maxDuration` — for heavy streaming or agent workloads, a long-lived Node host (Docker, Fly.io, Railway, Render) may suit better. An agent run keeps running to the end when its client disconnects, so its work completes; a `GET` stream (such as an MCP client's notification stream) stops when its client goes, instead of holding the function until `maxDuration`.
113
+ > The function runs on Vercel's Node.js runtime. Streaming agent responses (`/api/agent/*`) are exempt from `config.requestTimeout` and are bounded only by `maxDuration` — for heavy streaming or agent workloads, a long-lived Node host (Docker, Fly.io, Railway, Render) may suit better.
121
114
 
122
115
  All other Vercel configuration like domain names, preview deploy branches, serverless regions and redirects can be configured as desired.