@lowdefy/docs-content 0.0.0-experimental-20260710073520

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 (304) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +20 -0
  3. package/content/actions/callapi.md +66 -0
  4. package/content/actions/callmethod.md +41 -0
  5. package/content/actions/copytoclipboard.md +32 -0
  6. package/content/actions/displaymessage.md +53 -0
  7. package/content/actions/downloadcsv.md +89 -0
  8. package/content/actions/fetch.md +50 -0
  9. package/content/actions/geolocationcurrentposition.md +56 -0
  10. package/content/actions/link.md +104 -0
  11. package/content/actions/login.md +85 -0
  12. package/content/actions/logout.md +56 -0
  13. package/content/actions/pdfmake.md +304 -0
  14. package/content/actions/request.md +67 -0
  15. package/content/actions/reset.md +27 -0
  16. package/content/actions/resetvalidation.md +85 -0
  17. package/content/actions/scrollto.md +85 -0
  18. package/content/actions/setdarkmode.md +62 -0
  19. package/content/actions/setfocus.md +33 -0
  20. package/content/actions/setglobal.md +63 -0
  21. package/content/actions/setlocale.md +69 -0
  22. package/content/actions/setstate.md +70 -0
  23. package/content/actions/throw.md +72 -0
  24. package/content/actions/validate.md +87 -0
  25. package/content/actions/wait.md +24 -0
  26. package/content/agents/agent-endpoint-tools.md +190 -0
  27. package/content/agents/agent-mcp-tools.md +124 -0
  28. package/content/agents/agent-multi-agent.md +136 -0
  29. package/content/agents/agent-properties.md +174 -0
  30. package/content/agents/agent-server-hooks.md +336 -0
  31. package/content/agents/agentchat.md +515 -0
  32. package/content/agents/agentconversations.md +148 -0
  33. package/content/concepts/ai-agent-docs.md +190 -0
  34. package/content/concepts/cli.md +213 -0
  35. package/content/concepts/connections-and-requests.md +7 -0
  36. package/content/concepts/custom-html.md +3 -0
  37. package/content/concepts/custom-styling.md +161 -0
  38. package/content/concepts/events-and-actions.md +271 -0
  39. package/content/concepts/hosting-files.md +18 -0
  40. package/content/concepts/i18n.md +320 -0
  41. package/content/concepts/keyboard-shortcuts.md +218 -0
  42. package/content/concepts/layout-overview.md +478 -0
  43. package/content/concepts/lists.md +144 -0
  44. package/content/concepts/logger.md +43 -0
  45. package/content/concepts/lowdefy-schema.md +365 -0
  46. package/content/concepts/menus.md +144 -0
  47. package/content/concepts/module-authoring.md +564 -0
  48. package/content/concepts/modules.md +338 -0
  49. package/content/concepts/operators.md +45 -0
  50. package/content/concepts/overview.md +19 -0
  51. package/content/concepts/references-and-templates.md +207 -0
  52. package/content/concepts/secrets.md +24 -0
  53. package/content/concepts/selectors.md +143 -0
  54. package/content/connections/amazonredshift.md +176 -0
  55. package/content/connections/anthropic.md +232 -0
  56. package/content/connections/awss3.md +313 -0
  57. package/content/connections/azureblobstorage.md +133 -0
  58. package/content/connections/elasticsearch.md +371 -0
  59. package/content/connections/google.md +228 -0
  60. package/content/connections/googlecloudstorage.md +139 -0
  61. package/content/connections/googlesheet.md +313 -0
  62. package/content/connections/knex.md +206 -0
  63. package/content/connections/mariadb.md +177 -0
  64. package/content/connections/mcp.md +134 -0
  65. package/content/connections/mongodb.md +739 -0
  66. package/content/connections/mssql.md +191 -0
  67. package/content/connections/mysql.md +192 -0
  68. package/content/connections/openai-connection.md +228 -0
  69. package/content/connections/postgresql.md +200 -0
  70. package/content/connections/redis.md +116 -0
  71. package/content/connections/sendgridmail.md +94 -0
  72. package/content/connections/smtp.md +149 -0
  73. package/content/connections/sqlite.md +187 -0
  74. package/content/connections/stripe.md +115 -0
  75. package/content/container-blocks/affix.md +413 -0
  76. package/content/container-blocks/alert.md +937 -0
  77. package/content/container-blocks/badge.md +1222 -0
  78. package/content/container-blocks/box.md +1453 -0
  79. package/content/container-blocks/card.md +1200 -0
  80. package/content/container-blocks/carousel.md +2247 -0
  81. package/content/container-blocks/collapse.md +1335 -0
  82. package/content/container-blocks/configprovider.md +1070 -0
  83. package/content/container-blocks/confirmmodal.md +1159 -0
  84. package/content/container-blocks/content.md +597 -0
  85. package/content/container-blocks/descriptions.md +870 -0
  86. package/content/container-blocks/drawer.md +1379 -0
  87. package/content/container-blocks/dropdownmenu.md +643 -0
  88. package/content/container-blocks/flex.md +1510 -0
  89. package/content/container-blocks/footer.md +380 -0
  90. package/content/container-blocks/googlemaps.md +546 -0
  91. package/content/container-blocks/googlemapsheatmap.md +607 -0
  92. package/content/container-blocks/googlemapsscript.md +61 -0
  93. package/content/container-blocks/header.md +302 -0
  94. package/content/container-blocks/label.md +739 -0
  95. package/content/container-blocks/layout.md +604 -0
  96. package/content/container-blocks/masonry.md +1090 -0
  97. package/content/container-blocks/mobilemenu.md +1244 -0
  98. package/content/container-blocks/modal.md +1180 -0
  99. package/content/container-blocks/pageheadermenu.md +614 -0
  100. package/content/container-blocks/pagesidebarlayout.md +438 -0
  101. package/content/container-blocks/pagesidermenu.md +651 -0
  102. package/content/container-blocks/popover.md +1421 -0
  103. package/content/container-blocks/result.md +972 -0
  104. package/content/container-blocks/sider.md +1064 -0
  105. package/content/container-blocks/span.md +747 -0
  106. package/content/container-blocks/spinner.md +267 -0
  107. package/content/container-blocks/splitter.md +1735 -0
  108. package/content/container-blocks/tabs.md +1718 -0
  109. package/content/container-blocks/tooltip.md +1274 -0
  110. package/content/container-blocks/watermark.md +515 -0
  111. package/content/controls/for.md +103 -0
  112. package/content/controls/if.md +107 -0
  113. package/content/controls/log.md +50 -0
  114. package/content/controls/parallel.md +71 -0
  115. package/content/controls/parallel_for.md +36 -0
  116. package/content/controls/reject.md +56 -0
  117. package/content/controls/return.md +66 -0
  118. package/content/controls/set_state.md +98 -0
  119. package/content/controls/switch.md +90 -0
  120. package/content/controls/throw.md +79 -0
  121. package/content/controls/try.md +88 -0
  122. package/content/deployment/docker.md +149 -0
  123. package/content/deployment/node-server.md +27 -0
  124. package/content/deployment/vercel.md +101 -0
  125. package/content/display-blocks/aggrid.md +1459 -0
  126. package/content/display-blocks/anchor.md +336 -0
  127. package/content/display-blocks/avatar.md +1154 -0
  128. package/content/display-blocks/breadcrumb.md +517 -0
  129. package/content/display-blocks/button.md +758 -0
  130. package/content/display-blocks/calendar.md +156 -0
  131. package/content/display-blocks/dangeroushtml.md +314 -0
  132. package/content/display-blocks/dangerousmarkdown.md +423 -0
  133. package/content/display-blocks/diffgit.md +44 -0
  134. package/content/display-blocks/difflist.md +225 -0
  135. package/content/display-blocks/diffsidebyside.md +56 -0
  136. package/content/display-blocks/difftimeline.md +94 -0
  137. package/content/display-blocks/divider.md +406 -0
  138. package/content/display-blocks/download.md +60 -0
  139. package/content/display-blocks/dropdownbutton.md +661 -0
  140. package/content/display-blocks/echart.md +418 -0
  141. package/content/display-blocks/floatbutton.md +545 -0
  142. package/content/display-blocks/html.md +311 -0
  143. package/content/display-blocks/icon.md +717 -0
  144. package/content/display-blocks/img.md +479 -0
  145. package/content/display-blocks/markdown.md +520 -0
  146. package/content/display-blocks/markdownwithcode.md +730 -0
  147. package/content/display-blocks/menu.md +1123 -0
  148. package/content/display-blocks/message.md +941 -0
  149. package/content/display-blocks/notification.md +1410 -0
  150. package/content/display-blocks/paragraph.md +643 -0
  151. package/content/display-blocks/progress.md +818 -0
  152. package/content/display-blocks/qrcode.md +519 -0
  153. package/content/display-blocks/s3download.md +240 -0
  154. package/content/display-blocks/search.md +360 -0
  155. package/content/display-blocks/skeleton.md +272 -0
  156. package/content/display-blocks/skeletonavatar.md +222 -0
  157. package/content/display-blocks/skeletonbutton.md +245 -0
  158. package/content/display-blocks/skeletoninput.md +223 -0
  159. package/content/display-blocks/skeletonparagraph.md +201 -0
  160. package/content/display-blocks/statistic.md +485 -0
  161. package/content/display-blocks/steps.md +585 -0
  162. package/content/display-blocks/tag.md +620 -0
  163. package/content/display-blocks/title.md +654 -0
  164. package/content/display-blocks/tour.md +2359 -0
  165. package/content/input-blocks/autocomplete.md +786 -0
  166. package/content/input-blocks/buttonselector.md +964 -0
  167. package/content/input-blocks/checkboxselector.md +765 -0
  168. package/content/input-blocks/checkboxswitch.md +497 -0
  169. package/content/input-blocks/colorselector.md +884 -0
  170. package/content/input-blocks/daterangeselector.md +777 -0
  171. package/content/input-blocks/dateselector.md +693 -0
  172. package/content/input-blocks/datetimeselector.md +791 -0
  173. package/content/input-blocks/inputgallery.md +528 -0
  174. package/content/input-blocks/monthselector.md +717 -0
  175. package/content/input-blocks/multipleselector.md +1337 -0
  176. package/content/input-blocks/numberinput.md +855 -0
  177. package/content/input-blocks/pagination.md +679 -0
  178. package/content/input-blocks/paragraphinput.md +1664 -0
  179. package/content/input-blocks/passwordinput.md +480 -0
  180. package/content/input-blocks/phonenumberinput.md +688 -0
  181. package/content/input-blocks/radioselector.md +820 -0
  182. package/content/input-blocks/ratingslider.md +684 -0
  183. package/content/input-blocks/s3uploadbutton.md +384 -0
  184. package/content/input-blocks/s3uploaddragger.md +305 -0
  185. package/content/input-blocks/s3uploadphoto.md +288 -0
  186. package/content/input-blocks/segmentedselector.md +782 -0
  187. package/content/input-blocks/selector.md +1162 -0
  188. package/content/input-blocks/switch.md +552 -0
  189. package/content/input-blocks/textarea.md +714 -0
  190. package/content/input-blocks/textinput.md +639 -0
  191. package/content/input-blocks/tiptapinput.md +226 -0
  192. package/content/input-blocks/tiptapmentioninput.md +471 -0
  193. package/content/input-blocks/titleinput.md +1094 -0
  194. package/content/input-blocks/treeinput.md +144 -0
  195. package/content/input-blocks/treemultipleselector.md +162 -0
  196. package/content/input-blocks/treeselector.md +185 -0
  197. package/content/input-blocks/upload.md +149 -0
  198. package/content/input-blocks/uploaddragger.md +85 -0
  199. package/content/input-blocks/uploadphoto.md +84 -0
  200. package/content/input-blocks/weekselector.md +630 -0
  201. package/content/list-blocks/controlledlist.md +498 -0
  202. package/content/list-blocks/list.md +529 -0
  203. package/content/list-blocks/listselector.md +301 -0
  204. package/content/list-blocks/masonrylist.md +230 -0
  205. package/content/migration/upgrade-guide.md +106 -0
  206. package/content/migration/v4-to-v5.md +589 -0
  207. package/content/migration/v5-to-v6.md +36 -0
  208. package/content/operators/_actions.md +58 -0
  209. package/content/operators/_and.md +76 -0
  210. package/content/operators/_api.md +254 -0
  211. package/content/operators/_app.md +114 -0
  212. package/content/operators/_args.md +65 -0
  213. package/content/operators/_array.md +331 -0
  214. package/content/operators/_base64.md +49 -0
  215. package/content/operators/_boolean.md +33 -0
  216. package/content/operators/_build.md +166 -0
  217. package/content/operators/_change_case.md +357 -0
  218. package/content/operators/_date.md +415 -0
  219. package/content/operators/_dayjs.md +128 -0
  220. package/content/operators/_diff.md +61 -0
  221. package/content/operators/_divide.md +32 -0
  222. package/content/operators/_eq.md +52 -0
  223. package/content/operators/_event.md +86 -0
  224. package/content/operators/_function.md +52 -0
  225. package/content/operators/_get.md +92 -0
  226. package/content/operators/_global.md +86 -0
  227. package/content/operators/_gt.md +50 -0
  228. package/content/operators/_gte.md +50 -0
  229. package/content/operators/_hash.md +112 -0
  230. package/content/operators/_if.md +30 -0
  231. package/content/operators/_if_none.md +47 -0
  232. package/content/operators/_index.md +48 -0
  233. package/content/operators/_input.md +86 -0
  234. package/content/operators/_intl.md +135 -0
  235. package/content/operators/_item.md +166 -0
  236. package/content/operators/_js.md +113 -0
  237. package/content/operators/_json.md +120 -0
  238. package/content/operators/_jsonata.md +152 -0
  239. package/content/operators/_locale.md +65 -0
  240. package/content/operators/_location.md +40 -0
  241. package/content/operators/_log.md +22 -0
  242. package/content/operators/_lt.md +50 -0
  243. package/content/operators/_lte.md +50 -0
  244. package/content/operators/_math.md +407 -0
  245. package/content/operators/_media.md +83 -0
  246. package/content/operators/_menu.md +62 -0
  247. package/content/operators/_module.md +340 -0
  248. package/content/operators/_mql.md +95 -0
  249. package/content/operators/_ne.md +62 -0
  250. package/content/operators/_not.md +33 -0
  251. package/content/operators/_number.md +159 -0
  252. package/content/operators/_nunjucks.md +117 -0
  253. package/content/operators/_object.md +253 -0
  254. package/content/operators/_operator.md +33 -0
  255. package/content/operators/_or.md +67 -0
  256. package/content/operators/_product.md +45 -0
  257. package/content/operators/_random.md +90 -0
  258. package/content/operators/_ref.md +80 -0
  259. package/content/operators/_regex.md +69 -0
  260. package/content/operators/_request.md +35 -0
  261. package/content/operators/_request_details.md +29 -0
  262. package/content/operators/_secret.md +56 -0
  263. package/content/operators/_state.md +134 -0
  264. package/content/operators/_step.md +98 -0
  265. package/content/operators/_string.md +327 -0
  266. package/content/operators/_subtract.md +24 -0
  267. package/content/operators/_sum.md +45 -0
  268. package/content/operators/_switch.md +37 -0
  269. package/content/operators/_t.md +96 -0
  270. package/content/operators/_theme.md +65 -0
  271. package/content/operators/_type.md +78 -0
  272. package/content/operators/_uri.md +49 -0
  273. package/content/operators/_url_query.md +92 -0
  274. package/content/operators/_user.md +154 -0
  275. package/content/operators/_uuid.md +118 -0
  276. package/content/operators/_var.md +88 -0
  277. package/content/operators/_yaml.md +96 -0
  278. package/content/other/introduction.md +39 -0
  279. package/content/other/next-auth-providers.md +3 -0
  280. package/content/other/updatesession.md +26 -0
  281. package/content/plugins/plugins-actions.md +80 -0
  282. package/content/plugins/plugins-connections.md +98 -0
  283. package/content/plugins/plugins-dev.md +138 -0
  284. package/content/plugins/plugins-introduction.md +29 -0
  285. package/content/plugins/plugins-operators.md +71 -0
  286. package/content/testing/e2e-auth.md +108 -0
  287. package/content/testing/e2e-configuration.md +107 -0
  288. package/content/testing/e2e-getting-started.md +96 -0
  289. package/content/testing/e2e-introduction.md +53 -0
  290. package/content/testing/e2e-mocking.md +155 -0
  291. package/content/testing/e2e-writing-tests.md +214 -0
  292. package/content/tutorial/tutorial-actions-operators.md +222 -0
  293. package/content/tutorial/tutorial-add-blocks.md +86 -0
  294. package/content/tutorial/tutorial-create-page.md +57 -0
  295. package/content/tutorial/tutorial-display-data-page.md +181 -0
  296. package/content/tutorial/tutorial-next-steps.md +53 -0
  297. package/content/tutorial/tutorial-requests-sql.md +22 -0
  298. package/content/tutorial/tutorial-start.md +71 -0
  299. package/content/user-authentication/auth-providers.md +15 -0
  300. package/content/user-authentication/login-and-logout.md +122 -0
  301. package/content/user-authentication/users-introduction.md +31 -0
  302. package/index.json +2281 -0
  303. package/package.json +34 -0
  304. package/scripts/extractAgentDocs.js +130 -0
@@ -0,0 +1,338 @@
1
+ # Modules
2
+
3
+ Blocks are the smallest reusable unit in Lowdefy; apps are the largest. Modules sit between them — they package the shape of a feature teams want to share, like a user-admin panel or an events timeline. A module bundles pages, connections, API endpoints, components, and menus into a single distributable unit. Instead of copying config between projects, you install a module and configure it with variables.
4
+
5
+ A module is hosted in a GitHub repository or local directory. Each usage of a module in your app is called a **module entry** — identified by a user-chosen `id` that controls namespacing.
6
+
7
+ ## Using Modules
8
+
9
+ Add modules to the `modules` array in your `lowdefy.yaml`:
10
+
11
+ ```yaml
12
+ lowdefy: LOWDEFY_VERSION
13
+
14
+ modules:
15
+ - id: notifications
16
+ source: "github:lowdefy/notifications@v1.0.0"
17
+ vars:
18
+ sender_email: support@myapp.com
19
+ badge_position: top-right
20
+
21
+ - id: team-users
22
+ source: "github:my-org/user-admin@v1.0.0"
23
+ vars:
24
+ roles:
25
+ _ref: config/team-roles.yaml
26
+ collection: team_users
27
+ components:
28
+ table_columns:
29
+ _ref: config/team-users/table-columns.yaml
30
+ ```
31
+
32
+ Each module entry has:
33
+ - `id: string` — **Required.** A unique identifier for this entry. Must not contain `/`. Controls the namespace for scoped IDs and page paths.
34
+ - `source: string` — **Required.** Where to fetch the module. Supports GitHub repos and local paths.
35
+ - `vars: object` — Values passed to the module, accessible via [`_module.var`](/_module). Consumer values override manifest defaults; any value you omit falls back to the module's declared default.
36
+ - `connections: object` — Connection remapping. Maps module connection names to app connection IDs.
37
+ - `dependencies: object` — Dependency wiring. Maps abstract dependency names to concrete module entry IDs. See [Cross-Module Dependencies](#cross-module-dependencies).
38
+
39
+ The entry `id` becomes the URL prefix for every page the module contributes. A `user-admin` entry serves its pages at `/user-admin/all`, `/user-admin/invite`, `/user-admin/edit`; a `companies` entry serves `/companies/view`, `/companies/edit`, `/companies/create`.
40
+
41
+ ## Module Manifest
42
+
43
+ Each module has a `module.lowdefy.yaml` manifest that declares its contents and interface:
44
+
45
+ ```yaml
46
+ name: User Admin
47
+ description: User administration — list, edit, invite users
48
+
49
+ vars:
50
+ roles:
51
+ type: array
52
+ required: true
53
+ description: List of available user roles
54
+ collection:
55
+ type: string
56
+ default: users
57
+ description: MongoDB collection name
58
+
59
+ connections:
60
+ - _ref: connections/users-db.yaml
61
+
62
+ pages:
63
+ - _ref: pages/users-list.yaml
64
+ - _ref: pages/user-edit.yaml
65
+
66
+ api:
67
+ - _ref: api/invite-user.yaml
68
+
69
+ components:
70
+ - id: user-avatar
71
+ component:
72
+ _ref: components/user-avatar.yaml
73
+
74
+ menus:
75
+ - _ref: menus.yaml
76
+
77
+ # Default Lowdefy plugins do not need to be declared.
78
+ plugins:
79
+ - name: "@lowdefy/blocks-aggrid"
80
+ version: "^4"
81
+
82
+ secrets:
83
+ - name: MONGODB
84
+ description: MongoDB connection URI
85
+ ```
86
+
87
+ The manifest schema:
88
+ - `name: string` — Human-readable module name.
89
+ - `description: string` — Module description.
90
+ - `vars: object` — Variable declarations with `type`, `required`, `default`, and `description`.
91
+ - `connections: object[]` — Connection definitions used by the module.
92
+ - `pages: object[]` — Page definitions.
93
+ - `api: object[]` — API endpoint definitions.
94
+ - `dependencies: object[]` — Modules this module depends on. Each declares an abstract name (`id`) and `description`. The app wires these to concrete module entries. See [Cross-Module Dependencies](#cross-module-dependencies).
95
+ - `exports: object` — Declares the module's public interface. Lists IDs per section type (`pages`, `components`, `menus`, `connections`, `api`). The build validates cross-module references against exports.
96
+ - `components: object[]` — Named reusable config fragments exposed to the app.
97
+ - `menus: object[]` — Menu definitions.
98
+ - `plugins: object[]` — Required plugin dependencies with semver version constraints.
99
+ - `secrets: object[]` — Allowlist of secrets the module may access.
100
+
101
+ ## Consuming Module Resources
102
+
103
+ **Pages and APIs** are auto-included and auto-scoped — they appear in the app with the entry ID prefix.
104
+
105
+ **Components** are reusable config fragments included via [`_ref`](/_ref) with the `module` and `component` arguments. You can pass `vars` to customize the component at the point of inclusion:
106
+
107
+ ```yaml
108
+ blocks:
109
+ - _ref:
110
+ module: notifications
111
+ component: notification-badge
112
+ vars:
113
+ position: top-right
114
+ ```
115
+
116
+ Components can export any config — not just UI blocks. Enum maps, config templates, and schema fragments all work:
117
+
118
+ ```yaml
119
+ # Config template component
120
+ updated:
121
+ _ref:
122
+ module: events
123
+ component: change_stamp
124
+
125
+ # Enum map with key extraction
126
+ icon:
127
+ _ref:
128
+ module: events
129
+ component: event_types
130
+ key: login.icon
131
+ ```
132
+
133
+ **Menus** are included via `_ref` with the `module` and `menu` arguments. Use a `MenuGroup` to wrap each module's menu items:
134
+
135
+ ```yaml
136
+ menus:
137
+ - id: default
138
+ links:
139
+ - id: companies
140
+ type: MenuGroup
141
+ properties:
142
+ title: Companies
143
+ links:
144
+ _ref:
145
+ module: companies
146
+ menu: default
147
+ - id: user-admin
148
+ type: MenuGroup
149
+ properties:
150
+ title: User Admin
151
+ links:
152
+ _ref:
153
+ module: user-admin
154
+ menu: default
155
+ ```
156
+
157
+ ## ID Scoping
158
+
159
+ The build automatically scopes certain IDs using the module entry's `id`. Module authors write IDs without any prefix — the build adds it.
160
+
161
+ | ID type | Auto-scoped? | Module author writes | Becomes (in `team-users` entry) |
162
+ | --------------- | ------------ | -------------------- | ------------------------------- |
163
+ | Page ID | Yes | `users-list` | `team-users/users-list` |
164
+ | Connection ID | Yes | `users-db` | `team-users/users-db` |
165
+ | API endpoint ID | Yes | `invite-user` | `team-users/invite-user` |
166
+ | Menu item ID | Yes | `users` | `team-users/users` |
167
+ | Block ID | No | `my-block` | `my-block` |
168
+
169
+ Block IDs and request IDs are not scoped — they inherit scope from their parent page.
170
+
171
+ ## Page Paths
172
+
173
+ Module pages are served at `/{entryId}/{pageId}`:
174
+
175
+ | Module Entry ID | Page ID | URL Path |
176
+ | --------------- | ------------ | -------------------------- |
177
+ | `notifications` | `inbox` | `/notifications/inbox` |
178
+ | `team-users` | `users-list` | `/team-users/users-list` |
179
+ | `client-users` | `users-list` | `/client-users/users-list` |
180
+
181
+ From outside a module (app pages or other modules), reference scoped page IDs directly using the full path: `pageId: team-users/users-list`.
182
+
183
+ ## Connection Remapping
184
+
185
+ Modules declare their own connections. By default, each entry gets namespaced connections (e.g., `team-users/users-db`). You can remap a module connection to use an existing app connection instead:
186
+
187
+ ```yaml
188
+ modules:
189
+ - id: team-users
190
+ source: "github:lowdefy/user-admin@v1.0.0"
191
+ vars:
192
+ collection: team_users
193
+ connections:
194
+ users-db: my-app-mongodb
195
+ ```
196
+
197
+ When remapped, the module's connection definition is skipped. References via `_module.connectionId: users-db` resolve to `my-app-mongodb` instead of `team-users/users-db`.
198
+
199
+ ## Multi-Instance Support
200
+
201
+ Use the same module multiple times with different entry IDs:
202
+
203
+ ```yaml
204
+ modules:
205
+ - id: team-users
206
+ source: "github:lowdefy/user-admin@v1.0.0"
207
+ vars:
208
+ collection: team_users
209
+
210
+ - id: client-users
211
+ source: "github:lowdefy/user-admin@v1.0.0"
212
+ vars:
213
+ collection: client_users
214
+ ```
215
+
216
+ Each entry has its own namespace — pages, connections, and API endpoints do not collide.
217
+
218
+ ## Module Sources
219
+
220
+ **GitHub:** `github:owner/repo@ref` or `github:owner/repo/path@ref`
221
+
222
+ The `ref` can be a tag, branch, or commit SHA. For monorepos, the path after `owner/repo` specifies the subdirectory containing `module.lowdefy.yaml`.
223
+
224
+ ```yaml
225
+ # Single-module repo
226
+ source: "github:lowdefy/notifications@v1.0.0"
227
+
228
+ # Monorepo — module in subdirectory
229
+ source: "github:my-org/modules/user-admin@v1.0.0"
230
+ ```
231
+
232
+ **Local:** `file:./relative/path`
233
+
234
+ Local paths resolve relative to the project root. Useful for development and testing.
235
+
236
+ ```yaml
237
+ source: "file:../my-module"
238
+ ```
239
+
240
+ For private GitHub repositories, set the `GITHUB_TOKEN` environment variable. The CLI also checks `gh` CLI credentials and git credential helpers.
241
+
242
+ ## Plugin Dependency Validation
243
+
244
+ Modules declare required plugins with semver version constraints. The build validates that:
245
+ 1. Every declared plugin exists in the app's `plugins` array.
246
+ 2. The app's installed plugin version satisfies the module's declared semver range.
247
+
248
+ If validation fails, the build error includes remediation instructions.
249
+
250
+ ## Secret Allowlist
251
+
252
+ Modules declare which secrets they access. Undeclared `_secret` references cause build errors.
253
+
254
+ When a connection is remapped, the module's secret references for that connection are skipped — the app connection handles its own secrets. See [Secrets](/secrets) for more on secret management.
255
+
256
+ ## Cross-Module Dependencies
257
+
258
+ Modules can reference each other — embed components, link to pages, call APIs, and use connections from other modules. Dependencies use injection: the module declares what it needs, you wire it to a concrete entry.
259
+
260
+ ### Auto-Wiring
261
+
262
+ If a module declares a dependency and a module entry with the same `id` exists, the build wires them automatically. No configuration needed:
263
+
264
+ ```yaml
265
+ modules:
266
+ - id: contacts
267
+ source: "github:my-org/crm/contacts@v1"
268
+ # Declares dependency "companies" — auto-wires to entry below
269
+ - id: companies
270
+ source: "github:my-org/crm/companies@v1"
271
+ # Declares dependency "contacts" — auto-wires to entry above
272
+ ```
273
+
274
+ ### Explicit Wiring
275
+
276
+ When entry IDs don't match the dependency names, provide explicit `dependencies`:
277
+
278
+ ```yaml
279
+ modules:
280
+ - id: app-layout
281
+ source: "github:my-org/crm/layout-sidebar@v2"
282
+
283
+ - id: contacts
284
+ source: "github:my-org/crm/contacts@v1"
285
+ dependencies:
286
+ layout: app-layout # Module declares "layout", entry is "app-layout"
287
+ ```
288
+
289
+ `dependencies` keys are the abstract names the module declares. Values are the entry IDs from your `modules` list. Explicit `dependencies` override auto-wiring.
290
+
291
+ ### Multi-Instance with Dependencies
292
+
293
+ When the same module source has multiple entries, auto-wiring is ambiguous. Use explicit `dependencies` to wire each instance:
294
+
295
+ ```yaml
296
+ modules:
297
+ - id: internal-contacts
298
+ source: "github:my-org/crm/contacts@v1"
299
+ dependencies:
300
+ companies: internal-companies
301
+ vars:
302
+ collection: internal_contacts
303
+
304
+ - id: external-contacts
305
+ source: "github:my-org/crm/contacts@v1"
306
+ dependencies:
307
+ companies: external-companies
308
+ vars:
309
+ collection: external_contacts
310
+
311
+ - id: internal-companies
312
+ source: "github:my-org/crm/companies@v1"
313
+ dependencies:
314
+ contacts: internal-contacts
315
+
316
+ - id: external-companies
317
+ source: "github:my-org/crm/companies@v1"
318
+ dependencies:
319
+ contacts: external-contacts
320
+ ```
321
+
322
+ Each instance links to its own partner. The module code is identical — only the wiring differs.
323
+
324
+ ## Troubleshooting
325
+
326
+ **"Module 'X' requires plugin 'Y' version 'Z'"** — Add the required plugin to your app's `plugins` array in `lowdefy.yaml`, or update the version if already installed.
327
+
328
+ **"Module 'X' references undeclared secret 'Y'"** — The module author needs to declare this secret in `module.lowdefy.yaml`. If you're the module author, add it to the `secrets` array.
329
+
330
+ **"Duplicate page ID 'X'"** — Two module entries produce the same scoped page ID. Use different entry IDs for each module instance.
331
+
332
+ **Page not found at expected URL** — Module pages are served at `/{entryId}/{pageId}`, not `/{pageId}`. Check the entry ID in your `modules` config.
333
+
334
+ **"Module 'X' declares dependency 'Y' but no mapping provided and no module entry 'Y' exists"** — The module needs another module that isn't in your app. Either add a module entry with `id: Y`, or add `dependencies: { Y: your-entry-id }` to the module entry.
335
+
336
+ **"Module 'X' does not declare dependency 'Y'"** — You provided a `dependencies` key that the module doesn't expect. Check the module's `module.lowdefy.yaml` for declared dependencies.
337
+
338
+ **"dependencies.contacts references 'my-contacts' but no module entry 'my-contacts' exists"** — The entry ID in your `dependencies` mapping doesn't match any `id` in the `modules` array. Check the entry ID spelling.
@@ -0,0 +1,45 @@
1
+ # Operators
2
+
3
+ Operators are functions, that can be used to express logic. They are the reason why Lowdefy apps are not completely static, but can react to data and inputs. Operators can be used in `blocks`, `actions`, `requests`, and `connections`. See the specific documentation for more details.
4
+
5
+ Each operators expects arguments with a specific structure. They can be the result of other operators, since operators are evaluated beginning with the most nested operators.
6
+
7
+ If an operator errors while evaluating, it returns a `null` value, and logs the error to the console.
8
+
9
+ ## Client or server operators
10
+
11
+ Some operators are only available on either the client or the server. For example, the [`_menu`](/_menu) operator is only useful on the client and is thus not included in server requests. Likewise, the [`_secret`](/_secret) operator is only available on the server for security reasons.
12
+
13
+ If a operator has special environment considerations, it is indicated on the individual operator documentation page. If no indication is made, the operator can be used under both environments.
14
+
15
+ ##### Client only operators:
16
+ - [_actions](/_actions)
17
+ - [_api](/_api)
18
+ - [_event](/_event)
19
+ - [_global](/_global)
20
+ - [_index](/_index)
21
+ - [_input](/_input)
22
+ - [_location](/_location)
23
+ - [_media](/_media)
24
+ - [_menu](/_menu)
25
+ - [_request](/_request)
26
+ - [_url_query](/_url_query)
27
+
28
+ ##### Server only operators:
29
+ - [_hash](/_hash)
30
+ - [_item](/_item)
31
+ - [_payload](/_payload)
32
+ - [_secret](/_secret)
33
+ - [_step](/_step)
34
+
35
+ Operators that are client side only cannot be used in `Requests` and `Connections`, and operators which are server side only cannot be used in `Blocks` and `Actions`.
36
+
37
+ ## Build time operators
38
+
39
+ Besides the client and server environment, app build time is considered a third environment where special operator logic applies.
40
+
41
+ The `_ref` and `_var` operators do not work like other operators. They are evaluated while an app is being built, and can thus be used anywhere in the app configuration. They are used to split an app into multiple files, and to reuse configuration. See [`_ref`](/_ref) for more details.
42
+
43
+ Some operators can be evaluated at build time by using the [`_build`](/_build) operator. This is useful for once-off calculations when an app is built, for example looping over a list in a reference JSON file to calculate a value at build time instead of using normal operators which re-evaluate whenever the app state changes. It can also be used to read an environment variable.
44
+
45
+ The [`_module`](/_module) operators provide access to module-scoped values during the build. See [Writing Modules](/module-authoring) for details.
@@ -0,0 +1,19 @@
1
+ # Overview
2
+
3
+ A Lowdefy app is a [Hono](https://hono.dev) server with a [Vite](https://vite.dev)-built React client, that interprets / evaluates Lowdefy config. Lowdefy apps are written as YAML configuration files, which are easy to read, write and understand - and can be managed in source control. This makes Lowdefy quick to learn, maintain and pick up where others left off.
4
+
5
+ Lowdefy can be considered as another level of abstraction on top of the web stack. The Lowdefy schema is designed to be a standardized, declarative and flexible expression of application parameters and logic. This allows developers to focus on translating the business problem into configuration.
6
+
7
+ The Lowdefy schema abstracts app definitions into 5 categories:
8
+ - [**Blocks**](/blocks): The building blocks of the UI, the client-side React component to render. Blocks are usually stateless since all app state is managed by the Lowdefy engine.
9
+ - [**Operators**](/operators): The application logic is defined using operator functions, which can be used both server-side and client-side. These are synchronous methods, which are continuously evaluated every time the app state changes.
10
+ - [**Actions**](/events-and-actions): Asynchronous client-side methods triggered by events, such as clicking a button or initializing the page state. These methods usually apply an action like setting state, using the [SetState](/SetState) action, or calling a request, using the [Request](/Request) action.
11
+ - [**Connections and Requests**](/connections-and-requests): Server-side methods, which allow a Lowdefy app to make server requests to other services like APIs or databases. Requests are evoked by the [Request](/Request) action, and are only called after all user authentication and authorization checks have passed. Requests consume a payload from the client, and have access to server-side secrets like passwords and API keys.
12
+ - [**Auth Providers and Adapters**](/users-introduction): Lowdefy implements [Auth.js](https://authjs.dev) for authentication. Auth.js allows for the configuration of a wide range of authentication providers and adapters, which can be configured in Lowdefy apps.
13
+
14
+ The diagram below provides an overview of the Lowdefy app schematic:
15
+ ![Lowdefy App Diagram](/images/lowdefy_app_schema.png)
16
+
17
+ Lowdefy offers a large number of default actions, blocks, operators, connections, and auth integrations - but also provides a [plugin interface](/plugins) for the extension of new types. All plugins are installed as [npm](https://www.npmjs.com/) modules, which means you can extend your Lowdefy application by any existing npm module - enabling developers to make use of anything that is available in the Javascript ecosystem.
18
+
19
+ Since Lowdefy apps are self-hosted Node.js applications, they do not ship with a built in data store and typically connect to one or more APIs or databases. Server instances are also stateless, which simplifies deployment. You can deploy your app using Docker or any hosting provider that runs Node.js servers.
@@ -0,0 +1,207 @@
1
+ # References and Templates
2
+
3
+ References and templates have the following use cases:
4
+ - Splitting out the config for readability and code navigation.
5
+ - Splitting out a piece of config in order to use the exact same config in multiple places.
6
+ - Using a reference with variables to make use of a shared piece of config with dynamic variables.
7
+ - Using a `.njk` file to create config files using the Nunjucks templating language.
8
+ - Using resolver and transformer functions to create Lowdefy config using Javascript functions.
9
+
10
+ ## Using References to Improve Readability
11
+
12
+ References are made using the [`_ref`](/_ref) operator. If the referenced file has a `.yaml` or `.json` extension, the contents of the file will be parsed, else the file content is included as a string (this is useful for `.md` or `.html` files). As an example of splitting an app into logically distinct files, references can be used to write each page as a separate file:
13
+
14
+ ###### lowdefy.yaml
15
+ ```yaml
16
+ lowdefy: LOWDEFY_VERSION
17
+
18
+ pages:
19
+ _ref: pages/page1.yaml # Path to the referenced file. Always from the root of the project.
20
+ _ref: pages/page1.yaml
21
+ ```
22
+
23
+ ## Using References as Templates for Improved Reusability
24
+
25
+ The `_ref` operator can take an argument called `vars`. This can be any data, and is passed down to later be accessed with the [`_var`](/_var) operator. By using vars, the referenced file can become a template, using the given variables. For example, a standard page template might be used for multiple pages in an app:
26
+
27
+ ###### pages/page1.yaml
28
+ ```yaml
29
+ _ref:
30
+ path: templates/text_page.yaml
31
+ vars:
32
+ id: page1
33
+ title: Page 1
34
+ content:
35
+ _ref: markdowns/content.md
36
+ ```
37
+
38
+ ###### markdowns/content.md
39
+ ```yaml
40
+ Page content text.
41
+ ```
42
+
43
+ ###### templates/text_page.yaml
44
+ ```yaml
45
+ id:
46
+ _var: id
47
+ type: PageHeaderMenu
48
+ properties:
49
+ title:
50
+ _var: title
51
+ blocks:
52
+ - id: content_card
53
+ type: Card
54
+ blocks:
55
+ - id: title
56
+ type: Title
57
+ properties:
58
+ content:
59
+ _var: title
60
+ - id: content
61
+ type: Markdown
62
+ properties:
63
+ content:
64
+ _var: content
65
+ ```
66
+
67
+ ## Nunjucks Templating
68
+
69
+ Templating can be taken further by referencing [Nunjucks](https://mozilla.github.io/nunjucks/) template files. If a file ends with the `.njk` file extension, the file will first be hydrated as a Nunjucks template, using the `vars` as template variables. If the file ends with `.yaml.njk` or `.json.njk`, the output of the template will then be parsed. Nunjucks templates are useful since the template file does not need to be valid yaml before it is hydrated, and features like for-loops and if-statements can be used.
70
+
71
+ Templating is used extensively to create the Lowdefy docs (these docs are a Lowdefy app). You can look at how they are used [here](https://github.com/lowdefy/lowdefy/tree/main/packages/docs).
72
+
73
+ We can modify the example above to make use of nunjucks templating to allow us to add subsections to our page. This can be done as follows:
74
+
75
+ ###### pages/page1.yaml
76
+ ```yaml
77
+ _ref:
78
+ path: templates/text_page.yaml.njk
79
+ vars:
80
+ id: page1
81
+ title: Page 1
82
+ content:
83
+ _ref: markdowns/content.md
84
+ subsections:
85
+ - id: subsection1
86
+ title: Subsection 1
87
+ content: |
88
+ Subsection 1 content text.
89
+ - id: subsection2
90
+ title: Subsection 2
91
+ content: |
92
+ Subsection 2 content text.
93
+ ```
94
+
95
+ ###### markdowns/content.md
96
+ ```yaml
97
+ Page content text.
98
+ ```
99
+
100
+ ###### templates/text_page.yaml.njk
101
+ ```yaml
102
+ id:
103
+ _var: id
104
+ type: PageHeaderMenu
105
+ properties:
106
+ title:
107
+ _var: title
108
+ blocks:
109
+ - id: content_card
110
+ type: Card
111
+ blocks:
112
+ - id: title
113
+ type: Title
114
+ properties:
115
+ content:
116
+ _var: title
117
+ - id: content
118
+ type: Markdown
119
+ properties:
120
+ content:
121
+ _var: content
122
+ {% if subsections %}
123
+ {% for subsection in subsections %}
124
+ - id: {{ subsection.id }}_title
125
+ type: Title
126
+ properties:
127
+ content: {{ subsection.title }}
128
+ - id: {{ subsection.id }}_content
129
+ type: Markdown
130
+ properties:
131
+ content: {{ subsection.content }}
132
+ {% endfor %}
133
+ {% endif %}
134
+ ```
135
+
136
+ ## Custom JavaScript Functions
137
+
138
+ The `_ref` operator can also be extended with custom JavaScript functions. A `resolver` function can be specified, which can overwrite the default way configuration files are read from the filesystem. A `transformer` function can be used to transform the value returned by the `_ref` operator.
139
+
140
+ ### Resolver
141
+
142
+ This resolver function will first look for the configuration file in the current working directory, but if the file is not found it will be read from an adjacent "shared" directory. This pattern can be used to build apps that mostly use a shared configuration, with a few components that are customised per app.
143
+
144
+ ###### resolvers/useLocalOrSharedConfig.js
145
+ ```js
146
+ const fs = require('fs');
147
+ const path = require('path');
148
+ const { promisify } = require('util');
149
+
150
+ const readFilePromise = promisify(fs.readFile);
151
+
152
+ async function useLocalOrSharedConfig(refPath, vars, context) {
153
+ let fileContent
154
+ try {
155
+ fileContent = await readFilePromise(path.resolve(refPath), 'utf8');
156
+ return fileContent;
157
+ } catch (error) {
158
+ if (error.code === 'ENOENT') {
159
+ fileContent = readFilePromise(path.resolve('../shared', refPath), 'utf8');
160
+ return fileContent;
161
+ }
162
+ throw error;
163
+ }
164
+
165
+
166
+ }
167
+
168
+ module.exports = useLocalOrSharedConfig;
169
+ ```
170
+
171
+ ###### lowdefy.yaml
172
+ ```yaml
173
+ lowdefy: LOWDEFY_VERSION
174
+
175
+ cli:
176
+ refResolver: resolvers/useLocalOrSharedConfig.js
177
+
178
+ pages:
179
+ - _ref: pages/local-page.yaml
180
+ - _ref: pages/shared-page.yaml
181
+ ```
182
+
183
+ ### Transformer
184
+
185
+ This transformer adds a standard footer to each page:
186
+
187
+ ###### transformers/addFooter.js
188
+ ```js
189
+ function addFooter(page, vars) {
190
+ const footer = {
191
+ // ...
192
+ };
193
+ page.areas.footer = footer;
194
+ return page;
195
+ }
196
+ module.exports = addFooter;
197
+ ```
198
+
199
+ ###### lowdefy.yaml
200
+ ```yaml
201
+ lowdefy: LOWDEFY_VERSION
202
+
203
+ pages:
204
+ - _ref:
205
+ path: pages/page1.yaml
206
+ transformer: transformers/addFooter.js
207
+ ```
@@ -0,0 +1,24 @@
1
+ # Secrets
2
+
3
+ The `secrets` object is an object that can be used to securely store sensitive information such as passwords and API keys. Secrets can be accessed using the [`_secret`](/_secret) operator.
4
+
5
+ The secrets object only exists on the backend server, and therefore the `_secret` operator can only be used in `connections` and `requests`.
6
+
7
+ Secrets can be set by creating an environment variable prefixed with `LOWDEFY_SECRET_`. The secret will then be available in the secrets object with the remaining part of the name as key.
8
+
9
+ For example, if the environment variable `LOWDEFY_SECRET_MY_SECRET` is set to `supersecret`, then `_secret: MY_SECRET` will return `supersecret`.
10
+
11
+ To use secrets in the local development environment, environment variables can be set using a `.env` file. Create a file called `.env` at the root of the project directory, then set environment variables as follows:
12
+
13
+ ```
14
+ # .env
15
+ LOWDEFY_SECRET_MY_SECRET=supersecret
16
+ ```
17
+
18
+ ## Module Secret Allowlist
19
+
20
+ Modules declare the secrets they require in their `module.lowdefy.yaml` manifest. Undeclared `_secret` references cause build errors.
21
+
22
+ When a module connection is remapped to an app connection, the module's secret references for that connection are skipped — the app connection handles its own secrets.
23
+
24
+ See [Modules](/modules) for full details.