@softr/sdk 0.0.93 → 0.0.95
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/methods/emailCode2fa.d.ts +34 -0
- package/dist/auth/methods/emailCode2fa.js +71 -0
- package/dist/auth/methods/password.d.ts +4 -1
- package/dist/auth/methods/password.js +6 -1
- package/dist/auth/platform.js +25 -0
- package/dist/auth/server.d.ts +3 -0
- package/dist/auth/server.js +3 -0
- package/dist/default-error-overlay.js +5 -1
- package/dist/package.js +1 -1
- package/package.json +1 -1
- package/skills/softr-sdk/SKILL.md +1 -1
- package/skills/softr-sdk/ai/SKILL.md +10 -10
- package/skills/softr-sdk/auth/SKILL.md +33 -5
- 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 +1 -1
- 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 +4 -4
- package/skills/softr-sdk/workflows/SKILL.md +1 -1
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { User } from "../user.js";
|
|
2
|
+
import { AuthError, Result } from "./utils.js";
|
|
3
|
+
|
|
4
|
+
//#region src/auth/methods/emailCode2fa.d.ts
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Finishes a sign-in that answered `emailCodeRequired`, with the code emailed
|
|
8
|
+
* to the visitor.
|
|
9
|
+
*
|
|
10
|
+
* A `signedIn` result means the visitor is signed in. An app that also asks for
|
|
11
|
+
* an authenticator app answers `authenticatorRequired` instead, naming the step
|
|
12
|
+
* to send them to next.
|
|
13
|
+
*/
|
|
14
|
+
declare function verifyEmailCode(details: {
|
|
15
|
+
code: string;
|
|
16
|
+
}): Promise<Result<{
|
|
17
|
+
status: "signedIn";
|
|
18
|
+
user: User;
|
|
19
|
+
} | {
|
|
20
|
+
status: "authenticatorRequired";
|
|
21
|
+
/**
|
|
22
|
+
* `verify`: they have an authenticator app and owe a code.
|
|
23
|
+
* `setup`: the app requires one and they have none yet.
|
|
24
|
+
* `setupOptional`: same, except they may skip it instead.
|
|
25
|
+
*/
|
|
26
|
+
step: "verify" | "setup" | "setupOptional";
|
|
27
|
+
}, AuthError>>;
|
|
28
|
+
/**
|
|
29
|
+
* Emails the code for {@link verifyEmailCode} again. Asking again within a
|
|
30
|
+
* short wait sends nothing and still succeeds.
|
|
31
|
+
*/
|
|
32
|
+
declare function resendEmailCode(): Promise<Result<null, AuthError>>;
|
|
33
|
+
//#endregion
|
|
34
|
+
export { resendEmailCode, verifyEmailCode };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { assert, panic } from "../../assertions.js";
|
|
2
|
+
import { writeCookies } from "../../cookies.js";
|
|
3
|
+
import { sessionConfig } from "../config.js";
|
|
4
|
+
import { clearPendingAuth, makePendingAuthCookie, makeSessionDataCookie, makeSessionTokenCookie, readPendingAuthToken } from "../session.js";
|
|
5
|
+
import { makePlatform } from "../platform.js";
|
|
6
|
+
import { authError } from "./utils.js";
|
|
7
|
+
|
|
8
|
+
//#region src/auth/methods/emailCode2fa.ts
|
|
9
|
+
/**
|
|
10
|
+
* Finishes a sign-in that answered `emailCodeRequired`, with the code emailed
|
|
11
|
+
* to the visitor.
|
|
12
|
+
*
|
|
13
|
+
* A `signedIn` result means the visitor is signed in. An app that also asks for
|
|
14
|
+
* an authenticator app answers `authenticatorRequired` instead, naming the step
|
|
15
|
+
* to send them to next.
|
|
16
|
+
*/
|
|
17
|
+
async function verifyEmailCode(details) {
|
|
18
|
+
const result = await makePlatform(sessionConfig().applicationId).emailCodeVerify(readPendingAuthToken(), details.code);
|
|
19
|
+
if (!result.ok) {
|
|
20
|
+
if (result.status === 400 || result.status === 401) return authError("invalidCode", result.message);
|
|
21
|
+
if (result.status === 429) return authError("tooManyAttempts", result.message);
|
|
22
|
+
if (result.status >= 500) panic(`Expected to verify the emailed code, but got ${result.status}: ` + result.message);
|
|
23
|
+
throw new Error(`${result.message}. Check SOFTR_APPLICATION_ID and that the app asks for an emailed code at sign-in.`);
|
|
24
|
+
}
|
|
25
|
+
if (result.data.status === "MFA_REQUIRED") {
|
|
26
|
+
const { mfa } = result.data;
|
|
27
|
+
assert(mfa, "Expected a challenge from verification, but got none");
|
|
28
|
+
writeCookies([makePendingAuthCookie(mfa.challengeToken)]);
|
|
29
|
+
return {
|
|
30
|
+
success: true,
|
|
31
|
+
data: {
|
|
32
|
+
status: "authenticatorRequired",
|
|
33
|
+
step: mfa.action === "VERIFICATION_REQUIRED" ? "verify" : mfa.action === "SETUP_REQUIRED" ? "setup" : "setupOptional"
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
const { session } = result.data;
|
|
38
|
+
assert(session, "Expected a session from verification, but got none");
|
|
39
|
+
writeCookies([...makeSessionTokenCookie(session.jwt), makeSessionDataCookie({
|
|
40
|
+
user: session.user,
|
|
41
|
+
permissions: session.permissions
|
|
42
|
+
}, session.jwt)]);
|
|
43
|
+
clearPendingAuth();
|
|
44
|
+
return {
|
|
45
|
+
success: true,
|
|
46
|
+
data: {
|
|
47
|
+
status: "signedIn",
|
|
48
|
+
user: session.user
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Emails the code for {@link verifyEmailCode} again. Asking again within a
|
|
54
|
+
* short wait sends nothing and still succeeds.
|
|
55
|
+
*/
|
|
56
|
+
async function resendEmailCode() {
|
|
57
|
+
const result = await makePlatform(sessionConfig().applicationId).emailCodeResend(readPendingAuthToken());
|
|
58
|
+
if (!result.ok) {
|
|
59
|
+
if (result.status === 401) return authError("notAuthenticated", result.message);
|
|
60
|
+
if (result.status === 429) return authError("tooManyAttempts", result.message);
|
|
61
|
+
if (result.status >= 500) panic(`Expected the code to be emailed again, but got ${result.status}: ` + result.message);
|
|
62
|
+
throw new Error(`${result.message}. Check SOFTR_APPLICATION_ID and that the app asks for an emailed code at sign-in.`);
|
|
63
|
+
}
|
|
64
|
+
return {
|
|
65
|
+
success: true,
|
|
66
|
+
data: null
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
//#endregion
|
|
71
|
+
export { resendEmailCode, verifyEmailCode };
|
|
@@ -8,7 +8,8 @@ import { AuthError, Result } from "./utils.js";
|
|
|
8
8
|
*
|
|
9
9
|
* A `signedIn` result means the visitor is signed in. An app that also asks for
|
|
10
10
|
* an authenticator app answers `authenticatorRequired` instead, naming the step
|
|
11
|
-
* to send them to next.
|
|
11
|
+
* to send them to next. An app that also asks for an emailed code answers
|
|
12
|
+
* `emailCodeRequired`; `verifyEmailCode` finishes it.
|
|
12
13
|
*/
|
|
13
14
|
declare function signIn(credentials: {
|
|
14
15
|
email: string;
|
|
@@ -24,6 +25,8 @@ declare function signIn(credentials: {
|
|
|
24
25
|
* `setupOptional`: same, except they may skip it instead.
|
|
25
26
|
*/
|
|
26
27
|
step: "verify" | "setup" | "setupOptional";
|
|
28
|
+
} | {
|
|
29
|
+
status: "emailCodeRequired";
|
|
27
30
|
}, AuthError>>;
|
|
28
31
|
/**
|
|
29
32
|
* Signs the visitor out.
|
|
@@ -11,7 +11,8 @@ import { authError } from "./utils.js";
|
|
|
11
11
|
*
|
|
12
12
|
* A `signedIn` result means the visitor is signed in. An app that also asks for
|
|
13
13
|
* an authenticator app answers `authenticatorRequired` instead, naming the step
|
|
14
|
-
* to send them to next.
|
|
14
|
+
* to send them to next. An app that also asks for an emailed code answers
|
|
15
|
+
* `emailCodeRequired`; `verifyEmailCode` finishes it.
|
|
15
16
|
*/
|
|
16
17
|
async function signIn(credentials) {
|
|
17
18
|
const result = await makePlatform(sessionConfig().applicationId).tokens(credentials);
|
|
@@ -25,6 +26,10 @@ async function signIn(credentials) {
|
|
|
25
26
|
const { mfa } = result.data;
|
|
26
27
|
assert(mfa, "Expected a challenge from sign-in, but got none");
|
|
27
28
|
writeCookies([makePendingAuthCookie(mfa.challengeToken)]);
|
|
29
|
+
if (mfa.action === "EMAIL_CODE_REQUIRED") return {
|
|
30
|
+
success: true,
|
|
31
|
+
data: { status: "emailCodeRequired" }
|
|
32
|
+
};
|
|
28
33
|
return {
|
|
29
34
|
success: true,
|
|
30
35
|
data: {
|
package/dist/auth/platform.js
CHANGED
|
@@ -71,6 +71,27 @@ function makePlatform(applicationId) {
|
|
|
71
71
|
tokens: (credentials) => request(`/v1/vibe/applications/${applicationId}/users/tokens${withAttributes}`, {
|
|
72
72
|
method: "POST",
|
|
73
73
|
json: credentials
|
|
74
|
+
}, z.object({
|
|
75
|
+
status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
|
|
76
|
+
session: z.object({
|
|
77
|
+
jwt: z.string(),
|
|
78
|
+
user: userSchema,
|
|
79
|
+
permissions: permissionsSchema
|
|
80
|
+
}).nullish(),
|
|
81
|
+
mfa: z.object({
|
|
82
|
+
action: z.enum([
|
|
83
|
+
"VERIFICATION_REQUIRED",
|
|
84
|
+
"SETUP_REQUIRED",
|
|
85
|
+
"SETUP_OPTIONAL",
|
|
86
|
+
"EMAIL_CODE_REQUIRED"
|
|
87
|
+
]),
|
|
88
|
+
challengeToken: z.string()
|
|
89
|
+
}).nullish()
|
|
90
|
+
})),
|
|
91
|
+
emailCodeVerify: (token, code) => request(`/v1/vibe/applications/${applicationId}/users/tokens/email-code/verify${withAttributes}`, {
|
|
92
|
+
method: "POST",
|
|
93
|
+
token,
|
|
94
|
+
json: { code }
|
|
74
95
|
}, z.object({
|
|
75
96
|
status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
|
|
76
97
|
session: z.object({
|
|
@@ -87,6 +108,10 @@ function makePlatform(applicationId) {
|
|
|
87
108
|
challengeToken: z.string()
|
|
88
109
|
}).nullish()
|
|
89
110
|
})),
|
|
111
|
+
emailCodeResend: (token) => request(`/v1/vibe/applications/${applicationId}/users/tokens/email-code/resend`, {
|
|
112
|
+
method: "POST",
|
|
113
|
+
token
|
|
114
|
+
}, z.null()),
|
|
90
115
|
sendSignInCode: (email) => request(`/v1/vibe/applications/${applicationId}/users/tokens/send-code`, {
|
|
91
116
|
method: "POST",
|
|
92
117
|
json: { email }
|
package/dist/auth/server.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { confirmAuthenticatorSetup, removeAuthenticator, resetAuthenticator, sendAuthenticatorResetCode, skipAuthenticatorSetup, startAuthenticatorSetup, verifyAuthenticator } from "./methods/authenticator.js";
|
|
2
2
|
import { sendSignInCode, signInWithCode } from "./methods/code.js";
|
|
3
|
+
import { resendEmailCode, verifyEmailCode } from "./methods/emailCode2fa.js";
|
|
3
4
|
import { signInWithMagicLink } from "./methods/magicLink.js";
|
|
4
5
|
import { signIn, signOut } from "./methods/password.js";
|
|
5
6
|
import { checkPasswordLink, requestPasswordReset, setPasswordWithLink } from "./methods/passwordLink.js";
|
|
@@ -34,6 +35,8 @@ declare const auth: {
|
|
|
34
35
|
sendAuthenticatorResetCode: typeof sendAuthenticatorResetCode;
|
|
35
36
|
resetAuthenticator: typeof resetAuthenticator;
|
|
36
37
|
removeAuthenticator: typeof removeAuthenticator;
|
|
38
|
+
verifyEmailCode: typeof verifyEmailCode;
|
|
39
|
+
resendEmailCode: typeof resendEmailCode;
|
|
37
40
|
settings: typeof settings;
|
|
38
41
|
updateProfile: typeof updateProfile;
|
|
39
42
|
removeAvatar: typeof removeAvatar;
|
package/dist/auth/server.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { settings } from "./methods/settings.js";
|
|
2
2
|
import { confirmAuthenticatorSetup, removeAuthenticator, resetAuthenticator, sendAuthenticatorResetCode, skipAuthenticatorSetup, startAuthenticatorSetup, verifyAuthenticator } from "./methods/authenticator.js";
|
|
3
3
|
import { sendSignInCode, signInWithCode } from "./methods/code.js";
|
|
4
|
+
import { resendEmailCode, verifyEmailCode } from "./methods/emailCode2fa.js";
|
|
4
5
|
import { signInWithMagicLink } from "./methods/magicLink.js";
|
|
5
6
|
import { signIn, signOut } from "./methods/password.js";
|
|
6
7
|
import { checkPasswordLink, requestPasswordReset, setPasswordWithLink } from "./methods/passwordLink.js";
|
|
@@ -33,6 +34,8 @@ const auth = {
|
|
|
33
34
|
sendAuthenticatorResetCode,
|
|
34
35
|
resetAuthenticator,
|
|
35
36
|
removeAuthenticator,
|
|
37
|
+
verifyEmailCode,
|
|
38
|
+
resendEmailCode,
|
|
36
39
|
settings,
|
|
37
40
|
updateProfile,
|
|
38
41
|
removeAvatar,
|
|
@@ -64,7 +64,11 @@ function DevView({ error, reset }) {
|
|
|
64
64
|
reset,
|
|
65
65
|
router
|
|
66
66
|
]);
|
|
67
|
-
|
|
67
|
+
const shown = !running && !retryPending;
|
|
68
|
+
useEffect(() => {
|
|
69
|
+
if (shown) reportError(error);
|
|
70
|
+
}, [shown, error]);
|
|
71
|
+
if (!shown) return /* @__PURE__ */ jsx(UpdatingView, {});
|
|
68
72
|
return /* @__PURE__ */ jsx("div", {
|
|
69
73
|
style: s.overlay,
|
|
70
74
|
"data-softr-error-overlay": "error",
|
package/dist/package.js
CHANGED
package/package.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: ai
|
|
3
3
|
description: >-
|
|
4
|
-
Run an AI model from the app on Softr's own keys, billed to the workspace's
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
4
|
+
Run an AI model from the app on Softr's own keys, billed to the workspace's AI
|
|
5
|
+
credits, with nothing to connect: defineAiAction from @softr/sdk declares the
|
|
6
|
+
action with the catalog model it runs on and its permissions; ai.generate from
|
|
7
|
+
@softr/sdk/server runs it with a system text, a prompt, an optional JSON
|
|
8
|
+
schema for an answer that is data, and optional files; ai.stream runs it for
|
|
9
|
+
an answer the user watches being written. Load this for a summary, an
|
|
10
|
+
extraction, a classification, a draft, or a chat the app asks a model for,
|
|
11
|
+
before you decide whether a feature runs on Softr AI or on the user's own
|
|
12
|
+
account, and before you change the model it runs on.
|
|
13
13
|
metadata:
|
|
14
14
|
type: sub-skill
|
|
15
15
|
library: softr-sdk
|
|
16
|
-
library_version: 0.0.
|
|
16
|
+
library_version: 0.0.95
|
|
17
17
|
---
|
|
18
18
|
|
|
19
19
|
**Boundary.** `ai` lives on `@softr/sdk/server` and runs only inside a `createServerFn` handler — importing it into a component fails the build. `defineAiAction` and every type come from `@softr/sdk` and can be imported anywhere.
|
|
@@ -3,13 +3,13 @@ name: auth
|
|
|
3
3
|
description: >-
|
|
4
4
|
Sign a visitor in, out or up from a server function with auth from
|
|
5
5
|
@softr/sdk/server: password, code, Google and magic link, sign-up and its
|
|
6
|
-
confirmation, the authenticator-app steps, password reset
|
|
7
|
-
updateProfile, and getAuthSettings and useAuthSettings for the methods
|
|
8
|
-
enables. Covers the Result shape, its error codes, and toReturnPath.
|
|
6
|
+
confirmation, the emailed-code and authenticator-app steps, password reset
|
|
7
|
+
links, updateProfile, and getAuthSettings and useAuthSettings for the methods
|
|
8
|
+
the app enables. Covers the Result shape, its error codes, and toReturnPath.
|
|
9
9
|
metadata:
|
|
10
10
|
type: sub-skill
|
|
11
11
|
library: softr-sdk
|
|
12
|
-
library_version: 0.0.
|
|
12
|
+
library_version: 0.0.95
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
**Boundary.** `auth` lives on `@softr/sdk/server` and runs only inside a `createServerFn` handler — importing it into a component fails the build.
|
|
@@ -55,6 +55,13 @@ Signing out:
|
|
|
55
55
|
| --- | --- |
|
|
56
56
|
| `auth.signOut()` | Ends every session that visitor has in this app, on every device |
|
|
57
57
|
|
|
58
|
+
Finishing a sign-in that wants a code from the visitor's inbox:
|
|
59
|
+
|
|
60
|
+
| Call | Does |
|
|
61
|
+
| --- | --- |
|
|
62
|
+
| `auth.verifyEmailCode({ code })` | Answers it with the code that was emailed |
|
|
63
|
+
| `auth.resendEmailCode()` | Emails that code again |
|
|
64
|
+
|
|
58
65
|
Finishing a sign-in that wants an authenticator app:
|
|
59
66
|
|
|
60
67
|
| Call | Does |
|
|
@@ -197,6 +204,8 @@ Those calls take only what the visitor typed. The sign-in they finish is the one
|
|
|
197
204
|
|
|
198
205
|
An app with no authenticator app configured never answers `authenticatorRequired`. The type still has both arms either way, so `result.data.user` does not exist until you have narrowed on `status`.
|
|
199
206
|
|
|
207
|
+
`signIn` has a third answer, `{ status: 'emailCodeRequired' }`, for an app that asks a password sign-in for a code from the visitor's inbox as well. The code is already on its way. Show a code field as the next step and finish with `auth.verifyEmailCode({ code })`, see [Finishing a sign-in that needs an emailed code](#finishing-a-sign-in-that-needs-an-emailed-code). That call answers like `signIn` does, so an app that also wants an authenticator app goes on to that step after it.
|
|
208
|
+
|
|
200
209
|
## Landing after sign-in
|
|
201
210
|
|
|
202
211
|
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:
|
|
@@ -255,10 +264,13 @@ if (answer.message !== null) return setMessage(answer.message)
|
|
|
255
264
|
if (answer.outcome.status === 'authenticatorRequired') {
|
|
256
265
|
return setStep({ name: 'secondFactor', opensOn: answer.outcome.step })
|
|
257
266
|
}
|
|
267
|
+
if (answer.outcome.status === 'emailCodeRequired') {
|
|
268
|
+
return setStep({ name: 'emailCode' })
|
|
269
|
+
}
|
|
258
270
|
await navigate({ href: target })
|
|
259
271
|
```
|
|
260
272
|
|
|
261
|
-
|
|
273
|
+
Four exits: a message for the form to render, the emailed-code step, the authenticator step, the return target.
|
|
262
274
|
|
|
263
275
|
A server function that throws `redirect` needs the hook. Call the imported function directly and the throw never reaches the router, so a successful sign-in leaves the visitor on the form.
|
|
264
276
|
|
|
@@ -385,6 +397,22 @@ The UI has to carry email into step two, plus the name if step one collected one
|
|
|
385
397
|
|
|
386
398
|
`password` is what the account is created with. Leave it out only for an app that signs people in with an emailed code. An app that expects a password rejects a sign-up without one, and an app that does not expect one rejects a sign-up that sends it.
|
|
387
399
|
|
|
400
|
+
### Finishing a sign-in that needs an emailed code
|
|
401
|
+
|
|
402
|
+
After `signIn` answers `emailCodeRequired`, the visitor owes the code that was just emailed to them:
|
|
403
|
+
|
|
404
|
+
```ts
|
|
405
|
+
// invalidCode for a wrong or expired code, otherwise the same two-armed result as signIn.
|
|
406
|
+
const result = await auth.verifyEmailCode({ code })
|
|
407
|
+
|
|
408
|
+
// For a "Resend code" link.
|
|
409
|
+
const sent = await auth.resendEmailCode()
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
Send `authenticatorRequired` on to the authenticator step, never into the app.
|
|
413
|
+
|
|
414
|
+
Asking for a resend too soon sends nothing and still succeeds. It answers `notAuthenticated` once the sign-in has run out of time, and the visitor then signs in again from the start.
|
|
415
|
+
|
|
388
416
|
### Finishing a sign-in that needs an authenticator app
|
|
389
417
|
|
|
390
418
|
On `step: 'verify'` the visitor already has an app, and owes a code from it:
|
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
metadata:
|
|
10
10
|
type: sub-skill
|
|
11
11
|
library: softr-sdk
|
|
12
|
-
library_version: 0.0.
|
|
12
|
+
library_version: 0.0.95
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
**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.
|
|
@@ -7,7 +7,7 @@ description: >-
|
|
|
7
7
|
metadata:
|
|
8
8
|
type: sub-skill
|
|
9
9
|
library: softr-sdk
|
|
10
|
-
library_version: 0.0.
|
|
10
|
+
library_version: 0.0.95
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
**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.
|
|
@@ -7,7 +7,7 @@ description: >-
|
|
|
7
7
|
metadata:
|
|
8
8
|
type: sub-skill
|
|
9
9
|
library: softr-sdk
|
|
10
|
-
library_version: 0.0.
|
|
10
|
+
library_version: 0.0.95
|
|
11
11
|
---
|
|
12
12
|
|
|
13
13
|
**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.
|
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
metadata:
|
|
10
10
|
type: sub-skill
|
|
11
11
|
library: softr-sdk
|
|
12
|
-
library_version: 0.0.
|
|
12
|
+
library_version: 0.0.95
|
|
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.
|
|
@@ -8,7 +8,7 @@ description: >-
|
|
|
8
8
|
metadata:
|
|
9
9
|
type: sub-skill
|
|
10
10
|
library: softr-sdk
|
|
11
|
-
library_version: 0.0.
|
|
11
|
+
library_version: 0.0.95
|
|
12
12
|
---
|
|
13
13
|
|
|
14
14
|
**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.
|
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
metadata:
|
|
10
10
|
type: sub-skill
|
|
11
11
|
library: softr-sdk
|
|
12
|
-
library_version: 0.0.
|
|
12
|
+
library_version: 0.0.95
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
**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.
|
|
@@ -3,13 +3,13 @@ name: routes-and-visibility
|
|
|
3
3
|
description: >-
|
|
4
4
|
Add a route file and declare its settings: definePage with its visibility
|
|
5
5
|
(LOGGED_IN_USERS, NON_LOGGED_IN_USERS and customGroups) and its title,
|
|
6
|
-
guardRoute or assertRouteAccess in beforeLoad, pageHead in head,
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
guardRoute or assertRouteAccess in beforeLoad, pageHead in head, isAuthorized
|
|
7
|
+
and checkAccess anywhere, rendering an access error, and the lint rules that
|
|
8
|
+
require the declaration.
|
|
9
9
|
metadata:
|
|
10
10
|
type: sub-skill
|
|
11
11
|
library: softr-sdk
|
|
12
|
-
library_version: 0.0.
|
|
12
|
+
library_version: 0.0.95
|
|
13
13
|
---
|
|
14
14
|
|
|
15
15
|
**Boundary.** `definePage`, `pageHead`, the access functions and the error predicates come from `@softr/sdk` and work anywhere.
|
|
@@ -9,7 +9,7 @@ description: >-
|
|
|
9
9
|
metadata:
|
|
10
10
|
type: sub-skill
|
|
11
11
|
library: softr-sdk
|
|
12
|
-
library_version: 0.0.
|
|
12
|
+
library_version: 0.0.95
|
|
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.
|