@softr/sdk 0.0.64-alpha.0 → 0.0.64-alpha.1
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/dist/auth/isomorphic.d.ts +6 -6
- package/dist/default-error-overlay.d.ts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/mcp.d.ts +2 -2
- package/dist/package.js +1 -1
- package/dist/pwa.d.ts +2 -2
- package/dist/visibility/route.d.ts +13 -5
- package/dist/visibility/route.js +27 -8
- package/package.json +1 -1
- package/skills/softr-sdk/SKILL.md +1 -1
- package/skills/softr-sdk/auth/SKILL.md +9 -7
- package/skills/softr-sdk/charts-and-metrics/SKILL.md +1 -1
- package/skills/softr-sdk/current-user/SKILL.md +1 -1
- package/skills/softr-sdk/file-uploads/SKILL.md +1 -1
- package/skills/softr-sdk/formatting/SKILL.md +1 -1
- package/skills/softr-sdk/integrations/SKILL.md +1 -1
- package/skills/softr-sdk/mcp/SKILL.md +5 -5
- package/skills/softr-sdk/pwa/SKILL.md +1 -1
- package/skills/softr-sdk/record-mutations/SKILL.md +1 -1
- package/skills/softr-sdk/record-queries/SKILL.md +1 -1
- package/skills/softr-sdk/region-visibility/SKILL.md +1 -1
- package/skills/softr-sdk/routes-and-visibility/SKILL.md +2 -2
- package/skills/softr-sdk/workflows/SKILL.md +1 -1
|
@@ -2,9 +2,9 @@ import { User } from "./user.js";
|
|
|
2
2
|
import { Formatting } from "../formatting.js";
|
|
3
3
|
import { Permissions } from "./permissions.js";
|
|
4
4
|
import { SoftrContext } from "./context.js";
|
|
5
|
-
import * as
|
|
5
|
+
import * as react6 from "react";
|
|
6
6
|
import { ReactNode } from "react";
|
|
7
|
-
import * as
|
|
7
|
+
import * as _tanstack_react_start1 from "@tanstack/react-start";
|
|
8
8
|
|
|
9
9
|
//#region src/auth/isomorphic.d.ts
|
|
10
10
|
|
|
@@ -21,7 +21,7 @@ import * as _tanstack_react_start0 from "@tanstack/react-start";
|
|
|
21
21
|
* requestMiddleware: [softrAuthMiddleware()],
|
|
22
22
|
* }))
|
|
23
23
|
*/
|
|
24
|
-
declare function softrAuthMiddleware():
|
|
24
|
+
declare function softrAuthMiddleware(): _tanstack_react_start1.RequestMiddlewareAfterServer<{}, readonly [_tanstack_react_start1.RequestMiddlewareAfterServer<{}, undefined, undefined>, _tanstack_react_start1.RequestMiddlewareAfterServer<{}, undefined, undefined>], {
|
|
25
25
|
user: User | null;
|
|
26
26
|
permissions: Permissions;
|
|
27
27
|
formatting: Formatting;
|
|
@@ -35,7 +35,7 @@ declare function softrAuthMiddleware(): _tanstack_react_start0.RequestMiddleware
|
|
|
35
35
|
* beforeLoad: async () => await getSoftrContext(),
|
|
36
36
|
* })
|
|
37
37
|
*/
|
|
38
|
-
declare const getSoftrContext:
|
|
38
|
+
declare const getSoftrContext: _tanstack_react_start1.OptionalFetcher<undefined, undefined, Promise<SoftrContext>>;
|
|
39
39
|
/**
|
|
40
40
|
* The context to hand `createRouter`, before any request has resolved one.
|
|
41
41
|
*
|
|
@@ -83,7 +83,7 @@ type AuthOptions = {
|
|
|
83
83
|
* staleTime: 60_000,
|
|
84
84
|
* })
|
|
85
85
|
*/
|
|
86
|
-
declare const getAuthSettings:
|
|
86
|
+
declare const getAuthSettings: _tanstack_react_start1.OptionalFetcher<undefined, undefined, Promise<AuthOptions>>;
|
|
87
87
|
/**
|
|
88
88
|
* Makes the auth options readable with {@link useAuthSettings} anywhere below.
|
|
89
89
|
*
|
|
@@ -103,7 +103,7 @@ declare function AuthSettingsProvider({
|
|
|
103
103
|
}: {
|
|
104
104
|
value: AuthOptions;
|
|
105
105
|
children?: ReactNode;
|
|
106
|
-
}):
|
|
106
|
+
}): react6.JSX.Element;
|
|
107
107
|
/**
|
|
108
108
|
* Which ways in this app offers. Requires an {@link AuthSettingsProvider}
|
|
109
109
|
* above it.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react5 from "react";
|
|
2
2
|
|
|
3
3
|
//#region src/default-error-overlay.d.ts
|
|
4
4
|
type Props = {
|
|
@@ -8,6 +8,6 @@ type Props = {
|
|
|
8
8
|
declare function DefaultErrorOverlay({
|
|
9
9
|
error,
|
|
10
10
|
reset
|
|
11
|
-
}: Props):
|
|
11
|
+
}: Props): react5.JSX.Element;
|
|
12
12
|
//#endregion
|
|
13
13
|
export { DefaultErrorOverlay };
|
package/dist/index.d.ts
CHANGED
|
@@ -6,11 +6,11 @@ import { DateOptions, DateParts, DateSeparator, DateValue, FixedDateFormat, Form
|
|
|
6
6
|
import { SoftrContext } from "./auth/context.js";
|
|
7
7
|
import { AuthSettings } from "./auth/platform.js";
|
|
8
8
|
import { checkAccess, defineVisibility, isAuthorized } from "./visibility/visibility.js";
|
|
9
|
-
import { assertRouteAccess,
|
|
9
|
+
import { assertRouteAccess, guardRoute, isAccessError, isAlreadyAuthenticatedError, isForbiddenError, isUnauthenticatedError, toReturnPath } from "./visibility/route.js";
|
|
10
10
|
import { AuthOptions, AuthSettingsProvider, getAuthSettings, getSoftrContext, initialSoftrContext, softrAuthMiddleware, useAuthSettings, useCurrentUser } from "./auth/isomorphic.js";
|
|
11
11
|
import { softrMcpMiddleware } from "./mcp.js";
|
|
12
12
|
import { useUserTimezone } from "./timezone.js";
|
|
13
13
|
import { PwaInstall, PwaPlatform, SoftrPwaHead, usePwaInstall } from "./pwa.js";
|
|
14
14
|
import { DefaultErrorOverlay } from "./default-error-overlay.js";
|
|
15
15
|
import { Audience } from "./visibility/audience.js";
|
|
16
|
-
export { type ActionPermissions, Audience, type AuthOptions, type AuthSettings, AuthSettingsProvider, type DateOptions, type DateParts, type DateSeparator, type DateValue, DefaultErrorOverlay, type FileAttachment, type FileItem, type FixedDateFormat, FormattedDate, type Formatting, FormattingScope, type PwaInstall, type PwaPlatform, type SoftrContext, type SoftrDatasources, SoftrPwaHead, type SoftrUserGroupId, type SoftrUserGroups, type User, type WeekDay, assertRouteAccess,
|
|
16
|
+
export { type ActionPermissions, Audience, type AuthOptions, type AuthSettings, AuthSettingsProvider, type DateOptions, type DateParts, type DateSeparator, type DateValue, DefaultErrorOverlay, type FileAttachment, type FileItem, type FixedDateFormat, FormattedDate, type Formatting, FormattingScope, type PwaInstall, type PwaPlatform, type SoftrContext, type SoftrDatasources, SoftrPwaHead, type SoftrUserGroupId, type SoftrUserGroups, type User, type WeekDay, assertRouteAccess, checkAccess, defineIntegration, defineMutation, defineQuery, defineVisibility, defineWorkflow, formatDate, formatDateTime, formatNumber, getAuthSettings, getSoftrContext, guardRoute, initialSoftrContext, isAccessError, isAlreadyAuthenticatedError, isAuthorized, isForbiddenError, isUnauthenticatedError, softrAuthMiddleware, softrMcpMiddleware, toReturnPath, useAuthSettings, useCurrentUser, useFileUpload, useFormatting, usePwaInstall, useUserTimezone };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useFileUpload } from "./core/use-file-upload.js";
|
|
2
2
|
import { defineIntegration, defineMutation, defineQuery, defineWorkflow } from "./action.js";
|
|
3
3
|
import { checkAccess, defineVisibility, isAuthorized } from "./visibility/visibility.js";
|
|
4
|
-
import { assertRouteAccess,
|
|
4
|
+
import { assertRouteAccess, guardRoute, isAccessError, isAlreadyAuthenticatedError, isForbiddenError, isUnauthenticatedError, toReturnPath } from "./visibility/route.js";
|
|
5
5
|
import { FormattedDate, FormattingScope, formatDate, formatDateTime, formatNumber, useFormatting } from "./formatting.js";
|
|
6
6
|
import { SoftrPwaHead, usePwaInstall } from "./pwa.js";
|
|
7
7
|
import { AuthSettingsProvider, getAuthSettings, getSoftrContext, initialSoftrContext, softrAuthMiddleware, useAuthSettings, useCurrentUser } from "./auth/isomorphic.js";
|
|
@@ -10,4 +10,4 @@ import { useUserTimezone } from "./timezone.js";
|
|
|
10
10
|
import { DefaultErrorOverlay } from "./default-error-overlay.js";
|
|
11
11
|
import { Audience } from "./visibility/audience.js";
|
|
12
12
|
|
|
13
|
-
export { Audience, AuthSettingsProvider, DefaultErrorOverlay, FormattedDate, FormattingScope, SoftrPwaHead, assertRouteAccess,
|
|
13
|
+
export { Audience, AuthSettingsProvider, DefaultErrorOverlay, FormattedDate, FormattingScope, SoftrPwaHead, assertRouteAccess, checkAccess, defineIntegration, defineMutation, defineQuery, defineVisibility, defineWorkflow, formatDate, formatDateTime, formatNumber, getAuthSettings, getSoftrContext, guardRoute, initialSoftrContext, isAccessError, isAlreadyAuthenticatedError, isAuthorized, isForbiddenError, isUnauthenticatedError, softrAuthMiddleware, softrMcpMiddleware, toReturnPath, useAuthSettings, useCurrentUser, useFileUpload, useFormatting, usePwaInstall, useUserTimezone };
|
package/dist/mcp.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { DatasourceAction } from "./action.js";
|
|
2
|
-
import * as
|
|
2
|
+
import * as _tanstack_react_start0 from "@tanstack/react-start";
|
|
3
3
|
|
|
4
4
|
//#region src/mcp.d.ts
|
|
5
5
|
|
|
@@ -31,6 +31,6 @@ type SoftrMcpOptions = {
|
|
|
31
31
|
* ],
|
|
32
32
|
* }))
|
|
33
33
|
*/
|
|
34
|
-
declare function softrMcpMiddleware(options?: SoftrMcpOptions):
|
|
34
|
+
declare function softrMcpMiddleware(options?: SoftrMcpOptions): _tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>;
|
|
35
35
|
//#endregion
|
|
36
36
|
export { softrMcpMiddleware };
|
package/dist/package.js
CHANGED
package/dist/pwa.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react3 from "react";
|
|
2
2
|
import "@tanstack/react-start";
|
|
3
3
|
|
|
4
4
|
//#region src/pwa.d.ts
|
|
@@ -23,7 +23,7 @@ import "@tanstack/react-start";
|
|
|
23
23
|
* )
|
|
24
24
|
* }
|
|
25
25
|
*/
|
|
26
|
-
declare function SoftrPwaHead():
|
|
26
|
+
declare function SoftrPwaHead(): react3.FunctionComponentElement<react3.FragmentProps>;
|
|
27
27
|
type PwaPlatform = "ios" | "android" | "desktop";
|
|
28
28
|
type PwaInstall = {
|
|
29
29
|
available: false;
|
|
@@ -48,7 +48,7 @@ declare function isAlreadyAuthenticatedError(error: unknown): error is AccessErr
|
|
|
48
48
|
*
|
|
49
49
|
* Each reason falls back to the app's configured behaviour. Pass `overrides` to
|
|
50
50
|
* change what any one reason does. A redirected signed-out visitor carries the
|
|
51
|
-
* page they wanted, for {@link
|
|
51
|
+
* page they wanted, for {@link toReturnPath} to read back.
|
|
52
52
|
*
|
|
53
53
|
* Throws a router redirect, so it belongs in `beforeLoad` and nowhere else.
|
|
54
54
|
*
|
|
@@ -81,11 +81,19 @@ declare function assertRouteAccess<R extends VisibilityRule, O extends {
|
|
|
81
81
|
};
|
|
82
82
|
/**
|
|
83
83
|
* Where to send a visitor who just signed in: the path a guard sent them away
|
|
84
|
-
* from,
|
|
84
|
+
* from, else where `auth.guard.alreadyAuthenticated` in softr.json points, else
|
|
85
|
+
* `/`. Anything but a path on this app counts as missing. It always reloads the
|
|
86
|
+
* page, so the router picks up the new session.
|
|
85
87
|
*
|
|
86
88
|
* @example
|
|
87
|
-
* const
|
|
89
|
+
* const location = useLocation()
|
|
90
|
+
* navigate(toReturnPath(location))
|
|
88
91
|
*/
|
|
89
|
-
declare function
|
|
92
|
+
declare function toReturnPath(location: {
|
|
93
|
+
search: Record<string, unknown>;
|
|
94
|
+
}): {
|
|
95
|
+
href: string;
|
|
96
|
+
reloadDocument: true;
|
|
97
|
+
};
|
|
90
98
|
//#endregion
|
|
91
|
-
export { assertRouteAccess,
|
|
99
|
+
export { assertRouteAccess, guardRoute, isAccessError, isAlreadyAuthenticatedError, isForbiddenError, isUnauthenticatedError, toReturnPath };
|
package/dist/visibility/route.js
CHANGED
|
@@ -60,7 +60,7 @@ function thrownFor(reason, overrides, location) {
|
|
|
60
60
|
*
|
|
61
61
|
* Each reason falls back to the app's configured behaviour. Pass `overrides` to
|
|
62
62
|
* change what any one reason does. A redirected signed-out visitor carries the
|
|
63
|
-
* page they wanted, for {@link
|
|
63
|
+
* page they wanted, for {@link toReturnPath} to read back.
|
|
64
64
|
*
|
|
65
65
|
* Throws a router redirect, so it belongs in `beforeLoad` and nowhere else.
|
|
66
66
|
*
|
|
@@ -91,16 +91,35 @@ function assertRouteAccess(visibility, opts) {
|
|
|
91
91
|
}
|
|
92
92
|
/**
|
|
93
93
|
* Where to send a visitor who just signed in: the path a guard sent them away
|
|
94
|
-
* from,
|
|
94
|
+
* from, else where `auth.guard.alreadyAuthenticated` in softr.json points, else
|
|
95
|
+
* `/`. Anything but a path on this app counts as missing. It always reloads the
|
|
96
|
+
* page, so the router picks up the new session.
|
|
95
97
|
*
|
|
96
98
|
* @example
|
|
97
|
-
* const
|
|
99
|
+
* const location = useLocation()
|
|
100
|
+
* navigate(toReturnPath(location))
|
|
98
101
|
*/
|
|
99
|
-
function
|
|
100
|
-
const
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
function toReturnPath(location) {
|
|
103
|
+
const { auth } = softrConfig();
|
|
104
|
+
const target = location.search[auth.routes.login.redirectParam];
|
|
105
|
+
if (typeof target === "string" && target.startsWith("/") && new URL(target, "https://app.invalid").origin === "https://app.invalid") return {
|
|
106
|
+
href: target,
|
|
107
|
+
reloadDocument: true
|
|
108
|
+
};
|
|
109
|
+
const fallback = auth.guard.alreadyAuthenticated;
|
|
110
|
+
if (typeof fallback === "string") return {
|
|
111
|
+
href: fallback,
|
|
112
|
+
reloadDocument: true
|
|
113
|
+
};
|
|
114
|
+
if (fallback.strategy === "redirect") return {
|
|
115
|
+
href: fallback.to,
|
|
116
|
+
reloadDocument: true
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
href: "/",
|
|
120
|
+
reloadDocument: true
|
|
121
|
+
};
|
|
103
122
|
}
|
|
104
123
|
|
|
105
124
|
//#endregion
|
|
106
|
-
export { assertRouteAccess,
|
|
125
|
+
export { assertRouteAccess, guardRoute, isAccessError, isAlreadyAuthenticatedError, isForbiddenError, isUnauthenticatedError, softrConfig, toReturnPath };
|
package/package.json
CHANGED
|
@@ -14,12 +14,12 @@ description: >-
|
|
|
14
14
|
with and its codes invalidCredentials, tooManyAttempts, emailTaken,
|
|
15
15
|
invalidDetails, invalidCode, notAuthenticated, emailDomainNotAllowed and
|
|
16
16
|
linkExpired, the two-step sign-up, why a successful sign-in does not always
|
|
17
|
-
mean the visitor is signed in, and
|
|
17
|
+
mean the visitor is signed in, and toReturnPath for where to land after
|
|
18
18
|
signing in.
|
|
19
19
|
metadata:
|
|
20
20
|
type: sub-skill
|
|
21
21
|
library: softr-sdk
|
|
22
|
-
library_version: 0.0.64-alpha.
|
|
22
|
+
library_version: 0.0.64-alpha.1
|
|
23
23
|
---
|
|
24
24
|
|
|
25
25
|
**Boundary.** `auth` lives on `@softr/sdk/server` and runs only inside a `createServerFn` handler — importing it into a component fails the build.
|
|
@@ -202,20 +202,22 @@ An app with no authenticator app configured never answers `authenticatorRequired
|
|
|
202
202
|
|
|
203
203
|
## Landing after sign-in
|
|
204
204
|
|
|
205
|
-
A guard that turns a signed-out visitor away sends them to the page `softr.json` names for that, usually the login page. The page they wanted rides along in the search param named for the login page. `
|
|
205
|
+
A guard that turns a signed-out visitor away sends them to the page `softr.json` names for that, usually the login page. The page they wanted rides along in the search param named for the login page. `toReturnPath` from `@softr/sdk` reads it back:
|
|
206
206
|
|
|
207
207
|
```tsx
|
|
208
208
|
import { useLocation, useNavigate } from '@tanstack/react-router'
|
|
209
|
-
import {
|
|
209
|
+
import { toReturnPath } from '@softr/sdk'
|
|
210
210
|
|
|
211
|
-
const
|
|
211
|
+
const location = useLocation()
|
|
212
212
|
const navigate = useNavigate()
|
|
213
213
|
|
|
214
214
|
// once the visitor is signed in
|
|
215
|
-
await navigate(
|
|
215
|
+
await navigate(toReturnPath(location))
|
|
216
216
|
```
|
|
217
217
|
|
|
218
|
-
|
|
218
|
+
A loader that signs the visitor in throws it instead: `throw redirect(toReturnPath(location))`, with the loader's own `location`.
|
|
219
|
+
|
|
220
|
+
It goes to the page they wanted when that is a path on this app. Otherwise it goes where `auth.guard.alreadyAuthenticated` in `softr.json` points, or to `/` when that setting throws. It reloads the page, so the app sees the visitor as signed in. Pass its answer as is. Never read the param yourself: anyone can put a link to another site in it.
|
|
219
221
|
|
|
220
222
|
Every page that ends a sign-in lands there: login, sign-up, the magic link, a password link and the second-factor step. A link from one auth page to another keeps the search param, or the target is lost on the way.
|
|
221
223
|
|
|
@@ -12,7 +12,7 @@ description: >-
|
|
|
12
12
|
metadata:
|
|
13
13
|
type: sub-skill
|
|
14
14
|
library: softr-sdk
|
|
15
|
-
library_version: 0.0.64-alpha.
|
|
15
|
+
library_version: 0.0.64-alpha.1
|
|
16
16
|
---
|
|
17
17
|
|
|
18
18
|
**Boundary.** `ds` lives on `@softr/sdk/server` and runs only inside a `createServerFn` handler or a server-side route hook — importing it into a component fails the build. `defineQuery` and every type come from `@softr/sdk` and can be imported anywhere.
|
|
@@ -10,7 +10,7 @@ description: >-
|
|
|
10
10
|
metadata:
|
|
11
11
|
type: sub-skill
|
|
12
12
|
library: softr-sdk
|
|
13
|
-
library_version: 0.0.64-alpha.
|
|
13
|
+
library_version: 0.0.64-alpha.1
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
**Boundary.** `upload` lives on `@softr/sdk/server` and runs inside server functions. `useFileUpload` and `FileItem` live on `@softr/sdk` and run in components. `FileAttachment` comes from `@softr/sdk` and can be imported anywhere.
|
|
@@ -10,7 +10,7 @@ description: >-
|
|
|
10
10
|
metadata:
|
|
11
11
|
type: sub-skill
|
|
12
12
|
library: softr-sdk
|
|
13
|
-
library_version: 0.0.64-alpha.
|
|
13
|
+
library_version: 0.0.64-alpha.1
|
|
14
14
|
---
|
|
15
15
|
|
|
16
16
|
**Boundary.** `integration` lives on `@softr/sdk/server` and runs only inside a `createServerFn` handler — importing it into a component fails the build. `defineIntegration` and every type come from `@softr/sdk` and can be imported anywhere.
|
|
@@ -5,11 +5,11 @@ description: >-
|
|
|
5
5
|
@softr/sdk, registered in src/start.ts ahead of softrAuthMiddleware, turns the
|
|
6
6
|
actions you list into tools an assistant can call as the signed-in visitor.
|
|
7
7
|
The list is explicit — an action left out is invisible over MCP. The app's own
|
|
8
|
-
login must land on
|
|
8
|
+
login must land on toReturnPath, or the approval step dead-ends.
|
|
9
9
|
metadata:
|
|
10
10
|
type: sub-skill
|
|
11
11
|
library: softr-sdk
|
|
12
|
-
library_version: 0.0.64-alpha.
|
|
12
|
+
library_version: 0.0.64-alpha.1
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
**Boundary.** `softrMcpMiddleware` lives on `@softr/sdk` and is registered once, in `src/start.ts`. The actions you hand it are the same `defineQuery` / `defineMutation` values the app's own pages use — declared wherever they already live, not duplicated for MCP.
|
|
@@ -61,9 +61,9 @@ Reads first. Add a write only when the user asked for one, and name it back to t
|
|
|
61
61
|
|
|
62
62
|
Connecting starts with an approval page the app serves. Most people hit it signed out, and that page cannot sign anyone in. It sends them to the login page named in `softr.json` (`auth.routes.login.path`), with the approval page in the search param named there (`auth.routes.login.redirectParam`).
|
|
63
63
|
|
|
64
|
-
**The app's login has to send them back.** Every exit that ends a sign-in, the second-factor step included, goes to `
|
|
64
|
+
**The app's login has to send them back.** Every exit that ends a sign-in, the second-factor step included, goes to `toReturnPath(location)` instead of the home page. See [auth/SKILL.md](../auth/SKILL.md). Lose the search param anywhere along the way and the approval dies quietly: they land on the home page, the assistant never gets its answer, nothing reports an error.
|
|
65
65
|
|
|
66
|
-
`
|
|
66
|
+
`toReturnPath` only ever goes to a path on this app. Never follow the param without it. The whole flow starts with a link someone was sent, so this is the one redirect an attacker can reliably aim.
|
|
67
67
|
## Failure modes
|
|
68
68
|
|
|
69
69
|
**Registering with no actions.** `softrMcpMiddleware()` is valid and serves an endpoint with nothing on it. The assistant connects, lists tools, finds only `whoami`. Pass the actions.
|
|
@@ -74,7 +74,7 @@ Connecting starts with an approval page the app serves. Most people hit it signe
|
|
|
74
74
|
|
|
75
75
|
**A login that drops the return target.** Sign-in works, approval doesn't. The most common break, and silent — test the connect flow signed out, not only signed in.
|
|
76
76
|
|
|
77
|
-
**Following the param without `
|
|
77
|
+
**Following the param without `toReturnPath`.** Anything that is not a path on this app is someone else's page, and `/\evil.test` is one of them. A prefix check misses it.
|
|
78
78
|
|
|
79
79
|
## References
|
|
80
80
|
|
|
@@ -11,7 +11,7 @@ description: >-
|
|
|
11
11
|
metadata:
|
|
12
12
|
type: sub-skill
|
|
13
13
|
library: softr-sdk
|
|
14
|
-
library_version: 0.0.64-alpha.
|
|
14
|
+
library_version: 0.0.64-alpha.1
|
|
15
15
|
---
|
|
16
16
|
|
|
17
17
|
**Boundary.** `ds` lives on `@softr/sdk/server` and runs only inside a `createServerFn` handler — importing it into a component fails the build. `defineMutation` and every type come from `@softr/sdk` and can be imported anywhere.
|
|
@@ -13,7 +13,7 @@ description: >-
|
|
|
13
13
|
metadata:
|
|
14
14
|
type: sub-skill
|
|
15
15
|
library: softr-sdk
|
|
16
|
-
library_version: 0.0.64-alpha.
|
|
16
|
+
library_version: 0.0.64-alpha.1
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
**Boundary.** `ds` lives on `@softr/sdk/server` and runs only inside a `createServerFn` handler or a server-side route hook — importing it into a component fails the build. The same holds for any helper that calls `ds`: declare it inside the handler. A function at module level that calls `ds` keeps the server-only import in the browser bundle, and every page stops loading until it moves. `defineQuery` and every type come from `@softr/sdk` and can be imported anywhere.
|
|
@@ -13,7 +13,7 @@ description: >-
|
|
|
13
13
|
metadata:
|
|
14
14
|
type: sub-skill
|
|
15
15
|
library: softr-sdk
|
|
16
|
-
library_version: 0.0.64-alpha.
|
|
16
|
+
library_version: 0.0.64-alpha.1
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
**Boundary.** `defineVisibility`, the access functions and the error predicates come from `@softr/sdk` and work anywhere.
|
|
@@ -138,7 +138,7 @@ Every key is required, because nothing fills in one the file leaves out:
|
|
|
138
138
|
| `forbidden` | Signed in, in none of the named groups | `guard.forbidden` |
|
|
139
139
|
| `alreadyAuthenticated` | Signed-in visitor on a signed-out-only route | `guard.alreadyAuthenticated` |
|
|
140
140
|
|
|
141
|
-
`guard.unauthenticated` is where signed-out visitors go. It is usually the same as `routes.login.path`, but it can be another page, such as a public landing page. Every `unauthenticated` redirect, an override's included, carries the page they wanted under `routes.login.redirectParam`. The login page reads it back with `
|
|
141
|
+
`guard.unauthenticated` is where signed-out visitors go. It is usually the same as `routes.login.path`, but it can be another page, such as a public landing page. Every `unauthenticated` redirect, an override's included, carries the page they wanted under `routes.login.redirectParam`. The login page reads it back with `toReturnPath`. See [auth/SKILL.md](../auth/SKILL.md).
|
|
142
142
|
|
|
143
143
|
`auth.routes` names the app's sign-in pages. To move one, rename its route file and edit its `path` in `auth.routes` to match. When `guard.unauthenticated` points at the login page, edit it too.
|
|
144
144
|
|
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
metadata:
|
|
10
10
|
type: sub-skill
|
|
11
11
|
library: softr-sdk
|
|
12
|
-
library_version: 0.0.64-alpha.
|
|
12
|
+
library_version: 0.0.64-alpha.1
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
**Boundary.** `workflow` lives on `@softr/sdk/server` and runs only inside a `createServerFn` handler — importing it into a component fails the build. `defineWorkflow` and every type come from `@softr/sdk` and can be imported anywhere.
|