@hachej/boring-core 0.1.48 → 0.1.49
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/{PostgresMeteringStore-DhOVVtau.d.ts → PostgresMeteringStore-qjKGmVFr.d.ts} +1 -1
- package/dist/app/front/chatFirst/chatFirstPublicShell.css +269 -0
- package/dist/app/front/index.js +80 -40
- package/dist/app/front/styles.css +47 -0
- package/dist/app/server/index.d.ts +4 -4
- package/dist/app/server/index.js +4 -3
- package/dist/{authHook-DtzhSmqS.d.ts → authHook-BbgCBHjP.d.ts} +3 -3
- package/dist/{chunk-FZC3VL5D.js → chunk-BVZ2YT3M.js} +1 -1
- package/dist/chunk-I4PGL4ZD.js +17 -0
- package/dist/{chunk-VYXEXOCO.js → chunk-P4RF2D7H.js} +80 -32
- package/dist/{chunk-LIBHVT7V.js → chunk-QZGYKLXB.js} +1 -0
- package/dist/{chunk-6GAQRQKO.js → chunk-ZMS6O4CY.js} +26 -11
- package/dist/{connection-C5SiqoNc.d.ts → connection-B1iC6B-w.d.ts} +3 -2
- package/dist/front/index.d.ts +3 -2
- package/dist/front/index.js +3 -2
- package/dist/server/db/index.d.ts +4 -4
- package/dist/server/db/index.js +2 -2
- package/dist/server/index.d.ts +53 -48
- package/dist/server/index.js +8 -6
- package/dist/shared/index.d.ts +7 -13
- package/dist/shared/index.js +9 -1
- package/dist/telemetry-DR18MeI0.d.ts +13 -0
- package/dist/{types-CWtJ4kgd.d.ts → types-Bb7I-83I.d.ts} +3 -1
- package/package.json +6 -5
|
@@ -1,11 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
TopBarSlotProvider
|
|
3
3
|
} from "./chunk-HYNKZSTF.js";
|
|
4
|
+
import {
|
|
5
|
+
canUseProtectedApi,
|
|
6
|
+
isRuntimeEmailVerificationEnabled
|
|
7
|
+
} from "./chunk-I4PGL4ZD.js";
|
|
4
8
|
import {
|
|
5
9
|
ConfigFetchError,
|
|
6
10
|
ERROR_CODES,
|
|
7
11
|
HttpError
|
|
8
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-QZGYKLXB.js";
|
|
9
13
|
|
|
10
14
|
// src/front/AppErrorBoundary.tsx
|
|
11
15
|
import { Component } from "react";
|
|
@@ -660,11 +664,16 @@ function WorkspaceAuthProvider({
|
|
|
660
664
|
const queryClient = useQueryClient();
|
|
661
665
|
const routeWorkspaceId = id?.trim() ? id : workspaceIdFromPath(location.pathname, workspaceRoute, workspaceIdParam);
|
|
662
666
|
const session = useSession();
|
|
663
|
-
const
|
|
667
|
+
const config = useOptionalConfig();
|
|
668
|
+
const user = session.data?.user ?? null;
|
|
669
|
+
const canQueryProtectedApi = canUseProtectedApi(
|
|
670
|
+
user,
|
|
671
|
+
isRuntimeEmailVerificationEnabled(config)
|
|
672
|
+
);
|
|
664
673
|
const workspacesQuery = useQuery2({
|
|
665
674
|
queryKey: WORKSPACES_QUERY_KEY,
|
|
666
675
|
queryFn: fetchWorkspaces,
|
|
667
|
-
enabled:
|
|
676
|
+
enabled: canQueryProtectedApi
|
|
668
677
|
});
|
|
669
678
|
const defaultWorkspace = routeWorkspaceId === null ? workspacesQuery.data?.find((workspace2) => workspace2.isDefault) ?? workspacesQuery.data?.[0] ?? null : null;
|
|
670
679
|
const resolvedId = routeWorkspaceId ?? defaultWorkspace?.id ?? null;
|
|
@@ -677,13 +686,13 @@ function WorkspaceAuthProvider({
|
|
|
677
686
|
}
|
|
678
687
|
return fetchWorkspace(resolvedId);
|
|
679
688
|
},
|
|
680
|
-
enabled:
|
|
689
|
+
enabled: canQueryProtectedApi && resolvedId !== null
|
|
681
690
|
});
|
|
682
691
|
const detail = detailQuery.data ?? cachedDetail ?? null;
|
|
683
692
|
const workspace = detailQuery.isError ? null : detail?.workspace ?? null;
|
|
684
693
|
const role = detailQuery.isError ? null : detail?.role ?? null;
|
|
685
694
|
const routeStatus = (() => {
|
|
686
|
-
if (!
|
|
695
|
+
if (!canQueryProtectedApi) return { status: "idle", workspaceId: routeWorkspaceId };
|
|
687
696
|
if (routeWorkspaceId === null) return { status: "idle", workspaceId: null };
|
|
688
697
|
if (detailQuery.isError) return routeStatusFromError(routeWorkspaceId, detailQuery.error);
|
|
689
698
|
if (detailQuery.isPending && !detail) return { status: "loading", workspaceId: routeWorkspaceId };
|
|
@@ -709,11 +718,16 @@ var UserContext = createContext5(null);
|
|
|
709
718
|
var STALE_MS = 6e4;
|
|
710
719
|
function UserIdentityProvider({ children }) {
|
|
711
720
|
const { data: session } = useSession();
|
|
721
|
+
const config = useOptionalConfig();
|
|
722
|
+
const canFetchIdentity = canUseProtectedApi(
|
|
723
|
+
session?.user,
|
|
724
|
+
isRuntimeEmailVerificationEnabled(config)
|
|
725
|
+
);
|
|
712
726
|
const [identity, setIdentity] = useState6(null);
|
|
713
727
|
const fetchedForRef = useRef3(null);
|
|
714
728
|
const lastFetchRef = useRef3(0);
|
|
715
729
|
useEffect7(() => {
|
|
716
|
-
if (!session?.user) {
|
|
730
|
+
if (!session?.user || !canFetchIdentity) {
|
|
717
731
|
setIdentity(null);
|
|
718
732
|
fetchedForRef.current = null;
|
|
719
733
|
return;
|
|
@@ -736,7 +750,7 @@ function UserIdentityProvider({ children }) {
|
|
|
736
750
|
return () => {
|
|
737
751
|
cancelled = true;
|
|
738
752
|
};
|
|
739
|
-
}, [session?.user?.id]);
|
|
753
|
+
}, [canFetchIdentity, session?.user?.id]);
|
|
740
754
|
return /* @__PURE__ */ jsx6(UserContext.Provider, { value: identity, children });
|
|
741
755
|
}
|
|
742
756
|
function useUser() {
|
|
@@ -892,6 +906,7 @@ function SignInPage() {
|
|
|
892
906
|
// src/front/auth/SignUpPage.tsx
|
|
893
907
|
import { useState as useState9 } from "react";
|
|
894
908
|
import { useForm as useForm2 } from "react-hook-form";
|
|
909
|
+
import { useNavigate } from "react-router-dom";
|
|
895
910
|
import { zodResolver as zodResolver2 } from "@hookform/resolvers/zod";
|
|
896
911
|
import { z as z2 } from "zod";
|
|
897
912
|
import { Button as Button4, Card as Card2, CardContent as CardContent2, CardDescription as CardDescription2, CardFooter as CardFooter2, CardHeader as CardHeader2, CardTitle as CardTitle2, Input as Input2, Label as Label2 } from "@hachej/boring-ui-kit";
|
|
@@ -909,6 +924,7 @@ function readGoogleAuthError2() {
|
|
|
909
924
|
}
|
|
910
925
|
function SignUpPage() {
|
|
911
926
|
const signUp = useSignUp();
|
|
927
|
+
const navigate = useNavigate();
|
|
912
928
|
const config = useOptionalConfig();
|
|
913
929
|
const [serverError, setServerError] = useState9(null);
|
|
914
930
|
const [oauthError, setOauthError] = useState9(() => readGoogleAuthError2());
|
|
@@ -935,6 +951,8 @@ function SignUpPage() {
|
|
|
935
951
|
);
|
|
936
952
|
if (result.error) {
|
|
937
953
|
setServerError(result.error.message ?? "Sign up failed");
|
|
954
|
+
} else if (isRuntimeEmailVerificationEnabled(config)) {
|
|
955
|
+
navigate(routes.verifyEmail, { replace: true });
|
|
938
956
|
} else {
|
|
939
957
|
setSuccess(true);
|
|
940
958
|
}
|
|
@@ -1332,11 +1350,12 @@ function VerifyEmailPage() {
|
|
|
1332
1350
|
/* @__PURE__ */ jsx12(CardFooter5, { children: /* @__PURE__ */ jsx12("a", { href: routes.signin, className: "text-sm text-muted-foreground hover:underline", children: "Back to sign in" }) })
|
|
1333
1351
|
] }) });
|
|
1334
1352
|
}
|
|
1353
|
+
const isWaitingForEmailClick = status === "no-token" && Boolean(sessionEmail);
|
|
1335
1354
|
return /* @__PURE__ */ jsx12("div", { className: "flex min-h-screen items-center justify-center p-4", children: /* @__PURE__ */ jsxs5(Card5, { className: "w-full max-w-sm", children: [
|
|
1336
1355
|
inviteWarning && /* @__PURE__ */ jsx12("div", { role: "status", className: "px-6 pt-4", children: /* @__PURE__ */ jsx12("div", { className: "rounded-md bg-muted px-3 py-2 text-sm text-muted-foreground", children: inviteWarning }) }),
|
|
1337
1356
|
/* @__PURE__ */ jsxs5(CardHeader5, { children: [
|
|
1338
|
-
/* @__PURE__ */ jsx12(CardTitle5, { children: "Invalid verification link" }),
|
|
1339
|
-
/* @__PURE__ */ jsx12(CardDescription5, { children: status === "no-token" ? "No verification token found. Check the link in your email." : "This verification link is invalid. Request a new one below." })
|
|
1357
|
+
/* @__PURE__ */ jsx12(CardTitle5, { children: isWaitingForEmailClick ? "Check your email" : "Invalid verification link" }),
|
|
1358
|
+
/* @__PURE__ */ jsx12(CardDescription5, { children: isWaitingForEmailClick ? "We sent a verification link to your email address. Please check your inbox to continue." : status === "no-token" ? "No verification token found. Check the link in your email." : "This verification link is invalid. Request a new one below." })
|
|
1340
1359
|
] }),
|
|
1341
1360
|
/* @__PURE__ */ jsx12(CardContent5, { children: resendSection }),
|
|
1342
1361
|
/* @__PURE__ */ jsx12(CardFooter5, { children: /* @__PURE__ */ jsx12("a", { href: routes.signin, className: "text-sm text-muted-foreground hover:underline", children: "Back to sign in" }) })
|
|
@@ -1399,6 +1418,9 @@ function formatMemberSince(value) {
|
|
|
1399
1418
|
});
|
|
1400
1419
|
}
|
|
1401
1420
|
function SettingsTopBar() {
|
|
1421
|
+
const config = useOptionalConfig();
|
|
1422
|
+
const appTitle = config?.appName ?? "Boring UI";
|
|
1423
|
+
const appInitial = (appTitle.trim().charAt(0) || "B").toUpperCase();
|
|
1402
1424
|
return /* @__PURE__ */ jsx13(
|
|
1403
1425
|
"header",
|
|
1404
1426
|
{
|
|
@@ -1410,10 +1432,10 @@ function SettingsTopBar() {
|
|
|
1410
1432
|
{
|
|
1411
1433
|
"aria-hidden": "true",
|
|
1412
1434
|
className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-foreground text-[12px] font-semibold text-background",
|
|
1413
|
-
children:
|
|
1435
|
+
children: appInitial
|
|
1414
1436
|
}
|
|
1415
1437
|
),
|
|
1416
|
-
/* @__PURE__ */ jsx13("span", { className: "truncate text-[13px] font-medium tracking-tight text-foreground", children:
|
|
1438
|
+
/* @__PURE__ */ jsx13("span", { className: "truncate text-[13px] font-medium tracking-tight text-foreground", children: appTitle }),
|
|
1417
1439
|
/* @__PURE__ */ jsx13("span", { "aria-hidden": "true", className: "text-muted-foreground/30", children: "/" }),
|
|
1418
1440
|
/* @__PURE__ */ jsx13("span", { className: "truncate text-[13px] text-muted-foreground", children: "Account settings" })
|
|
1419
1441
|
] })
|
|
@@ -1740,7 +1762,7 @@ function UserSettingsPage({ topBar, extraSections = [] } = {}) {
|
|
|
1740
1762
|
|
|
1741
1763
|
// src/front/auth/InviteAcceptPage.tsx
|
|
1742
1764
|
import { useCallback as useCallback5, useState as useState14 } from "react";
|
|
1743
|
-
import { useParams as useParams2, useNavigate } from "react-router-dom";
|
|
1765
|
+
import { useParams as useParams2, useNavigate as useNavigate2 } from "react-router-dom";
|
|
1744
1766
|
import { useQuery as useQuery3, useMutation, useQueryClient as useQueryClient2 } from "@tanstack/react-query";
|
|
1745
1767
|
import {
|
|
1746
1768
|
Button as Button9,
|
|
@@ -1757,7 +1779,7 @@ import { jsx as jsx14, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
|
1757
1779
|
function InviteAcceptPage() {
|
|
1758
1780
|
const { token } = useParams2();
|
|
1759
1781
|
const session = useSession();
|
|
1760
|
-
const navigate =
|
|
1782
|
+
const navigate = useNavigate2();
|
|
1761
1783
|
const queryClient = useQueryClient2();
|
|
1762
1784
|
const [acceptError, setAcceptError] = useState14(null);
|
|
1763
1785
|
const isSignedIn = Boolean(session.data);
|
|
@@ -1891,6 +1913,15 @@ import { matchPath as matchPath2 } from "react-router-dom";
|
|
|
1891
1913
|
import { Fragment as Fragment3, jsx as jsx15 } from "react/jsx-runtime";
|
|
1892
1914
|
var DEFAULT_GRACE_MS = 3e4;
|
|
1893
1915
|
var UNSAFE_REDIRECT_RE = /[\0\r\n<>"'`]/;
|
|
1916
|
+
var UNVERIFIED_ALLOWED_PATHS = /* @__PURE__ */ new Set([
|
|
1917
|
+
routes.signup,
|
|
1918
|
+
routes.forgotPassword,
|
|
1919
|
+
routes.resetPassword,
|
|
1920
|
+
routes.verifyEmail,
|
|
1921
|
+
routes.authError,
|
|
1922
|
+
routes.callbackGithub,
|
|
1923
|
+
routes.callbackGoogle
|
|
1924
|
+
]);
|
|
1894
1925
|
function normalizePath(pathname) {
|
|
1895
1926
|
if (!pathname) return "/";
|
|
1896
1927
|
return pathname.startsWith("/") ? pathname : `/${pathname}`;
|
|
@@ -1921,6 +1952,9 @@ function isPublicPath(pathname, publicPaths) {
|
|
|
1921
1952
|
return normalizedPath === candidate || normalizedPath.startsWith(`${candidate}/`);
|
|
1922
1953
|
});
|
|
1923
1954
|
}
|
|
1955
|
+
function shouldBlockUnverifiedUser(pathname, hasSession, requireEmailVerification, isEmailVerified) {
|
|
1956
|
+
return hasSession && requireEmailVerification && !isEmailVerified && !UNVERIFIED_ALLOWED_PATHS.has(normalizePath(pathname));
|
|
1957
|
+
}
|
|
1924
1958
|
function readSafeRedirect(search) {
|
|
1925
1959
|
const redirect = new URLSearchParams(normalizeSearch(search)).get("redirect");
|
|
1926
1960
|
if (!redirect) return null;
|
|
@@ -1950,7 +1984,8 @@ function AuthGate({
|
|
|
1950
1984
|
graceMs = DEFAULT_GRACE_MS,
|
|
1951
1985
|
location,
|
|
1952
1986
|
navigate,
|
|
1953
|
-
now
|
|
1987
|
+
now,
|
|
1988
|
+
requireEmailVerification = false
|
|
1954
1989
|
}) {
|
|
1955
1990
|
const session = useSession();
|
|
1956
1991
|
const nullSinceRef = useRef5(null);
|
|
@@ -1962,6 +1997,7 @@ function AuthGate({
|
|
|
1962
1997
|
() => publicPaths.map(normalizePublicPath),
|
|
1963
1998
|
[publicPaths]
|
|
1964
1999
|
);
|
|
2000
|
+
const isEmailVerified = session.data?.user?.emailVerified ?? false;
|
|
1965
2001
|
useEffect9(() => {
|
|
1966
2002
|
return () => {
|
|
1967
2003
|
if (!redirectTimerRef.current) return;
|
|
@@ -1978,6 +2014,10 @@ function AuthGate({
|
|
|
1978
2014
|
const currentPath = buildCurrentPath(currentLocation);
|
|
1979
2015
|
if (session.data) {
|
|
1980
2016
|
nullSinceRef.current = null;
|
|
2017
|
+
if (shouldBlockUnverifiedUser(pathname2, true, requireEmailVerification, isEmailVerified)) {
|
|
2018
|
+
goTo(routes.verifyEmail, { replace: true });
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
1981
2021
|
if (pathname2 === routes.signin) {
|
|
1982
2022
|
const destination = readSafeRedirect(currentLocation.search) ?? "/";
|
|
1983
2023
|
if (destination !== currentPath) {
|
|
@@ -2008,15 +2048,16 @@ function AuthGate({
|
|
|
2008
2048
|
goTo(`${routes.signin}?redirect=${encodeURIComponent(currentPath)}`, { replace: true });
|
|
2009
2049
|
}, remainingMs);
|
|
2010
2050
|
redirectTimerRef.current.unref?.();
|
|
2011
|
-
}, [currentLocation, goTo, graceMs, normalizedPublicPaths, readNow, session.data, session.isPending]);
|
|
2051
|
+
}, [currentLocation, goTo, graceMs, isEmailVerified, normalizedPublicPaths, readNow, requireEmailVerification, session.data, session.isPending]);
|
|
2012
2052
|
const pathname = normalizePath(currentLocation.pathname);
|
|
2053
|
+
if (shouldBlockUnverifiedUser(pathname, Boolean(session.data), requireEmailVerification, isEmailVerified)) return null;
|
|
2013
2054
|
if (session.isPending && !isPublicPath(pathname, normalizedPublicPaths)) return null;
|
|
2014
2055
|
return /* @__PURE__ */ jsx15(Fragment3, { children });
|
|
2015
2056
|
}
|
|
2016
2057
|
|
|
2017
2058
|
// src/front/CoreFront.tsx
|
|
2018
2059
|
import { Suspense, useCallback as useCallback9, useMemo as useMemo6 } from "react";
|
|
2019
|
-
import { BrowserRouter, Routes, Route, useLocation as useLocation2, useNavigate as
|
|
2060
|
+
import { BrowserRouter, Routes, Route, useLocation as useLocation2, useNavigate as useNavigate6 } from "react-router-dom";
|
|
2020
2061
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
2021
2062
|
import { Helmet, HelmetProvider } from "react-helmet-async";
|
|
2022
2063
|
|
|
@@ -2040,7 +2081,7 @@ import {
|
|
|
2040
2081
|
Settings,
|
|
2041
2082
|
Sun
|
|
2042
2083
|
} from "lucide-react";
|
|
2043
|
-
import { useNavigate as
|
|
2084
|
+
import { useNavigate as useNavigate3 } from "react-router-dom";
|
|
2044
2085
|
import { jsx as jsx16, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2045
2086
|
var THEME_ORDER = ["light", "dark", "system"];
|
|
2046
2087
|
function labelForTheme(preference) {
|
|
@@ -2062,7 +2103,7 @@ function initialsFor2(name, email) {
|
|
|
2062
2103
|
function UserMenu() {
|
|
2063
2104
|
const identity = useUser();
|
|
2064
2105
|
const signOut = useSignOut();
|
|
2065
|
-
const navigate =
|
|
2106
|
+
const navigate = useNavigate3();
|
|
2066
2107
|
const { preference, setTheme } = useTheme();
|
|
2067
2108
|
const [isSigningOut, setIsSigningOut] = useState15(false);
|
|
2068
2109
|
const user = identity?.user;
|
|
@@ -2192,7 +2233,7 @@ import {
|
|
|
2192
2233
|
useToast
|
|
2193
2234
|
} from "@hachej/boring-ui-kit";
|
|
2194
2235
|
import { ChevronsUpDown, LayoutGrid, Plus, Settings as Settings2 } from "lucide-react";
|
|
2195
|
-
import { useNavigate as
|
|
2236
|
+
import { useNavigate as useNavigate4 } from "react-router-dom";
|
|
2196
2237
|
import { z as z6 } from "zod";
|
|
2197
2238
|
import { Fragment as Fragment4, jsx as jsx17, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2198
2239
|
var workspaceNameSchema = z6.object({
|
|
@@ -2238,10 +2279,12 @@ function OpenInNewTabIcon({ className }) {
|
|
|
2238
2279
|
] });
|
|
2239
2280
|
}
|
|
2240
2281
|
function WorkspaceSwitcher({
|
|
2241
|
-
appTitle
|
|
2282
|
+
appTitle,
|
|
2242
2283
|
workspacePathPrefix = "/workspace"
|
|
2243
2284
|
}) {
|
|
2244
|
-
const
|
|
2285
|
+
const config = useOptionalConfig();
|
|
2286
|
+
const resolvedAppTitle = appTitle ?? config?.appName ?? "Boring UI";
|
|
2287
|
+
const navigate = useNavigate4();
|
|
2245
2288
|
const queryClient = useQueryClient3();
|
|
2246
2289
|
const { toast } = useToastCompat();
|
|
2247
2290
|
const currentWorkspace = useCurrentWorkspace();
|
|
@@ -2328,7 +2371,7 @@ function WorkspaceSwitcher({
|
|
|
2328
2371
|
{
|
|
2329
2372
|
"aria-hidden": "true",
|
|
2330
2373
|
className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-foreground text-[12px] font-semibold text-background",
|
|
2331
|
-
children:
|
|
2374
|
+
children: resolvedAppTitle.charAt(0).toUpperCase()
|
|
2332
2375
|
}
|
|
2333
2376
|
),
|
|
2334
2377
|
/* @__PURE__ */ jsx17("span", { className: "text-[13px] font-medium text-foreground", children: "Create your first workspace" })
|
|
@@ -2348,11 +2391,11 @@ function WorkspaceSwitcher({
|
|
|
2348
2391
|
{
|
|
2349
2392
|
"aria-hidden": "true",
|
|
2350
2393
|
className: "flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-foreground text-[12px] font-semibold text-background",
|
|
2351
|
-
children:
|
|
2394
|
+
children: resolvedAppTitle.charAt(0).toUpperCase()
|
|
2352
2395
|
}
|
|
2353
2396
|
),
|
|
2354
2397
|
/* @__PURE__ */ jsxs9("span", { className: "flex min-w-0 items-center gap-1.5", children: [
|
|
2355
|
-
/* @__PURE__ */ jsx17("span", { className: "truncate text-[13px] font-medium text-foreground", children:
|
|
2398
|
+
/* @__PURE__ */ jsx17("span", { className: "truncate text-[13px] font-medium text-foreground", children: resolvedAppTitle }),
|
|
2356
2399
|
/* @__PURE__ */ jsx17("span", { "aria-hidden": "true", className: "text-muted-foreground/30", children: "/" }),
|
|
2357
2400
|
/* @__PURE__ */ jsx17("span", { className: "truncate text-[13px] font-normal text-muted-foreground", children: switcherLabel })
|
|
2358
2401
|
] }),
|
|
@@ -2985,7 +3028,7 @@ function MembersPage() {
|
|
|
2985
3028
|
// src/front/workspace/WorkspaceSettingsPage.tsx
|
|
2986
3029
|
import { useCallback as useCallback8, useEffect as useEffect10, useState as useState19 } from "react";
|
|
2987
3030
|
import { useQuery as useQuery6, useMutation as useMutation4, useQueryClient as useQueryClient6 } from "@tanstack/react-query";
|
|
2988
|
-
import { useNavigate as
|
|
3031
|
+
import { useNavigate as useNavigate5 } from "react-router-dom";
|
|
2989
3032
|
import {
|
|
2990
3033
|
AlertDialog as AlertDialog3,
|
|
2991
3034
|
AlertDialogCancel as AlertDialogCancel3,
|
|
@@ -3020,7 +3063,10 @@ var STATE_TONES = {
|
|
|
3020
3063
|
error: "danger"
|
|
3021
3064
|
};
|
|
3022
3065
|
function SettingsTopBar2({ workspaceId, workspaceName }) {
|
|
3023
|
-
const
|
|
3066
|
+
const config = useOptionalConfig();
|
|
3067
|
+
const appTitle = config?.appName ?? "Boring UI";
|
|
3068
|
+
const appInitial = (appTitle.trim().charAt(0) || "B").toUpperCase();
|
|
3069
|
+
const navigate = useNavigate5();
|
|
3024
3070
|
const workspaceHref = workspaceId ? `/workspace/${encodeURIComponent(workspaceId)}` : "/";
|
|
3025
3071
|
return /* @__PURE__ */ jsx21(
|
|
3026
3072
|
"header",
|
|
@@ -3038,10 +3084,10 @@ function SettingsTopBar2({ workspaceId, workspaceName }) {
|
|
|
3038
3084
|
title: "Back to workspace",
|
|
3039
3085
|
onClick: () => navigate(workspaceHref),
|
|
3040
3086
|
className: "shrink-0 bg-foreground text-[12px] font-semibold text-background hover:bg-foreground/90",
|
|
3041
|
-
children:
|
|
3087
|
+
children: appInitial
|
|
3042
3088
|
}
|
|
3043
3089
|
),
|
|
3044
|
-
/* @__PURE__ */ jsx21("span", { className: "truncate text-[13px] font-medium tracking-tight text-foreground", children:
|
|
3090
|
+
/* @__PURE__ */ jsx21("span", { className: "truncate text-[13px] font-medium tracking-tight text-foreground", children: appTitle }),
|
|
3045
3091
|
/* @__PURE__ */ jsx21("span", { "aria-hidden": "true", className: "text-muted-foreground/30", children: "/" }),
|
|
3046
3092
|
/* @__PURE__ */ jsx21("span", { className: "truncate text-[13px] text-muted-foreground", children: workspaceName }),
|
|
3047
3093
|
/* @__PURE__ */ jsx21("span", { "aria-hidden": "true", className: "text-muted-foreground/30", children: "/" }),
|
|
@@ -3091,7 +3137,7 @@ function WorkspaceSettingsPage({ topBar } = {}) {
|
|
|
3091
3137
|
const workspace = useCurrentWorkspace();
|
|
3092
3138
|
const role = useWorkspaceRole();
|
|
3093
3139
|
const queryClient = useQueryClient6();
|
|
3094
|
-
const navigate =
|
|
3140
|
+
const navigate = useNavigate5();
|
|
3095
3141
|
const workspaceId = workspace?.id ?? "";
|
|
3096
3142
|
const [nameValue, setNameValue] = useState19(null);
|
|
3097
3143
|
const [nameError, setNameError] = useState19(null);
|
|
@@ -3533,8 +3579,9 @@ function createDefaultQueryClient() {
|
|
|
3533
3579
|
});
|
|
3534
3580
|
}
|
|
3535
3581
|
function RouterAuthGate({ children, publicPaths }) {
|
|
3582
|
+
const config = useConfig();
|
|
3536
3583
|
const location = useLocation2();
|
|
3537
|
-
const navigate =
|
|
3584
|
+
const navigate = useNavigate6();
|
|
3538
3585
|
const authLocation = useMemo6(
|
|
3539
3586
|
() => ({ pathname: location.pathname, search: location.search, hash: location.hash }),
|
|
3540
3587
|
[location.hash, location.pathname, location.search]
|
|
@@ -3551,6 +3598,7 @@ function RouterAuthGate({ children, publicPaths }) {
|
|
|
3551
3598
|
location: authLocation,
|
|
3552
3599
|
navigate: navigateWithinRouter,
|
|
3553
3600
|
publicPaths,
|
|
3601
|
+
requireEmailVerification: isRuntimeEmailVerificationEnabled(config),
|
|
3554
3602
|
children
|
|
3555
3603
|
}
|
|
3556
3604
|
);
|
|
@@ -3605,7 +3653,7 @@ function CoreFront({ children, authPages, cspNonce, workspaceRoute, workspaceIdP
|
|
|
3605
3653
|
|
|
3606
3654
|
// src/front/commands/CoreCommandContributions.tsx
|
|
3607
3655
|
import { useMemo as useMemo7, useState as useState20 } from "react";
|
|
3608
|
-
import { useNavigate as
|
|
3656
|
+
import { useNavigate as useNavigate7 } from "react-router-dom";
|
|
3609
3657
|
|
|
3610
3658
|
// src/front/workspace/commands.ts
|
|
3611
3659
|
function getWorkspaceCommands(workspaceId, navigate) {
|
|
@@ -3643,7 +3691,7 @@ function toPaletteCommand(command) {
|
|
|
3643
3691
|
};
|
|
3644
3692
|
}
|
|
3645
3693
|
function useCoreCommands() {
|
|
3646
|
-
const navigate =
|
|
3694
|
+
const navigate = useNavigate7();
|
|
3647
3695
|
const signOut = useSignOut();
|
|
3648
3696
|
const workspace = useCurrentWorkspace();
|
|
3649
3697
|
const [isSigningOut, setIsSigningOut] = useState20(false);
|
|
@@ -12,16 +12,19 @@ import {
|
|
|
12
12
|
workspaceRuntimes,
|
|
13
13
|
workspaceSettings,
|
|
14
14
|
workspaces
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-BVZ2YT3M.js";
|
|
16
16
|
import {
|
|
17
17
|
noopTelemetry,
|
|
18
18
|
safeCapture
|
|
19
19
|
} from "./chunk-AQBXNPMD.js";
|
|
20
|
+
import {
|
|
21
|
+
isCoreEmailVerificationEnabled
|
|
22
|
+
} from "./chunk-I4PGL4ZD.js";
|
|
20
23
|
import {
|
|
21
24
|
ConfigValidationError,
|
|
22
25
|
ERROR_CODES,
|
|
23
26
|
HttpError
|
|
24
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-QZGYKLXB.js";
|
|
25
28
|
|
|
26
29
|
// src/server/config/schema.ts
|
|
27
30
|
import { z } from "zod";
|
|
@@ -290,7 +293,8 @@ function buildRuntimeConfigPayload(config) {
|
|
|
290
293
|
githubOauth: config.features.githubOauth,
|
|
291
294
|
googleOauth: isGoogleOauthUsable(config),
|
|
292
295
|
invitesEnabled: config.features.invitesEnabled,
|
|
293
|
-
sendWelcomeEmail: config.features.sendWelcomeEmail
|
|
296
|
+
sendWelcomeEmail: config.features.sendWelcomeEmail,
|
|
297
|
+
emailVerification: isCoreEmailVerificationEnabled(config)
|
|
294
298
|
}
|
|
295
299
|
};
|
|
296
300
|
}
|
|
@@ -419,7 +423,7 @@ function registerCapabilities(app) {
|
|
|
419
423
|
contributors.set(name, fn);
|
|
420
424
|
}
|
|
421
425
|
);
|
|
422
|
-
const
|
|
426
|
+
const emailVerificationEnabled = isCoreEmailVerificationEnabled(app.config);
|
|
423
427
|
app.registerCapabilitiesContributor("core", () => {
|
|
424
428
|
const googleOauth = isGoogleOauthUsable(app.config);
|
|
425
429
|
const core = {
|
|
@@ -428,15 +432,15 @@ function registerCapabilities(app) {
|
|
|
428
432
|
invitesEnabled: app.config.features.invitesEnabled,
|
|
429
433
|
githubOauth: app.config.features.githubOauth,
|
|
430
434
|
googleOauth,
|
|
431
|
-
emailFlows:
|
|
435
|
+
emailFlows: emailVerificationEnabled
|
|
432
436
|
},
|
|
433
437
|
auth: {
|
|
434
438
|
emailPassword: true,
|
|
435
439
|
github: false,
|
|
436
440
|
google: googleOauth,
|
|
437
|
-
emailVerification:
|
|
438
|
-
passwordReset:
|
|
439
|
-
magicLink:
|
|
441
|
+
emailVerification: emailVerificationEnabled,
|
|
442
|
+
passwordReset: emailVerificationEnabled,
|
|
443
|
+
magicLink: emailVerificationEnabled
|
|
440
444
|
}
|
|
441
445
|
};
|
|
442
446
|
return { core };
|
|
@@ -1747,7 +1751,8 @@ function buildMailTransport(config) {
|
|
|
1747
1751
|
function createAuth(config, db, opts) {
|
|
1748
1752
|
const transport = buildMailTransport(config);
|
|
1749
1753
|
const telemetry = opts?.telemetry ?? noopTelemetry;
|
|
1750
|
-
const
|
|
1754
|
+
const emailVerificationEnabled = isCoreEmailVerificationEnabled(config);
|
|
1755
|
+
const emailVerificationConfig = emailVerificationEnabled && transport ? {
|
|
1751
1756
|
sendOnSignUp: true,
|
|
1752
1757
|
sendVerificationEmail: async (data) => {
|
|
1753
1758
|
const email = await renderVerifyEmail({
|
|
@@ -1930,7 +1935,8 @@ var authHookPlugin = async (app, opts) => {
|
|
|
1930
1935
|
request.user = {
|
|
1931
1936
|
id: result.user.id,
|
|
1932
1937
|
email: result.user.email,
|
|
1933
|
-
name: result.user.name ?? null
|
|
1938
|
+
name: result.user.name ?? null,
|
|
1939
|
+
emailVerified: Boolean(result.user.emailVerified)
|
|
1934
1940
|
};
|
|
1935
1941
|
}
|
|
1936
1942
|
} catch {
|
|
@@ -1938,7 +1944,8 @@ var authHookPlugin = async (app, opts) => {
|
|
|
1938
1944
|
}
|
|
1939
1945
|
}
|
|
1940
1946
|
const path = request.url.split("?")[0];
|
|
1941
|
-
|
|
1947
|
+
const isProtectedApi = path.startsWith("/api/v1/") && !publicPatterns.some((re) => re.test(path));
|
|
1948
|
+
if (isProtectedApi && !request.user) {
|
|
1942
1949
|
throw new HttpError({
|
|
1943
1950
|
status: 401,
|
|
1944
1951
|
code: ERROR_CODES.UNAUTHORIZED,
|
|
@@ -1946,6 +1953,14 @@ var authHookPlugin = async (app, opts) => {
|
|
|
1946
1953
|
requestId: request.id
|
|
1947
1954
|
});
|
|
1948
1955
|
}
|
|
1956
|
+
if (isProtectedApi && isCoreEmailVerificationEnabled(app.config) && request.user?.emailVerified !== true) {
|
|
1957
|
+
throw new HttpError({
|
|
1958
|
+
status: 403,
|
|
1959
|
+
code: ERROR_CODES.EMAIL_NOT_VERIFIED,
|
|
1960
|
+
message: "Email verification required",
|
|
1961
|
+
requestId: request.id
|
|
1962
|
+
});
|
|
1963
|
+
}
|
|
1949
1964
|
});
|
|
1950
1965
|
};
|
|
1951
1966
|
var authHook = fp2(authHookPlugin, { name: "auth-hook" });
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as CoreConfig,
|
|
1
|
+
import { C as CoreConfig, c as Workspace, E as ERROR_CODES, M as MemberRole, d as WorkspaceMember, U as User, e as WorkspaceInvite, f as WorkspaceRuntime, W as WorkspaceRuntimeResourceSelector, a as WorkspaceRuntimeResource, b as WorkspaceRuntimeResourceInput, g as CapabilitiesResponse } from './types-Bb7I-83I.js';
|
|
2
2
|
import { drizzle } from 'drizzle-orm/postgres-js';
|
|
3
3
|
import postgres from 'postgres';
|
|
4
4
|
|
|
@@ -131,6 +131,7 @@ declare module 'fastify' {
|
|
|
131
131
|
id: string;
|
|
132
132
|
email: string;
|
|
133
133
|
name: string | null;
|
|
134
|
+
emailVerified: boolean;
|
|
134
135
|
} | null;
|
|
135
136
|
cspNonce?: string;
|
|
136
137
|
}
|
|
@@ -142,4 +143,4 @@ declare function createDatabase(config: CoreConfig): {
|
|
|
142
143
|
sql: postgres.Sql;
|
|
143
144
|
};
|
|
144
145
|
|
|
145
|
-
export { type AuthProvider as A, type CreateCoreAppOptions as C, type Database as D, type ProvisionContext as P, type UserStore as U, type WorkspaceStore as W, type WorkspaceProvisioner as a, type CapabilitiesContributor as b,
|
|
146
|
+
export { type AuthProvider as A, type CreateCoreAppOptions as C, type Database as D, type ProvisionContext as P, type UserStore as U, type WorkspaceStore as W, type WorkspaceProvisioner as a, type CapabilitiesContributor as b, type ProvisionResult as c, createDatabase as d };
|
package/dist/front/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import * as react from 'react';
|
|
3
3
|
import { Component, ReactNode, ErrorInfo } from 'react';
|
|
4
|
-
import { R as RuntimeConfig, g as CapabilitiesResponse,
|
|
4
|
+
import { R as RuntimeConfig, g as CapabilitiesResponse, d as WorkspaceMember, U as User, c as Workspace, M as MemberRole, S as SessionState } from '../types-Bb7I-83I.js';
|
|
5
5
|
import * as _tanstack_react_query from '@tanstack/react-query';
|
|
6
6
|
import * as better_auth_react from 'better-auth/react';
|
|
7
7
|
import { createAuthClient } from 'better-auth/react';
|
|
@@ -461,8 +461,9 @@ interface AuthGateProps {
|
|
|
461
461
|
replace?: boolean;
|
|
462
462
|
}) => void;
|
|
463
463
|
now?: () => number;
|
|
464
|
+
requireEmailVerification?: boolean;
|
|
464
465
|
}
|
|
465
|
-
declare function AuthGate({ children, publicPaths, graceMs, location, navigate, now, }: AuthGateProps): react_jsx_runtime.JSX.Element | null;
|
|
466
|
+
declare function AuthGate({ children, publicPaths, graceMs, location, navigate, now, requireEmailVerification, }: AuthGateProps): react_jsx_runtime.JSX.Element | null;
|
|
466
467
|
|
|
467
468
|
interface CoreCommand {
|
|
468
469
|
id: string;
|
package/dist/front/index.js
CHANGED
|
@@ -58,12 +58,13 @@ import {
|
|
|
58
58
|
useWorkspaceMembers,
|
|
59
59
|
useWorkspaceRole,
|
|
60
60
|
useWorkspaceRouteStatus
|
|
61
|
-
} from "../chunk-
|
|
61
|
+
} from "../chunk-P4RF2D7H.js";
|
|
62
62
|
import {
|
|
63
63
|
TopBarSlotProvider,
|
|
64
64
|
useTopBarSlot
|
|
65
65
|
} from "../chunk-HYNKZSTF.js";
|
|
66
|
-
import "../chunk-
|
|
66
|
+
import "../chunk-I4PGL4ZD.js";
|
|
67
|
+
import "../chunk-QZGYKLXB.js";
|
|
67
68
|
import "../chunk-MLKGABMK.js";
|
|
68
69
|
export {
|
|
69
70
|
AppErrorBoundary,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { U as UserStore, W as WorkspaceStore } from '../../connection-
|
|
2
|
-
export { D as Database,
|
|
3
|
-
export { F as FinishReservationInput, G as GrantOnceInput, I as InsufficientCreditError, M as MeteringBalance, P as PostgresMeteringStore, R as RecordUsageInput, a as RecordUsageResult, b as ReservationFinalStatus, c as ReserveInput, d as ReserveResult, e as RunMigrationsOptions, r as runMigrations } from '../../PostgresMeteringStore-
|
|
4
|
-
import { U as User,
|
|
1
|
+
import { U as UserStore, W as WorkspaceStore } from '../../connection-B1iC6B-w.js';
|
|
2
|
+
export { D as Database, d as createDatabase } from '../../connection-B1iC6B-w.js';
|
|
3
|
+
export { F as FinishReservationInput, G as GrantOnceInput, I as InsufficientCreditError, M as MeteringBalance, P as PostgresMeteringStore, R as RecordUsageInput, a as RecordUsageResult, b as ReservationFinalStatus, c as ReserveInput, d as ReserveResult, e as RunMigrationsOptions, r as runMigrations } from '../../PostgresMeteringStore-qjKGmVFr.js';
|
|
4
|
+
import { U as User, c as Workspace, E as ERROR_CODES, M as MemberRole, d as WorkspaceMember, e as WorkspaceInvite, f as WorkspaceRuntime, W as WorkspaceRuntimeResourceSelector, a as WorkspaceRuntimeResource, b as WorkspaceRuntimeResourceInput } from '../../types-Bb7I-83I.js';
|
|
5
5
|
import { PostgresJsDatabase } from 'drizzle-orm/postgres-js';
|
|
6
6
|
import 'postgres';
|
|
7
7
|
|
package/dist/server/db/index.js
CHANGED
|
@@ -7,8 +7,8 @@ import {
|
|
|
7
7
|
PostgresWorkspaceStore,
|
|
8
8
|
createDatabase,
|
|
9
9
|
runMigrations
|
|
10
|
-
} from "../../chunk-
|
|
11
|
-
import "../../chunk-
|
|
10
|
+
} from "../../chunk-BVZ2YT3M.js";
|
|
11
|
+
import "../../chunk-QZGYKLXB.js";
|
|
12
12
|
import "../../chunk-MLKGABMK.js";
|
|
13
13
|
export {
|
|
14
14
|
InsufficientCreditError,
|