@hachej/boring-core 0.1.23 → 0.1.26
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/{CoreFront-CgAkiEts.d.ts → CoreFront-N0QJSYaM.d.ts} +4 -1
- package/dist/app/front/index.d.ts +17 -3
- package/dist/app/front/index.js +462 -70
- package/dist/app/server/index.js +6 -5
- package/dist/{chunk-6D7LEQSL.js → chunk-2JDK4XUZ.js} +72 -31
- package/dist/{chunk-JMCBLJ6W.js → chunk-5R3U6QKD.js} +174 -81
- package/dist/front/index.d.ts +33 -3
- package/dist/front/index.js +5 -3
- package/dist/server/index.js +1 -1
- package/package.json +7 -6
package/dist/app/server/index.js
CHANGED
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
registerRoutes,
|
|
10
10
|
registerSettingsRoutes,
|
|
11
11
|
registerWorkspaceRoutes
|
|
12
|
-
} from "../../chunk-
|
|
12
|
+
} from "../../chunk-2JDK4XUZ.js";
|
|
13
13
|
import {
|
|
14
14
|
PostgresUserStore,
|
|
15
15
|
PostgresWorkspaceStore,
|
|
@@ -531,7 +531,8 @@ async function createCoreWorkspaceAgentServer(options = {}) {
|
|
|
531
531
|
const { app, sql, db, userStore, workspaceStore } = await createCoreRuntime(config);
|
|
532
532
|
const appRoot = options.appRoot;
|
|
533
533
|
const serveFrontend = options.serveFrontend ?? (process.env.NODE_ENV !== "development" && Boolean(appRoot));
|
|
534
|
-
const
|
|
534
|
+
const pluginWorkspaceRoot = process.cwd();
|
|
535
|
+
const workspaceRoot = options.workspaceRoot ?? process.env.BORING_AGENT_WORKSPACE_ROOT ?? process.cwd();
|
|
535
536
|
const telemetrySource = options.telemetry ? "custom" : process.env.BORING_TELEMETRY_ENABLED === "true" ? "db-env" : "noop-env";
|
|
536
537
|
const telemetry = options.telemetry ?? createDatabaseTelemetryFromEnv(db, { appId: config.appId }, process.env);
|
|
537
538
|
app.log.debug({ telemetry: { source: telemetrySource } }, "resolved telemetry sink");
|
|
@@ -544,7 +545,7 @@ async function createCoreWorkspaceAgentServer(options = {}) {
|
|
|
544
545
|
serveSpaShell: (request, reply) => serveFrontendShell(request, reply, path.resolve(appRoot, "dist/front/index.html"), telemetry)
|
|
545
546
|
} : void 0);
|
|
546
547
|
const defaultPluginPackagePaths = resolveDefaultWorkspacePluginPackagePaths({
|
|
547
|
-
workspaceRoot,
|
|
548
|
+
workspaceRoot: pluginWorkspaceRoot,
|
|
548
549
|
appPackageJsonPath: options.appPackageJsonPath,
|
|
549
550
|
defaultPluginPackages: options.defaultPluginPackages
|
|
550
551
|
});
|
|
@@ -568,7 +569,7 @@ async function createCoreWorkspaceAgentServer(options = {}) {
|
|
|
568
569
|
return bridge;
|
|
569
570
|
};
|
|
570
571
|
const pluginResolveContext = {
|
|
571
|
-
workspaceRoot,
|
|
572
|
+
workspaceRoot: pluginWorkspaceRoot,
|
|
572
573
|
bridge: createUnavailableCorePluginBridge()
|
|
573
574
|
};
|
|
574
575
|
const resolvedPlugins = await Promise.all(
|
|
@@ -578,7 +579,7 @@ async function createCoreWorkspaceAgentServer(options = {}) {
|
|
|
578
579
|
))
|
|
579
580
|
);
|
|
580
581
|
const pluginCollection = collectWorkspaceAgentServerPlugins({
|
|
581
|
-
workspaceRoot,
|
|
582
|
+
workspaceRoot: pluginWorkspaceRoot,
|
|
582
583
|
systemPromptAppend: staticSystemPromptAppend,
|
|
583
584
|
pi: mergePiOptions(options.pi, defaultPackagePiOptions),
|
|
584
585
|
plugins: resolvedPlugins,
|
|
@@ -1951,9 +1951,79 @@ var updateWorkspaceBody = z3.object({
|
|
|
1951
1951
|
}).strict();
|
|
1952
1952
|
|
|
1953
1953
|
// src/server/routes/workspaces.ts
|
|
1954
|
+
var DEFAULT_WORKSPACE_NAME = "My Workspace";
|
|
1954
1955
|
var workspaceRoutesPlugin = async (app) => {
|
|
1955
1956
|
const store = app.workspaceStore;
|
|
1956
1957
|
const provisioner = app.provisioner;
|
|
1958
|
+
const defaultWorkspaceCreates = /* @__PURE__ */ new Map();
|
|
1959
|
+
async function provisionWorkspace(workspace, ownerId, request) {
|
|
1960
|
+
if (!provisioner) return;
|
|
1961
|
+
await store.putWorkspaceRuntime(workspace.id, { state: "pending" });
|
|
1962
|
+
try {
|
|
1963
|
+
const result = await provisioner.provision({
|
|
1964
|
+
workspaceId: workspace.id,
|
|
1965
|
+
workspaceName: workspace.name,
|
|
1966
|
+
ownerId,
|
|
1967
|
+
appId: app.config.appId
|
|
1968
|
+
});
|
|
1969
|
+
await store.putWorkspaceRuntime(workspace.id, {
|
|
1970
|
+
state: "ready",
|
|
1971
|
+
volumePath: result.volumePath
|
|
1972
|
+
});
|
|
1973
|
+
} catch (err) {
|
|
1974
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1975
|
+
await store.putWorkspaceRuntime(workspace.id, {
|
|
1976
|
+
state: "error",
|
|
1977
|
+
lastError: message,
|
|
1978
|
+
lastErrorOp: "provision"
|
|
1979
|
+
});
|
|
1980
|
+
request.log.error({ workspaceId: workspace.id, err }, "workspace.provision.failed");
|
|
1981
|
+
throw new HttpError({
|
|
1982
|
+
status: 500,
|
|
1983
|
+
code: ERROR_CODES.PROVISION_FAILED,
|
|
1984
|
+
message: "Workspace provisioning failed",
|
|
1985
|
+
requestId: request.id
|
|
1986
|
+
});
|
|
1987
|
+
}
|
|
1988
|
+
}
|
|
1989
|
+
async function createWorkspaceForUser(userId, name, isDefault, request) {
|
|
1990
|
+
const workspace = await store.create(userId, name, app.config.appId, { isDefault });
|
|
1991
|
+
await provisionWorkspace(workspace, userId, request);
|
|
1992
|
+
return workspace;
|
|
1993
|
+
}
|
|
1994
|
+
async function ensureDefaultWorkspaceProvisioned(workspace, request) {
|
|
1995
|
+
if (!provisioner || !workspace.isDefault) return;
|
|
1996
|
+
const runtime = await store.getWorkspaceRuntime(workspace.id);
|
|
1997
|
+
const needsProvisioning = !runtime || runtime.state === "ready" && !runtime.volumePath;
|
|
1998
|
+
if (needsProvisioning) await provisionWorkspace(workspace, workspace.createdBy, request);
|
|
1999
|
+
}
|
|
2000
|
+
async function listOrCreateDefaultWorkspace(userId, request) {
|
|
2001
|
+
const existing = await store.list(userId, app.config.appId);
|
|
2002
|
+
if (existing.length > 0) {
|
|
2003
|
+
await Promise.all(existing.map((workspace) => ensureDefaultWorkspaceProvisioned(workspace, request)));
|
|
2004
|
+
return existing;
|
|
2005
|
+
}
|
|
2006
|
+
const createKey = `${app.config.appId}:${userId}`;
|
|
2007
|
+
const inFlight = defaultWorkspaceCreates.get(createKey);
|
|
2008
|
+
if (inFlight) return await inFlight;
|
|
2009
|
+
const createPromise = (async () => {
|
|
2010
|
+
try {
|
|
2011
|
+
const created = await createWorkspaceForUser(userId, DEFAULT_WORKSPACE_NAME, true, request);
|
|
2012
|
+
return [created];
|
|
2013
|
+
} catch (error) {
|
|
2014
|
+
if (error instanceof HttpError) throw error;
|
|
2015
|
+
const racedExisting = await store.list(userId, app.config.appId);
|
|
2016
|
+
if (racedExisting.length > 0) return racedExisting;
|
|
2017
|
+
throw error;
|
|
2018
|
+
}
|
|
2019
|
+
})();
|
|
2020
|
+
defaultWorkspaceCreates.set(createKey, createPromise);
|
|
2021
|
+
try {
|
|
2022
|
+
return await createPromise;
|
|
2023
|
+
} finally {
|
|
2024
|
+
if (defaultWorkspaceCreates.get(createKey) === createPromise) defaultWorkspaceCreates.delete(createKey);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
1957
2027
|
app.post("/api/v1/workspaces", async (request, reply) => {
|
|
1958
2028
|
const parsed = createWorkspaceBody.safeParse(request.body);
|
|
1959
2029
|
if (!parsed.success) {
|
|
@@ -1967,42 +2037,13 @@ var workspaceRoutesPlugin = async (app) => {
|
|
|
1967
2037
|
const user = request.user;
|
|
1968
2038
|
const existing = await store.list(user.id, app.config.appId);
|
|
1969
2039
|
const isDefault = existing.length === 0;
|
|
1970
|
-
const workspace = await
|
|
1971
|
-
if (provisioner) {
|
|
1972
|
-
await store.putWorkspaceRuntime(workspace.id, { state: "pending" });
|
|
1973
|
-
try {
|
|
1974
|
-
const result = await provisioner.provision({
|
|
1975
|
-
workspaceId: workspace.id,
|
|
1976
|
-
workspaceName: workspace.name,
|
|
1977
|
-
ownerId: user.id,
|
|
1978
|
-
appId: app.config.appId
|
|
1979
|
-
});
|
|
1980
|
-
await store.putWorkspaceRuntime(workspace.id, {
|
|
1981
|
-
state: "ready",
|
|
1982
|
-
volumePath: result.volumePath
|
|
1983
|
-
});
|
|
1984
|
-
} catch (err) {
|
|
1985
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
1986
|
-
await store.putWorkspaceRuntime(workspace.id, {
|
|
1987
|
-
state: "error",
|
|
1988
|
-
lastError: message,
|
|
1989
|
-
lastErrorOp: "provision"
|
|
1990
|
-
});
|
|
1991
|
-
request.log.error({ workspaceId: workspace.id, err }, "workspace.provision.failed");
|
|
1992
|
-
throw new HttpError({
|
|
1993
|
-
status: 500,
|
|
1994
|
-
code: ERROR_CODES.PROVISION_FAILED,
|
|
1995
|
-
message: "Workspace provisioning failed",
|
|
1996
|
-
requestId: request.id
|
|
1997
|
-
});
|
|
1998
|
-
}
|
|
1999
|
-
}
|
|
2040
|
+
const workspace = await createWorkspaceForUser(user.id, parsed.data.name, isDefault, request);
|
|
2000
2041
|
request.log.info({ workspaceId: workspace.id, userId: user.id }, "workspace.create");
|
|
2001
2042
|
reply.status(201);
|
|
2002
2043
|
return { workspace, role: "owner" };
|
|
2003
2044
|
});
|
|
2004
2045
|
app.get("/api/v1/workspaces", async (request) => {
|
|
2005
|
-
const workspaces2 = await
|
|
2046
|
+
const workspaces2 = await listOrCreateDefaultWorkspace(request.user.id, request);
|
|
2006
2047
|
return { workspaces: workspaces2 };
|
|
2007
2048
|
});
|
|
2008
2049
|
app.get(
|
|
@@ -471,68 +471,12 @@ function useWorkspaceMembers(workspaceId) {
|
|
|
471
471
|
}
|
|
472
472
|
|
|
473
473
|
// src/front/WorkspaceAuthProvider.tsx
|
|
474
|
-
import { createContext as
|
|
474
|
+
import { createContext as createContext4, useContext as useContext4 } from "react";
|
|
475
475
|
import { useQuery as useQuery2, useQueryClient } from "@tanstack/react-query";
|
|
476
476
|
import { matchPath, useLocation, useParams } from "react-router-dom";
|
|
477
|
-
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
478
|
-
var WorkspaceContext = createContext3({
|
|
479
|
-
workspace: null,
|
|
480
|
-
role: null
|
|
481
|
-
});
|
|
482
|
-
var WORKSPACES_QUERY_KEY = ["workspaces"];
|
|
483
|
-
function workspaceQueryKey(workspaceId) {
|
|
484
|
-
return ["workspace", workspaceId ?? null];
|
|
485
|
-
}
|
|
486
|
-
async function fetchWorkspaces() {
|
|
487
|
-
const data = await apiFetchJson("/api/v1/workspaces");
|
|
488
|
-
return data.workspaces;
|
|
489
|
-
}
|
|
490
|
-
async function fetchWorkspace(workspaceId) {
|
|
491
|
-
return await apiFetchJson(
|
|
492
|
-
`/api/v1/workspaces/${encodeURIComponent(workspaceId)}`
|
|
493
|
-
);
|
|
494
|
-
}
|
|
495
|
-
function workspaceIdFromPath(pathname) {
|
|
496
|
-
const match = matchPath("/w/:id/*", pathname) ?? matchPath("/w/:id", pathname) ?? matchPath("/workspace/:id/*", pathname) ?? matchPath("/workspace/:id", pathname);
|
|
497
|
-
const id = match?.params.id?.trim();
|
|
498
|
-
return id ? id : null;
|
|
499
|
-
}
|
|
500
|
-
function WorkspaceAuthProvider({ children }) {
|
|
501
|
-
const { id } = useParams();
|
|
502
|
-
const location = useLocation();
|
|
503
|
-
const queryClient = useQueryClient();
|
|
504
|
-
const routeWorkspaceId = id?.trim() ? id : workspaceIdFromPath(location.pathname);
|
|
505
|
-
const workspacesQuery = useQuery2({
|
|
506
|
-
queryKey: WORKSPACES_QUERY_KEY,
|
|
507
|
-
queryFn: fetchWorkspaces
|
|
508
|
-
});
|
|
509
|
-
const defaultWorkspace = routeWorkspaceId === null ? workspacesQuery.data?.find((workspace2) => workspace2.isDefault) ?? workspacesQuery.data?.[0] ?? null : null;
|
|
510
|
-
const resolvedId = routeWorkspaceId ?? defaultWorkspace?.id ?? null;
|
|
511
|
-
const cachedDetail = resolvedId ? queryClient.getQueryData(workspaceQueryKey(resolvedId)) : void 0;
|
|
512
|
-
const detailQuery = useQuery2({
|
|
513
|
-
queryKey: workspaceQueryKey(resolvedId),
|
|
514
|
-
queryFn: () => {
|
|
515
|
-
if (!resolvedId) {
|
|
516
|
-
throw new Error("Workspace id is required");
|
|
517
|
-
}
|
|
518
|
-
return fetchWorkspace(resolvedId);
|
|
519
|
-
},
|
|
520
|
-
enabled: resolvedId !== null
|
|
521
|
-
});
|
|
522
|
-
const detail = detailQuery.data ?? cachedDetail ?? null;
|
|
523
|
-
const workspace = detailQuery.isError ? null : detail?.workspace ?? null;
|
|
524
|
-
const role = detailQuery.isError ? null : detail?.role ?? null;
|
|
525
|
-
return /* @__PURE__ */ jsx4(WorkspaceContext.Provider, { value: { workspace, role }, children });
|
|
526
|
-
}
|
|
527
|
-
function useCurrentWorkspace() {
|
|
528
|
-
return useContext3(WorkspaceContext).workspace;
|
|
529
|
-
}
|
|
530
|
-
function useWorkspaceRole() {
|
|
531
|
-
return useContext3(WorkspaceContext).role;
|
|
532
|
-
}
|
|
533
477
|
|
|
534
478
|
// src/front/auth/AuthProvider.tsx
|
|
535
|
-
import { createContext as
|
|
479
|
+
import { createContext as createContext3, useContext as useContext3, useCallback as useCallback2, useMemo as useMemo2 } from "react";
|
|
536
480
|
|
|
537
481
|
// src/front/auth/authClient.ts
|
|
538
482
|
import { createAuthClient } from "better-auth/react";
|
|
@@ -555,8 +499,8 @@ function getAuthClient(baseURL) {
|
|
|
555
499
|
}
|
|
556
500
|
|
|
557
501
|
// src/front/auth/AuthProvider.tsx
|
|
558
|
-
import { jsx as
|
|
559
|
-
var AuthContext =
|
|
502
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
503
|
+
var AuthContext = createContext3(null);
|
|
560
504
|
function toISOString(value) {
|
|
561
505
|
if (!value) return "";
|
|
562
506
|
if (value instanceof Date) return value.toISOString();
|
|
@@ -589,10 +533,10 @@ function AuthProvider({
|
|
|
589
533
|
() => ({ client, signOut }),
|
|
590
534
|
[client, signOut]
|
|
591
535
|
);
|
|
592
|
-
return /* @__PURE__ */
|
|
536
|
+
return /* @__PURE__ */ jsx4(AuthContext.Provider, { value, children });
|
|
593
537
|
}
|
|
594
538
|
function useAuthContext() {
|
|
595
|
-
const ctx =
|
|
539
|
+
const ctx = useContext3(AuthContext);
|
|
596
540
|
if (!ctx) throw new Error("useSession/signIn/signOut must be used within an AuthProvider");
|
|
597
541
|
return ctx;
|
|
598
542
|
}
|
|
@@ -620,8 +564,21 @@ function useSignUp() {
|
|
|
620
564
|
return client.signUp;
|
|
621
565
|
}
|
|
622
566
|
function useForgetPassword() {
|
|
623
|
-
|
|
624
|
-
return
|
|
567
|
+
useAuthContext();
|
|
568
|
+
return async (opts) => {
|
|
569
|
+
const endpoint = buildApiUrl("/auth/request-password-reset");
|
|
570
|
+
const response = await fetch(endpoint, {
|
|
571
|
+
method: "POST",
|
|
572
|
+
headers: { "content-type": "application/json" },
|
|
573
|
+
credentials: "include",
|
|
574
|
+
body: JSON.stringify(opts)
|
|
575
|
+
});
|
|
576
|
+
const data = await response.json().catch(() => null);
|
|
577
|
+
if (!response.ok) {
|
|
578
|
+
return { data: null, error: data ?? { status: response.status, message: "Request failed" } };
|
|
579
|
+
}
|
|
580
|
+
return { data, error: null };
|
|
581
|
+
};
|
|
625
582
|
}
|
|
626
583
|
function useResetPassword() {
|
|
627
584
|
const { client } = useAuthContext();
|
|
@@ -644,6 +601,107 @@ function useSignOut() {
|
|
|
644
601
|
return signOut;
|
|
645
602
|
}
|
|
646
603
|
|
|
604
|
+
// src/front/WorkspaceAuthProvider.tsx
|
|
605
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
606
|
+
var WorkspaceContext = createContext4({
|
|
607
|
+
workspace: null,
|
|
608
|
+
role: null,
|
|
609
|
+
routeStatus: { status: "idle", workspaceId: null }
|
|
610
|
+
});
|
|
611
|
+
var WORKSPACES_QUERY_KEY = ["workspaces"];
|
|
612
|
+
function workspaceQueryKey(workspaceId) {
|
|
613
|
+
return ["workspace", workspaceId ?? null];
|
|
614
|
+
}
|
|
615
|
+
async function fetchWorkspaces() {
|
|
616
|
+
const data = await apiFetchJson("/api/v1/workspaces");
|
|
617
|
+
return data.workspaces;
|
|
618
|
+
}
|
|
619
|
+
async function fetchWorkspace(workspaceId) {
|
|
620
|
+
return await apiFetchJson(
|
|
621
|
+
`/api/v1/workspaces/${encodeURIComponent(workspaceId)}`
|
|
622
|
+
);
|
|
623
|
+
}
|
|
624
|
+
function routePatterns(route) {
|
|
625
|
+
const normalized = route.endsWith("/*") ? route.slice(0, -2) : route;
|
|
626
|
+
return [`${normalized}/*`, normalized];
|
|
627
|
+
}
|
|
628
|
+
function workspaceIdFromPath(pathname, workspaceRoute = "/workspace/:id", workspaceIdParam = "id") {
|
|
629
|
+
const patterns = [
|
|
630
|
+
...routePatterns(workspaceRoute),
|
|
631
|
+
"/w/:id/*",
|
|
632
|
+
"/w/:id",
|
|
633
|
+
"/workspace/:id/*",
|
|
634
|
+
"/workspace/:id"
|
|
635
|
+
];
|
|
636
|
+
for (const pattern of patterns) {
|
|
637
|
+
const match = matchPath(pattern, pathname);
|
|
638
|
+
const id = match?.params[workspaceIdParam]?.trim() ?? match?.params.id?.trim();
|
|
639
|
+
if (id) return id;
|
|
640
|
+
}
|
|
641
|
+
return null;
|
|
642
|
+
}
|
|
643
|
+
function routeStatusFromError(workspaceId, error) {
|
|
644
|
+
const detail = getHttpErrorDetail(error);
|
|
645
|
+
if (detail.status === 404 || detail.code === "not_found") {
|
|
646
|
+
return { status: "not-found", workspaceId, message: detail.message };
|
|
647
|
+
}
|
|
648
|
+
if (detail.status === 403 || detail.code === "forbidden" || detail.code === "not_member") {
|
|
649
|
+
return { status: "forbidden", workspaceId, message: detail.message };
|
|
650
|
+
}
|
|
651
|
+
return { status: "switch-failed", workspaceId, message: detail.message };
|
|
652
|
+
}
|
|
653
|
+
function WorkspaceAuthProvider({
|
|
654
|
+
children,
|
|
655
|
+
workspaceRoute,
|
|
656
|
+
workspaceIdParam
|
|
657
|
+
}) {
|
|
658
|
+
const { id } = useParams();
|
|
659
|
+
const location = useLocation();
|
|
660
|
+
const queryClient = useQueryClient();
|
|
661
|
+
const routeWorkspaceId = id?.trim() ? id : workspaceIdFromPath(location.pathname, workspaceRoute, workspaceIdParam);
|
|
662
|
+
const session = useSession();
|
|
663
|
+
const isAuthenticated = Boolean(session.data?.user);
|
|
664
|
+
const workspacesQuery = useQuery2({
|
|
665
|
+
queryKey: WORKSPACES_QUERY_KEY,
|
|
666
|
+
queryFn: fetchWorkspaces,
|
|
667
|
+
enabled: isAuthenticated
|
|
668
|
+
});
|
|
669
|
+
const defaultWorkspace = routeWorkspaceId === null ? workspacesQuery.data?.find((workspace2) => workspace2.isDefault) ?? workspacesQuery.data?.[0] ?? null : null;
|
|
670
|
+
const resolvedId = routeWorkspaceId ?? defaultWorkspace?.id ?? null;
|
|
671
|
+
const cachedDetail = resolvedId ? queryClient.getQueryData(workspaceQueryKey(resolvedId)) : void 0;
|
|
672
|
+
const detailQuery = useQuery2({
|
|
673
|
+
queryKey: workspaceQueryKey(resolvedId),
|
|
674
|
+
queryFn: () => {
|
|
675
|
+
if (!resolvedId) {
|
|
676
|
+
throw new Error("Workspace id is required");
|
|
677
|
+
}
|
|
678
|
+
return fetchWorkspace(resolvedId);
|
|
679
|
+
},
|
|
680
|
+
enabled: isAuthenticated && resolvedId !== null
|
|
681
|
+
});
|
|
682
|
+
const detail = detailQuery.data ?? cachedDetail ?? null;
|
|
683
|
+
const workspace = detailQuery.isError ? null : detail?.workspace ?? null;
|
|
684
|
+
const role = detailQuery.isError ? null : detail?.role ?? null;
|
|
685
|
+
const routeStatus = (() => {
|
|
686
|
+
if (!isAuthenticated) return { status: "idle", workspaceId: routeWorkspaceId };
|
|
687
|
+
if (routeWorkspaceId === null) return { status: "idle", workspaceId: null };
|
|
688
|
+
if (detailQuery.isError) return routeStatusFromError(routeWorkspaceId, detailQuery.error);
|
|
689
|
+
if (detailQuery.isPending && !detail) return { status: "loading", workspaceId: routeWorkspaceId };
|
|
690
|
+
if (workspace?.id === routeWorkspaceId) return { status: "matched", workspaceId: routeWorkspaceId, workspace };
|
|
691
|
+
return { status: "mismatched", workspaceId: routeWorkspaceId, currentWorkspaceId: workspace?.id ?? null };
|
|
692
|
+
})();
|
|
693
|
+
return /* @__PURE__ */ jsx5(WorkspaceContext.Provider, { value: { workspace, role, routeStatus }, children });
|
|
694
|
+
}
|
|
695
|
+
function useCurrentWorkspace() {
|
|
696
|
+
return useContext4(WorkspaceContext).workspace;
|
|
697
|
+
}
|
|
698
|
+
function useWorkspaceRole() {
|
|
699
|
+
return useContext4(WorkspaceContext).role;
|
|
700
|
+
}
|
|
701
|
+
function useWorkspaceRouteStatus() {
|
|
702
|
+
return useContext4(WorkspaceContext).routeStatus;
|
|
703
|
+
}
|
|
704
|
+
|
|
647
705
|
// src/front/auth/UserIdentityProvider.tsx
|
|
648
706
|
import { createContext as createContext5, useContext as useContext5, useEffect as useEffect7, useState as useState6, useRef as useRef3 } from "react";
|
|
649
707
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
@@ -984,6 +1042,8 @@ function ForgotPasswordPage() {
|
|
|
984
1042
|
const forgetPassword = useForgetPassword();
|
|
985
1043
|
const [isSubmitting, setIsSubmitting] = useState10(false);
|
|
986
1044
|
const [submitted, setSubmitted] = useState10(false);
|
|
1045
|
+
const redirect = typeof window === "undefined" ? null : new URLSearchParams(window.location.search).get("redirect");
|
|
1046
|
+
const signinHref = redirect ? `${routes.signin}?redirect=${encodeURIComponent(redirect)}` : routes.signin;
|
|
987
1047
|
const {
|
|
988
1048
|
register,
|
|
989
1049
|
handleSubmit,
|
|
@@ -1007,7 +1067,7 @@ function ForgotPasswordPage() {
|
|
|
1007
1067
|
/* @__PURE__ */ jsx10(CardTitle3, { children: "Check your inbox" }),
|
|
1008
1068
|
/* @__PURE__ */ jsx10(CardDescription3, { children: "If an account exists with that email, we sent a password reset link. Check your inbox and follow the instructions." })
|
|
1009
1069
|
] }),
|
|
1010
|
-
/* @__PURE__ */ jsx10(CardFooter3, { children: /* @__PURE__ */ jsx10("a", { href:
|
|
1070
|
+
/* @__PURE__ */ jsx10(CardFooter3, { children: /* @__PURE__ */ jsx10("a", { href: signinHref, className: "text-sm text-muted-foreground hover:underline", children: "Back to sign in" }) })
|
|
1011
1071
|
] }) });
|
|
1012
1072
|
}
|
|
1013
1073
|
return /* @__PURE__ */ jsx10("div", { className: "flex min-h-screen items-center justify-center p-4", children: /* @__PURE__ */ jsxs3(Card3, { className: "w-full max-w-sm", children: [
|
|
@@ -1032,7 +1092,7 @@ function ForgotPasswordPage() {
|
|
|
1032
1092
|
] }) }),
|
|
1033
1093
|
/* @__PURE__ */ jsxs3(CardFooter3, { className: "flex flex-col gap-4", children: [
|
|
1034
1094
|
/* @__PURE__ */ jsx10(Button5, { type: "submit", className: "w-full", disabled: isSubmitting, children: isSubmitting ? "Sending\u2026" : "Send reset link" }),
|
|
1035
|
-
/* @__PURE__ */ jsx10("a", { href:
|
|
1095
|
+
/* @__PURE__ */ jsx10("a", { href: signinHref, className: "text-sm text-muted-foreground hover:underline", children: "Back to sign in" })
|
|
1036
1096
|
] })
|
|
1037
1097
|
] })
|
|
1038
1098
|
] }) });
|
|
@@ -1816,6 +1876,7 @@ function InviteAcceptPage() {
|
|
|
1816
1876
|
|
|
1817
1877
|
// src/front/AuthGate.tsx
|
|
1818
1878
|
import { useEffect as useEffect9, useMemo as useMemo3, useRef as useRef5 } from "react";
|
|
1879
|
+
import { matchPath as matchPath2 } from "react-router-dom";
|
|
1819
1880
|
import { Fragment as Fragment3, jsx as jsx15 } from "react/jsx-runtime";
|
|
1820
1881
|
var DEFAULT_GRACE_MS = 3e4;
|
|
1821
1882
|
var UNSAFE_REDIRECT_RE = /[\0\r\n<>"'`]/;
|
|
@@ -1842,7 +1903,12 @@ function normalizePublicPath(path) {
|
|
|
1842
1903
|
function isPublicPath(pathname, publicPaths) {
|
|
1843
1904
|
const normalizedPath = normalizePath(pathname);
|
|
1844
1905
|
if (normalizedPath === "/auth" || normalizedPath.startsWith("/auth/")) return true;
|
|
1845
|
-
return publicPaths.some((candidate) =>
|
|
1906
|
+
return publicPaths.some((candidate) => {
|
|
1907
|
+
if (candidate.includes(":") || candidate.includes("*")) {
|
|
1908
|
+
return Boolean(matchPath2({ path: candidate, end: !candidate.includes("*") }, normalizedPath));
|
|
1909
|
+
}
|
|
1910
|
+
return normalizedPath === candidate || normalizedPath.startsWith(`${candidate}/`);
|
|
1911
|
+
});
|
|
1846
1912
|
}
|
|
1847
1913
|
function readSafeRedirect(search) {
|
|
1848
1914
|
const redirect = new URLSearchParams(normalizeSearch(search)).get("redirect");
|
|
@@ -1938,8 +2004,8 @@ function AuthGate({
|
|
|
1938
2004
|
}
|
|
1939
2005
|
|
|
1940
2006
|
// src/front/CoreFront.tsx
|
|
1941
|
-
import { Suspense, useMemo as useMemo6 } from "react";
|
|
1942
|
-
import { BrowserRouter, Routes, Route } from "react-router-dom";
|
|
2007
|
+
import { Suspense, useCallback as useCallback9, useMemo as useMemo6 } from "react";
|
|
2008
|
+
import { BrowserRouter, Routes, Route, useLocation as useLocation2, useNavigate as useNavigate5 } from "react-router-dom";
|
|
1943
2009
|
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
1944
2010
|
import { Helmet, HelmetProvider } from "react-helmet-async";
|
|
1945
2011
|
|
|
@@ -2202,12 +2268,15 @@ function WorkspaceSwitcher({
|
|
|
2202
2268
|
headers: { "content-type": "application/json" },
|
|
2203
2269
|
body: JSON.stringify({ name: parsed.data.name })
|
|
2204
2270
|
});
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2271
|
+
queryClient.setQueryData(workspaceQueryKey(data.workspace.id), data);
|
|
2272
|
+
queryClient.setQueryData(WORKSPACES_QUERY_KEY, (current = []) => {
|
|
2273
|
+
if (current.some((workspace) => workspace.id === data.workspace.id)) return current;
|
|
2274
|
+
return [...current, data.workspace];
|
|
2275
|
+
});
|
|
2209
2276
|
onModalChange(false);
|
|
2210
2277
|
navigate(hrefForWorkspace(workspacePathPrefix, data.workspace.id));
|
|
2278
|
+
void queryClient.invalidateQueries({ queryKey: WORKSPACES_QUERY_KEY });
|
|
2279
|
+
void queryClient.invalidateQueries({ queryKey: workspaceQueryKey(data.workspace.id) });
|
|
2211
2280
|
} catch (error) {
|
|
2212
2281
|
const detail = getHttpErrorDetail(error);
|
|
2213
2282
|
if (typeof detail.status === "number" && detail.status >= 400 && detail.status < 500) {
|
|
@@ -3420,7 +3489,30 @@ function createDefaultQueryClient() {
|
|
|
3420
3489
|
}
|
|
3421
3490
|
});
|
|
3422
3491
|
}
|
|
3423
|
-
function
|
|
3492
|
+
function RouterAuthGate({ children, publicPaths }) {
|
|
3493
|
+
const location = useLocation2();
|
|
3494
|
+
const navigate = useNavigate5();
|
|
3495
|
+
const authLocation = useMemo6(
|
|
3496
|
+
() => ({ pathname: location.pathname, search: location.search, hash: location.hash }),
|
|
3497
|
+
[location.hash, location.pathname, location.search]
|
|
3498
|
+
);
|
|
3499
|
+
const navigateWithinRouter = useCallback9(
|
|
3500
|
+
(to, options) => {
|
|
3501
|
+
navigate(to, { replace: options?.replace });
|
|
3502
|
+
},
|
|
3503
|
+
[navigate]
|
|
3504
|
+
);
|
|
3505
|
+
return /* @__PURE__ */ jsx22(
|
|
3506
|
+
AuthGate,
|
|
3507
|
+
{
|
|
3508
|
+
location: authLocation,
|
|
3509
|
+
navigate: navigateWithinRouter,
|
|
3510
|
+
publicPaths,
|
|
3511
|
+
children
|
|
3512
|
+
}
|
|
3513
|
+
);
|
|
3514
|
+
}
|
|
3515
|
+
function CoreFront({ children, authPages, cspNonce, workspaceRoute, workspaceIdParam, publicPaths }) {
|
|
3424
3516
|
const queryClient = useMemo6(createDefaultQueryClient, []);
|
|
3425
3517
|
const resolvedCspNonce = useMemo6(
|
|
3426
3518
|
() => cspNonce ?? readCspNonceFromDom(),
|
|
@@ -3433,7 +3525,7 @@ function CoreFront({ children, authPages, cspNonce }) {
|
|
|
3433
3525
|
const VerifyEmailPage2 = authPages?.verifyEmail ?? VerifyEmailPage;
|
|
3434
3526
|
const AuthErrorPage2 = authPages?.authError ?? AuthErrorPage;
|
|
3435
3527
|
const UserSettingsPage2 = authPages?.userSettings ?? UserSettingsPage;
|
|
3436
|
-
return /* @__PURE__ */ jsx22(HelmetProvider, { children: /* @__PURE__ */ jsx22(AppErrorBoundary, { children: /* @__PURE__ */ jsx22(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx22(ConfigProvider, { children: /* @__PURE__ */ jsx22(ThemeProvider, { children: /* @__PURE__ */ jsx22(AuthProvider, { queryClient, children: /* @__PURE__ */ jsx22(UserIdentityProvider, { children: /* @__PURE__ */ jsx22(BrowserRouter, { children: /* @__PURE__ */ jsx22(WorkspaceAuthProvider, { children: /* @__PURE__ */ jsxs15(TopBarSlotProvider, { slot: /* @__PURE__ */ jsx22(UserMenu, {}), children: [
|
|
3528
|
+
return /* @__PURE__ */ jsx22(HelmetProvider, { children: /* @__PURE__ */ jsx22(AppErrorBoundary, { children: /* @__PURE__ */ jsx22(QueryClientProvider, { client: queryClient, children: /* @__PURE__ */ jsx22(ConfigProvider, { children: /* @__PURE__ */ jsx22(ThemeProvider, { children: /* @__PURE__ */ jsx22(AuthProvider, { queryClient, children: /* @__PURE__ */ jsx22(UserIdentityProvider, { children: /* @__PURE__ */ jsx22(BrowserRouter, { children: /* @__PURE__ */ jsx22(WorkspaceAuthProvider, { workspaceRoute, workspaceIdParam, children: /* @__PURE__ */ jsxs15(TopBarSlotProvider, { slot: /* @__PURE__ */ jsx22(UserMenu, {}), children: [
|
|
3437
3529
|
/* @__PURE__ */ jsx22(Helmet, { children: resolvedCspNonce ? /* @__PURE__ */ jsxs15(Fragment6, { children: [
|
|
3438
3530
|
/* @__PURE__ */ jsx22("meta", { name: CSP_NONCE_META_NAME, content: resolvedCspNonce }),
|
|
3439
3531
|
/* @__PURE__ */ jsx22(
|
|
@@ -3446,7 +3538,7 @@ function CoreFront({ children, authPages, cspNonce }) {
|
|
|
3446
3538
|
}
|
|
3447
3539
|
)
|
|
3448
3540
|
] }) : null }),
|
|
3449
|
-
/* @__PURE__ */ jsx22(
|
|
3541
|
+
/* @__PURE__ */ jsx22(RouterAuthGate, { publicPaths: ["/invites", ...publicPaths ?? []], children: /* @__PURE__ */ jsx22(Suspense, { fallback: null, children: /* @__PURE__ */ jsxs15(Routes, { children: [
|
|
3450
3542
|
/* @__PURE__ */ jsx22(Route, { path: routes.signin, element: /* @__PURE__ */ jsx22(SignInPage2, {}) }),
|
|
3451
3543
|
/* @__PURE__ */ jsx22(Route, { path: routes.signup, element: /* @__PURE__ */ jsx22(SignUpPage2, {}) }),
|
|
3452
3544
|
/* @__PURE__ */ jsx22(Route, { path: routes.forgotPassword, element: /* @__PURE__ */ jsx22(ForgotPasswordPage2, {}) }),
|
|
@@ -3470,7 +3562,7 @@ function CoreFront({ children, authPages, cspNonce }) {
|
|
|
3470
3562
|
|
|
3471
3563
|
// src/front/commands/CoreCommandContributions.tsx
|
|
3472
3564
|
import { useMemo as useMemo7, useState as useState20 } from "react";
|
|
3473
|
-
import { useNavigate as
|
|
3565
|
+
import { useNavigate as useNavigate6 } from "react-router-dom";
|
|
3474
3566
|
|
|
3475
3567
|
// src/front/workspace/commands.ts
|
|
3476
3568
|
function getWorkspaceCommands(workspaceId, navigate) {
|
|
@@ -3508,7 +3600,7 @@ function toPaletteCommand(command) {
|
|
|
3508
3600
|
};
|
|
3509
3601
|
}
|
|
3510
3602
|
function useCoreCommands() {
|
|
3511
|
-
const navigate =
|
|
3603
|
+
const navigate = useNavigate6();
|
|
3512
3604
|
const signOut = useSignOut();
|
|
3513
3605
|
const workspace = useCurrentWorkspace();
|
|
3514
3606
|
const [isSigningOut, setIsSigningOut] = useState20(false);
|
|
@@ -3632,9 +3724,6 @@ export {
|
|
|
3632
3724
|
useBlobUrl,
|
|
3633
3725
|
useCapabilities,
|
|
3634
3726
|
useWorkspaceMembers,
|
|
3635
|
-
WorkspaceAuthProvider,
|
|
3636
|
-
useCurrentWorkspace,
|
|
3637
|
-
useWorkspaceRole,
|
|
3638
3727
|
getAuthClient,
|
|
3639
3728
|
AuthProvider,
|
|
3640
3729
|
useSession,
|
|
@@ -3644,6 +3733,10 @@ export {
|
|
|
3644
3733
|
useSendVerificationEmail,
|
|
3645
3734
|
useChangePassword,
|
|
3646
3735
|
useSignOut,
|
|
3736
|
+
WorkspaceAuthProvider,
|
|
3737
|
+
useCurrentWorkspace,
|
|
3738
|
+
useWorkspaceRole,
|
|
3739
|
+
useWorkspaceRouteStatus,
|
|
3647
3740
|
UserIdentityProvider,
|
|
3648
3741
|
useUser,
|
|
3649
3742
|
GoogleAuthButton,
|
package/dist/front/index.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ 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';
|
|
8
8
|
import * as better_auth from 'better-auth';
|
|
9
|
-
export { a as CoreFront, C as CoreFrontAuthPagesOverride, b as CoreFrontProps } from '../CoreFront-
|
|
9
|
+
export { a as CoreFront, C as CoreFrontAuthPagesOverride, b as CoreFrontProps } from '../CoreFront-N0QJSYaM.js';
|
|
10
10
|
import { NavigateFunction } from 'react-router-dom';
|
|
11
11
|
export { TopBarSlotProvider, useTopBarSlot } from './top-bar-slot.js';
|
|
12
12
|
|
|
@@ -70,12 +70,42 @@ type EnrichedMember = WorkspaceMember & {
|
|
|
70
70
|
};
|
|
71
71
|
declare function useWorkspaceMembers(workspaceId: string): _tanstack_react_query.UseQueryResult<EnrichedMember[], Error>;
|
|
72
72
|
|
|
73
|
+
type WorkspaceRouteStatus = {
|
|
74
|
+
status: 'idle';
|
|
75
|
+
workspaceId: string | null;
|
|
76
|
+
} | {
|
|
77
|
+
status: 'loading';
|
|
78
|
+
workspaceId: string | null;
|
|
79
|
+
} | {
|
|
80
|
+
status: 'matched';
|
|
81
|
+
workspaceId: string;
|
|
82
|
+
workspace: Workspace;
|
|
83
|
+
} | {
|
|
84
|
+
status: 'mismatched';
|
|
85
|
+
workspaceId: string;
|
|
86
|
+
currentWorkspaceId: string | null;
|
|
87
|
+
} | {
|
|
88
|
+
status: 'not-found';
|
|
89
|
+
workspaceId: string;
|
|
90
|
+
message: string;
|
|
91
|
+
} | {
|
|
92
|
+
status: 'forbidden';
|
|
93
|
+
workspaceId: string;
|
|
94
|
+
message: string;
|
|
95
|
+
} | {
|
|
96
|
+
status: 'switch-failed';
|
|
97
|
+
workspaceId: string;
|
|
98
|
+
message: string;
|
|
99
|
+
};
|
|
73
100
|
interface WorkspaceAuthProviderProps {
|
|
74
101
|
children: ReactNode;
|
|
102
|
+
workspaceRoute?: string;
|
|
103
|
+
workspaceIdParam?: string;
|
|
75
104
|
}
|
|
76
|
-
declare function WorkspaceAuthProvider({ children }: WorkspaceAuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
105
|
+
declare function WorkspaceAuthProvider({ children, workspaceRoute, workspaceIdParam, }: WorkspaceAuthProviderProps): react_jsx_runtime.JSX.Element;
|
|
77
106
|
declare function useCurrentWorkspace(): Workspace | null;
|
|
78
107
|
declare function useWorkspaceRole(): MemberRole | null;
|
|
108
|
+
declare function useWorkspaceRouteStatus(): WorkspaceRouteStatus;
|
|
79
109
|
|
|
80
110
|
interface AuthProviderProps {
|
|
81
111
|
children: ReactNode;
|
|
@@ -464,4 +494,4 @@ declare function sanitizeToolOutput(input: string): string;
|
|
|
464
494
|
|
|
465
495
|
declare function debounce<T extends (...args: unknown[]) => unknown>(fn: T, ms: number): T;
|
|
466
496
|
|
|
467
|
-
export { AppErrorBoundary, type AuthClient, AuthGate, type AuthGateProps, AuthProvider, type AuthProviderProps, type Binding, type Breakpoint, ConfigProvider, type ConfigProviderProps, type CoreCommand, type EnrichedMember, ForgotPasswordPage, GoogleAuthButton, type GoogleAuthButtonProps, InviteAcceptPage, InvitesPage, MembersPage, ResetPasswordPage, type RouteMap, SignInPage, SignUpPage, type ThemeApi, ThemeProvider, type ThemeProviderProps, ThemeToggle, type UserIdentity, UserIdentityProvider, type UserIdentityProviderProps, UserMenu, UserSettingsPage, VerifyEmailPage, WorkspaceAuthProvider, type WorkspaceAuthProviderProps, type WorkspaceCommand, WorkspaceSettingsPage, WorkspaceSwitcher, apiFetch, apiFetchJson, buildApiUrl, buildWsUrl, debounce, getApiBase, getAuthClient, getHttpErrorDetail, getWorkspaceCommands, getWsBase, openWebSocket, routeHref, routes, sanitizeMarkdown, sanitizeToolOutput, setApiBase, useBlobUrl, useCapabilities, useChangePassword, useConfig, useConfigLoaded, useCoreCommands, useCurrentWorkspace, useKeyboardShortcuts, useReducedMotion, useSendVerificationEmail, useSession, useSignIn, useSignOut, useSignUp, useTheme, useUser, useVerifyEmail, useViewportBreakpoint, useWorkspaceMembers, useWorkspaceRole };
|
|
497
|
+
export { AppErrorBoundary, type AuthClient, AuthGate, type AuthGateProps, AuthProvider, type AuthProviderProps, type Binding, type Breakpoint, ConfigProvider, type ConfigProviderProps, type CoreCommand, type EnrichedMember, ForgotPasswordPage, GoogleAuthButton, type GoogleAuthButtonProps, InviteAcceptPage, InvitesPage, MembersPage, ResetPasswordPage, type RouteMap, SignInPage, SignUpPage, type ThemeApi, ThemeProvider, type ThemeProviderProps, ThemeToggle, type UserIdentity, UserIdentityProvider, type UserIdentityProviderProps, UserMenu, UserSettingsPage, VerifyEmailPage, WorkspaceAuthProvider, type WorkspaceAuthProviderProps, type WorkspaceCommand, type WorkspaceRouteStatus, WorkspaceSettingsPage, WorkspaceSwitcher, apiFetch, apiFetchJson, buildApiUrl, buildWsUrl, debounce, getApiBase, getAuthClient, getHttpErrorDetail, getWorkspaceCommands, getWsBase, openWebSocket, routeHref, routes, sanitizeMarkdown, sanitizeToolOutput, setApiBase, useBlobUrl, useCapabilities, useChangePassword, useConfig, useConfigLoaded, useCoreCommands, useCurrentWorkspace, useKeyboardShortcuts, useReducedMotion, useSendVerificationEmail, useSession, useSignIn, useSignOut, useSignUp, useTheme, useUser, useVerifyEmail, useViewportBreakpoint, useWorkspaceMembers, useWorkspaceRole, useWorkspaceRouteStatus };
|
package/dist/front/index.js
CHANGED
|
@@ -56,8 +56,9 @@ import {
|
|
|
56
56
|
useVerifyEmail,
|
|
57
57
|
useViewportBreakpoint,
|
|
58
58
|
useWorkspaceMembers,
|
|
59
|
-
useWorkspaceRole
|
|
60
|
-
|
|
59
|
+
useWorkspaceRole,
|
|
60
|
+
useWorkspaceRouteStatus
|
|
61
|
+
} from "../chunk-5R3U6QKD.js";
|
|
61
62
|
import {
|
|
62
63
|
TopBarSlotProvider,
|
|
63
64
|
useTopBarSlot
|
|
@@ -124,5 +125,6 @@ export {
|
|
|
124
125
|
useVerifyEmail,
|
|
125
126
|
useViewportBreakpoint,
|
|
126
127
|
useWorkspaceMembers,
|
|
127
|
-
useWorkspaceRole
|
|
128
|
+
useWorkspaceRole,
|
|
129
|
+
useWorkspaceRouteStatus
|
|
128
130
|
};
|