@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 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
- export { type AuthClient, type ClientModuleSpec, type CreateKuckitWebProviderOptions, type CreateServicesOptions, type KuckitWebConfig, type KuckitWebContext, type KuckitWebProviderProps, type KuckitWebRouterProps, type KuckitWebServices, type ModuleRoute, type NavItem, type ORPCUtils, type RouteDefinition, createAuthClientService, createKuckitWebProvider, createKuckitWebServices, createORPCUtils, createQueryClient, createRPCClient, createRPCLink, useAuth, useKuckitWeb, useOrpc, useQueryClient, useRpc, useServices, withKuckitWeb };
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
- export { createAuthClientService, createKuckitWebProvider, createKuckitWebServices, createORPCUtils, createQueryClient, createRPCClient, createRPCLink, useAuth, useKuckitWeb, useOrpc, useQueryClient, useRpc, useServices, withKuckitWeb };
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": "2.0.7",
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": "^2.0.7",
27
- "@kuckit/api": "^2.0.7",
28
- "@kuckit/auth": "^2.0.7",
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",