@lowdefy/docs-content 0.0.0-experimental-20260909201552 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. package/README.md +0 -1
  2. package/content/actions/login.md +5 -23
  3. package/content/actions/logout.md +5 -5
  4. package/content/agents/agentchat.md +1 -13
  5. package/content/concepts/ai-agent-docs.md +4 -90
  6. package/content/concepts/custom-styling.md +5 -50
  7. package/content/concepts/events-and-actions.md +2 -64
  8. package/content/concepts/i18n.md +1 -1
  9. package/content/connections/mongodb.md +3 -109
  10. package/content/container-blocks/modal.md +1 -1
  11. package/content/container-blocks/pagesidebarlayout.md +0 -1
  12. package/content/controls/reject.md +1 -3
  13. package/content/controls/throw.md +0 -1
  14. package/content/controls/try.md +2 -3
  15. package/content/display-blocks/difflist.md +1 -1
  16. package/content/display-blocks/difftimeline.md +1 -1
  17. package/content/display-blocks/s3download.md +1 -1
  18. package/content/display-blocks/search.md +0 -1
  19. package/content/input-blocks/checkboxselector.md +4 -80
  20. package/content/input-blocks/radioselector.md +3 -65
  21. package/content/input-blocks/s3uploadbutton.md +1 -1
  22. package/content/input-blocks/s3uploaddragger.md +1 -1
  23. package/content/input-blocks/s3uploadphoto.md +1 -1
  24. package/content/input-blocks/tiptapmentioninput.md +1 -1
  25. package/content/list-blocks/masonrylist.md +1 -1
  26. package/content/operators/_type.md +3 -14
  27. package/content/operators/_user.md +3 -3
  28. package/content/user-authentication/login-and-logout.md +8 -158
  29. package/content/user-authentication/users-introduction.md +0 -8
  30. package/index.json +1 -99
  31. package/package.json +1 -3
  32. package/content/actions/emailotpsend.md +0 -58
  33. package/content/actions/emailotpverify.md +0 -77
  34. package/content/actions/magiclinkverify.md +0 -113
  35. package/content/controls/while.md +0 -46
  36. package/content/input-blocks/captcha.md +0 -40
  37. package/content/input-blocks/tagmultipleselector.md +0 -101
  38. package/content/input-blocks/tagselector.md +0 -101
  39. package/content/migration/auth-upgrade.md +0 -315
  40. package/content/other/mongodbadapter.md +0 -3
  41. package/content/user-authentication/auth-steps.md +0 -111
  42. package/content/user-authentication/mcp-oauth.md +0 -289
  43. package/content/user-authentication/organizations.md +0 -134
  44. package/content/user-authentication/two-factor.md +0 -225
  45. package/content/user-authentication/user-object.md +0 -58
  46. package/hazards.json +0 -44
@@ -1,6 +1,6 @@
1
1
  # Modal
2
2
 
3
- Modal dialog overlay for focused content. Add `shortcut: Escape` to the `onClose` event to run custom actions when Escape is pressed. Ant Design's Modal already closes on Escape by default — the shortcut triggers your custom actions in addition to the built-in close.
3
+ Modal dialog overlay for focused content. Add `shortcut: Escape` to the `onClose` event to run custom actions when Escape is pressed. Ant Design's Modal already closes on Escape by default — the shortcut triggers your custom actions in addition to the built-in close.
4
4
 
5
5
  This is a basic modal dialog with a title, content area, and default Ok/Cancel buttons.
6
6
 
@@ -411,7 +411,6 @@ Dashboard Overview
411
411
  | `/mobileMenu` | The PageSidebarLayout mobile menu. |
412
412
  | `/header` | The PageSidebarLayout header. |
413
413
  | `/headerActions` | The header actions container (notifications, profile, dark mode toggle). |
414
- | `/headerContent` | The PageSidebarLayout header content area (the header slot row). |
415
414
  | `/logo` | The PageSidebarLayout logo. |
416
415
  | `/notifications` | The notification bell button. |
417
416
  | `/notificationsBadge` | The notification badge wrapper. |
@@ -7,9 +7,7 @@
7
7
  The `:reject` control is used to return a user-friendly error to the client when validation fails or business rules are violated.
8
8
  Unlike [`:throw`](/:throw), which indicates a system error, `:reject` represents an expected failure condition that should be communicated to the user.
9
9
  The control immediately stops routine execution and returns with a `"reject"` status.
10
- Importantly, `:reject` does not trigger `:catch` blocks in [`:try`](/:try) statements: the reject flows past every enclosing `:try`, so a `:catch` in an outer `:try` never runs either, while `:finally` still runs.
11
- This makes `:reject` ideal for handling validation and business logic errors separately from system errors.
12
- Choose [`:throw`](/:throw) when a step failed and the routine may recover; choose `:reject` when the routine decided the request cannot be fulfilled.
10
+ Importantly, `:reject` does not trigger `:catch` blocks in [`:try`](/:try) statements, making it ideal for handling validation and business logic errors separately from system errors.
13
11
 
14
12
  #### Keys
15
13
 
@@ -8,7 +8,6 @@ The `:throw` control creates a system error that immediately stops routine execu
8
8
  Unlike [`:reject`](/:reject), which handles expected user errors, `:throw` is designed for unexpected system failures, programming errors, or critical issues that require attention.
9
9
  The key difference is that `:throw` can be caught and handled by [`:try`](/:try)/`:catch` blocks, while [`:reject`](/:reject) cannot.
10
10
  This makes `:throw` ideal for recoverable system errors where you might want to implement fallback logic.
11
- Choose `:throw` when a step failed and the routine may recover; choose [`:reject`](/:reject) when the routine decided the request cannot be fulfilled.
12
11
 
13
12
  #### Keys
14
13
 
@@ -7,13 +7,12 @@
7
7
  If one control in the routine chain defined in the `:try` key fails by throwing an error, the steps in the list following the failed control will not be executed.
8
8
  To handle any errors thrown by a routine element, a routine can be provided using `catch` key.
9
9
  The routine defined using the `:finally` key will be run regardless of whether or not the routine throws an error.
10
- A [`:reject`](/:reject) inside the `:try` routine is __not__ caught. `:reject` is the routine's own reply — it stops the routine, returns a `"reject"` status to the caller, and flows past every enclosing `:catch`. `:finally` still runs. Use [`:throw`](/:throw) for failures a `:catch` should handle.
11
10
 
12
11
  #### Keys
13
12
 
14
13
  - `:try: routine`: __Required__ - The routine to be run.
15
- - `:catch: routine`: The routine to execute if any step in the routine defined errors. Runs on a thrown error only — a `:reject` is not caught.
16
- - `:finally: routine`: The routine to be run regardless of the out come of the initial routine. Runs on success, error and reject.
14
+ - `:catch: routine`: The routine to execute if any step in the routine defined errors.
15
+ - `:finally: routine`: The routine to be run regardless of the out come of the initial routine.
17
16
 
18
17
  #### Examples
19
18
 
@@ -1,6 +1,6 @@
1
1
  # DiffList
2
2
 
3
- `DiffList` renders a polished, user-friendly diff between a `before` and an `after` object as a grouped table of changes. Built on `microdiff` for the diff engine and antd primitives for rendering, it groups changes by top-level key, tags each row as Added / Removed / Changed, and supports per-path value formatters (`date`, `datetime`, `boolean`, `currency`, `enum`, `json`, `code`), humanised `labels`, and `hide` / `show` glob filtering. All colours come from antd's semantic tokens so dark mode and `theme` overrides work automatically.
3
+ `DiffList` renders a polished, user-friendly diff between a `before` and an `after` object as a grouped table of changes. Built on `microdiff` for the diff engine and antd primitives for rendering, it groups changes by top-level key, tags each row as Added / Removed / Changed, and supports per-path value formatters (`date`, `datetime`, `boolean`, `currency`, `enum`, `json`, `code`), humanised `labels`, and `hide` / `show` glob filtering. All colours come from antd's semantic tokens so dark mode and `theme` overrides work automatically.
4
4
 
5
5
  ```yaml
6
6
  - id: diff_list_profile
@@ -1,6 +1,6 @@
1
1
  # DiffTimeline
2
2
 
3
- `DiffTimeline` renders a diff as a vertical audit trail using Ant Design's `Timeline` component. Each change becomes a timeline entry with a colour-coded dot (green for added, red for removed, blue for changed) and a breadcrumb-style label that shows the full path to the changed field. Uses the same filtering, labelling, and per-path value formatters as `DiffList`.
3
+ `DiffTimeline` renders a diff as a vertical audit trail using Ant Design's `Timeline` component. Each change becomes a timeline entry with a colour-coded dot (green for added, red for removed, blue for changed) and a breadcrumb-style label that shows the full path to the changed field. Uses the same filtering, labelling, and per-path value formatters as `DiffList`.
4
4
 
5
5
  ```yaml
6
6
  - id: diff_timeline_order
@@ -1,6 +1,6 @@
1
1
  # S3Download
2
2
 
3
- __Deprecated__ — use the provider-neutral <a href="/Download">Download</a> block with `downloadPolicyRequestId` instead. S3Download remains as an alias so existing apps keep working. Download files from AWS S3. Requires an AwsS3Bucket connection and an AwsS3PresignedGetObject request. The s3GetPolicyRequestId property must reference the request id. If files were uploaded with S3Upload, its fileList value can be mapped directly to this block.
3
+ __Deprecated__ — use the provider-neutral &lt;a href=&quot;/Download&quot;&gt;Download&lt;/a&gt; block with `downloadPolicyRequestId` instead. S3Download remains as an alias so existing apps keep working. Download files from AWS S3. Requires an AwsS3Bucket connection and an AwsS3PresignedGetObject request. The s3GetPolicyRequestId property must reference the request id. If files were uploaded with S3Upload, its fileList value can be mapped directly to this block.
4
4
 
5
5
  > The S3Download block requires an AwsS3Bucket connection and an AwsS3PresignedGetObject request. The examples below show configuration structure but will not download files without a configured connection.
6
6
 
@@ -356,6 +356,5 @@ See the [MiniSearch API docs](https://lucaong.github.io/minisearch/classes/MiniS
356
356
  | `/itemDescription` | The description/snippet in a result item. |
357
357
  | `/highlight` | Highlighted match text (<mark> elements). |
358
358
  | `/empty` | The empty state message. |
359
- | `/loading` | The loading spinner container. |
360
359
 
361
360
  No slots defined.
@@ -703,89 +703,13 @@ Checkbox group for selecting multiple options.
703
703
  valueKey: id
704
704
  ```
705
705
 
706
- ```yaml
707
- - id: columns_two
708
- type: CheckboxSelector
709
- properties:
710
- title: Two columns
711
- columns: 2
712
- options:
713
- - Weekday mornings
714
- - Weekday afternoons
715
- - Weekday evenings
716
- - Weekend mornings
717
- - Weekend afternoons
718
- - Weekend evenings
719
- - id: columns_four
720
- type: CheckboxSelector
721
- properties:
722
- title: Four columns
723
- columns: 4
724
- options:
725
- - January
726
- - February
727
- - March
728
- - April
729
- - May
730
- - June
731
- - July
732
- - August
733
- - id: columns_responsive
734
- type: CheckboxSelector
735
- properties:
736
- title: One column below md, three from md up
737
- columns:
738
- xs: 1
739
- md: 3
740
- options:
741
- - Email
742
- - SMS
743
- - Push notification
744
- - Webhook
745
- - In-app message
746
- - Weekly digest
747
- - id: columns_gutter
748
- type: CheckboxSelector
749
- properties:
750
- title: Wider gutter
751
- columns: 2
752
- gutter:
753
- - 24
754
- - 12
755
- options:
756
- - Read
757
- - Write
758
- - Delete
759
- - Administer
760
- - id: columns_per_option_color
761
- type: CheckboxSelector
762
- properties:
763
- title: Coloured options in a grid
764
- columns: 2
765
- options:
766
- - label: Low
767
- value: low
768
- color: "#16a34a"
769
- - label: Medium
770
- value: medium
771
- color: "#d97706"
772
- - label: High
773
- value: high
774
- color: "#dc2626"
775
- - label: Critical
776
- value: critical
777
- color: "#7e22ce"
778
- ```
779
-
780
706
  | Property | Type | Default | Description |
781
707
  | --- | --- | --- | --- |
782
- | `align` | string | `"start"` | Align options. Ignored when 'columns' is set. Enum: `start`, `end`, `center`, `baseline`. |
708
+ | `align` | string | `"start"` | Align options. Enum: `start`, `end`, `center`, `baseline`. |
783
709
  | `color` | string | - | Selected checkbox color. |
784
- | `columns` | integer \| object | - | Number of columns to lay the options out in, or a responsive breakpoint object. Use a count that divides 24 evenly. |
785
710
  | `disabled` | boolean | `false` | Disable the block if true. |
786
- | `direction` | string | `"horizontal"` | List options horizontally or vertical. Ignored when 'columns' is set. Enum: `horizontal`, `vertical`. |
787
- | `gutter` | number \| array | - | Gap between options in the grid. Number or [horizontal, vertical] array. Applies when 'columns' is set. |
788
- | `wrap` | boolean | `true` | Specifies wrapping of options. Applies when 'direction' is 'horizontal'. Ignored when 'columns' is set. |
711
+ | `direction` | string | `"horizontal"` | List options horizontally or vertical. Enum: `horizontal`, `vertical`. |
712
+ | `wrap` | boolean | `true` | Specifies wrapping of options. Applies when 'direction' is 'horizontal'. |
789
713
  | `options` | array | `[]` | Options can either be an array of primitive values, on an array of label, value pairs - supports html. |
790
714
  | `options.$.label` | string | - | Value label shown to user - supports html. |
791
715
  | `options.$.value` | string \| number \| boolean | - | Option value. |
@@ -822,7 +746,7 @@ Checkbox group for selecting multiple options.
822
746
  | `theme.lineWidth` | number | `1` | Border width of the checkbox. |
823
747
  | `theme.lineType` | string | `"solid"` | Border style of the checkbox. |
824
748
  | `theme.fontSize` | number | `14` | Font size for checkbox labels. |
825
- | `theme.marginXS` | number | `8` | Column gap on the checkbox group element. Does not space the options apart; set 'gutter' for a grid. |
749
+ | `theme.marginXS` | number | `8` | Horizontal gap between checkboxes in a group. |
826
750
  | `theme.paddingXS` | number | `8` | Inline padding between the checkbox and its label text. |
827
751
 
828
752
  | Event | Event Data | Description |
@@ -752,75 +752,13 @@ Radio group for selecting a single option.
752
752
  valueKey: id
753
753
  ```
754
754
 
755
- ```yaml
756
- - id: radio_columns_two
757
- type: RadioSelector
758
- properties:
759
- title: Two columns
760
- columns: 2
761
- options:
762
- - Weekday mornings
763
- - Weekday afternoons
764
- - Weekday evenings
765
- - Weekend mornings
766
- - Weekend afternoons
767
- - Weekend evenings
768
- - id: radio_columns_responsive
769
- type: RadioSelector
770
- properties:
771
- title: One column below md, three from md up
772
- columns:
773
- xs: 1
774
- md: 3
775
- options:
776
- - Email
777
- - SMS
778
- - Push notification
779
- - Webhook
780
- - In-app message
781
- - Weekly digest
782
- - id: radio_columns_gutter
783
- type: RadioSelector
784
- properties:
785
- title: Wider gutter
786
- columns: 2
787
- gutter:
788
- - 24
789
- - 12
790
- options:
791
- - Read only
792
- - Read and write
793
- - Administer
794
- - No access
795
- - id: radio_columns_per_option_color
796
- type: RadioSelector
797
- properties:
798
- title: Coloured options in a grid
799
- columns: 2
800
- options:
801
- - label: Low
802
- value: low
803
- color: "#16a34a"
804
- - label: Medium
805
- value: medium
806
- color: "#d97706"
807
- - label: High
808
- value: high
809
- color: "#dc2626"
810
- - label: Critical
811
- value: critical
812
- color: "#7e22ce"
813
- ```
814
-
815
755
  | Property | Type | Default | Description |
816
756
  | --- | --- | --- | --- |
817
- | `align` | string | `"start"` | Align options. Ignored when 'columns' is set. Enum: `start`, `end`, `center`, `baseline`. |
757
+ | `align` | string | `"start"` | Align options. Enum: `start`, `end`, `center`, `baseline`. |
818
758
  | `color` | string | - | Selected radio color. |
819
- | `columns` | integer \| object | - | Number of columns to lay the options out in, or a responsive breakpoint object. Use a count that divides 24 evenly. |
820
759
  | `disabled` | boolean | `false` | Disable the block if true. |
821
- | `direction` | string | `"horizontal"` | List options horizontally or vertical. Ignored when 'columns' is set. Enum: `horizontal`, `vertical`. |
822
- | `gutter` | number \| array | - | Gap between options in the grid. Number or [horizontal, vertical] array. Applies when 'columns' is set. |
823
- | `wrap` | boolean | `true` | Specifies wrapping of options. Applies when 'direction' is 'horizontal'. Ignored when 'columns' is set. |
760
+ | `direction` | string | `"horizontal"` | List options horizontally or vertical. Enum: `horizontal`, `vertical`. |
761
+ | `wrap` | boolean | `true` | Specifies wrapping of options. Applies when 'direction' is 'horizontal'. |
824
762
  | `label` | object | - | Label properties. |
825
763
  | `label.align` | string | `"left"` | Align label left or right when inline. Enum: `left`, `right`. |
826
764
  | `label.colon` | boolean | `true` | Append label with colon. |
@@ -1,6 +1,6 @@
1
1
  # S3UploadButton
2
2
 
3
- __Deprecated__ — use the provider-neutral <a href="/Upload">Upload</a> block with `uploadPolicyRequestId` instead. S3UploadButton remains as an alias so existing apps keep working. Upload files to AWS S3 with a button trigger. Supports file type filtering, upload limits, and custom button styling. Requires an `AwsS3PresignedPostPolicy` request to define the S3 upload policy.
3
+ __Deprecated__ — use the provider-neutral &lt;a href=&quot;/Upload&quot;&gt;Upload&lt;/a&gt; block with `uploadPolicyRequestId` instead. S3UploadButton remains as an alias so existing apps keep working. Upload files to AWS S3 with a button trigger. Supports file type filtering, upload limits, and custom button styling. Requires an `AwsS3PresignedPostPolicy` request to define the S3 upload policy.
4
4
 
5
5
  > The S3UploadButton requires an AwsS3Bucket connection and AwsS3PresignedPostPolicy request to upload files. The examples on this page demonstrate UI configuration only — uploads will not function without a configured S3 connection.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # S3UploadDragger
2
2
 
3
- __Deprecated__ — use the provider-neutral <a href="/UploadDragger">UploadDragger</a> block with `uploadPolicyRequestId` instead. S3UploadDragger remains as an alias so existing apps keep working. Drag-and-drop file upload area for AWS S3. Supports file type filtering, upload limits, custom drag zone styling, and paste-to-upload. Requires an `AwsS3PresignedPostPolicy` request to define the S3 upload policy.
3
+ __Deprecated__ — use the provider-neutral &lt;a href=&quot;/UploadDragger&quot;&gt;UploadDragger&lt;/a&gt; block with `uploadPolicyRequestId` instead. S3UploadDragger remains as an alias so existing apps keep working. Drag-and-drop file upload area for AWS S3. Supports file type filtering, upload limits, custom drag zone styling, and paste-to-upload. Requires an `AwsS3PresignedPostPolicy` request to define the S3 upload policy.
4
4
 
5
5
  > The S3UploadDragger requires an AwsS3Bucket connection and AwsS3PresignedPostPolicy request to upload files. The examples on this page demonstrate UI configuration only — uploads will not function without a configured S3 connection.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # S3UploadPhoto
2
2
 
3
- __Deprecated__ — use the provider-neutral <a href="/UploadPhoto">UploadPhoto</a> block with `uploadPolicyRequestId` instead. S3UploadPhoto remains as an alias so existing apps keep working. Picture-card style image upload for AWS S3. Displays a camera icon with upload text in a card format. Only accepts image files. Requires an `AwsS3PresignedPostPolicy` request to define the S3 upload policy.
3
+ __Deprecated__ — use the provider-neutral &lt;a href=&quot;/UploadPhoto&quot;&gt;UploadPhoto&lt;/a&gt; block with `uploadPolicyRequestId` instead. S3UploadPhoto remains as an alias so existing apps keep working. Picture-card style image upload for AWS S3. Displays a camera icon with upload text in a card format. Only accepts image files. Requires an `AwsS3PresignedPostPolicy` request to define the S3 upload policy.
4
4
 
5
5
  > The S3UploadPhoto requires an AwsS3Bucket connection and AwsS3PresignedPostPolicy request to upload files. The examples on this page demonstrate UI configuration only — uploads will not function without a configured S3 connection.
6
6
 
@@ -1,6 +1,6 @@
1
1
  # TiptapMentionInput
2
2
 
3
- Rich-text editor with @-mention support. Same feature set as TiptapInput, plus a mention dropdown populated from a static options list or a request. Mention options can be marked as groups (roles, teams, queues) to render under their own menu section, as distinctly coloured chips, and with a hover popover listing the group's current members. See the guide below.
3
+ Rich-text editor with @-mention support. Same feature set as TiptapInput, plus a mention dropdown populated from a static options list or a request. Mention options can be marked as groups (roles, teams, queues) to render under their own menu section, as distinctly coloured chips, and with a hover popover listing the group&#39;s current members. See the guide below.
4
4
 
5
5
  ## Group mentions
6
6
 
@@ -1,6 +1,6 @@
1
1
  # MasonryList
2
2
 
3
- Masonry-style grid layout for list data. Items flow into columns and stack vertically, filling gaps left by shorter items. Provide an array in state and use _state operators in the template to access each item's data.
3
+ Masonry-style grid layout for list data. Items flow into columns and stack vertically, filling gaps left by shorter items. Provide an array in state and use _state operators in the template to access each item&#39;s data.
4
4
 
5
5
  ```yaml
6
6
  - id: ml_basic
@@ -29,7 +29,6 @@ The regex operator has shorthand argument definitions that can be used on web cl
29
29
  - `null`
30
30
  - `undefined`
31
31
  - `none` (`null` or `undefined`)
32
- - `empty` (`null`, `undefined`, `''`, or `[]` - note that `0`, `false` and `{}` are not empty)
33
32
  - `primitive` (`undefined`, `null`, `string`, `number`, `boolean`, or `date`)
34
33
  - `on: any`: The value to test. One of `on` or `key` must be specified unless the operator is used in an input block.
35
34
  - `key: string`: The key of a value in `state` to test. One of `on` or `key` must be specified unless the operator is used in an input block.
@@ -61,23 +60,13 @@ Returns: `true` if a number.
61
60
  id: input
62
61
  type: TextInput
63
62
  validate:
64
- - message: This field is required.
63
+ - message: This field id required.
65
64
  status: error
66
65
  pass:
67
66
  _not:
68
- _type: empty
67
+ _type: none
69
68
  ```
70
- Returns: `true` if the input has a value. This is the test the `required` block field applies.
71
-
72
- ###### Check if a value is empty:
73
- ```yaml
74
- _type:
75
- type: empty
76
- on:
77
- _state: selected_tags
78
- ```
79
- Returns: `true` if `selected_tags` is `null`, `undefined`, `''` or `[]`, and `false` for any
80
- other value, including `0`, `false` and `{}`.
69
+ Returns: `true` if the input is none.
81
70
 
82
71
  ###### Test if an id in the `urlQuery` is undefined or null:
83
72
  ```yaml
@@ -10,7 +10,7 @@
10
10
  }): any
11
11
  ```
12
12
 
13
- The `_user` operator gets a value from the [`user`](/user-object) object — the caller Lowdefy resolves for the signed-in user in their active organization. It has a [fixed shape](/user-object); see that page for the available fields.
13
+ The `_user` operator gets a value from the [`user`](/user-object) object. The `user` object contains the data in the user idToken if OpenID Connect authentication is configured and a user is logged in.
14
14
 
15
15
  #### Arguments
16
16
 
@@ -50,7 +50,7 @@ Returns: The entire `user` object.
50
50
  ###### Dot notation:
51
51
  Assuming user:
52
52
  ```yaml
53
- id: abc123
53
+ sub: abc123
54
54
  name: User Name
55
55
  my_object:
56
56
  subfield: 'Value'
@@ -76,7 +76,7 @@ Returns: The value of `might_not_exist`, or `"Default value"`.
76
76
  ###### Block list indices:
77
77
  Assuming `user`:
78
78
  ```yaml
79
- id: abc123
79
+ sub: abc123
80
80
  name: User Name
81
81
  my_array:
82
82
  - value: 0
@@ -8,19 +8,15 @@ The `Login` action is used to start the user login flow. If only one OAuth provi
8
8
 
9
9
  The authorization url usually hosts a page where the user can input their credentials. After the user has logged in successfully, the user is redirected to the `/api/auth/callback/<provider_id>` route in the Lowdefy app, where the rest of the authorization code flow is completed. This URL usually needs to be configured in the identity provider's settings.
10
10
 
11
- The `callbackUrl` parameter of the Login action specifies where the user lands after login is complete. Three sources are consulted, in order: the `callbackUrl` param, then the `?callbackUrl=` query parameter Lowdefy sets when it redirects an unauthenticated user to the sign-in page, then the app's home page. If none resolves the action throws, rather than staying silently on the sign-in page.
12
-
13
- In a protected app a signed-out visitor is sent to the sign-in page for every URL, present or absent, so a `404` means you are signed in — see [Page and API existence](/auth-upgrade#page-and-api-existence-is-no-longer-observable-before-you-sign-in).
14
-
15
- To sign in without navigating at all - a login form in a modal, or an embedded panel - set `callbackUrl: false`. This is not valid for magic-link or social/OAuth sign-in, which redirect through a hop Lowdefy does not control.
11
+ The `callbackUrl` parameters of the Login action specify where the user is redirected after login is complete. If `callbackUrl` parameters not set, the user will return to the page from which the action was called.
16
12
 
17
13
  The parameters are:
18
14
  - `authUrl: object`:
19
15
  - `urlQuery: object`: Query parameters to set for the authorization URL.
20
- - `callbackUrl: object | false`: Set to `false` to sign in without navigating. As an object:
16
+ - `callbackUrl: object`:
21
17
  - `home: boolean`: Redirect to the home page after the login flow is complete.
22
18
  - `pageId: string`: The pageId of the page to redirect to after the login flow is complete.
23
- - `url: string`: The URL to redirect to after the login flow is complete. An absolute URL is not `basePath`-prefixed, so it can be an external landing page.
19
+ - `url: string`: The URL to redirect to after the login flow is complete.
24
20
  - `urlQuery: object`: The urlQuery to set for the page the user is redirected to after login.
25
21
  - `providerId: string`: The ID of the provider that should be used for login. If not set and only one provider is configured the configured provider will be used. Else the user will be redirected to a sign in page where they can choose a provider.
26
22
 
@@ -95,164 +91,18 @@ events:
95
91
  screen_hint: signup
96
92
  ```
97
93
 
98
- ## Magic link sign-in
99
-
100
- `Login` with `magicLink: true` emails the user a sign-in link. By default that link points straight at Better Auth's verify endpoint, which consumes the single-use token on the first `GET` of the URL.
101
-
102
- That is a problem in corporate inboxes. Mail security products — Microsoft Defender Safe Links, Proofpoint URL Defense, Mimecast — fetch every link in a message as it is delivered, so the scanner spends the token minutes before the person clicks, and the person lands on the error page with `INVALID_TOKEN`.
103
-
104
- Set [`auth.authPages.magicLink`](/auth-configuration#auth-pages) to a page in your app to close that gap. The email then links to your page, carrying the token and the callback destinations on its URL query, and a [`MagicLinkVerify`](/MagicLinkVerify) action on a **button click** walks to the verify endpoint. Fetching the landing page does nothing, so a scanner cannot consume the token.
105
-
106
- ```yaml
107
- lowdefy: {{ version }}
108
- auth:
109
- magicLink:
110
- enabled: true
111
- authPages:
112
- magicLink: /magic-link
113
- ```
114
-
115
- ```yaml
116
- id: magic-link
117
- type: PageHeaderMenu
118
- blocks:
119
- - id: content
120
- type: Box
121
- blocks:
122
- - id: title
123
- type: Title
124
- properties:
125
- content: Sign in
126
- level: 3
127
- - id: description
128
- type: Paragraph
129
- properties:
130
- content: Click the button below to finish signing in.
131
- - id: verify_button
132
- type: Button
133
- properties:
134
- title: Sign in
135
- events:
136
- onClick:
137
- - id: verify
138
- type: MagicLinkVerify
139
- ```
140
-
141
- The landing page must be reachable while signed out, so add it to `auth.pages.public`.
142
-
143
- Do **not** run `MagicLinkVerify` in the page's `onMount`, and do not auto-redirect to the verify endpoint. Some scanning sandboxes render the page and execute its JavaScript, so an automatic verify hands the token back to the scanner and you are no better off than linking at the endpoint directly. The whole protection is that a human has to click.
144
-
145
- The action needs no parameters: the token and the `callbackURL`, `newUserCallbackURL` and `errorCallbackURL` values are read from the landing page's own URL query, which the email put there. Pass parameters only to override them.
146
-
147
- ## Email code sign-in
148
-
149
- With `auth.emailOTP` enabled the app can sign a person in with a code emailed to them. Unlike a magic link, the code is typed into the tab they started from — so it survives corporate mail security that pre-fetches links (and consumes the single-use link token), and it works when the email is read on another device.
150
-
151
- Two actions drive it:
152
-
153
- - [`EmailOtpSend`](/EmailOtpSend) sends the code to an email address.
154
- - [`EmailOtpVerify`](/EmailOtpVerify) signs the person in with the code they typed.
155
-
156
- `EmailOtpVerify` lands the user through the same three sources as `Login`: the `callbackUrl` param, then the `?callbackUrl=` query, then the app's home page. `callbackUrl: false` verifies without navigating — it is a plain JSON sign-in with no redirect hop, so staying put is valid here.
157
-
158
- ### With magic link, one email carries both
159
-
160
- When `auth.magicLink` is enabled alongside `auth.emailOTP`, the magic-link email also carries the code, so one email serves both paths. Keep using `Login` with `magicLink: true` to send it — no change is needed — and offer `EmailOtpVerify` on the same page for people whose link does not work. `EmailOtpSend` is then only needed for a code-only page, where no link is offered at all.
161
-
162
- ###### A sign-in page offering a code:
163
- ```yaml
164
- id: email-code-login
165
- type: Box
166
- blocks:
167
- - id: email
168
- type: TextInput
169
- required: true
170
- properties:
171
- title: Email
172
- - id: send_code
173
- type: Button
174
- properties:
175
- title: Send code
176
- events:
177
- onClick:
178
- - id: validate
179
- type: Validate
180
- params:
181
- regex: ^email$
182
- - id: send
183
- type: EmailOtpSend
184
- params:
185
- email:
186
- _state: email
187
- - id: sent
188
- type: DisplayMessage
189
- params:
190
- content: Check your email for the sign-in code.
191
- - id: otp
192
- type: TextInput
193
- properties:
194
- title: Sign-in code
195
- - id: sign_in
196
- type: Button
197
- properties:
198
- title: Sign in
199
- events:
200
- onClick:
201
- - id: verify
202
- type: EmailOtpVerify
203
- params:
204
- email:
205
- _state: email
206
- otp:
207
- _state: otp
208
- ```
209
-
210
- An expired, mistyped or already-used code is the auth server rejecting the attempt, not an app fault: the action throws a `UserError`, so `onClick` `catch` actions run and the message displays, but nothing is reported to the server.
211
-
212
- ## SMS sign-in
213
-
214
- `PhoneNumberVerify` completes a sign-in with an SMS code, and lands the user through the same three sources as `Login`: the `callbackUrl` param, then the `?callbackUrl=` query, then the app's home page. `callbackUrl: false` verifies without navigating.
215
-
216
- Two modes are exempt, because neither ends with the user arriving somewhere new:
217
-
218
- - `disableSession: true` creates no session to arrive with.
219
- - `updatePhoneNumber: true` is a signed-in user confirming a new number. They already had a session, and the confirmation usually runs in a modal a navigation would yank them out of.
220
-
221
- ### Carrying the destination to a separate SMS form
222
-
223
- The `?callbackUrl=` query is read from the page the action runs on, and the unauthenticated bounce puts it on `authPages.signIn`. If your SMS form lives on its own page, the link that gets the user there has to carry the parameter, or the destination falls back to the home page:
224
-
225
- ```yaml
226
- - id: to_phone_login
227
- type: Link
228
- params:
229
- pageId: phone-login
230
- urlQuery:
231
- _if:
232
- test:
233
- _eq:
234
- - _url_query: callbackUrl
235
- - null
236
- then: null
237
- else:
238
- callbackUrl:
239
- _url_query: callbackUrl
240
- ```
241
-
242
- The `_if` is what keeps a user who reached the sign-in page directly from being sent to `/phone-login?callbackUrl=null` — `urlQuery` serialises a null value rather than dropping the key.
243
-
244
94
  ## Logout
245
95
 
246
96
  When the `Logout` action is called, the user data and authorization cookies are cleared by the app.
247
97
 
248
- The `callbackUrl` parameter of the Logout action specifies where the user lands after logout is complete. Unlike the `Login` action it has no default and does not read the `?callbackUrl=` query: with no `callbackUrl` the page is reloaded and the server re-applies the page's auth rules, which sends a signed-out user off a protected page to the sign-in page.
98
+ The `callbackUrl` parameters of the Logout action specify where the user is redirected after logout is complete. If `callbackUrl` parameters are not set, the user will return to the page from which the action was called.
249
99
 
250
100
  The parameters are:
251
101
  - `callbackUrl: object`:
252
- - `home: boolean`: Redirect to the home page after the logout flow is complete.
253
- - `pageId: string`: The pageId of the page to redirect to after the logout flow is complete.
254
- - `url: string`: The URL to redirect to after the logout flow is complete. An absolute URL is not `basePath`-prefixed, so it can be an external logout landing page.
255
- - `urlQuery: object`: The urlQuery to set for the page the user is redirected to after logout.
102
+ - `home: boolean`: Redirect to the home page after the login flow is complete.
103
+ - `pageId: string`: The pageId of the page to redirect to after the login flow is complete.
104
+ - `url: string`: The URL to redirect to after the login flow is complete.
105
+ - `urlQuery: object`: The urlQuery to set for the page the user is redirected to after login.
256
106
  - `redirect: boolean`: If set to `false` the user session will be cleared, but the page will not be reloaded.
257
107
 
258
108
 
@@ -29,11 +29,3 @@ The Login and Logout actions are used to start the login and logout processes.
29
29
  ## \_user operator
30
30
 
31
31
  The `_user` operator can be used to access data in the user object received from the identity provider. The OpenID Connect standard claims (fields like `name` or `email`) are mapped to the user object by default and addition fields can be configured using the `userFields` configuration option.
32
-
33
- ### `two_factor_enrolled`
34
-
35
- `_user: two_factor_enrolled` is `true` when the caller holds a factor that satisfies [`auth.twoFactor.required`](/two-factor) — a TOTP enrolment **or** a registered passkey.
36
-
37
- It is a fact about the **user**, not the session: it does not assert that a factor was presented on this sign-in, only that the user has one on file. (The name is imperfect — a passkey is not literally a second factor. The field means precisely "holds a factor that satisfies `auth.twoFactor.required`", which a passkey does on its own.)
38
-
39
- It is present only on session-resolved callers. The API strategy and the injected callers used in dev and e2e carry no session and so do not carry this field.