@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.
- package/LICENSE +201 -0
- package/README.md +20 -0
- package/content/actions/callapi.md +66 -0
- package/content/actions/callmethod.md +41 -0
- package/content/actions/copytoclipboard.md +32 -0
- package/content/actions/displaymessage.md +53 -0
- package/content/actions/downloadcsv.md +89 -0
- package/content/actions/fetch.md +50 -0
- package/content/actions/geolocationcurrentposition.md +56 -0
- package/content/actions/link.md +104 -0
- package/content/actions/login.md +85 -0
- package/content/actions/logout.md +56 -0
- package/content/actions/pdfmake.md +304 -0
- package/content/actions/request.md +67 -0
- package/content/actions/reset.md +27 -0
- package/content/actions/resetvalidation.md +85 -0
- package/content/actions/scrollto.md +85 -0
- package/content/actions/setdarkmode.md +62 -0
- package/content/actions/setfocus.md +33 -0
- package/content/actions/setglobal.md +63 -0
- package/content/actions/setlocale.md +69 -0
- package/content/actions/setstate.md +70 -0
- package/content/actions/throw.md +72 -0
- package/content/actions/validate.md +87 -0
- package/content/actions/wait.md +24 -0
- package/content/agents/agent-endpoint-tools.md +190 -0
- package/content/agents/agent-mcp-tools.md +124 -0
- package/content/agents/agent-multi-agent.md +136 -0
- package/content/agents/agent-properties.md +174 -0
- package/content/agents/agent-server-hooks.md +336 -0
- package/content/agents/agentchat.md +515 -0
- package/content/agents/agentconversations.md +148 -0
- package/content/concepts/ai-agent-docs.md +190 -0
- package/content/concepts/cli.md +213 -0
- package/content/concepts/connections-and-requests.md +7 -0
- package/content/concepts/custom-html.md +3 -0
- package/content/concepts/custom-styling.md +161 -0
- package/content/concepts/events-and-actions.md +271 -0
- package/content/concepts/hosting-files.md +18 -0
- package/content/concepts/i18n.md +320 -0
- package/content/concepts/keyboard-shortcuts.md +218 -0
- package/content/concepts/layout-overview.md +478 -0
- package/content/concepts/lists.md +144 -0
- package/content/concepts/logger.md +43 -0
- package/content/concepts/lowdefy-schema.md +365 -0
- package/content/concepts/menus.md +144 -0
- package/content/concepts/module-authoring.md +564 -0
- package/content/concepts/modules.md +338 -0
- package/content/concepts/operators.md +45 -0
- package/content/concepts/overview.md +19 -0
- package/content/concepts/references-and-templates.md +207 -0
- package/content/concepts/secrets.md +24 -0
- package/content/concepts/selectors.md +143 -0
- package/content/connections/amazonredshift.md +176 -0
- package/content/connections/anthropic.md +232 -0
- package/content/connections/awss3.md +313 -0
- package/content/connections/azureblobstorage.md +133 -0
- package/content/connections/elasticsearch.md +371 -0
- package/content/connections/google.md +228 -0
- package/content/connections/googlecloudstorage.md +139 -0
- package/content/connections/googlesheet.md +313 -0
- package/content/connections/knex.md +206 -0
- package/content/connections/mariadb.md +177 -0
- package/content/connections/mcp.md +134 -0
- package/content/connections/mongodb.md +739 -0
- package/content/connections/mssql.md +191 -0
- package/content/connections/mysql.md +192 -0
- package/content/connections/openai-connection.md +228 -0
- package/content/connections/postgresql.md +200 -0
- package/content/connections/redis.md +116 -0
- package/content/connections/sendgridmail.md +94 -0
- package/content/connections/smtp.md +149 -0
- package/content/connections/sqlite.md +187 -0
- package/content/connections/stripe.md +115 -0
- package/content/container-blocks/affix.md +413 -0
- package/content/container-blocks/alert.md +937 -0
- package/content/container-blocks/badge.md +1222 -0
- package/content/container-blocks/box.md +1453 -0
- package/content/container-blocks/card.md +1200 -0
- package/content/container-blocks/carousel.md +2247 -0
- package/content/container-blocks/collapse.md +1335 -0
- package/content/container-blocks/configprovider.md +1070 -0
- package/content/container-blocks/confirmmodal.md +1159 -0
- package/content/container-blocks/content.md +597 -0
- package/content/container-blocks/descriptions.md +870 -0
- package/content/container-blocks/drawer.md +1379 -0
- package/content/container-blocks/dropdownmenu.md +643 -0
- package/content/container-blocks/flex.md +1510 -0
- package/content/container-blocks/footer.md +380 -0
- package/content/container-blocks/googlemaps.md +546 -0
- package/content/container-blocks/googlemapsheatmap.md +607 -0
- package/content/container-blocks/googlemapsscript.md +61 -0
- package/content/container-blocks/header.md +302 -0
- package/content/container-blocks/label.md +739 -0
- package/content/container-blocks/layout.md +604 -0
- package/content/container-blocks/masonry.md +1090 -0
- package/content/container-blocks/mobilemenu.md +1244 -0
- package/content/container-blocks/modal.md +1180 -0
- package/content/container-blocks/pageheadermenu.md +614 -0
- package/content/container-blocks/pagesidebarlayout.md +438 -0
- package/content/container-blocks/pagesidermenu.md +651 -0
- package/content/container-blocks/popover.md +1421 -0
- package/content/container-blocks/result.md +972 -0
- package/content/container-blocks/sider.md +1064 -0
- package/content/container-blocks/span.md +747 -0
- package/content/container-blocks/spinner.md +267 -0
- package/content/container-blocks/splitter.md +1735 -0
- package/content/container-blocks/tabs.md +1718 -0
- package/content/container-blocks/tooltip.md +1274 -0
- package/content/container-blocks/watermark.md +515 -0
- package/content/controls/for.md +103 -0
- package/content/controls/if.md +107 -0
- package/content/controls/log.md +50 -0
- package/content/controls/parallel.md +71 -0
- package/content/controls/parallel_for.md +36 -0
- package/content/controls/reject.md +56 -0
- package/content/controls/return.md +66 -0
- package/content/controls/set_state.md +98 -0
- package/content/controls/switch.md +90 -0
- package/content/controls/throw.md +79 -0
- package/content/controls/try.md +88 -0
- package/content/deployment/docker.md +149 -0
- package/content/deployment/node-server.md +27 -0
- package/content/deployment/vercel.md +101 -0
- package/content/display-blocks/aggrid.md +1459 -0
- package/content/display-blocks/anchor.md +336 -0
- package/content/display-blocks/avatar.md +1154 -0
- package/content/display-blocks/breadcrumb.md +517 -0
- package/content/display-blocks/button.md +758 -0
- package/content/display-blocks/calendar.md +156 -0
- package/content/display-blocks/dangeroushtml.md +314 -0
- package/content/display-blocks/dangerousmarkdown.md +423 -0
- package/content/display-blocks/diffgit.md +44 -0
- package/content/display-blocks/difflist.md +225 -0
- package/content/display-blocks/diffsidebyside.md +56 -0
- package/content/display-blocks/difftimeline.md +94 -0
- package/content/display-blocks/divider.md +406 -0
- package/content/display-blocks/download.md +60 -0
- package/content/display-blocks/dropdownbutton.md +661 -0
- package/content/display-blocks/echart.md +418 -0
- package/content/display-blocks/floatbutton.md +545 -0
- package/content/display-blocks/html.md +311 -0
- package/content/display-blocks/icon.md +717 -0
- package/content/display-blocks/img.md +479 -0
- package/content/display-blocks/markdown.md +520 -0
- package/content/display-blocks/markdownwithcode.md +730 -0
- package/content/display-blocks/menu.md +1123 -0
- package/content/display-blocks/message.md +941 -0
- package/content/display-blocks/notification.md +1410 -0
- package/content/display-blocks/paragraph.md +643 -0
- package/content/display-blocks/progress.md +818 -0
- package/content/display-blocks/qrcode.md +519 -0
- package/content/display-blocks/s3download.md +240 -0
- package/content/display-blocks/search.md +360 -0
- package/content/display-blocks/skeleton.md +272 -0
- package/content/display-blocks/skeletonavatar.md +222 -0
- package/content/display-blocks/skeletonbutton.md +245 -0
- package/content/display-blocks/skeletoninput.md +223 -0
- package/content/display-blocks/skeletonparagraph.md +201 -0
- package/content/display-blocks/statistic.md +485 -0
- package/content/display-blocks/steps.md +585 -0
- package/content/display-blocks/tag.md +620 -0
- package/content/display-blocks/title.md +654 -0
- package/content/display-blocks/tour.md +2359 -0
- package/content/input-blocks/autocomplete.md +786 -0
- package/content/input-blocks/buttonselector.md +964 -0
- package/content/input-blocks/checkboxselector.md +765 -0
- package/content/input-blocks/checkboxswitch.md +497 -0
- package/content/input-blocks/colorselector.md +884 -0
- package/content/input-blocks/daterangeselector.md +777 -0
- package/content/input-blocks/dateselector.md +693 -0
- package/content/input-blocks/datetimeselector.md +791 -0
- package/content/input-blocks/inputgallery.md +528 -0
- package/content/input-blocks/monthselector.md +717 -0
- package/content/input-blocks/multipleselector.md +1337 -0
- package/content/input-blocks/numberinput.md +855 -0
- package/content/input-blocks/pagination.md +679 -0
- package/content/input-blocks/paragraphinput.md +1664 -0
- package/content/input-blocks/passwordinput.md +480 -0
- package/content/input-blocks/phonenumberinput.md +688 -0
- package/content/input-blocks/radioselector.md +820 -0
- package/content/input-blocks/ratingslider.md +684 -0
- package/content/input-blocks/s3uploadbutton.md +384 -0
- package/content/input-blocks/s3uploaddragger.md +305 -0
- package/content/input-blocks/s3uploadphoto.md +288 -0
- package/content/input-blocks/segmentedselector.md +782 -0
- package/content/input-blocks/selector.md +1162 -0
- package/content/input-blocks/switch.md +552 -0
- package/content/input-blocks/textarea.md +714 -0
- package/content/input-blocks/textinput.md +639 -0
- package/content/input-blocks/tiptapinput.md +226 -0
- package/content/input-blocks/tiptapmentioninput.md +471 -0
- package/content/input-blocks/titleinput.md +1094 -0
- package/content/input-blocks/treeinput.md +144 -0
- package/content/input-blocks/treemultipleselector.md +162 -0
- package/content/input-blocks/treeselector.md +185 -0
- package/content/input-blocks/upload.md +149 -0
- package/content/input-blocks/uploaddragger.md +85 -0
- package/content/input-blocks/uploadphoto.md +84 -0
- package/content/input-blocks/weekselector.md +630 -0
- package/content/list-blocks/controlledlist.md +498 -0
- package/content/list-blocks/list.md +529 -0
- package/content/list-blocks/listselector.md +301 -0
- package/content/list-blocks/masonrylist.md +230 -0
- package/content/migration/upgrade-guide.md +106 -0
- package/content/migration/v4-to-v5.md +589 -0
- package/content/migration/v5-to-v6.md +36 -0
- package/content/operators/_actions.md +58 -0
- package/content/operators/_and.md +76 -0
- package/content/operators/_api.md +254 -0
- package/content/operators/_app.md +114 -0
- package/content/operators/_args.md +65 -0
- package/content/operators/_array.md +331 -0
- package/content/operators/_base64.md +49 -0
- package/content/operators/_boolean.md +33 -0
- package/content/operators/_build.md +166 -0
- package/content/operators/_change_case.md +357 -0
- package/content/operators/_date.md +415 -0
- package/content/operators/_dayjs.md +128 -0
- package/content/operators/_diff.md +61 -0
- package/content/operators/_divide.md +32 -0
- package/content/operators/_eq.md +52 -0
- package/content/operators/_event.md +86 -0
- package/content/operators/_function.md +52 -0
- package/content/operators/_get.md +92 -0
- package/content/operators/_global.md +86 -0
- package/content/operators/_gt.md +50 -0
- package/content/operators/_gte.md +50 -0
- package/content/operators/_hash.md +112 -0
- package/content/operators/_if.md +30 -0
- package/content/operators/_if_none.md +47 -0
- package/content/operators/_index.md +48 -0
- package/content/operators/_input.md +86 -0
- package/content/operators/_intl.md +135 -0
- package/content/operators/_item.md +166 -0
- package/content/operators/_js.md +113 -0
- package/content/operators/_json.md +120 -0
- package/content/operators/_jsonata.md +152 -0
- package/content/operators/_locale.md +65 -0
- package/content/operators/_location.md +40 -0
- package/content/operators/_log.md +22 -0
- package/content/operators/_lt.md +50 -0
- package/content/operators/_lte.md +50 -0
- package/content/operators/_math.md +407 -0
- package/content/operators/_media.md +83 -0
- package/content/operators/_menu.md +62 -0
- package/content/operators/_module.md +340 -0
- package/content/operators/_mql.md +95 -0
- package/content/operators/_ne.md +62 -0
- package/content/operators/_not.md +33 -0
- package/content/operators/_number.md +159 -0
- package/content/operators/_nunjucks.md +117 -0
- package/content/operators/_object.md +253 -0
- package/content/operators/_operator.md +33 -0
- package/content/operators/_or.md +67 -0
- package/content/operators/_product.md +45 -0
- package/content/operators/_random.md +90 -0
- package/content/operators/_ref.md +80 -0
- package/content/operators/_regex.md +69 -0
- package/content/operators/_request.md +35 -0
- package/content/operators/_request_details.md +29 -0
- package/content/operators/_secret.md +56 -0
- package/content/operators/_state.md +134 -0
- package/content/operators/_step.md +98 -0
- package/content/operators/_string.md +327 -0
- package/content/operators/_subtract.md +24 -0
- package/content/operators/_sum.md +45 -0
- package/content/operators/_switch.md +37 -0
- package/content/operators/_t.md +96 -0
- package/content/operators/_theme.md +65 -0
- package/content/operators/_type.md +78 -0
- package/content/operators/_uri.md +49 -0
- package/content/operators/_url_query.md +92 -0
- package/content/operators/_user.md +154 -0
- package/content/operators/_uuid.md +118 -0
- package/content/operators/_var.md +88 -0
- package/content/operators/_yaml.md +96 -0
- package/content/other/introduction.md +39 -0
- package/content/other/next-auth-providers.md +3 -0
- package/content/other/updatesession.md +26 -0
- package/content/plugins/plugins-actions.md +80 -0
- package/content/plugins/plugins-connections.md +98 -0
- package/content/plugins/plugins-dev.md +138 -0
- package/content/plugins/plugins-introduction.md +29 -0
- package/content/plugins/plugins-operators.md +71 -0
- package/content/testing/e2e-auth.md +108 -0
- package/content/testing/e2e-configuration.md +107 -0
- package/content/testing/e2e-getting-started.md +96 -0
- package/content/testing/e2e-introduction.md +53 -0
- package/content/testing/e2e-mocking.md +155 -0
- package/content/testing/e2e-writing-tests.md +214 -0
- package/content/tutorial/tutorial-actions-operators.md +222 -0
- package/content/tutorial/tutorial-add-blocks.md +86 -0
- package/content/tutorial/tutorial-create-page.md +57 -0
- package/content/tutorial/tutorial-display-data-page.md +181 -0
- package/content/tutorial/tutorial-next-steps.md +53 -0
- package/content/tutorial/tutorial-requests-sql.md +22 -0
- package/content/tutorial/tutorial-start.md +71 -0
- package/content/user-authentication/auth-providers.md +15 -0
- package/content/user-authentication/login-and-logout.md +122 -0
- package/content/user-authentication/users-introduction.md +31 -0
- package/index.json +2281 -0
- package/package.json +34 -0
- 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
|
+

|
|
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.
|