@softr/sdk 0.0.63-alpha.0 → 0.0.64-alpha.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 (56) hide show
  1. package/dist/action.d.ts +1 -31
  2. package/dist/action.js +1 -26
  3. package/dist/auth/isomorphic.d.ts +60 -1
  4. package/dist/auth/isomorphic.js +63 -5
  5. package/dist/auth/methods/passwordLink.d.ts +47 -0
  6. package/dist/auth/methods/passwordLink.js +86 -0
  7. package/dist/auth/methods/settings.d.ts +11 -0
  8. package/dist/auth/methods/settings.js +17 -0
  9. package/dist/auth/methods/signup.js +1 -0
  10. package/dist/auth/methods/social.js +1 -0
  11. package/dist/auth/methods/utils.d.ts +1 -1
  12. package/dist/auth/platform.d.ts +46 -0
  13. package/dist/auth/platform.js +54 -0
  14. package/dist/auth/server.d.ts +6 -0
  15. package/dist/auth/server.js +7 -1
  16. package/dist/client.d.ts +1 -2
  17. package/dist/client.js +1 -2
  18. package/dist/core/file-upload.d.ts +2 -7
  19. package/dist/core/file-upload.js +1 -6
  20. package/dist/core/use-file-upload.d.ts +2 -2
  21. package/dist/datasource/record.js +11 -5
  22. package/dist/default-error-overlay.d.ts +2 -2
  23. package/dist/formatting.d.ts +3 -3
  24. package/dist/index.d.ts +5 -5
  25. package/dist/index.js +4 -4
  26. package/dist/mcp.d.ts +2 -8
  27. package/dist/mcp.js +8 -8
  28. package/dist/package.js +1 -1
  29. package/dist/pwa.d.ts +2 -2
  30. package/dist/server.d.ts +1 -2
  31. package/dist/server.js +1 -2
  32. package/dist/softr-config.d.ts +1 -0
  33. package/dist/softr-config.js +26 -5
  34. package/dist/visibility/route.d.ts +26 -6
  35. package/dist/visibility/route.js +36 -13
  36. package/package.json +33 -12
  37. package/schema/softr.schema.json +42 -1
  38. package/skills/softr-sdk/SKILL.md +7 -10
  39. package/skills/softr-sdk/auth/SKILL.md +129 -31
  40. package/skills/softr-sdk/charts-and-metrics/SKILL.md +1 -1
  41. package/skills/softr-sdk/current-user/SKILL.md +1 -1
  42. package/skills/softr-sdk/file-uploads/SKILL.md +4 -5
  43. package/skills/softr-sdk/formatting/SKILL.md +4 -4
  44. package/skills/softr-sdk/integrations/SKILL.md +1 -1
  45. package/skills/softr-sdk/mcp/SKILL.md +7 -14
  46. package/skills/softr-sdk/pwa/SKILL.md +3 -3
  47. package/skills/softr-sdk/record-mutations/SKILL.md +1 -1
  48. package/skills/softr-sdk/record-queries/SKILL.md +1 -1
  49. package/skills/softr-sdk/region-visibility/SKILL.md +1 -1
  50. package/skills/softr-sdk/routes-and-visibility/SKILL.md +24 -12
  51. package/skills/softr-sdk/workflows/SKILL.md +1 -1
  52. package/dist/comments/comments.d.ts +0 -168
  53. package/dist/comments/comments.js +0 -413
  54. package/dist/comments/use-comment-composer.d.ts +0 -46
  55. package/dist/comments/use-comment-composer.js +0 -134
  56. package/skills/softr-sdk/comments/SKILL.md +0 -181
package/dist/action.d.ts CHANGED
@@ -234,35 +234,5 @@ type IntegrationDefinition<TId extends string> = {
234
234
  * const res = await listEvents({ query: { timeMin: now, singleEvents: "true" } })
235
235
  */
236
236
  declare function defineIntegration<const TId extends string>(definition: IntegrationDefinition<TId>): IntegrationAction<TId>;
237
- type CommentsResource = {
238
- type: "COMMENTS";
239
- datasourceId: SoftrDatasourceId;
240
- };
241
- /** Comment threads on the records of one datasource. It has no `permissions`. */
242
- type CommentsAction<TId extends string = string> = {
243
- id: TId;
244
- resource: CommentsResource;
245
- };
246
- type CommentsDefinition<TId extends string> = {
247
- id: TId;
248
- datasourceId: SoftrDatasourceId;
249
- };
250
- /**
251
- * Declares comment threads on the records of a datasource. Each record has one thread.
252
- *
253
- * Who may read, post and delete comes from the app's comment settings in Softr, not from code. Two
254
- * declarations on the same datasource share the same threads.
255
- *
256
- * Pass the returned object to `comments.*` from `@softr/sdk/server`.
257
- *
258
- * @example
259
- * const orderComments = defineComments({
260
- * id: "orderComments",
261
- * datasourceId: "8f14e45f-ceea-467a-9d0b-2c1a0e3b5d77",
262
- * })
263
- *
264
- * const thread = await comments.list(orderComments, { recordId })
265
- */
266
- declare function defineComments<const TId extends string>(definition: CommentsDefinition<TId>): CommentsAction<TId>;
267
237
  //#endregion
268
- export { ActionData, ActionPermissions, ActionRecord, ActionShape, CommentsAction, DatasourceAction, FieldTypeOf, IntegrationAction, ReadOf, ReadShape, SoftrDatasources, WorkflowAction, defineComments, defineIntegration, defineMutation, defineQuery, defineWorkflow };
238
+ export { ActionData, ActionPermissions, ActionRecord, ActionShape, DatasourceAction, FieldTypeOf, IntegrationAction, ReadOf, ReadShape, SoftrDatasources, WorkflowAction, defineIntegration, defineMutation, defineQuery, defineWorkflow };
package/dist/action.js CHANGED
@@ -50,31 +50,6 @@ function defineIntegration(definition) {
50
50
  permissions
51
51
  };
52
52
  }
53
- /**
54
- * Declares comment threads on the records of a datasource. Each record has one thread.
55
- *
56
- * Who may read, post and delete comes from the app's comment settings in Softr, not from code. Two
57
- * declarations on the same datasource share the same threads.
58
- *
59
- * Pass the returned object to `comments.*` from `@softr/sdk/server`.
60
- *
61
- * @example
62
- * const orderComments = defineComments({
63
- * id: "orderComments",
64
- * datasourceId: "8f14e45f-ceea-467a-9d0b-2c1a0e3b5d77",
65
- * })
66
- *
67
- * const thread = await comments.list(orderComments, { recordId })
68
- */
69
- function defineComments(definition) {
70
- return {
71
- id: definition.id,
72
- resource: {
73
- type: "COMMENTS",
74
- datasourceId: definition.datasourceId
75
- }
76
- };
77
- }
78
53
  function isDatasourceAction(value) {
79
54
  if (typeof value !== "object" || value === null) return false;
80
55
  const candidate = value;
@@ -83,4 +58,4 @@ function isDatasourceAction(value) {
83
58
  }
84
59
 
85
60
  //#endregion
86
- export { defineComments, defineIntegration, defineMutation, defineQuery, defineWorkflow, isDatasourceAction };
61
+ export { defineIntegration, defineMutation, defineQuery, defineWorkflow, isDatasourceAction };
@@ -2,6 +2,8 @@ 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 react0 from "react";
6
+ import { ReactNode } from "react";
5
7
  import * as _tanstack_react_start0 from "@tanstack/react-start";
6
8
 
7
9
  //#region src/auth/isomorphic.d.ts
@@ -54,5 +56,62 @@ declare function initialSoftrContext(): SoftrContext;
54
56
  * }
55
57
  */
56
58
  declare function useCurrentUser(): User | null;
59
+ /** Which ways in this app offers, each named for the `auth` call it unlocks. */
60
+ type AuthOptions = {
61
+ /** `auth.signIn` */
62
+ password: boolean;
63
+ /** `auth.sendSignInCode`, then `auth.signInWithCode` */
64
+ emailCode: boolean;
65
+ /** `auth.signInWithMagicLink` */
66
+ magicLink: boolean;
67
+ /** `auth.signInWithGoogle`, with the client id to start Google sign-in with. */
68
+ google: {
69
+ clientId: string;
70
+ } | null;
71
+ /** `auth.signUp`, then `auth.confirmSignUp` */
72
+ signUp: boolean;
73
+ /** The builder asked for strong passwords whenever a visitor sets one. */
74
+ strongPasswords: boolean;
75
+ };
76
+ /**
77
+ * Loads the app's {@link AuthOptions}. Call it from the auth layout's loader
78
+ * and hand the result to {@link AuthSettingsProvider}.
79
+ *
80
+ * @example
81
+ * export const Route = createFileRoute("/_auth")({
82
+ * loader: () => getAuthSettings(),
83
+ * staleTime: 60_000,
84
+ * })
85
+ */
86
+ declare const getAuthSettings: _tanstack_react_start0.OptionalFetcher<undefined, undefined, Promise<AuthOptions>>;
87
+ /**
88
+ * Makes the auth options readable with {@link useAuthSettings} anywhere below.
89
+ *
90
+ * @example
91
+ * function AuthLayout() {
92
+ * const authSettings = Route.useLoaderData()
93
+ * return (
94
+ * <AuthSettingsProvider value={authSettings}>
95
+ * <Outlet />
96
+ * </AuthSettingsProvider>
97
+ * )
98
+ * }
99
+ */
100
+ declare function AuthSettingsProvider({
101
+ value,
102
+ children
103
+ }: {
104
+ value: AuthOptions;
105
+ children?: ReactNode;
106
+ }): react0.JSX.Element;
107
+ /**
108
+ * Which ways in this app offers. Requires an {@link AuthSettingsProvider}
109
+ * above it.
110
+ *
111
+ * @example
112
+ * const options = useAuthSettings()
113
+ * return options.password && <PasswordForm />
114
+ */
115
+ declare function useAuthSettings(): AuthOptions;
57
116
  //#endregion
58
- export { getSoftrContext, initialSoftrContext, softrAuthMiddleware, useCurrentUser };
117
+ export { AuthOptions, AuthSettingsProvider, getAuthSettings, getSoftrContext, initialSoftrContext, softrAuthMiddleware, useAuthSettings, useCurrentUser };
@@ -1,17 +1,20 @@
1
- import { assert, panic } from "../assertions.js";
1
+ import { assert, panic, requireDefined } from "../assertions.js";
2
2
  import { readUserTimezone, writeCookies } from "../cookies.js";
3
3
  import { sessionConfig } from "./config.js";
4
4
  import { clearSession, makeSessionDataCookie, readSessionData, readSessionToken } from "./session.js";
5
5
  import { makePlatform } from "./platform.js";
6
6
  import { defaultFormatting, resolveFormatting } from "../formatting.js";
7
7
  import { readLocaleSettings } from "../locale-settings.js";
8
+ import { settings } from "./methods/settings.js";
8
9
  import { bootErrorMiddleware } from "../boot-error.js";
9
10
  import { pwaMiddleware } from "../pwa.js";
11
+ import { createContext, useContext } from "react";
10
12
  import { createMiddleware, createServerFn, getGlobalStartContext } from "@tanstack/react-start";
11
13
  import { getRequestHeader } from "@tanstack/react-start/server";
12
14
  import { rootRouteId, useRouteContext } from "@tanstack/react-router";
15
+ import { jsx } from "react/jsx-runtime";
13
16
 
14
- //#region src/auth/isomorphic.ts
17
+ //#region src/auth/isomorphic.tsx
15
18
  /**
16
19
  * Resolves the Softr visitor, their permissions and the app's formatting for
17
20
  * every request, so that `getSoftrContext` and the route guards have something
@@ -41,11 +44,11 @@ function softrAuthMiddleware() {
41
44
  writeCookies([makeSessionDataCookie(session, token)]);
42
45
  return session;
43
46
  }
44
- const [{ user, permissions }, settings] = await Promise.all([getSession(), readLocaleSettings()]);
47
+ const [{ user, permissions }, settings$1] = await Promise.all([getSession(), readLocaleSettings()]);
45
48
  return next({ context: {
46
49
  user,
47
50
  permissions,
48
- formatting: resolveFormatting(settings, getRequestHeader("accept-language") ?? null, readUserTimezone())
51
+ formatting: resolveFormatting(settings$1, getRequestHeader("accept-language") ?? null, readUserTimezone())
49
52
  } });
50
53
  });
51
54
  }
@@ -94,6 +97,61 @@ function useCurrentUser() {
94
97
  select: (context) => context.user
95
98
  });
96
99
  }
100
+ /**
101
+ * Loads the app's {@link AuthOptions}. Call it from the auth layout's loader
102
+ * and hand the result to {@link AuthSettingsProvider}.
103
+ *
104
+ * @example
105
+ * export const Route = createFileRoute("/_auth")({
106
+ * loader: () => getAuthSettings(),
107
+ * staleTime: 60_000,
108
+ * })
109
+ */
110
+ const getAuthSettings = createServerFn({ method: "GET" }).handler(async () => {
111
+ const raw = await settings();
112
+ const on = (method) => raw.loginEnabled && raw.authenticationMethods.includes(method);
113
+ const emailMethods = on("EMAIL") ? raw.emailAuth?.loginMethods ?? [] : [];
114
+ const clientId = raw.googleAuth?.clientId?.trim();
115
+ return {
116
+ password: emailMethods.includes("PASSWORD"),
117
+ emailCode: emailMethods.includes("EMAIL_CODE"),
118
+ magicLink: on("MAGIC_LINK"),
119
+ google: on("GOOGLE") && clientId ? { clientId } : null,
120
+ signUp: raw.loginEnabled && (raw.signUpPolicy === "OPEN_TO_PUBLIC" || raw.signUpPolicy === "DOMAIN_RESTRICTED"),
121
+ strongPasswords: on("EMAIL") && (raw.emailAuth?.strongPasswords ?? false)
122
+ };
123
+ });
124
+ const AuthSettingsContext = createContext(null);
125
+ /**
126
+ * Makes the auth options readable with {@link useAuthSettings} anywhere below.
127
+ *
128
+ * @example
129
+ * function AuthLayout() {
130
+ * const authSettings = Route.useLoaderData()
131
+ * return (
132
+ * <AuthSettingsProvider value={authSettings}>
133
+ * <Outlet />
134
+ * </AuthSettingsProvider>
135
+ * )
136
+ * }
137
+ */
138
+ function AuthSettingsProvider({ value, children }) {
139
+ return /* @__PURE__ */ jsx(AuthSettingsContext.Provider, {
140
+ value,
141
+ children
142
+ });
143
+ }
144
+ /**
145
+ * Which ways in this app offers. Requires an {@link AuthSettingsProvider}
146
+ * above it.
147
+ *
148
+ * @example
149
+ * const options = useAuthSettings()
150
+ * return options.password && <PasswordForm />
151
+ */
152
+ function useAuthSettings() {
153
+ return requireDefined(useContext(AuthSettingsContext), "useAuthSettings needs an AuthSettingsProvider above it.");
154
+ }
97
155
 
98
156
  //#endregion
99
- export { getSoftrContext, initialSoftrContext, softrAuthMiddleware, useCurrentUser };
157
+ export { AuthSettingsProvider, getAuthSettings, getSoftrContext, initialSoftrContext, softrAuthMiddleware, useAuthSettings, useCurrentUser };
@@ -0,0 +1,47 @@
1
+ import { User } from "../user.js";
2
+ import { AuthError, Result } from "./utils.js";
3
+
4
+ //#region src/auth/methods/passwordLink.d.ts
5
+
6
+ /**
7
+ * Emails a link to set a new password.
8
+ *
9
+ * Succeeds whether or not the address has an account, and sends nothing when
10
+ * it has none.
11
+ */
12
+ declare function requestPasswordReset(details: {
13
+ email: string;
14
+ }): Promise<Result<null, AuthError>>;
15
+ /**
16
+ * Checks a password reset or invitation link, and returns the address it was
17
+ * mailed to. The link stays usable.
18
+ */
19
+ declare function checkPasswordLink(details: {
20
+ token: string;
21
+ }): Promise<Result<{
22
+ email: string;
23
+ }, AuthError>>;
24
+ /**
25
+ * Sets a new password with a password reset or invitation link, and signs the
26
+ * visitor in.
27
+ *
28
+ * Any success uses up the link, `authenticatorRequired` included, and ends
29
+ * the visitor's other sessions.
30
+ */
31
+ declare function setPasswordWithLink(details: {
32
+ token: string;
33
+ password: string;
34
+ }): Promise<Result<{
35
+ status: "signedIn";
36
+ user: User;
37
+ } | {
38
+ status: "authenticatorRequired";
39
+ /**
40
+ * `verify`: they have an authenticator app and owe a code.
41
+ * `setup`: the app requires one and they have none yet.
42
+ * `setupOptional`: same, except they may skip it instead.
43
+ */
44
+ step: "verify" | "setup" | "setupOptional";
45
+ }, AuthError>>;
46
+ //#endregion
47
+ export { checkPasswordLink, requestPasswordReset, setPasswordWithLink };
@@ -0,0 +1,86 @@
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 } from "../session.js";
5
+ import { makePlatform } from "../platform.js";
6
+ import { authError } from "./utils.js";
7
+
8
+ //#region src/auth/methods/passwordLink.ts
9
+ /**
10
+ * Emails a link to set a new password.
11
+ *
12
+ * Succeeds whether or not the address has an account, and sends nothing when
13
+ * it has none.
14
+ */
15
+ async function requestPasswordReset(details) {
16
+ const result = await makePlatform(sessionConfig().applicationId).forgotPassword(details);
17
+ if (!result.ok) {
18
+ if (result.status === 429) return authError("tooManyAttempts", result.message);
19
+ panic(`Expected the password reset link to be emailed, but got ${result.status}: ${result.message}.`);
20
+ }
21
+ return {
22
+ success: true,
23
+ data: null
24
+ };
25
+ }
26
+ /**
27
+ * Checks a password reset or invitation link, and returns the address it was
28
+ * mailed to. The link stays usable.
29
+ */
30
+ async function checkPasswordLink(details) {
31
+ const result = await makePlatform(sessionConfig().applicationId).checkPasswordToken(details);
32
+ if (!result.ok) {
33
+ if (result.status === 429) return authError("tooManyAttempts", result.message);
34
+ if (result.status === 400 || result.status === 401) return authError("linkExpired", result.message);
35
+ panic(`Expected the link to be checked, but got ${result.status}: ${result.message}.`);
36
+ }
37
+ return {
38
+ success: true,
39
+ data: result.data
40
+ };
41
+ }
42
+ /**
43
+ * Sets a new password with a password reset or invitation link, and signs the
44
+ * visitor in.
45
+ *
46
+ * Any success uses up the link, `authenticatorRequired` included, and ends
47
+ * the visitor's other sessions.
48
+ */
49
+ async function setPasswordWithLink(details) {
50
+ const result = await makePlatform(sessionConfig().applicationId).setPassword(details);
51
+ if (!result.ok) {
52
+ if (result.status === 429) return authError("tooManyAttempts", result.message);
53
+ if (result.status === 400 && result.message === "Password must be at least 8 characters long.") return authError("invalidDetails", result.message);
54
+ if (result.status === 400 || result.status === 401) return authError("linkExpired", result.message);
55
+ panic(`Expected the password to be set, but got ${result.status}: ${result.message}.`);
56
+ }
57
+ if (result.data.status === "MFA_REQUIRED") {
58
+ const { mfa } = result.data;
59
+ assert(mfa, "Expected a challenge from setting a password, but got none");
60
+ writeCookies([makePendingAuthCookie(mfa.challengeToken)]);
61
+ return {
62
+ success: true,
63
+ data: {
64
+ status: "authenticatorRequired",
65
+ step: mfa.action === "VERIFICATION_REQUIRED" ? "verify" : mfa.action === "SETUP_REQUIRED" ? "setup" : "setupOptional"
66
+ }
67
+ };
68
+ }
69
+ const { session } = result.data;
70
+ assert(session, "Expected a session from setting a password, but got none");
71
+ writeCookies([makeSessionTokenCookie(session.jwt), makeSessionDataCookie({
72
+ user: session.user,
73
+ permissions: session.permissions
74
+ }, session.jwt)]);
75
+ clearPendingAuth();
76
+ return {
77
+ success: true,
78
+ data: {
79
+ status: "signedIn",
80
+ user: session.user
81
+ }
82
+ };
83
+ }
84
+
85
+ //#endregion
86
+ export { checkPasswordLink, requestPasswordReset, setPasswordWithLink };
@@ -0,0 +1,11 @@
1
+ import { AuthSettings } from "../platform.js";
2
+
3
+ //#region src/auth/methods/settings.d.ts
4
+
5
+ /**
6
+ * How visitors may sign in and sign up to this app, as configured in Studio.
7
+ * A login or sign-up page renders only the methods it lists.
8
+ */
9
+ declare function settings(): Promise<AuthSettings>;
10
+ //#endregion
11
+ export { settings };
@@ -0,0 +1,17 @@
1
+ import { panic } from "../../assertions.js";
2
+ import { sessionConfig } from "../config.js";
3
+ import { makePlatform } from "../platform.js";
4
+
5
+ //#region src/auth/methods/settings.ts
6
+ /**
7
+ * How visitors may sign in and sign up to this app, as configured in Studio.
8
+ * A login or sign-up page renders only the methods it lists.
9
+ */
10
+ async function settings() {
11
+ const result = await makePlatform(sessionConfig().applicationId).authSettings();
12
+ if (!result.ok) panic(`Expected the auth settings, but got ${result.status}: ${result.message}`);
13
+ return result.data;
14
+ }
15
+
16
+ //#endregion
17
+ export { settings };
@@ -17,6 +17,7 @@ async function signUp(details) {
17
17
  if (result.status === 409) return authError("emailTaken", result.message);
18
18
  if (result.status === 429) return authError("tooManyAttempts", result.message);
19
19
  if (result.status === 400) return authError("invalidDetails", result.message);
20
+ if (result.status === 401 && result.message === "Email domain not allowed") return authError("emailDomainNotAllowed", result.message);
20
21
  if (result.status >= 500) panic(`Expected the sign-up code to be emailed, but got ${result.status}: ` + result.message);
21
22
  throw new Error(`${result.message}. Check SOFTR_APPLICATION_ID and that the app allows sign-up.`);
22
23
  }
@@ -22,6 +22,7 @@ async function signInWithGoogle(credentials) {
22
22
  const result = await makePlatform(sessionConfig().applicationId).signInWithGoogle(credentials);
23
23
  if (!result.ok) {
24
24
  if (result.status === 429) return authError("tooManyAttempts", result.message);
25
+ if (result.status === 400 && result.message.startsWith("Emails with ") && result.message.endsWith(" domain is not allowed to signup.")) return authError("emailDomainNotAllowed", result.message);
25
26
  if (result.status === 400 || result.status === 401) return authError("invalidCredentials", result.message);
26
27
  if (result.status >= 500) panic(`Expected Google sign-in to succeed, but got ${result.status}: ` + result.message);
27
28
  throw new Error(`${result.message}. Check SOFTR_APPLICATION_ID and that the app allows Google sign-in.`);
@@ -10,6 +10,6 @@ type AuthError = {
10
10
  code: AuthErrorCode;
11
11
  message: string;
12
12
  };
13
- type AuthErrorCode = "invalidCredentials" | "tooManyAttempts" | "emailTaken" | "invalidDetails" | "invalidCode" | "notAuthenticated";
13
+ type AuthErrorCode = "invalidCredentials" | "tooManyAttempts" | "emailTaken" | "invalidDetails" | "invalidCode" | "notAuthenticated" | "emailDomainNotAllowed" | "linkExpired";
14
14
  //#endregion
15
15
  export { AuthError, Result };
@@ -0,0 +1,46 @@
1
+ import "./user.js";
2
+ import "./context.js";
3
+ import { z } from "zod";
4
+
5
+ //#region src/auth/platform.d.ts
6
+
7
+ declare const authSettingsSchema: z.ZodObject<{
8
+ loginEnabled: z.ZodBoolean;
9
+ authenticationMethods: z.ZodArray<z.ZodEnum<{
10
+ EMAIL: "EMAIL";
11
+ SSO: "SSO";
12
+ GOOGLE: "GOOGLE";
13
+ MAGIC_LINK: "MAGIC_LINK";
14
+ }>>;
15
+ signUpPolicy: z.ZodNullable<z.ZodEnum<{
16
+ DISABLED: "DISABLED";
17
+ OPEN_TO_PUBLIC: "OPEN_TO_PUBLIC";
18
+ DOMAIN_RESTRICTED: "DOMAIN_RESTRICTED";
19
+ }>>;
20
+ sessionExpirationDays: z.ZodNullable<z.ZodNumber>;
21
+ inactivityTimeoutMinutes: z.ZodNullable<z.ZodNumber>;
22
+ emailAuth: z.ZodNullable<z.ZodObject<{
23
+ loginMethods: z.ZodArray<z.ZodEnum<{
24
+ PASSWORD: "PASSWORD";
25
+ EMAIL_CODE: "EMAIL_CODE";
26
+ }>>;
27
+ strongPasswords: z.ZodBoolean;
28
+ emailCodeExpirationMinutes: z.ZodNullable<z.ZodNumber>;
29
+ }, z.core.$strip>>;
30
+ googleAuth: z.ZodNullable<z.ZodObject<{
31
+ clientId: z.ZodNullable<z.ZodString>;
32
+ userType: z.ZodNullable<z.ZodEnum<{
33
+ INTERNAL: "INTERNAL";
34
+ EXTERNAL: "EXTERNAL";
35
+ }>>;
36
+ }, z.core.$strip>>;
37
+ sso: z.ZodNullable<z.ZodObject<{
38
+ type: z.ZodNullable<z.ZodEnum<{
39
+ SAML: "SAML";
40
+ OPEN_ID: "OPEN_ID";
41
+ }>>;
42
+ }, z.core.$strip>>;
43
+ }, z.core.$strip>;
44
+ type AuthSettings = z.infer<typeof authSettingsSchema>;
45
+ //#endregion
46
+ export { AuthSettings };
@@ -6,8 +6,35 @@ import { userSchema } from "./user.js";
6
6
  import { z } from "zod";
7
7
 
8
8
  //#region src/auth/platform.ts
9
+ const authSettingsSchema = z.object({
10
+ loginEnabled: z.boolean(),
11
+ authenticationMethods: z.array(z.enum([
12
+ "EMAIL",
13
+ "SSO",
14
+ "GOOGLE",
15
+ "MAGIC_LINK"
16
+ ])),
17
+ signUpPolicy: z.enum([
18
+ "DISABLED",
19
+ "OPEN_TO_PUBLIC",
20
+ "DOMAIN_RESTRICTED"
21
+ ]).nullable(),
22
+ sessionExpirationDays: z.number().nullable(),
23
+ inactivityTimeoutMinutes: z.number().nullable(),
24
+ emailAuth: z.object({
25
+ loginMethods: z.array(z.enum(["PASSWORD", "EMAIL_CODE"])),
26
+ strongPasswords: z.boolean(),
27
+ emailCodeExpirationMinutes: z.number().nullable()
28
+ }).nullable(),
29
+ googleAuth: z.object({
30
+ clientId: z.string().nullable(),
31
+ userType: z.enum(["INTERNAL", "EXTERNAL"]).nullable()
32
+ }).nullable(),
33
+ sso: z.object({ type: z.enum(["SAML", "OPEN_ID"]).nullable() }).nullable()
34
+ });
9
35
  function makePlatform(applicationId) {
10
36
  return {
37
+ authSettings: () => request(`/v1/vibe/applications/${applicationId}/users/auth-settings`, { method: "GET" }, authSettingsSchema),
11
38
  session: async (token) => {
12
39
  const result = await request(`/v1/vibe/applications/${applicationId}/users/session`, {
13
40
  method: "GET",
@@ -99,6 +126,33 @@ function makePlatform(applicationId) {
99
126
  challengeToken: z.string()
100
127
  }).nullish()
101
128
  })),
129
+ forgotPassword: (body) => request(`/v1/vibe/applications/${applicationId}/users/forgot-password`, {
130
+ method: "POST",
131
+ json: body
132
+ }, z.null()),
133
+ checkPasswordToken: (body) => request(`/v1/vibe/applications/${applicationId}/users/set-password/check`, {
134
+ method: "POST",
135
+ json: body
136
+ }, z.object({ email: z.string() })),
137
+ setPassword: (body) => request(`/v1/vibe/applications/${applicationId}/users/set-password`, {
138
+ method: "POST",
139
+ json: body
140
+ }, z.object({
141
+ status: z.enum(["AUTHENTICATED", "MFA_REQUIRED"]),
142
+ session: z.object({
143
+ jwt: z.string(),
144
+ user: userSchema,
145
+ permissions: permissionsSchema
146
+ }).nullish(),
147
+ mfa: z.object({
148
+ action: z.enum([
149
+ "VERIFICATION_REQUIRED",
150
+ "SETUP_REQUIRED",
151
+ "SETUP_OPTIONAL"
152
+ ]),
153
+ challengeToken: z.string()
154
+ }).nullish()
155
+ })),
102
156
  sendSignUpCode: (body) => request(`/v1/vibe/applications/${applicationId}/users/sign-up/send-code`, {
103
157
  method: "POST",
104
158
  json: body
@@ -2,6 +2,8 @@ import { confirmAuthenticatorSetup, removeAuthenticator, resetAuthenticator, sen
2
2
  import { sendSignInCode, signInWithCode } from "./methods/code.js";
3
3
  import { signInWithMagicLink } from "./methods/magicLink.js";
4
4
  import { signIn, signOut } from "./methods/password.js";
5
+ import { checkPasswordLink, requestPasswordReset, setPasswordWithLink } from "./methods/passwordLink.js";
6
+ import { settings } from "./methods/settings.js";
5
7
  import { confirmSignUp, signUp } from "./methods/signup.js";
6
8
  import { signInWithGoogle } from "./methods/social.js";
7
9
  import "@tanstack/react-start/server-only";
@@ -20,6 +22,9 @@ declare const auth: {
20
22
  signInWithCode: typeof signInWithCode;
21
23
  signInWithGoogle: typeof signInWithGoogle;
22
24
  signInWithMagicLink: typeof signInWithMagicLink;
25
+ requestPasswordReset: typeof requestPasswordReset;
26
+ checkPasswordLink: typeof checkPasswordLink;
27
+ setPasswordWithLink: typeof setPasswordWithLink;
23
28
  startAuthenticatorSetup: typeof startAuthenticatorSetup;
24
29
  confirmAuthenticatorSetup: typeof confirmAuthenticatorSetup;
25
30
  skipAuthenticatorSetup: typeof skipAuthenticatorSetup;
@@ -27,6 +32,7 @@ declare const auth: {
27
32
  sendAuthenticatorResetCode: typeof sendAuthenticatorResetCode;
28
33
  resetAuthenticator: typeof resetAuthenticator;
29
34
  removeAuthenticator: typeof removeAuthenticator;
35
+ settings: typeof settings;
30
36
  };
31
37
  //#endregion
32
38
  export { auth };
@@ -1,7 +1,9 @@
1
+ import { settings } from "./methods/settings.js";
1
2
  import { confirmAuthenticatorSetup, removeAuthenticator, resetAuthenticator, sendAuthenticatorResetCode, skipAuthenticatorSetup, startAuthenticatorSetup, verifyAuthenticator } from "./methods/authenticator.js";
2
3
  import { sendSignInCode, signInWithCode } from "./methods/code.js";
3
4
  import { signInWithMagicLink } from "./methods/magicLink.js";
4
5
  import { signIn, signOut } from "./methods/password.js";
6
+ import { checkPasswordLink, requestPasswordReset, setPasswordWithLink } from "./methods/passwordLink.js";
5
7
  import { confirmSignUp, signUp } from "./methods/signup.js";
6
8
  import { signInWithGoogle } from "./methods/social.js";
7
9
  import "@tanstack/react-start/server-only";
@@ -19,13 +21,17 @@ const auth = {
19
21
  signInWithCode,
20
22
  signInWithGoogle,
21
23
  signInWithMagicLink,
24
+ requestPasswordReset,
25
+ checkPasswordLink,
26
+ setPasswordWithLink,
22
27
  startAuthenticatorSetup,
23
28
  confirmAuthenticatorSetup,
24
29
  skipAuthenticatorSetup,
25
30
  verifyAuthenticator,
26
31
  sendAuthenticatorResetCode,
27
32
  resetAuthenticator,
28
- removeAuthenticator
33
+ removeAuthenticator,
34
+ settings
29
35
  };
30
36
 
31
37
  //#endregion
package/dist/client.d.ts CHANGED
@@ -1,4 +1,3 @@
1
1
  import { FileItem, useFileUpload } from "./core/use-file-upload.js";
2
- import { useCommentComposer } from "./comments/use-comment-composer.js";
3
2
  import "@tanstack/react-start/client-only";
4
- export { type FileItem, useCommentComposer, useFileUpload };
3
+ export { type FileItem, useFileUpload };
package/dist/client.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { useFileUpload } from "./core/use-file-upload.js";
2
- import { useCommentComposer } from "./comments/use-comment-composer.js";
3
2
  import "@tanstack/react-start/client-only";
4
3
 
5
- export { useCommentComposer, useFileUpload };
4
+ export { useFileUpload };
@@ -1,4 +1,4 @@
1
- import { CommentsAction, DatasourceAction } from "../action.js";
1
+ import { DatasourceAction } from "../action.js";
2
2
 
3
3
  //#region src/core/file-upload.d.ts
4
4
 
@@ -10,12 +10,7 @@ type FileAttachment = {
10
10
  url: string;
11
11
  filename: string;
12
12
  id: string;
13
- type?: string | null;
14
13
  };
15
- /**
16
- * A COMMENTS action uploads a comment attachment.
17
- * The platform checks the comment settings.
18
- */
19
- declare function upload(action: DatasourceAction | CommentsAction, file: File): Promise<FileAttachment>;
14
+ declare function upload(action: DatasourceAction, file: File): Promise<FileAttachment>;
20
15
  //#endregion
21
16
  export { FileAttachment, upload };
@@ -5,10 +5,6 @@ import { platformApiUrl } from "../auth/platform.js";
5
5
  import { randomUUID } from "node:crypto";
6
6
 
7
7
  //#region src/core/file-upload.ts
8
- /**
9
- * A COMMENTS action uploads a comment attachment.
10
- * The platform checks the comment settings.
11
- */
12
8
  async function upload(action, file) {
13
9
  const { applicationId } = sessionConfig();
14
10
  const baseUrl = await platformApiUrl();
@@ -27,8 +23,7 @@ async function upload(action, file) {
27
23
  return {
28
24
  url: resultJSON.url,
29
25
  filename: resultJSON.filename || "Untitled file",
30
- id: resultJSON.id || randomUUID(),
31
- type: resultJSON.type ?? null
26
+ id: resultJSON.id || randomUUID()
32
27
  };
33
28
  }
34
29