@softr/sdk 0.0.92-emailotc.0 → 0.0.92
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/app-identity.js +25 -0
- package/dist/auth/isomorphic.d.ts +1 -1
- package/dist/auth/isomorphic.js +2 -0
- package/dist/auth/methods/password.d.ts +1 -4
- package/dist/auth/methods/password.js +1 -6
- package/dist/auth/platform.js +0 -25
- package/dist/auth/server.d.ts +0 -3
- package/dist/auth/server.js +0 -3
- package/dist/default-error-overlay.d.ts +2 -2
- package/dist/formatting.d.ts +3 -3
- package/dist/mcp.d.ts +2 -2
- package/dist/package.js +1 -1
- package/dist/pwa.d.ts +2 -2
- package/package.json +10 -33
- package/skills/softr-sdk/SKILL.md +1 -1
- package/skills/softr-sdk/ai/SKILL.md +1 -1
- package/skills/softr-sdk/auth/SKILL.md +3 -31
- 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 +1 -1
- package/skills/softr-sdk/workflows/SKILL.md +1 -1
- package/dist/auth/methods/emailCode2fa.d.ts +0 -34
- package/dist/auth/methods/emailCode2fa.js +0 -71
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { createMiddleware } from "@tanstack/react-start";
|
|
2
|
+
|
|
3
|
+
//#region src/app-identity.ts
|
|
4
|
+
/**
|
|
5
|
+
* Tells support which Softr app answered, in an `x-softr-app-id` response
|
|
6
|
+
* header.
|
|
7
|
+
*/
|
|
8
|
+
function appIdentityMiddleware() {
|
|
9
|
+
return createMiddleware({ type: "request" }).server(async ({ next }) => {
|
|
10
|
+
const result = await next();
|
|
11
|
+
const applicationId = process.env.SOFTR_APPLICATION_ID;
|
|
12
|
+
if (!applicationId) return result;
|
|
13
|
+
try {
|
|
14
|
+
result.response.headers.set("x-softr-app-id", applicationId);
|
|
15
|
+
return result;
|
|
16
|
+
} catch {
|
|
17
|
+
const response = new Response(result.response.body, result.response);
|
|
18
|
+
response.headers.set("x-softr-app-id", applicationId);
|
|
19
|
+
return response;
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
//#endregion
|
|
25
|
+
export { appIdentityMiddleware };
|
|
@@ -22,7 +22,7 @@ import * as _tanstack_react_start0 from "@tanstack/react-start";
|
|
|
22
22
|
* requestMiddleware: [softrAuthMiddleware()],
|
|
23
23
|
* }))
|
|
24
24
|
*/
|
|
25
|
-
declare function softrAuthMiddleware(): _tanstack_react_start0.RequestMiddlewareAfterServer<{}, readonly [_tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>, _tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>, _tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>, _tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>], {
|
|
25
|
+
declare function softrAuthMiddleware(): _tanstack_react_start0.RequestMiddlewareAfterServer<{}, readonly [_tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>, _tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>, _tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>, _tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>, _tanstack_react_start0.RequestMiddlewareAfterServer<{}, undefined, undefined>], {
|
|
26
26
|
user: User | null;
|
|
27
27
|
permissions: Permissions;
|
|
28
28
|
formatting: Formatting;
|
package/dist/auth/isomorphic.js
CHANGED
|
@@ -10,6 +10,7 @@ import { bootErrorMiddleware } from "../boot-error.js";
|
|
|
10
10
|
import { pwaMiddleware } from "../pwa.js";
|
|
11
11
|
import { faviconMiddleware } from "../favicon.js";
|
|
12
12
|
import { embeddingMiddleware } from "../embedding.js";
|
|
13
|
+
import { appIdentityMiddleware } from "../app-identity.js";
|
|
13
14
|
import { createContext, useContext } from "react";
|
|
14
15
|
import { createMiddleware, createServerFn, getGlobalStartContext } from "@tanstack/react-start";
|
|
15
16
|
import { getRequestHeader } from "@tanstack/react-start/server";
|
|
@@ -34,6 +35,7 @@ import { jsx } from "react/jsx-runtime";
|
|
|
34
35
|
function softrAuthMiddleware() {
|
|
35
36
|
return createMiddleware({ type: "request" }).middleware([
|
|
36
37
|
embeddingMiddleware(),
|
|
38
|
+
appIdentityMiddleware(),
|
|
37
39
|
bootErrorMiddleware(),
|
|
38
40
|
pwaMiddleware(),
|
|
39
41
|
faviconMiddleware()
|
|
@@ -8,8 +8,7 @@ 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.
|
|
12
|
-
* `emailCodeRequired`; `verifyEmailCode` finishes it.
|
|
11
|
+
* to send them to next.
|
|
13
12
|
*/
|
|
14
13
|
declare function signIn(credentials: {
|
|
15
14
|
email: string;
|
|
@@ -25,8 +24,6 @@ declare function signIn(credentials: {
|
|
|
25
24
|
* `setupOptional`: same, except they may skip it instead.
|
|
26
25
|
*/
|
|
27
26
|
step: "verify" | "setup" | "setupOptional";
|
|
28
|
-
} | {
|
|
29
|
-
status: "emailCodeRequired";
|
|
30
27
|
}, AuthError>>;
|
|
31
28
|
/**
|
|
32
29
|
* Signs the visitor out.
|
|
@@ -11,8 +11,7 @@ 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.
|
|
15
|
-
* `emailCodeRequired`; `verifyEmailCode` finishes it.
|
|
14
|
+
* to send them to next.
|
|
16
15
|
*/
|
|
17
16
|
async function signIn(credentials) {
|
|
18
17
|
const result = await makePlatform(sessionConfig().applicationId).tokens(credentials);
|
|
@@ -26,10 +25,6 @@ async function signIn(credentials) {
|
|
|
26
25
|
const { mfa } = result.data;
|
|
27
26
|
assert(mfa, "Expected a challenge from sign-in, but got none");
|
|
28
27
|
writeCookies([makePendingAuthCookie(mfa.challengeToken)]);
|
|
29
|
-
if (mfa.action === "EMAIL_CODE_REQUIRED") return {
|
|
30
|
-
success: true,
|
|
31
|
-
data: { status: "emailCodeRequired" }
|
|
32
|
-
};
|
|
33
28
|
return {
|
|
34
29
|
success: true,
|
|
35
30
|
data: {
|
package/dist/auth/platform.js
CHANGED
|
@@ -71,27 +71,6 @@ 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 }
|
|
95
74
|
}, z.object({
|
|
96
75
|
status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
|
|
97
76
|
session: z.object({
|
|
@@ -108,10 +87,6 @@ function makePlatform(applicationId) {
|
|
|
108
87
|
challengeToken: z.string()
|
|
109
88
|
}).nullish()
|
|
110
89
|
})),
|
|
111
|
-
emailCodeResend: (token) => request(`/v1/vibe/applications/${applicationId}/users/tokens/email-code/resend`, {
|
|
112
|
-
method: "POST",
|
|
113
|
-
token
|
|
114
|
-
}, z.null()),
|
|
115
90
|
sendSignInCode: (email) => request(`/v1/vibe/applications/${applicationId}/users/tokens/send-code`, {
|
|
116
91
|
method: "POST",
|
|
117
92
|
json: { email }
|
package/dist/auth/server.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
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";
|
|
4
3
|
import { signInWithMagicLink } from "./methods/magicLink.js";
|
|
5
4
|
import { signIn, signOut } from "./methods/password.js";
|
|
6
5
|
import { checkPasswordLink, requestPasswordReset, setPasswordWithLink } from "./methods/passwordLink.js";
|
|
@@ -35,8 +34,6 @@ declare const auth: {
|
|
|
35
34
|
sendAuthenticatorResetCode: typeof sendAuthenticatorResetCode;
|
|
36
35
|
resetAuthenticator: typeof resetAuthenticator;
|
|
37
36
|
removeAuthenticator: typeof removeAuthenticator;
|
|
38
|
-
verifyEmailCode: typeof verifyEmailCode;
|
|
39
|
-
resendEmailCode: typeof resendEmailCode;
|
|
40
37
|
settings: typeof settings;
|
|
41
38
|
updateProfile: typeof updateProfile;
|
|
42
39
|
removeAvatar: typeof removeAvatar;
|
package/dist/auth/server.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
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";
|
|
5
4
|
import { signInWithMagicLink } from "./methods/magicLink.js";
|
|
6
5
|
import { signIn, signOut } from "./methods/password.js";
|
|
7
6
|
import { checkPasswordLink, requestPasswordReset, setPasswordWithLink } from "./methods/passwordLink.js";
|
|
@@ -34,8 +33,6 @@ const auth = {
|
|
|
34
33
|
sendAuthenticatorResetCode,
|
|
35
34
|
resetAuthenticator,
|
|
36
35
|
removeAuthenticator,
|
|
37
|
-
verifyEmailCode,
|
|
38
|
-
resendEmailCode,
|
|
39
36
|
settings,
|
|
40
37
|
updateProfile,
|
|
41
38
|
removeAvatar,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react6 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): react6.JSX.Element;
|
|
12
12
|
//#endregion
|
|
13
13
|
export { DefaultErrorOverlay };
|
package/dist/formatting.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react0 from "react";
|
|
3
3
|
import { ReactNode } from "react";
|
|
4
4
|
|
|
5
5
|
//#region src/formatting.d.ts
|
|
@@ -94,7 +94,7 @@ declare function FormattingScope({
|
|
|
94
94
|
/** A BCP 47 locale, such as `de-DE`. It drops the app's fixed date format inside the scope. */
|
|
95
95
|
locale?: string;
|
|
96
96
|
children?: ReactNode;
|
|
97
|
-
}):
|
|
97
|
+
}): react0.FunctionComponentElement<react0.ProviderProps<Scope>>;
|
|
98
98
|
/**
|
|
99
99
|
* A date in the app's format, safe to render on the server. A timestamp whose
|
|
100
100
|
* zone is not known yet renders `fallback` until the browser supplies it, so
|
|
@@ -115,6 +115,6 @@ declare function FormattedDate({
|
|
|
115
115
|
time?: boolean;
|
|
116
116
|
/** What renders while the visitor's zone is unknown. */
|
|
117
117
|
fallback?: ReactNode;
|
|
118
|
-
}):
|
|
118
|
+
}): react0.FunctionComponentElement<react0.FragmentProps>;
|
|
119
119
|
//#endregion
|
|
120
120
|
export { DateOptions, DateParts, DateSeparator, DateValue, FixedDateFormat, FormattedDate, Formatting, FormattingScope, WeekDay, formatDate, formatDateTime, formatNumber, useFormatting };
|
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_start7 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_start7.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 react4 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(): react4.FunctionComponentElement<react4.FragmentProps>;
|
|
27
27
|
type PwaPlatform = "ios" | "android" | "desktop";
|
|
28
28
|
type PwaInstall = {
|
|
29
29
|
available: false;
|
package/package.json
CHANGED
|
@@ -1,37 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@softr/sdk",
|
|
3
|
-
"version": "0.0.92
|
|
3
|
+
"version": "0.0.92",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"exports": {
|
|
6
|
-
".": {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"./server": {
|
|
15
|
-
"types": "./dist/server.d.ts",
|
|
16
|
-
"import": "./dist/server.js"
|
|
17
|
-
},
|
|
18
|
-
"./vite": {
|
|
19
|
-
"types": "./dist/vite.d.ts",
|
|
20
|
-
"import": "./dist/vite.js"
|
|
21
|
-
}
|
|
22
|
-
},
|
|
23
|
-
"bin": {
|
|
24
|
-
"softr-sdk": "./dist/cli.js"
|
|
25
|
-
},
|
|
26
|
-
"files": [
|
|
27
|
-
"dist",
|
|
28
|
-
"schema",
|
|
29
|
-
"skills",
|
|
30
|
-
"!skills/_artifacts"
|
|
31
|
-
],
|
|
32
|
-
"publishConfig": {
|
|
33
|
-
"access": "public"
|
|
34
|
-
},
|
|
6
|
+
".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" },
|
|
7
|
+
"./client": { "types": "./dist/client.d.ts", "import": "./dist/client.js" },
|
|
8
|
+
"./server": { "types": "./dist/server.d.ts", "import": "./dist/server.js" },
|
|
9
|
+
"./vite": { "types": "./dist/vite.d.ts", "import": "./dist/vite.js" }
|
|
10
|
+
},
|
|
11
|
+
"bin": { "softr-sdk": "./dist/cli.js" },
|
|
12
|
+
"files": ["dist", "schema", "skills", "!skills/_artifacts"],
|
|
13
|
+
"publishConfig": { "access": "public" },
|
|
35
14
|
"scripts": {
|
|
36
15
|
"build": "tsdown",
|
|
37
16
|
"test": "node --import ./src/test-utils/setup.ts --test",
|
|
@@ -63,9 +42,7 @@
|
|
|
63
42
|
"optional": true
|
|
64
43
|
}
|
|
65
44
|
},
|
|
66
|
-
"keywords": [
|
|
67
|
-
"tanstack-intent"
|
|
68
|
-
],
|
|
45
|
+
"keywords": ["tanstack-intent"],
|
|
69
46
|
"intent": {
|
|
70
47
|
"version": 1,
|
|
71
48
|
"repo": "@softr/sdk",
|
|
@@ -13,7 +13,7 @@ description: >-
|
|
|
13
13
|
metadata:
|
|
14
14
|
type: sub-skill
|
|
15
15
|
library: softr-sdk
|
|
16
|
-
library_version: 0.0.
|
|
16
|
+
library_version: 0.0.92
|
|
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
|
|
6
|
+
confirmation, the authenticator-app steps, password reset links,
|
|
7
7
|
updateProfile, and getAuthSettings and useAuthSettings for the methods the app
|
|
8
8
|
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.92
|
|
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,13 +55,6 @@ 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
|
-
|
|
65
58
|
Finishing a sign-in that wants an authenticator app:
|
|
66
59
|
|
|
67
60
|
| Call | Does |
|
|
@@ -204,8 +197,6 @@ Those calls take only what the visitor typed. The sign-in they finish is the one
|
|
|
204
197
|
|
|
205
198
|
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`.
|
|
206
199
|
|
|
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
|
-
|
|
209
200
|
## Landing after sign-in
|
|
210
201
|
|
|
211
202
|
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:
|
|
@@ -264,13 +255,10 @@ if (answer.message !== null) return setMessage(answer.message)
|
|
|
264
255
|
if (answer.outcome.status === 'authenticatorRequired') {
|
|
265
256
|
return setStep({ name: 'secondFactor', opensOn: answer.outcome.step })
|
|
266
257
|
}
|
|
267
|
-
if (answer.outcome.status === 'emailCodeRequired') {
|
|
268
|
-
return setStep({ name: 'emailCode' })
|
|
269
|
-
}
|
|
270
258
|
await navigate({ href: target })
|
|
271
259
|
```
|
|
272
260
|
|
|
273
|
-
|
|
261
|
+
Three exits: a message for the form to render, the second-factor step, the return target.
|
|
274
262
|
|
|
275
263
|
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.
|
|
276
264
|
|
|
@@ -397,22 +385,6 @@ The UI has to carry email into step two, plus the name if step one collected one
|
|
|
397
385
|
|
|
398
386
|
`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.
|
|
399
387
|
|
|
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
|
-
|
|
416
388
|
### Finishing a sign-in that needs an authenticator app
|
|
417
389
|
|
|
418
390
|
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.92
|
|
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.92
|
|
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.92
|
|
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.92
|
|
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.92
|
|
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.92
|
|
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.
|
|
@@ -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.92
|
|
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.92
|
|
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.
|
|
@@ -1,34 +0,0 @@
|
|
|
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 };
|
|
@@ -1,71 +0,0 @@
|
|
|
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 };
|