@xyd-js/plugin-access-control 0.0.0-build-8804789-20260430104829
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/LICENSE +21 -0
- package/dist/AccessControlContext.js +130 -0
- package/dist/AccessControlContext.js.map +1 -0
- package/dist/AuthCallbackPage.js +116 -0
- package/dist/AuthCallbackPage.js.map +1 -0
- package/dist/AuthGuard.js +115 -0
- package/dist/AuthGuard.js.map +1 -0
- package/dist/LoginPage.js +158 -0
- package/dist/LoginPage.js.map +1 -0
- package/dist/client.d.ts +167 -0
- package/dist/client.js +484 -0
- package/dist/client.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +1200 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/AccessControlContext.tsx","../src/devOnly.ts","../src/components/AuthGuard.tsx","../src/components/LoginPage.tsx","../src/components/AuthCallbackPage.tsx","../src/access.ts","../src/navigation.ts"],"sourcesContent":["import React, { createContext, useContext, useEffect, useState, useCallback } from \"react\";\nimport { isDevEnvironment as isDevEnv } from \"../devOnly\";\n\nexport interface AccessControlActions {\n /** Current auth config from docs.json */\n config: any | null;\n /** Whether config has loaded */\n ready: boolean;\n /** Last error message */\n error: string;\n /** Clear error */\n clearError: () => void;\n\n // --- Auth actions ---\n\n /** Redirect to external OAuth provider */\n signInWithOAuth: () => void;\n /** Redirect to external JWT login URL */\n signInWithRedirect: () => void;\n /** Sign in with test token (dev/edge server) */\n signInAsUser: () => void;\n /** Sign in as admin with test token (dev/edge server) */\n signInAsAdmin: () => void;\n /** Sign in with specific groups */\n signInWithGroups: (groups: string[]) => void;\n // --- Info ---\n\n /** Provider type: \"jwt\" | \"oauth\" */\n providerType: string;\n /** Whether an external auth URL is configured */\n hasExternalAuth: boolean;\n /** Login page title from config */\n title: string;\n /** Login page description from config */\n description: string;\n /** Login page logo URL from config */\n logo: string;\n /** Login page background image from config */\n backgroundImage: string;\n /** The redirect URL (where to go after login) */\n redirectUrl: string;\n}\n\nconst AccessControlCtx = createContext<AccessControlActions | null>(null);\n\n/**\n * Hook to access auth actions in custom login pages.\n *\n * @example\n * ```tsx\n * import { useAccessControl } from \"@xyd-js/plugin-access-control\"\n *\n * function MyLoginPage() {\n * const { signInWithOAuth, title, logo, error } = useAccessControl()\n *\n * return (\n * <div>\n * {logo && <img src={logo} />}\n * <h1>{title}</h1>\n * {error && <p>{error}</p>}\n * <button onClick={signInWithOAuth}>Sign in</button>\n * </div>\n * )\n * }\n * ```\n */\nexport function useAccessControl(): AccessControlActions {\n const ctx = useContext(AccessControlCtx);\n if (!ctx) {\n throw new Error(\"useAccessControl must be used inside <AccessControlProvider>\");\n }\n return ctx;\n}\n\nexport function AccessControlProvider({ children }: { children: React.ReactNode }) {\n const [config, setConfig] = useState<any>(null);\n const [error, setError] = useState(\"\");\n const [ready, setReady] = useState(false);\n\n useEffect(() => {\n const globalConfig = (window as any).__xydAccessControlSettings?.accessControlConfig;\n if (globalConfig) {\n setConfig(globalConfig);\n setReady(true);\n return;\n }\n // @ts-ignore\n import(\"virtual:xyd-access-control-settings\")\n .then((mod: any) => { setConfig(mod.accessControlConfig); setReady(true); })\n .catch(() => setReady(true));\n }, []);\n\n const providerType = config?.provider?.type || \"jwt\";\n const loginUrl = config?.provider?.loginUrl || \"\";\n const authorizationUrl = config?.provider?.authorizationUrl || \"\";\n const hasExternalAuth = providerType === \"oauth\"\n ? !!authorizationUrl\n : !!loginUrl && loginUrl !== \"/login\";\n\n // login can be a string (custom component path) or an object (config)\n const loginConfig = typeof config?.login === \"string\" ? {} : (config?.login || {});\n const title = loginConfig.title || \"Sign in to access documentation\";\n const description = loginConfig.description || \"\";\n const logo = loginConfig.logo || \"\";\n const backgroundImage = loginConfig.backgroundImage || \"\";\n\n const params = typeof window !== \"undefined\" ? new URLSearchParams(window.location.search) : null;\n const redirectUrl = params?.get(\"redirect\") || \"/\";\n\n const storeTokenAndRedirect = useCallback((token: string) => {\n const cookieName = config?.session?.cookieName || \"xyd-auth-token\";\n localStorage.setItem(cookieName, token);\n document.cookie = `${cookieName}=${token}; path=/; max-age=86400; SameSite=Lax`;\n window.location.href = redirectUrl;\n }, [config, redirectUrl]);\n\n const signInWithOAuth = useCallback(() => {\n if (!authorizationUrl) { setError(\"No OAuth authorization URL configured\"); return; }\n const callbackPath = config?.provider?.callbackPath || \"/auth/callback\";\n const redirectUri = window.location.origin + callbackPath;\n const scopes = config?.provider?.scopes || [];\n const clientId = config?.provider?.clientId || \"\";\n\n const oauthParams = new URLSearchParams({\n client_id: clientId,\n redirect_uri: redirectUri,\n response_type: \"code\",\n scope: scopes.join(\" \"),\n state: redirectUrl,\n });\n window.location.href = `${authorizationUrl}?${oauthParams.toString()}`;\n }, [config, authorizationUrl, redirectUrl]);\n\n const signInWithRedirect = useCallback(() => {\n if (!loginUrl || loginUrl === \"/login\") { setError(\"No external login URL configured\"); return; }\n const sep = loginUrl.includes(\"?\") ? \"&\" : \"?\";\n window.location.href = `${loginUrl}${sep}redirect=${encodeURIComponent(redirectUrl)}`;\n }, [loginUrl, redirectUrl]);\n\n const signInWithGroups = useCallback((groups: string[]) => {\n // Production with deploy config: use /auth/test-login (server-signed)\n const hasDeploy = !!config?.deploy;\n if (hasDeploy) {\n const groupsParam = groups.length ? `&groups=${groups.join(\",\")}` : \"\";\n window.location.href = `/auth/test-login?redirect=${encodeURIComponent(redirectUrl)}${groupsParam}`;\n return;\n }\n\n // Dev only: generate unsigned client-side token\n if (!isDevEnv()) {\n setError(\"Test login is only available in development mode.\");\n return;\n }\n const header = btoa(JSON.stringify({ alg: \"HS256\", typ: \"JWT\" }));\n const payload = btoa(JSON.stringify({\n sub: \"test-user\",\n groups,\n exp: Math.floor(Date.now() / 1000) + 86400,\n iat: Math.floor(Date.now() / 1000),\n }));\n storeTokenAndRedirect(`${header}.${payload}.dGVzdA`);\n }, [config, redirectUrl, storeTokenAndRedirect]);\n\n const signInAsUser = useCallback(() => signInWithGroups([]), [signInWithGroups]);\n const signInAsAdmin = useCallback(() => signInWithGroups([\"admin\"]), [signInWithGroups]);\n\n const value: AccessControlActions = {\n config,\n ready,\n error,\n clearError: () => setError(\"\"),\n signInWithOAuth,\n signInWithRedirect,\n signInAsUser,\n signInAsAdmin,\n signInWithGroups,\n providerType,\n hasExternalAuth,\n title,\n description,\n logo,\n backgroundImage,\n redirectUrl,\n };\n\n return <AccessControlCtx.Provider value={value}>{children}</AccessControlCtx.Provider>;\n}","/**\n * Check if running in development mode.\n * Server-side: checks NODE_ENV\n * Client-side: checks import.meta.env (set by Vite)\n */\nexport function isDevEnvironment(): boolean {\n // Server-side (Node.js)\n if (typeof window === \"undefined\") {\n return process.env.NODE_ENV !== \"production\";\n }\n\n // Client-side (Vite)\n try {\n return !!(import.meta as any).env?.DEV;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if auth bypass is enabled. Only works in development mode.\n * Controlled by XYD_AUTH_BYPASS=1 environment variable.\n */\nexport function isAuthBypassed(): boolean {\n if (!isDevEnvironment()) return false;\n\n return (\n process.env.XYD_AUTH_BYPASS === \"1\" ||\n process.env.XYD_AUTH_BYPASS === \"true\"\n );\n}","import React, {\n createContext,\n useContext,\n useEffect,\n useState,\n useMemo,\n} from \"react\";\n\nexport interface AuthState {\n authenticated: boolean;\n groups: string[];\n token: string | null;\n}\n\nconst AuthContext = createContext<AuthState>({\n authenticated: false,\n groups: [],\n token: null,\n});\n\ndeclare global {\n interface Window {\n __xydAuthState?: AuthState;\n __xydAuthDebug?: any;\n }\n}\n\ninterface AuthGuardProps {\n children: React.ReactNode;\n accessMap: Record<string, string>;\n config: {\n provider: { type: string; loginUrl?: string };\n unauthorizedBehavior?: \"redirect\" | \"404\";\n session?: { cookieName?: string };\n };\n}\n\nfunction buildLoginUrl(loginUrl: string, returnPath: string): string {\n const separator = loginUrl.includes(\"?\") ? \"&\" : \"?\";\n return `${loginUrl}${separator}redirect=${encodeURIComponent(returnPath)}`;\n}\n\n/**\n * AuthGuard wraps the application and enforces access control.\n * It reads auth state from window.__xydAuthState (set by pre-hydration script)\n * and checks the access map for the current route.\n */\nexport default function AuthGuard({ children, accessMap, config }: AuthGuardProps) {\n const [authState, setAuthState] = useState<AuthState>(() => {\n if (typeof window !== \"undefined\" && window.__xydAuthState) {\n return window.__xydAuthState;\n }\n return { authenticated: false, groups: [], token: null };\n });\n\n useEffect(() => {\n // Listen for auth state changes (e.g., after login callback)\n const handleStorage = (e: StorageEvent) => {\n const cookieName = config.session?.cookieName || \"xyd-auth-token\";\n if (e.key === cookieName) {\n if (e.newValue) {\n try {\n const payload = JSON.parse(atob(e.newValue.split(\".\")[1]));\n setAuthState({\n authenticated: true,\n groups: payload.groups || [],\n token: e.newValue,\n });\n } catch {\n setAuthState({ authenticated: false, groups: [], token: null });\n }\n } else {\n setAuthState({ authenticated: false, groups: [], token: null });\n }\n }\n };\n\n window.addEventListener(\"storage\", handleStorage);\n return () => window.removeEventListener(\"storage\", handleStorage);\n }, [config.session?.cookieName]);\n\n const value = useMemo(() => authState, [authState]);\n\n return (\n <AuthContext.Provider value={value}>\n <AuthEnforcer accessMap={accessMap} config={config}>\n {children}\n </AuthEnforcer>\n </AuthContext.Provider>\n );\n}\n\n/**\n * Enforces access control on route changes.\n */\nfunction AuthEnforcer({\n children,\n accessMap,\n config,\n}: {\n children: React.ReactNode;\n accessMap: Record<string, string>;\n config: AuthGuardProps[\"config\"];\n}) {\n const authState = useContext(AuthContext);\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n const pathname = window.location.pathname;\n const pageAccess = accessMap[pathname];\n\n // No access entry or public = allow\n if (!pageAccess || pageAccess === \"public\") return;\n\n // Requires auth but user is not authenticated\n if (!authState.authenticated) {\n const loginUrl = config.provider.loginUrl;\n if (loginUrl) {\n window.location.href = buildLoginUrl(loginUrl, pathname);\n }\n return;\n }\n\n // Group-based access\n if (pageAccess !== \"authenticated\") {\n const requiredGroups = pageAccess.split(\",\");\n const hasAccess = requiredGroups.some((g) =>\n authState.groups.includes(g)\n );\n if (!hasAccess) {\n if (config.unauthorizedBehavior === \"404\") {\n // Replace with a 404-like state\n window.location.href = \"/404\";\n } else {\n const loginUrl = config.provider.loginUrl;\n if (loginUrl) {\n window.location.href = buildLoginUrl(loginUrl, pathname);\n }\n }\n }\n }\n }, [authState, accessMap, config]);\n\n return <>{children}</>;\n}\n\n/**\n * Hook to access authentication state.\n */\nexport function useAuth(): AuthState & {\n login: () => void;\n logout: () => void;\n} {\n const state = useContext(AuthContext);\n\n return {\n ...state,\n login() {\n // Will be overridden by config at runtime\n console.warn(\"[xyd:access-control] login() called without config\");\n },\n logout() {\n if (typeof window === \"undefined\") return;\n\n const cookieName = \"xyd-auth-token\";\n localStorage.removeItem(cookieName);\n document.cookie = `${cookieName}=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;\n document.cookie = `${cookieName}-state=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/`;\n\n window.__xydAuthState = {\n authenticated: false,\n groups: [],\n token: null,\n };\n document.documentElement.setAttribute(\"data-auth\", \"anonymous\");\n window.location.reload();\n },\n };\n}\n","import React from \"react\";\nimport { AccessControlProvider, useAccessControl } from \"./AccessControlContext\";\n\n/**\n * Default login page. Wraps itself with AccessControlProvider\n * so it works regardless of the host wrapper.\n */\nexport default function LoginPage() {\n return (\n <AccessControlProvider>\n <LoginPageUI />\n </AccessControlProvider>\n );\n}\n\nfunction LoginPageUI() {\n const {\n providerType,\n hasExternalAuth,\n title,\n description,\n logo,\n backgroundImage,\n error,\n signInWithOAuth,\n signInWithRedirect,\n signInAsUser,\n signInAsAdmin,\n } = useAccessControl();\n\n const handleSignIn = () => {\n if (providerType === \"oauth\") signInWithOAuth();\n else signInWithRedirect();\n };\n\n const bgOverride = backgroundImage\n ? { backgroundImage: `url(${backgroundImage})`, backgroundSize: \"cover\" as const, backgroundPosition: \"center\", background: \"none\" }\n : undefined;\n\n return (\n <div className=\"xyd-login-page\" style={bgOverride}>\n <div part=\"card\">\n {logo && <img part=\"logo\" src={logo} alt=\"\" />}\n\n <h1 part=\"title\">{title}</h1>\n\n {description && <p part=\"description\">{description}</p>}\n\n {error && <p part=\"error\">{error}</p>}\n\n {hasExternalAuth ? (\n <button part=\"button\" onClick={handleSignIn}>Sign in</button>\n ) : (\n <div part=\"actions\">\n <button part=\"button\" onClick={signInAsUser}>Sign in as User</button>\n <button part=\"button\" data-kind=\"secondary\" onClick={signInAsAdmin}>Sign in as Admin</button>\n </div>\n )}\n </div>\n </div>\n );\n}","import React, { useEffect, useState } from \"react\";\n\n/**\n * Handles both JWT and OAuth callback flows:\n *\n * JWT: /auth/jwt-callback#eyJ... → extract token from hash\n * OAuth: /auth/callback?code=XXX&state=/page → exchange code for token\n */\nexport default function AuthCallbackPage() {\n const [error, setError] = useState(\"\");\n\n useEffect(() => {\n if (typeof window === \"undefined\") return;\n\n // @ts-ignore - virtual module resolved by Vite at runtime\n import(\"virtual:xyd-access-control-settings\")\n .then((mod: any) => {\n const config = mod.accessControlConfig;\n handleCallback(config);\n })\n .catch(() => {\n // Fallback: try JWT flow without config\n handleCallback(null);\n });\n }, []);\n\n function storeTokenAndRedirect(\n token: string,\n groups: string[],\n redirect: string,\n cookieName: string\n ) {\n localStorage.setItem(cookieName, token);\n document.cookie = `${cookieName}=${token}; path=/; max-age=86400; SameSite=Lax`;\n\n (window as any).__xydAuthState = {\n authenticated: true,\n groups,\n token,\n };\n document.documentElement.setAttribute(\"data-auth\", \"authenticated\");\n window.location.href = redirect;\n }\n\n async function handleCallback(config: any) {\n const params = new URLSearchParams(window.location.search);\n const hash = window.location.hash.slice(1);\n const code = params.get(\"code\");\n const state = params.get(\"state\") || \"/\";\n const cookieName = config?.session?.cookieName || \"xyd-auth-token\";\n const groupsClaim = config?.provider?.groupsClaim || \"groups\";\n\n // OAuth flow: code in query params\n if (code && config?.provider?.type === \"oauth\") {\n try {\n await handleOAuthCallback(code, state, config, cookieName, groupsClaim);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"OAuth authentication failed\");\n }\n return;\n }\n\n // JWT flow: token in query param (?token=...) or hash fragment (#eyJ...)\n const token = params.get(\"token\") || hash;\n const redirect = params.get(\"redirect\") || state;\n if (token) {\n try {\n handleJWTCallback(token, redirect, cookieName, groupsClaim);\n } catch (e) {\n setError(e instanceof Error ? e.message : \"JWT authentication failed\");\n }\n return;\n }\n\n setError(\"No authentication data found in callback URL.\");\n }\n\n function handleJWTCallback(\n hash: string,\n redirect: string,\n cookieName: string,\n groupsClaim: string\n ) {\n const parts = hash.split(\".\");\n if (parts.length !== 3) throw new Error(\"Invalid JWT format\");\n\n const payload = JSON.parse(atob(parts[1]));\n if (payload.exp && payload.exp * 1000 < Date.now()) {\n throw new Error(\"Token has expired\");\n }\n\n storeTokenAndRedirect(hash, payload[groupsClaim] || [], redirect, cookieName);\n }\n\n async function handleOAuthCallback(\n code: string,\n redirect: string,\n config: any,\n cookieName: string,\n groupsClaim: string\n ) {\n const tokenUrl = config.provider.tokenUrl;\n const userInfoUrl = config.provider.userInfoUrl;\n const clientId = config.provider.clientId || \"\";\n const callbackPath = config.provider.callbackPath || \"/auth/callback\";\n const redirectUri = window.location.origin + callbackPath;\n\n if (!tokenUrl) throw new Error(\"No token URL configured\");\n\n // Exchange code for access token\n const tokenRes = await fetch(tokenUrl, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/x-www-form-urlencoded\" },\n body: new URLSearchParams({\n grant_type: \"authorization_code\",\n code,\n client_id: clientId,\n redirect_uri: redirectUri,\n }).toString(),\n });\n\n if (!tokenRes.ok) {\n throw new Error(`Token exchange failed: ${tokenRes.status}`);\n }\n\n const tokenData = await tokenRes.json();\n const accessToken = tokenData.access_token;\n if (!accessToken) throw new Error(\"No access token in response\");\n\n // Fetch user info to get groups/roles\n let groups: string[] = [];\n if (userInfoUrl) {\n try {\n const userRes = await fetch(userInfoUrl, {\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (userRes.ok) {\n const userInfo = await userRes.json();\n groups = userInfo[groupsClaim] || userInfo.roles || userInfo.groups || [];\n }\n } catch {\n // User info fetch failed — continue without groups\n }\n }\n\n // Create a session JWT from the access token info\n const header = btoa(JSON.stringify({ alg: \"HS256\", typ: \"JWT\" }));\n const payload = btoa(JSON.stringify({\n sub: \"oauth-user\",\n [groupsClaim]: groups,\n exp: Math.floor(Date.now() / 1000) + 86400,\n iat: Math.floor(Date.now() / 1000),\n access_token: accessToken,\n }));\n const sessionToken = `${header}.${payload}.oauth`;\n\n storeTokenAndRedirect(sessionToken, groups, redirect, cookieName);\n }\n\n if (error) {\n return (\n <div className=\"xyd-callback-page\">\n <div part=\"card\">\n <h2 part=\"title\" data-error=\"\">Authentication Error</h2>\n <p part=\"message\">{error}</p>\n <button part=\"button\" onClick={() => (window.location.href = \"/\")}>\n Go to homepage\n </button>\n </div>\n </div>\n );\n }\n\n return (\n <div className=\"xyd-callback-page\">\n <div part=\"card\">\n <p part=\"message\">Authenticating...</p>\n </div>\n </div>\n );\n}\n","import type { AccessControl, AccessControlRule } from \"@xyd-js/core\";\n\nexport type AccessLevel = \"public\" | \"authenticated\" | string; // string = comma-separated groups\n\nexport type AccessMap = Record<string, AccessLevel>;\n\nexport interface AccessEvaluation {\n allowed: boolean;\n reason: string;\n}\n\n/**\n * Matches a path against a glob-like pattern.\n * Supports ** (any depth) and * (single segment).\n */\nexport function matchPattern(pattern: string, path: string): boolean {\n const regexStr = pattern\n .replace(/\\*\\*/g, \"___GLOBSTAR___\")\n .replace(/\\*/g, \"[^/]*\")\n .replace(/___GLOBSTAR___/g, \".*\");\n\n const regex = new RegExp(`^${regexStr}$`);\n return regex.test(path);\n}\n\n/**\n * Evaluate access for a specific page given its metadata and access control config.\n * Returns the access level string for the access map.\n */\nexport function resolvePageAccess(\n pagePath: string,\n metadata: { public?: boolean; accessGroups?: string[] },\n config: AccessControl\n): AccessLevel {\n // Normalize: ensure path has leading slash for consistent matching\n const normalizedPath = pagePath.startsWith(\"/\") ? pagePath : `/${pagePath}`;\n\n // 1. Frontmatter overrides (highest priority)\n if (metadata.public === true) {\n return \"public\";\n }\n if (metadata.public === false) {\n if (metadata.accessGroups?.length) {\n return metadata.accessGroups.join(\",\");\n }\n return \"authenticated\";\n }\n\n // 2. Pattern rules (first match wins)\n if (config.rules) {\n for (const rule of config.rules) {\n if (matchPattern(rule.match, normalizedPath)) {\n if (rule.access === \"public\") {\n return \"public\";\n }\n if (rule.groups?.length) {\n return rule.groups.join(\",\");\n }\n return \"authenticated\";\n }\n }\n }\n\n // 3. Default access (lowest priority)\n return config.defaultAccess === \"protected\" ? \"authenticated\" : \"public\";\n}\n\n/**\n * Evaluate whether a user has access to a page.\n */\nexport function evaluateAccess(\n pagePath: string,\n accessMap: AccessMap,\n userGroups: string[]\n): AccessEvaluation {\n const access = accessMap[pagePath];\n\n // No entry in access map = public\n if (!access || access === \"public\") {\n return { allowed: true, reason: `access:public` };\n }\n\n // Requires authentication\n if (access === \"authenticated\") {\n return {\n allowed: userGroups.length > 0 || false,\n reason: \"access:authenticated\",\n };\n }\n\n // Group-based access\n const requiredGroups = access.split(\",\");\n const hasGroup = requiredGroups.some((g) => userGroups.includes(g));\n return {\n allowed: hasGroup,\n reason: `access:groups:${access}`,\n };\n}\n\n/**\n * Build a complete access map from page path mapping and access control config.\n * Used at build time to pre-compute access levels for all pages.\n */\nexport function buildAccessMap(\n pagePathMapping: Record<string, string>,\n metadataMap: Record<string, { public?: boolean; accessGroups?: string[] }>,\n config: AccessControl\n): AccessMap {\n const accessMap: AccessMap = {};\n\n for (const pagePath of Object.keys(pagePathMapping)) {\n const metadata = metadataMap[pagePath] || {};\n accessMap[pagePath] = resolvePageAccess(pagePath, metadata, config);\n }\n\n return accessMap;\n}\n","import type { AccessMap } from \"./access\";\n\ninterface SidebarItem {\n title: string;\n href: string;\n items?: SidebarItem[];\n [key: string]: any;\n}\n\ninterface SidebarGroup {\n group: string;\n groupIndex: number;\n items: SidebarItem[];\n icon?: string;\n [key: string]: any;\n}\n\n/**\n * Filters sidebar navigation groups to hide pages the user cannot access.\n * This runs at runtime in the browser based on the user's auth state.\n */\nexport function filterSidebarGroups(\n sidebarGroups: SidebarGroup[],\n accessMap: AccessMap,\n userGroups: string[]\n): SidebarGroup[] {\n return sidebarGroups\n .map((group) => ({\n ...group,\n items: filterItems(group.items, accessMap, userGroups),\n }))\n .filter((group) => group.items.length > 0);\n}\n\nfunction filterItems(\n items: SidebarItem[],\n accessMap: AccessMap,\n userGroups: string[]\n): SidebarItem[] {\n return items\n .filter((item) => {\n const href = item.href;\n if (!href) return true;\n\n const normalizedHref = href.startsWith(\"/\") ? href : `/${href}`;\n const access = accessMap[normalizedHref] || accessMap[href];\n\n // No entry or public = show\n if (!access || access === \"public\") return true;\n\n // Requires auth - user must have groups\n if (access === \"authenticated\") return userGroups.length > 0;\n\n // Group-based access\n const requiredGroups = access.split(\",\");\n return requiredGroups.some((g) => userGroups.includes(g));\n })\n .map((item) => {\n // Recursively filter nested items\n if (item.items?.length) {\n return {\n ...item,\n items: filterItems(item.items, accessMap, userGroups),\n };\n }\n return item;\n });\n}\n\n/**\n * Filters an array of paths (used for sitemap/llms.txt) to exclude protected pages.\n */\nexport function filterProtectedPaths(\n paths: string[],\n accessMap: AccessMap\n): string[] {\n return paths.filter((p) => {\n const normalizedPath = p.startsWith(\"/\") ? p : `/${p}`;\n const access = accessMap[normalizedPath] || accessMap[p];\n return !access || access === \"public\";\n });\n}\n"],"mappings":"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","names":["React","createContext","useContext","useEffect","useState","React","React","React","useEffect","useState"]}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Plugin } from '@xyd-js/plugins';
|
|
2
|
+
import { AccessControl } from '@xyd-js/core';
|
|
3
|
+
export { AccessControlActions, AccessControlProvider, AccessEvaluation, AccessLevel, AccessMap, AuthCallbackPage, AuthGuard, LoginPage, buildAccessMap, evaluateAccess, filterProtectedPaths, filterSidebarGroups, resolvePageAccess, useAccessControl, useAuth } from './client.js';
|
|
4
|
+
import 'react';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Access control plugin for xyd documentation sites.
|
|
8
|
+
*
|
|
9
|
+
* Provides:
|
|
10
|
+
* - Pre-hydration script to prevent flash of protected content
|
|
11
|
+
* - AuthGuard React component for route-level access enforcement
|
|
12
|
+
* - Virtual modules with access control config and access map
|
|
13
|
+
* - Edge middleware generators for Netlify, Vercel, Cloudflare
|
|
14
|
+
* - Login and callback page components
|
|
15
|
+
*/
|
|
16
|
+
declare function AccessControlPlugin(pluginOptions: AccessControl): Plugin;
|
|
17
|
+
|
|
18
|
+
export { AccessControlPlugin as default };
|