@kuckit/app-web 2.0.7 → 3.0.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.
- package/dist/index.d.ts +46 -2
- package/dist/index.js +159 -3
- package/package.json +4 -4
package/dist/index.d.ts
CHANGED
|
@@ -2,13 +2,14 @@ import * as react0 from "react";
|
|
|
2
2
|
import { ComponentType, ReactNode } from "react";
|
|
3
3
|
import * as _tanstack_react_query0 from "@tanstack/react-query";
|
|
4
4
|
import { QueryClient } from "@tanstack/react-query";
|
|
5
|
-
import { RouteComponent } from "@tanstack/react-router";
|
|
5
|
+
import { AnyRoute, RouteComponent } from "@tanstack/react-router";
|
|
6
6
|
import { ClientModuleSpec, ClientModuleSpec as ClientModuleSpec$1, NavItem, NavRegistry, RouteDefinition, RouteRegistry, SlotRegistry } from "@kuckit/sdk-react";
|
|
7
7
|
import * as _orpc_client0 from "@orpc/client";
|
|
8
8
|
import { RPCLink } from "@orpc/client/fetch";
|
|
9
9
|
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
|
|
10
10
|
import * as better_auth_react0 from "better-auth/react";
|
|
11
11
|
import { createAuthClient } from "better-auth/react";
|
|
12
|
+
import * as react_jsx_runtime0 from "react/jsx-runtime";
|
|
12
13
|
import * as better_auth0 from "better-auth";
|
|
13
14
|
import { AppRouterClient as AppRouterClient$1 } from "@kuckit/api/routers/index";
|
|
14
15
|
|
|
@@ -765,4 +766,47 @@ declare function createORPCUtils(client: AppRouterClient$1): ORPCUtils;
|
|
|
765
766
|
declare function createAuthClientService(serverUrl: string): any;
|
|
766
767
|
declare function createKuckitWebServices(options?: CreateServicesOptions): KuckitWebServices;
|
|
767
768
|
//#endregion
|
|
768
|
-
|
|
769
|
+
//#region src/router.d.ts
|
|
770
|
+
/**
|
|
771
|
+
* Context type for TanStack Router integration with Kuckit.
|
|
772
|
+
* This is passed via router context to enable oRPC access in route loaders.
|
|
773
|
+
*/
|
|
774
|
+
interface KuckitRouterContext {
|
|
775
|
+
orpc: ORPCUtils;
|
|
776
|
+
queryClient: QueryClient;
|
|
777
|
+
authClient: AuthClient;
|
|
778
|
+
}
|
|
779
|
+
/**
|
|
780
|
+
* Build TanStack Router routes from a RouteRegistry
|
|
781
|
+
*
|
|
782
|
+
* This function converts module-registered routes into TanStack Router
|
|
783
|
+
* route objects that can be added to the route tree.
|
|
784
|
+
*
|
|
785
|
+
* @param routeRegistry - Registry containing module routes
|
|
786
|
+
* @param rootRoute - The root route to attach module routes to
|
|
787
|
+
* @returns Array of TanStack route objects
|
|
788
|
+
*/
|
|
789
|
+
declare function buildModuleRoutes(routeRegistry: RouteRegistry, rootRoute: AnyRoute): AnyRoute[];
|
|
790
|
+
/**
|
|
791
|
+
* Merge static routes with module routes
|
|
792
|
+
*
|
|
793
|
+
* This is used to combine the codegen route tree with dynamic module routes.
|
|
794
|
+
*/
|
|
795
|
+
declare function mergeRouteTrees<TStaticRoutes extends object>(staticRouteTree: TStaticRoutes, _moduleRoutes: AnyRoute[]): TStaticRoutes;
|
|
796
|
+
//#endregion
|
|
797
|
+
//#region src/components/KuckitModuleRoute.d.ts
|
|
798
|
+
/**
|
|
799
|
+
* Dynamic route renderer for Kuckit module routes.
|
|
800
|
+
*
|
|
801
|
+
* This component looks up the current path in the RouteRegistry
|
|
802
|
+
* and renders the corresponding module component if found.
|
|
803
|
+
*
|
|
804
|
+
* Route resolution is context-aware:
|
|
805
|
+
* - When rendered under /dashboard/*: matches dashboard routes
|
|
806
|
+
* - When rendered at root level: matches root-level routes (paths starting with '/' but not '/dashboard/')
|
|
807
|
+
*
|
|
808
|
+
* For root routes with meta.requiresAuth: true, redirects to /login if not authenticated.
|
|
809
|
+
*/
|
|
810
|
+
declare function KuckitModuleRoute(): react_jsx_runtime0.JSX.Element | null;
|
|
811
|
+
//#endregion
|
|
812
|
+
export { type AuthClient, type ClientModuleSpec, type CreateKuckitWebProviderOptions, type CreateServicesOptions, KuckitModuleRoute, type KuckitRouterContext, type KuckitWebConfig, type KuckitWebContext, type KuckitWebProviderProps, type KuckitWebRouterProps, type KuckitWebServices, type ModuleRoute, type NavItem, type ORPCUtils, type RouteDefinition, buildModuleRoutes, createAuthClientService, createKuckitWebProvider, createKuckitWebServices, createORPCUtils, createQueryClient, createRPCClient, createRPCLink, mergeRouteTrees, useAuth, useKuckitWeb, useOrpc, useQueryClient, useRpc, useServices, withKuckitWeb };
|
package/dist/index.js
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { createContext, createElement, useContext, useEffect, useMemo, useState } from "react";
|
|
2
2
|
import { QueryCache, QueryClient, QueryClientProvider } from "@tanstack/react-query";
|
|
3
|
-
import { RouterProvider, createRoute, createRouter } from "@tanstack/react-router";
|
|
3
|
+
import { Link, RouterProvider, createRoute, createRouter, useNavigate, useRouterState } from "@tanstack/react-router";
|
|
4
4
|
import { KuckitNavProvider, KuckitRpcProvider, KuckitSlotProvider, loadKuckitClientModules } from "@kuckit/sdk-react";
|
|
5
5
|
import { createORPCClient } from "@orpc/client";
|
|
6
6
|
import { RPCLink } from "@orpc/client/fetch";
|
|
7
7
|
import { createTanstackQueryUtils } from "@orpc/tanstack-query";
|
|
8
8
|
import { createAuthClient } from "better-auth/react";
|
|
9
9
|
import { inferAdditionalFields } from "better-auth/client/plugins";
|
|
10
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
10
11
|
|
|
11
12
|
//#region src/services.ts
|
|
12
13
|
function createQueryClient(onError) {
|
|
@@ -158,7 +159,8 @@ function InternalKuckitWebProvider({ config, routeTree, rootRoute, children }) {
|
|
|
158
159
|
defaultPendingComponent: Loader,
|
|
159
160
|
context: {
|
|
160
161
|
orpc: services.orpc,
|
|
161
|
-
queryClient: services.queryClient
|
|
162
|
+
queryClient: services.queryClient,
|
|
163
|
+
authClient: services.authClient
|
|
162
164
|
}
|
|
163
165
|
});
|
|
164
166
|
}, [
|
|
@@ -207,4 +209,158 @@ function withKuckitWeb(Component, options) {
|
|
|
207
209
|
}
|
|
208
210
|
|
|
209
211
|
//#endregion
|
|
210
|
-
|
|
212
|
+
//#region src/router.ts
|
|
213
|
+
/**
|
|
214
|
+
* Build TanStack Router routes from a RouteRegistry
|
|
215
|
+
*
|
|
216
|
+
* This function converts module-registered routes into TanStack Router
|
|
217
|
+
* route objects that can be added to the route tree.
|
|
218
|
+
*
|
|
219
|
+
* @param routeRegistry - Registry containing module routes
|
|
220
|
+
* @param rootRoute - The root route to attach module routes to
|
|
221
|
+
* @returns Array of TanStack route objects
|
|
222
|
+
*/
|
|
223
|
+
function buildModuleRoutes(routeRegistry, rootRoute) {
|
|
224
|
+
const routes = routeRegistry.getAll();
|
|
225
|
+
const routeMap = /* @__PURE__ */ new Map();
|
|
226
|
+
for (const routeDef of routes) {
|
|
227
|
+
const route = createModuleRoute(routeDef, rootRoute);
|
|
228
|
+
routeMap.set(routeDef.id, route);
|
|
229
|
+
}
|
|
230
|
+
return routes.filter((r) => !r.parentRouteId || r.parentRouteId === "__root__").map((r) => routeMap.get(r.id)).filter(Boolean);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Create a single TanStack route from a RouteDefinition
|
|
234
|
+
*/
|
|
235
|
+
function createModuleRoute(routeDef, parentRoute) {
|
|
236
|
+
return createRoute({
|
|
237
|
+
getParentRoute: () => parentRoute,
|
|
238
|
+
path: routeDef.path,
|
|
239
|
+
component: routeDef.component,
|
|
240
|
+
...routeDef.meta?.title && { head: () => ({ meta: [{ title: routeDef.meta.title }] }) }
|
|
241
|
+
});
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Merge static routes with module routes
|
|
245
|
+
*
|
|
246
|
+
* This is used to combine the codegen route tree with dynamic module routes.
|
|
247
|
+
*/
|
|
248
|
+
function mergeRouteTrees(staticRouteTree, _moduleRoutes) {
|
|
249
|
+
return staticRouteTree;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
//#endregion
|
|
253
|
+
//#region src/components/KuckitModuleRoute.tsx
|
|
254
|
+
/**
|
|
255
|
+
* Helper to determine if a route path is a root-level route (outside dashboard).
|
|
256
|
+
* Root routes start with '/' but NOT '/dashboard'.
|
|
257
|
+
*/
|
|
258
|
+
function isRootLevelRoute(path) {
|
|
259
|
+
return path.startsWith("/") && !path.startsWith("/dashboard");
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Dynamic route renderer for Kuckit module routes.
|
|
263
|
+
*
|
|
264
|
+
* This component looks up the current path in the RouteRegistry
|
|
265
|
+
* and renders the corresponding module component if found.
|
|
266
|
+
*
|
|
267
|
+
* Route resolution is context-aware:
|
|
268
|
+
* - When rendered under /dashboard/*: matches dashboard routes
|
|
269
|
+
* - When rendered at root level: matches root-level routes (paths starting with '/' but not '/dashboard/')
|
|
270
|
+
*
|
|
271
|
+
* For root routes with meta.requiresAuth: true, redirects to /login if not authenticated.
|
|
272
|
+
*/
|
|
273
|
+
function KuckitModuleRoute() {
|
|
274
|
+
const { routeRegistry } = useKuckitWeb();
|
|
275
|
+
const authClient = useAuth();
|
|
276
|
+
const { location } = useRouterState();
|
|
277
|
+
const navigate = useNavigate();
|
|
278
|
+
const pathname = location.pathname;
|
|
279
|
+
const [authChecked, setAuthChecked] = useState(false);
|
|
280
|
+
const [isAuthenticated, setIsAuthenticated] = useState(false);
|
|
281
|
+
const isDashboardContext = pathname.startsWith("/dashboard");
|
|
282
|
+
const contextRoutes = routeRegistry.getAll().filter((r) => {
|
|
283
|
+
const isRoot = isRootLevelRoute(r.path);
|
|
284
|
+
return isDashboardContext ? !isRoot : isRoot;
|
|
285
|
+
});
|
|
286
|
+
const modulePathname = isDashboardContext ? pathname.replace("/dashboard", "") || "/" : pathname;
|
|
287
|
+
function matchRoute(routePath, pathname$1) {
|
|
288
|
+
if (routePath === pathname$1) return true;
|
|
289
|
+
if (routePath.endsWith("/$")) {
|
|
290
|
+
const base = routePath.slice(0, -1);
|
|
291
|
+
return pathname$1.startsWith(base);
|
|
292
|
+
}
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
const exactMatch = contextRoutes.find((r) => r.path === pathname);
|
|
296
|
+
const catchAllMatch = contextRoutes.find((r) => r.path.endsWith("/$") && matchRoute(r.path, pathname));
|
|
297
|
+
let routeDef = exactMatch || catchAllMatch;
|
|
298
|
+
if (!routeDef && isDashboardContext) {
|
|
299
|
+
const exactDash = contextRoutes.find((r) => r.path === modulePathname);
|
|
300
|
+
const catchAllDash = contextRoutes.find((r) => r.path.endsWith("/$") && matchRoute(r.path, modulePathname));
|
|
301
|
+
routeDef = exactDash || catchAllDash;
|
|
302
|
+
}
|
|
303
|
+
useEffect(() => {
|
|
304
|
+
async function checkAuth() {
|
|
305
|
+
if (!routeDef) {
|
|
306
|
+
setAuthChecked(true);
|
|
307
|
+
return;
|
|
308
|
+
}
|
|
309
|
+
if (isDashboardContext) {
|
|
310
|
+
setAuthChecked(true);
|
|
311
|
+
setIsAuthenticated(true);
|
|
312
|
+
return;
|
|
313
|
+
}
|
|
314
|
+
if (routeDef.meta?.requiresAuth) {
|
|
315
|
+
if (!(await authClient.getSession()).data) {
|
|
316
|
+
navigate({
|
|
317
|
+
to: "/login",
|
|
318
|
+
search: { redirect: pathname }
|
|
319
|
+
});
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
setIsAuthenticated(true);
|
|
323
|
+
}
|
|
324
|
+
setAuthChecked(true);
|
|
325
|
+
}
|
|
326
|
+
checkAuth();
|
|
327
|
+
}, [
|
|
328
|
+
routeDef,
|
|
329
|
+
isDashboardContext,
|
|
330
|
+
pathname,
|
|
331
|
+
navigate,
|
|
332
|
+
authClient
|
|
333
|
+
]);
|
|
334
|
+
if (!isDashboardContext && routeDef?.meta?.requiresAuth && !authChecked) return /* @__PURE__ */ jsx("div", {
|
|
335
|
+
className: "flex items-center justify-center min-h-screen",
|
|
336
|
+
children: /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full h-8 w-8 border-b-2 border-primary" })
|
|
337
|
+
});
|
|
338
|
+
if (!isDashboardContext && routeDef?.meta?.requiresAuth && !isAuthenticated) return null;
|
|
339
|
+
if (!routeDef) return /* @__PURE__ */ jsxs("div", {
|
|
340
|
+
className: "flex flex-col items-center justify-center min-h-[50vh] gap-4",
|
|
341
|
+
children: [
|
|
342
|
+
/* @__PURE__ */ jsx("h1", {
|
|
343
|
+
className: "text-2xl font-bold",
|
|
344
|
+
children: "Page Not Found"
|
|
345
|
+
}),
|
|
346
|
+
/* @__PURE__ */ jsxs("p", {
|
|
347
|
+
className: "text-muted-foreground",
|
|
348
|
+
children: [
|
|
349
|
+
"The page \"",
|
|
350
|
+
pathname,
|
|
351
|
+
"\" could not be found."
|
|
352
|
+
]
|
|
353
|
+
}),
|
|
354
|
+
/* @__PURE__ */ jsx(Link, {
|
|
355
|
+
to: "/",
|
|
356
|
+
className: "text-primary hover:underline",
|
|
357
|
+
children: "Go Home"
|
|
358
|
+
})
|
|
359
|
+
]
|
|
360
|
+
});
|
|
361
|
+
const Component = routeDef.component;
|
|
362
|
+
return /* @__PURE__ */ jsx(Component, {});
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
//#endregion
|
|
366
|
+
export { KuckitModuleRoute, buildModuleRoutes, createAuthClientService, createKuckitWebProvider, createKuckitWebServices, createORPCUtils, createQueryClient, createRPCClient, createRPCLink, mergeRouteTrees, useAuth, useKuckitWeb, useOrpc, useQueryClient, useRpc, useServices, withKuckitWeb };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kuckit/app-web",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -23,9 +23,9 @@
|
|
|
23
23
|
"prepublishOnly": "npm run build && node ../../scripts/resolve-workspace-protocols.cjs && node ../../scripts/check-no-workspace-protocol.cjs"
|
|
24
24
|
},
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@kuckit/sdk-react": "^
|
|
27
|
-
"@kuckit/api": "^
|
|
28
|
-
"@kuckit/auth": "^
|
|
26
|
+
"@kuckit/sdk-react": "^3.0.0",
|
|
27
|
+
"@kuckit/api": "^3.0.0",
|
|
28
|
+
"@kuckit/auth": "^3.0.0",
|
|
29
29
|
"@tanstack/react-query": "^5.85.5",
|
|
30
30
|
"@tanstack/react-router": "^1.114.25",
|
|
31
31
|
"@orpc/client": "^1.10.0",
|