create-croissant 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (56) hide show
  1. package/package.json +2 -2
  2. package/template/apps/web/node_modules/@better-auth/core/dist/api/index.mjs +29 -3
  3. package/template/apps/web/node_modules/@better-auth/core/dist/context/global.mjs +1 -1
  4. package/template/apps/web/node_modules/@better-auth/core/dist/db/adapter/factory.mjs +1 -1
  5. package/template/apps/web/node_modules/@better-auth/core/dist/instrumentation/api.mjs +1 -31
  6. package/template/apps/web/node_modules/@better-auth/core/dist/instrumentation/noop.mjs +42 -0
  7. package/template/apps/web/node_modules/@better-auth/core/dist/instrumentation/pure.index.d.mts +7 -0
  8. package/template/apps/web/node_modules/@better-auth/core/dist/instrumentation/pure.index.mjs +7 -0
  9. package/template/apps/web/node_modules/@better-auth/core/dist/instrumentation/tracer.mjs +1 -1
  10. package/template/apps/web/node_modules/@better-auth/core/dist/oauth2/index.d.mts +2 -2
  11. package/template/apps/web/node_modules/@better-auth/core/dist/oauth2/index.mjs +2 -2
  12. package/template/apps/web/node_modules/@better-auth/core/dist/oauth2/utils.d.mts +10 -1
  13. package/template/apps/web/node_modules/@better-auth/core/dist/oauth2/utils.mjs +13 -1
  14. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/apple.d.mts +11 -2
  15. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/apple.mjs +7 -1
  16. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/atlassian.mjs +1 -1
  17. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/cognito.d.mts +1 -1
  18. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/cognito.mjs +3 -2
  19. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/facebook.d.mts +1 -1
  20. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/facebook.mjs +7 -0
  21. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/figma.mjs +1 -1
  22. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/google.d.mts +1 -1
  23. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/google.mjs +3 -2
  24. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/microsoft-entra-id.d.mts +2 -2
  25. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/microsoft-entra-id.mjs +6 -1
  26. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/paybin.mjs +1 -1
  27. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/paypal.mjs +1 -1
  28. package/template/apps/web/node_modules/@better-auth/core/dist/social-providers/salesforce.mjs +1 -1
  29. package/template/apps/web/node_modules/@better-auth/core/dist/utils/is-api-error.d.mts +6 -0
  30. package/template/apps/web/node_modules/@better-auth/core/dist/utils/is-api-error.mjs +8 -0
  31. package/template/apps/web/node_modules/@better-auth/core/package.json +7 -1
  32. package/template/apps/web/node_modules/@better-auth/core/src/api/index.ts +39 -5
  33. package/template/apps/web/node_modules/@better-auth/core/src/instrumentation/api.ts +2 -49
  34. package/template/apps/web/node_modules/@better-auth/core/src/instrumentation/noop.ts +74 -0
  35. package/template/apps/web/node_modules/@better-auth/core/src/instrumentation/pure.index.ts +31 -0
  36. package/template/apps/web/node_modules/@better-auth/core/src/oauth2/index.ts +5 -1
  37. package/template/apps/web/node_modules/@better-auth/core/src/oauth2/utils.ts +13 -0
  38. package/template/apps/web/node_modules/@better-auth/core/src/social-providers/apple.ts +10 -2
  39. package/template/apps/web/node_modules/@better-auth/core/src/social-providers/cognito.ts +3 -2
  40. package/template/apps/web/node_modules/@better-auth/core/src/social-providers/facebook.ts +10 -1
  41. package/template/apps/web/node_modules/@better-auth/core/src/social-providers/google.ts +3 -2
  42. package/template/apps/web/node_modules/@better-auth/core/src/social-providers/microsoft-entra-id.ts +13 -3
  43. package/template/apps/web/node_modules/@better-auth/core/src/utils/is-api-error.ts +10 -0
  44. package/template/apps/web/node_modules/@better-auth/drizzle-adapter/package.json +3 -3
  45. package/template/apps/web/package.json +4 -4
  46. package/template/apps/web/src/components/app-sidebar.tsx +77 -121
  47. package/template/apps/web/src/routeTree.gen.ts +112 -1
  48. package/template/apps/web/src/routes/__root.tsx +13 -1
  49. package/template/apps/web/src/routes/client-orpc-auth.tsx +62 -0
  50. package/template/apps/web/src/routes/client-orpc.tsx +43 -0
  51. package/template/apps/web/src/routes/isr.tsx +33 -0
  52. package/template/apps/web/src/routes/ssr-orpc-auth.tsx +53 -0
  53. package/template/apps/web/src/routes/ssr-orpc.tsx +36 -0
  54. package/template/package.json +2 -2
  55. package/template/packages/auth/package.json +1 -1
  56. package/template/packages/orpc/package.json +2 -4
@@ -0,0 +1,74 @@
1
+ import type { Span, Tracer } from "@opentelemetry/api";
2
+
3
+ export type OpenTelemetryAPI = Pick<
4
+ typeof import("@opentelemetry/api"),
5
+ "trace" | "SpanStatusCode"
6
+ >;
7
+
8
+ function createNoopSpan(): Span {
9
+ const span = {
10
+ end(): void {},
11
+ setAttribute(_key: string, _value: unknown): void {},
12
+ setStatus(_status: unknown): void {},
13
+ recordException(_exception: unknown): void {},
14
+ updateName(_name: string) {
15
+ return span;
16
+ },
17
+ } as unknown as Span;
18
+ return span;
19
+ }
20
+
21
+ function createNoopTracer(noopSpan: Span): Tracer {
22
+ // OpenTelemetry `Tracer.startActiveSpan` has three overloads:
23
+ // (name, fn)
24
+ // (name, options, fn)
25
+ // (name, options, context, fn)
26
+ // The callback is always the last argument; fish it out by arity so a
27
+ // 2-arg call (options omitted) doesn't try to invoke `undefined`.
28
+ function startActiveSpan<F extends (span: Span) => unknown>(
29
+ _name: string,
30
+ fn: F,
31
+ ): ReturnType<F>;
32
+ function startActiveSpan<F extends (span: Span) => unknown>(
33
+ _name: string,
34
+ _options: { attributes?: Record<string, string | number | boolean> },
35
+ fn: F,
36
+ ): ReturnType<F>;
37
+ function startActiveSpan<F extends (span: Span) => unknown>(
38
+ _name: string,
39
+ _options: { attributes?: Record<string, string | number | boolean> },
40
+ _context: unknown,
41
+ fn: F,
42
+ ): ReturnType<F>;
43
+ function startActiveSpan(_name: string, ...rest: Array<unknown>): unknown {
44
+ const fn = rest[rest.length - 1] as (span: Span) => unknown;
45
+ return fn(noopSpan);
46
+ }
47
+ return { startActiveSpan } as Tracer;
48
+ }
49
+
50
+ function createNoopTraceAPI() {
51
+ const noopTracer = createNoopTracer(createNoopSpan());
52
+ return {
53
+ getTracer(_name?: string, _version?: string) {
54
+ return noopTracer;
55
+ },
56
+ getActiveSpan(): Span | undefined {
57
+ return undefined;
58
+ },
59
+ };
60
+ }
61
+
62
+ function createNoopOpenTelemetryAPI(): OpenTelemetryAPI {
63
+ return {
64
+ SpanStatusCode: {
65
+ UNSET: 0,
66
+ OK: 1,
67
+ ERROR: 2,
68
+ },
69
+ trace: createNoopTraceAPI(),
70
+ } as OpenTelemetryAPI;
71
+ }
72
+
73
+ export const noopOpenTelemetryAPI: OpenTelemetryAPI =
74
+ createNoopOpenTelemetryAPI();
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Noop variant of `./instrumentation` for runtimes where the dynamic
3
+ * `import("@opentelemetry/api")` in `./api` throws synchronously instead of
4
+ * rejecting its returned promise. Convex's V8 isolate is the reproducer: bare
5
+ * specifiers are rejected at resolve time in `get-convex/convex-backend`
6
+ * `crates/isolate/src/request_scope.rs`, so the `.catch()` in
7
+ * `getOpenTelemetryAPI` never runs and every `withSpan` call surfaces an
8
+ * uncaught error.
9
+ *
10
+ * Public surface must stay identical to `./index` (enforced by `pure.test.ts`).
11
+ */
12
+
13
+ export * from "./attributes";
14
+
15
+ export function withSpan<T>(
16
+ name: string,
17
+ attributes: Record<string, string | number | boolean>,
18
+ fn: () => T,
19
+ ): T;
20
+ export function withSpan<T>(
21
+ name: string,
22
+ attributes: Record<string, string | number | boolean>,
23
+ fn: () => Promise<T>,
24
+ ): Promise<T>;
25
+ export function withSpan<T>(
26
+ _name: string,
27
+ _attributes: Record<string, string | number | boolean>,
28
+ fn: () => T | Promise<T>,
29
+ ): T | Promise<T> {
30
+ return fn();
31
+ }
@@ -15,7 +15,11 @@ export {
15
15
  refreshAccessToken,
16
16
  refreshAccessTokenRequest,
17
17
  } from "./refresh-access-token";
18
- export { generateCodeChallenge, getOAuth2Tokens } from "./utils";
18
+ export {
19
+ generateCodeChallenge,
20
+ getOAuth2Tokens,
21
+ getPrimaryClientId,
22
+ } from "./utils";
19
23
  export {
20
24
  authorizationCodeRequest,
21
25
  createAuthorizationCodeRequest,
@@ -28,6 +28,19 @@ export function getOAuth2Tokens(data: Record<string, any>): OAuth2Tokens {
28
28
  };
29
29
  }
30
30
 
31
+ /**
32
+ * Return the provider's primary Client ID: the single string, or the entry at
33
+ * array index 0 for the cross-platform form used by ID token audience
34
+ * verification. Index 0 is the designated primary and pairs with
35
+ * `clientSecret` for the authorization code flow; later array entries are
36
+ * only used as additional accepted audiences. Returns `undefined` when the
37
+ * primary value is missing or an empty string.
38
+ */
39
+ export function getPrimaryClientId(clientId: unknown): string | undefined {
40
+ const value = Array.isArray(clientId) ? clientId[0] : clientId;
41
+ return typeof value === "string" && value.length > 0 ? value : undefined;
42
+ }
43
+
31
44
  export async function generateCodeChallenge(codeVerifier: string) {
32
45
  const encoder = new TextEncoder();
33
46
  const data = encoder.encode(codeVerifier);
@@ -1,10 +1,12 @@
1
1
  import { betterFetch } from "@better-fetch/fetch";
2
2
 
3
3
  import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
4
- import { APIError } from "../error";
4
+ import { logger } from "../env";
5
+ import { APIError, BetterAuthError } from "../error";
5
6
  import type { OAuthProvider, ProviderOptions } from "../oauth2";
6
7
  import {
7
8
  createAuthorizationURL,
9
+ getPrimaryClientId,
8
10
  refreshAccessToken,
9
11
  validateAuthorizationCode,
10
12
  } from "../oauth2";
@@ -70,7 +72,7 @@ export interface AppleNonConformUser {
70
72
  }
71
73
 
72
74
  export interface AppleOptions extends ProviderOptions<AppleProfile> {
73
- clientId: string;
75
+ clientId: string | string[];
74
76
  appBundleIdentifier?: string | undefined;
75
77
  audience?: (string | string[]) | undefined;
76
78
  }
@@ -81,6 +83,12 @@ export const apple = (options: AppleOptions) => {
81
83
  id: "apple",
82
84
  name: "Apple",
83
85
  async createAuthorizationURL({ state, scopes, redirectURI }) {
86
+ if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
87
+ logger.error(
88
+ "Client ID and client secret are required for Apple. Make sure to provide them in the options.",
89
+ );
90
+ throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
91
+ }
84
92
  const _scope = options.disableDefaultScope ? [] : ["email", "name"];
85
93
  if (options.scope) _scope.push(...options.scope);
86
94
  if (scopes) _scope.push(...scopes);
@@ -5,6 +5,7 @@ import { APIError, BetterAuthError } from "../error";
5
5
  import type { OAuthProvider, ProviderOptions } from "../oauth2";
6
6
  import {
7
7
  createAuthorizationURL,
8
+ getPrimaryClientId,
8
9
  refreshAccessToken,
9
10
  validateAuthorizationCode,
10
11
  } from "../oauth2";
@@ -30,7 +31,7 @@ export interface CognitoProfile {
30
31
  }
31
32
 
32
33
  export interface CognitoOptions extends ProviderOptions<CognitoProfile> {
33
- clientId: string;
34
+ clientId: string | string[];
34
35
  /**
35
36
  * The Cognito domain (e.g., "your-app.auth.us-east-1.amazoncognito.com")
36
37
  */
@@ -60,7 +61,7 @@ export const cognito = (options: CognitoOptions) => {
60
61
  id: "cognito",
61
62
  name: "Cognito",
62
63
  async createAuthorizationURL({ state, scopes, codeVerifier, redirectURI }) {
63
- if (!options.clientId) {
64
+ if (!getPrimaryClientId(options.clientId)) {
64
65
  logger.error(
65
66
  "ClientId is required for Amazon Cognito. Make sure to provide them in the options.",
66
67
  );
@@ -1,8 +1,11 @@
1
1
  import { betterFetch } from "@better-fetch/fetch";
2
2
  import { createRemoteJWKSet, decodeJwt, jwtVerify } from "jose";
3
+ import { logger } from "../env";
4
+ import { BetterAuthError } from "../error";
3
5
  import type { OAuthProvider, ProviderOptions } from "../oauth2";
4
6
  import {
5
7
  createAuthorizationURL,
8
+ getPrimaryClientId,
6
9
  refreshAccessToken,
7
10
  validateAuthorizationCode,
8
11
  } from "../oauth2";
@@ -22,7 +25,7 @@ export interface FacebookProfile {
22
25
  }
23
26
 
24
27
  export interface FacebookOptions extends ProviderOptions<FacebookProfile> {
25
- clientId: string;
28
+ clientId: string | string[];
26
29
  /**
27
30
  * Extend list of fields to retrieve from the Facebook user profile.
28
31
  *
@@ -41,6 +44,12 @@ export const facebook = (options: FacebookOptions) => {
41
44
  id: "facebook",
42
45
  name: "Facebook",
43
46
  async createAuthorizationURL({ state, scopes, redirectURI, loginHint }) {
47
+ if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
48
+ logger.error(
49
+ "Client ID and client secret are required for Facebook. Make sure to provide them in the options.",
50
+ );
51
+ throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
52
+ }
44
53
  const _scopes = options.disableDefaultScope
45
54
  ? []
46
55
  : ["email", "public_profile"];
@@ -5,6 +5,7 @@ import { APIError, BetterAuthError } from "../error";
5
5
  import type { OAuthProvider, ProviderOptions } from "../oauth2";
6
6
  import {
7
7
  createAuthorizationURL,
8
+ getPrimaryClientId,
8
9
  refreshAccessToken,
9
10
  validateAuthorizationCode,
10
11
  } from "../oauth2";
@@ -37,7 +38,7 @@ export interface GoogleProfile {
37
38
  }
38
39
 
39
40
  export interface GoogleOptions extends ProviderOptions<GoogleProfile> {
40
- clientId: string;
41
+ clientId: string | string[];
41
42
  /**
42
43
  * The access type to use for the authorization code request
43
44
  */
@@ -64,7 +65,7 @@ export const google = (options: GoogleOptions) => {
64
65
  loginHint,
65
66
  display,
66
67
  }) {
67
- if (!options.clientId || !options.clientSecret) {
68
+ if (!getPrimaryClientId(options.clientId) || !options.clientSecret) {
68
69
  logger.error(
69
70
  "Client Id and Client Secret is required for Google. Make sure to provide them in the options.",
70
71
  );
@@ -2,10 +2,11 @@ import { base64 } from "@better-auth/utils/base64";
2
2
  import { betterFetch } from "@better-fetch/fetch";
3
3
  import { decodeJwt, decodeProtectedHeader, importJWK, jwtVerify } from "jose";
4
4
  import { logger } from "../env";
5
- import { APIError } from "../error";
5
+ import { APIError, BetterAuthError } from "../error";
6
6
  import type { OAuthProvider, ProviderOptions } from "../oauth2";
7
7
  import {
8
8
  createAuthorizationURL,
9
+ getPrimaryClientId,
9
10
  refreshAccessToken,
10
11
  validateAuthorizationCode,
11
12
  } from "../oauth2";
@@ -116,7 +117,7 @@ export interface MicrosoftEntraIDProfile extends Record<string, any> {
116
117
 
117
118
  export interface MicrosoftOptions
118
119
  extends ProviderOptions<MicrosoftEntraIDProfile> {
119
- clientId: string;
120
+ clientId: string | string[];
120
121
  /**
121
122
  * The tenant ID of the Microsoft account
122
123
  * @default "common"
@@ -149,6 +150,15 @@ export const microsoft = (options: MicrosoftOptions) => {
149
150
  id: "microsoft",
150
151
  name: "Microsoft EntraID",
151
152
  createAuthorizationURL(data) {
153
+ // Microsoft Entra supports public clients (SPA / native apps with
154
+ // PKCE only), so clientSecret is intentionally not required here.
155
+ // See https://learn.microsoft.com/en-us/entra/identity-platform/v2-oauth2-auth-code-flow
156
+ if (!getPrimaryClientId(options.clientId)) {
157
+ logger.error(
158
+ "Client Id is required for Microsoft Entra ID. Make sure to provide it in the options.",
159
+ );
160
+ throw new BetterAuthError("CLIENT_ID_AND_SECRET_REQUIRED");
161
+ }
152
162
  const scopes = options.disableDefaultScope
153
163
  ? []
154
164
  : ["openid", "profile", "email", "User.Read", "offline_access"];
@@ -190,7 +200,7 @@ export const microsoft = (options: MicrosoftOptions) => {
190
200
  const publicKey = await getMicrosoftPublicKey(kid, tenant, authority);
191
201
  const verifyOptions: {
192
202
  algorithms: [string];
193
- audience: string;
203
+ audience: string | string[];
194
204
  maxTokenAge: string;
195
205
  issuer?: string;
196
206
  } = {
@@ -0,0 +1,10 @@
1
+ import { APIError as BaseAPIError } from "better-call";
2
+ import { APIError } from "../error";
3
+
4
+ export function isAPIError(error: unknown): error is APIError {
5
+ return (
6
+ error instanceof BaseAPIError ||
7
+ error instanceof APIError ||
8
+ (error as { name?: string })?.name === "APIError"
9
+ );
10
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@better-auth/drizzle-adapter",
3
- "version": "1.6.6",
3
+ "version": "1.6.7",
4
4
  "description": "Drizzle adapter for Better Auth",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -37,7 +37,7 @@
37
37
  "peerDependencies": {
38
38
  "@better-auth/utils": "0.4.0",
39
39
  "drizzle-orm": "^0.45.2",
40
- "@better-auth/core": "^1.6.6"
40
+ "@better-auth/core": "^1.6.7"
41
41
  },
42
42
  "peerDependenciesMeta": {
43
43
  "drizzle-orm": {
@@ -49,7 +49,7 @@
49
49
  "drizzle-orm": "^0.45.2",
50
50
  "tsdown": "0.21.1",
51
51
  "typescript": "^5.9.3",
52
- "@better-auth/core": "1.6.6"
52
+ "@better-auth/core": "1.6.7"
53
53
  },
54
54
  "scripts": {
55
55
  "build": "tsdown",
@@ -14,10 +14,10 @@
14
14
  "db:studio": "drizzle-kit studio"
15
15
  },
16
16
  "dependencies": {
17
- "@better-auth/drizzle-adapter": "^1.6.6",
17
+ "@better-auth/drizzle-adapter": "^1.6.7",
18
18
  "@noble/ciphers": "^2.2.0",
19
- "@orpc/client": "^1.13.14",
20
- "@orpc/server": "^1.13.14",
19
+ "@orpc/client": "^1.14.0",
20
+ "@orpc/server": "^1.14.0",
21
21
  "@tailwindcss/vite": "^4.2.4",
22
22
  "@tanstack/react-router": "^1.132.0",
23
23
  "@tanstack/react-start": "^1.132.0",
@@ -25,7 +25,7 @@
25
25
  "@workspace/auth": "*",
26
26
  "@workspace/orpc": "*",
27
27
  "@workspace/ui": "*",
28
- "better-auth": "^1.6.6",
28
+ "better-auth": "^1.6.7",
29
29
  "lucide-react": "^1.8.0",
30
30
  "nitro": "latest",
31
31
  "react": "^19.2.4",
@@ -1,8 +1,11 @@
1
1
  import * as React from "react"
2
+ import { Link } from "@tanstack/react-router"
3
+ import { LogOut, User } from "lucide-react"
2
4
 
3
5
  import {
4
6
  Sidebar,
5
7
  SidebarContent,
8
+ SidebarFooter,
6
9
  SidebarGroup,
7
10
  SidebarGroupContent,
8
11
  SidebarGroupLabel,
@@ -12,149 +15,57 @@ import {
12
15
  SidebarMenuItem,
13
16
  SidebarRail,
14
17
  } from "@workspace/ui/components/sidebar"
15
- import { SearchForm } from "@/components/search-form"
16
- import { VersionSwitcher } from "@/components/version-switcher"
18
+ import { Avatar, AvatarFallback, AvatarImage } from "@workspace/ui/components/avatar"
19
+ import { authClient } from "../lib/auth-client"
17
20
 
18
21
  // This is sample data.
19
22
  const data = {
20
- versions: ["1.0.1", "1.1.0-alpha", "2.0.0-beta1"],
21
23
  navMain: [
22
24
  {
23
- title: "Getting Started",
24
- url: "#",
25
+ title: "Examples",
25
26
  items: [
26
27
  {
27
- title: "Installation",
28
- url: "#",
28
+ title: "SSR + oRPC",
29
+ url: "/ssr-orpc",
29
30
  },
30
31
  {
31
- title: "Project Structure",
32
- url: "#",
33
- },
34
- ],
35
- },
36
- {
37
- title: "Build Your Application",
38
- url: "#",
39
- items: [
40
- {
41
- title: "Routing",
42
- url: "#",
43
- },
44
- {
45
- title: "Data Fetching",
46
- url: "#",
47
- isActive: true,
48
- },
49
- {
50
- title: "Rendering",
51
- url: "#",
52
- },
53
- {
54
- title: "Caching",
55
- url: "#",
56
- },
57
- {
58
- title: "Styling",
59
- url: "#",
32
+ title: "SSR + oRPC (Auth)",
33
+ url: "/ssr-orpc-auth",
60
34
  },
61
35
  {
62
- title: "Optimizing",
63
- url: "#",
36
+ title: "Client + oRPC",
37
+ url: "/client-orpc",
64
38
  },
65
39
  {
66
- title: "Configuring",
67
- url: "#",
40
+ title: "Client + oRPC (Auth)",
41
+ url: "/client-orpc-auth",
68
42
  },
69
43
  {
70
- title: "Testing",
71
- url: "#",
72
- },
73
- {
74
- title: "Authentication",
75
- url: "#",
76
- },
77
- {
78
- title: "Deploying",
79
- url: "#",
80
- },
81
- {
82
- title: "Upgrading",
83
- url: "#",
84
- },
85
- {
86
- title: "Examples",
87
- url: "#",
88
- },
89
- ],
90
- },
91
- {
92
- title: "API Reference",
93
- url: "#",
94
- items: [
95
- {
96
- title: "Components",
97
- url: "#",
98
- },
99
- {
100
- title: "File Conventions",
101
- url: "#",
102
- },
103
- {
104
- title: "Functions",
105
- url: "#",
106
- },
107
- {
108
- title: "next.config.js Options",
109
- url: "#",
110
- },
111
- {
112
- title: "CLI",
113
- url: "#",
114
- },
115
- {
116
- title: "Edge Runtime",
117
- url: "#",
118
- },
119
- ],
120
- },
121
- {
122
- title: "Architecture",
123
- url: "#",
124
- items: [
125
- {
126
- title: "Accessibility",
127
- url: "#",
128
- },
129
- {
130
- title: "Fast Refresh",
131
- url: "#",
132
- },
133
- {
134
- title: "Next.js Compiler",
135
- url: "#",
136
- },
137
- {
138
- title: "Supported Browsers",
139
- url: "#",
140
- },
141
- {
142
- title: "Turbopack",
143
- url: "#",
44
+ title: "ISR",
45
+ url: "/isr",
144
46
  },
145
47
  ],
146
48
  },
147
49
  ],
148
50
  }
51
+
149
52
  export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
53
+ const [user, setUser] = React.useState<any>(null)
54
+
55
+ React.useEffect(() => {
56
+ const checkSession = async () => {
57
+ const { data: sessionData } = await authClient.getSession()
58
+ setUser(sessionData?.user || null)
59
+ }
60
+ checkSession()
61
+ }, [])
62
+
150
63
  return (
151
64
  <Sidebar {...props}>
152
65
  <SidebarHeader>
153
- <VersionSwitcher
154
- versions={data.versions}
155
- defaultVersion={data.versions[0]}
156
- />
157
- <SearchForm />
66
+ <div className="flex items-center gap-2 px-4 py-2">
67
+ <span className="font-bold">LLM Trust</span>
68
+ </div>
158
69
  </SidebarHeader>
159
70
  <SidebarContent>
160
71
  {data.navMain.map((item) => (
@@ -165,8 +76,12 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
165
76
  {item.items.map((subItem) => (
166
77
  <SidebarMenuItem key={subItem.title}>
167
78
  <SidebarMenuButton
168
- isActive={subItem.isActive}
169
- render={<a href={subItem.url} />}
79
+ render={
80
+ <Link
81
+ to={subItem.url}
82
+ activeProps={{ className: "bg-sidebar-accent" }}
83
+ />
84
+ }
170
85
  >
171
86
  {subItem.title}
172
87
  </SidebarMenuButton>
@@ -177,6 +92,47 @@ export function AppSidebar({ ...props }: React.ComponentProps<typeof Sidebar>) {
177
92
  </SidebarGroup>
178
93
  ))}
179
94
  </SidebarContent>
95
+ <SidebarFooter>
96
+ <SidebarMenu>
97
+ <SidebarMenuItem>
98
+ {user ? (
99
+ <SidebarMenuButton
100
+ size="lg"
101
+ className="data-[state=open]:bg-sidebar-accent data-[state=open]:text-sidebar-accent-foreground"
102
+ >
103
+ <Avatar className="h-8 w-8 rounded-lg">
104
+ <AvatarImage src={user.image || ""} alt={user.name} />
105
+ <AvatarFallback className="rounded-lg">
106
+ {user.name?.charAt(0) || "U"}
107
+ </AvatarFallback>
108
+ </Avatar>
109
+ <div className="grid flex-1 text-left text-sm leading-tight">
110
+ <span className="truncate font-semibold">{user.name}</span>
111
+ <span className="truncate text-xs">{user.email}</span>
112
+ </div>
113
+ <button
114
+ onClick={async () => {
115
+ await authClient.signOut()
116
+ window.location.reload()
117
+ }}
118
+ className="ml-auto"
119
+ >
120
+ <LogOut className="h-4 w-4" />
121
+ </button>
122
+ </SidebarMenuButton>
123
+ ) : (
124
+ <SidebarMenuButton
125
+ render={
126
+ <Link to="/login" className="flex items-center gap-2" />
127
+ }
128
+ >
129
+ <User className="h-4 w-4" />
130
+ <span>Sign In</span>
131
+ </SidebarMenuButton>
132
+ )}
133
+ </SidebarMenuItem>
134
+ </SidebarMenu>
135
+ </SidebarFooter>
180
136
  <SidebarRail />
181
137
  </Sidebar>
182
138
  )