@classic-homes/theme-mcp 0.1.26 → 0.1.28

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/cli.js CHANGED
@@ -14198,6 +14198,104 @@ var auth_catalog_default = {
14198
14198
  ]
14199
14199
  }
14200
14200
  ]
14201
+ },
14202
+ errors: {
14203
+ description: "Custom error types for authentication operations",
14204
+ functions: [
14205
+ {
14206
+ name: "RoleDeniedError",
14207
+ signature: "class extends Error",
14208
+ description: "Error thrown when a user authenticates but lacks required roles",
14209
+ example: "import { authService, RoleDeniedError } from '@classic-homes/auth/core';\n\ntry {\n const response = await authService.login(credentials, {\n allowedRoles: ['admin', 'manager', 'agent'],\n });\n} catch (error) {\n if (error instanceof RoleDeniedError) {\n // User authenticated but lacks required role\n console.log('User roles:', error.user.roles);\n console.log('Required roles:', error.requiredRoles);\n goto('/auth/login?error=insufficient_permissions');\n }\n}"
14210
+ },
14211
+ {
14212
+ name: "isRoleDeniedError",
14213
+ signature: "(error: unknown) => error is RoleDeniedError",
14214
+ description: "Type guard to check if an error is a RoleDeniedError"
14215
+ }
14216
+ ],
14217
+ types: [
14218
+ {
14219
+ name: "RoleDeniedError",
14220
+ description: "Error with user and role information for handling access denial",
14221
+ properties: [
14222
+ { name: "name", type: "'RoleDeniedError'", required: true, description: "Error name for identification" },
14223
+ { name: "user", type: "User", required: true, description: "The authenticated user (allows logging before redirect)" },
14224
+ { name: "requiredRoles", type: "string[]", required: true, description: "The roles that were required (user has none of these)" },
14225
+ { name: "redirectTo", type: "string", required: false, description: "Optional redirect path for convenience" },
14226
+ { name: "message", type: "string", required: true, description: "Human-readable error message" }
14227
+ ]
14228
+ }
14229
+ ]
14230
+ },
14231
+ "user-utils": {
14232
+ description: "Helper functions for displaying user information in the UI",
14233
+ functions: [
14234
+ {
14235
+ name: "getDisplayName",
14236
+ signature: "(user: User | null | undefined) => string",
14237
+ description: "Get a display-friendly name for a user. Priority: full name > first name > username > email > 'Unknown'",
14238
+ example: `import { getDisplayName } from '@classic-homes/auth/core';
14239
+
14240
+ const name = getDisplayName(user);
14241
+ // Returns: "John Doe", "John", "johndoe", or "john@example.com"`
14242
+ },
14243
+ {
14244
+ name: "getUserInitials",
14245
+ signature: "(user: User | null | undefined, maxLength?: number) => string",
14246
+ description: "Get initials from a user's name for avatar fallbacks",
14247
+ example: `import { getUserInitials } from '@classic-homes/auth/core';
14248
+
14249
+ const initials = getUserInitials(user);
14250
+ // Returns: "JD" for "John Doe", "J" for "John", "?" for unknown`
14251
+ },
14252
+ {
14253
+ name: "getAvatarFallback",
14254
+ signature: "(user: User | null | undefined) => string",
14255
+ description: "Get avatar fallback text for a user. Alias for getUserInitials for semantic clarity.",
14256
+ example: "import { getAvatarFallback } from '@classic-homes/auth/core';\n\n<Avatar>\n <AvatarFallback>{getAvatarFallback(user)}</AvatarFallback>\n</Avatar>"
14257
+ },
14258
+ {
14259
+ name: "getUserEmail",
14260
+ signature: "(user: User | null | undefined, masked?: boolean) => string",
14261
+ description: "Get the user's primary email, optionally masked for privacy",
14262
+ example: `import { getUserEmail } from '@classic-homes/auth/core';
14263
+
14264
+ getUserEmail(user); // "john@example.com"
14265
+ getUserEmail(user, true); // "j***@example.com"`
14266
+ },
14267
+ {
14268
+ name: "getGreeting",
14269
+ signature: "(user: User | null | undefined, includeTime?: boolean) => string",
14270
+ description: "Get a greeting for the user based on time of day",
14271
+ example: `import { getGreeting } from '@classic-homes/auth/core';
14272
+
14273
+ getGreeting(user); // "Good morning, John"
14274
+ getGreeting(user, false); // "Hello, John"`
14275
+ },
14276
+ {
14277
+ name: "formatUserRoles",
14278
+ signature: "(user: User | null | undefined, options?: FormatUserRolesOptions) => string",
14279
+ description: "Format user roles for display with customizable formatting",
14280
+ example: `import { formatUserRoles } from '@classic-homes/auth/core';
14281
+
14282
+ formatUserRoles(user); // "Admin, Manager"
14283
+ formatUserRoles(user, { max: 1 }); // "Admin +1 more"
14284
+ formatUserRoles(user, { lowercase: true }); // "admin, manager"`
14285
+ }
14286
+ ],
14287
+ types: [
14288
+ {
14289
+ name: "FormatUserRolesOptions",
14290
+ description: "Options for formatUserRoles function",
14291
+ properties: [
14292
+ { name: "max", type: "number", required: false, description: "Maximum roles to show before '+N more'" },
14293
+ { name: "separator", type: "string", required: false, description: "Separator between roles (default: ', ')" },
14294
+ { name: "lowercase", type: "boolean", required: false, description: "Convert to lowercase (default: false)" },
14295
+ { name: "capitalize", type: "boolean", required: false, description: "Capitalize first letter of each role (default: true)" }
14296
+ ]
14297
+ }
14298
+ ]
14201
14299
  }
14202
14300
  },
14203
14301
  types: [
@@ -14509,9 +14607,9 @@ var auth_catalog_default = {
14509
14607
  },
14510
14608
  {
14511
14609
  name: "authActions",
14512
- signature: "{ setAuth, updateTokens, updateUser, logout, logoutWithSSO, hasPermission, hasRole, hasAnyRole, hasAllRoles, hasAnyPermission, hasAllPermissions, rehydrate }",
14610
+ signature: "{ setAuth, updateTokens, updateUser, logout, logoutWithSSO, handleSessionExpired, hasPermission, hasRole, hasAnyRole, hasAllRoles, hasAnyPermission, hasAllPermissions, rehydrate, reset }",
14513
14611
  description: "Auth action functions that update the store and check permissions",
14514
- example: "import { authActions } from '@classic-homes/auth/svelte';\n\n// After successful login, set the auth state\nauthActions.setAuth(accessToken, refreshToken, user, sessionToken);\n\n// Update tokens after refresh\nauthActions.updateTokens(newAccessToken, newRefreshToken);\n\n// Update user data\nauthActions.updateUser(updatedUser);\n\n// Logout (clears local state)\nauthActions.logout();\n\n// Logout with SSO (calls API and clears state)\nconst { ssoLogoutUrl } = await authActions.logoutWithSSO();\nif (ssoLogoutUrl) window.location.href = ssoLogoutUrl;\n\n// Permission/role checks\nif (authActions.hasRole('admin')) { /* admin logic */ }\nif (authActions.hasPermission('users:write')) { /* write logic */ }"
14612
+ example: "import { authActions } from '@classic-homes/auth/svelte';\n\n// After successful login, set the auth state\nauthActions.setAuth(accessToken, refreshToken, user, sessionToken);\n\n// Update tokens after refresh\nauthActions.updateTokens(newAccessToken, newRefreshToken);\n\n// Update user data\nauthActions.updateUser(updatedUser);\n\n// Logout (clears local state)\nauthActions.logout();\n\n// Logout with SSO (calls API and clears state)\nconst { ssoLogoutUrl } = await authActions.logoutWithSSO();\nif (ssoLogoutUrl) window.location.href = ssoLogoutUrl;\n\n// Handle session expiration (triggers onSessionExpired callback)\nauthActions.handleSessionExpired();\n\n// Permission/role checks\nif (authActions.hasRole('admin')) { /* admin logic */ }\nif (authActions.hasPermission('users:write')) { /* write logic */ }\n\n// Reset store for testing (clears state, storage, and subscribers)\nauthActions.reset();"
14515
14613
  }
14516
14614
  ]
14517
14615
  },
@@ -14576,6 +14674,141 @@ var auth_catalog_default = {
14576
14674
  ]
14577
14675
  }
14578
14676
  ]
14677
+ },
14678
+ client: {
14679
+ description: "Simplified auth client factory for one-liner setup",
14680
+ functions: [
14681
+ {
14682
+ name: "createAuthClient",
14683
+ signature: "(options: CreateAuthClientOptions) => AuthClient",
14684
+ description: "Create and initialize the auth client with stores and services bundled",
14685
+ example: "import { createAuthClient } from '@classic-homes/auth/svelte';\nimport { PUBLIC_API_URL } from '$env/static/public';\n\n// In your lib/auth.ts\nexport const {\n authStore,\n authActions,\n authService,\n isAuthenticated,\n currentUser,\n} = createAuthClient({\n baseUrl: PUBLIC_API_URL,\n storageKey: 'my_app_auth',\n sso: { enabled: true, provider: 'authentik' },\n onSessionExpired: (currentPath) => {\n window.location.href = `/login?redirect=${encodeURIComponent(currentPath)}`;\n },\n});\n\n// In Svelte component\nimport { isAuthenticated, currentUser } from '$lib/auth';\n\n{#if $isAuthenticated}\n <p>Welcome, {$currentUser?.firstName}</p>\n{/if}"
14686
+ },
14687
+ {
14688
+ name: "initAuth",
14689
+ signature: "(config: AuthConfig) => void",
14690
+ description: "Re-exported from core for cases where you need more control"
14691
+ },
14692
+ {
14693
+ name: "isInitialized",
14694
+ signature: "() => boolean",
14695
+ description: "Re-exported from core to check if auth has been initialized"
14696
+ }
14697
+ ],
14698
+ types: [
14699
+ {
14700
+ name: "CreateAuthClientOptions",
14701
+ description: "Options for createAuthClient, extending AuthConfig",
14702
+ properties: [
14703
+ { name: "baseUrl", type: "string", required: true, description: "Base URL for the API" },
14704
+ { name: "storageKey", type: "string", required: false, description: "Storage key prefix for auth data" },
14705
+ { name: "autoRehydrate", type: "boolean", required: false, description: "Auto-rehydrate auth state from storage on creation (default: true)" },
14706
+ { name: "sso", type: "SSOConfig", required: false, description: "SSO configuration" },
14707
+ { name: "onSessionExpired", type: "(currentPath: string) => void", required: false, description: "Callback when session expires" },
14708
+ { name: "onAuthError", type: "(error: Error) => void", required: false, description: "Callback for auth errors" },
14709
+ { name: "onLogout", type: "() => void", required: false, description: "Callback when user logs out" }
14710
+ ]
14711
+ },
14712
+ {
14713
+ name: "AuthClient",
14714
+ description: "Return type from createAuthClient with all auth utilities",
14715
+ properties: [
14716
+ { name: "authStore", type: "AuthStore", required: true, description: "The auth store (Svelte store contract)" },
14717
+ { name: "authActions", type: "AuthActions", required: true, description: "Actions for modifying auth state" },
14718
+ { name: "authService", type: "AuthService", required: true, description: "Service for API calls" },
14719
+ { name: "isAuthenticated", type: "Readable<boolean>", required: true, description: "Derived store for isAuthenticated" },
14720
+ { name: "currentUser", type: "Readable<User | null>", required: true, description: "Derived store for currentUser" }
14721
+ ]
14722
+ }
14723
+ ]
14724
+ },
14725
+ hooks: {
14726
+ description: "Server-side authentication middleware for SvelteKit hooks.server.ts",
14727
+ functions: [
14728
+ {
14729
+ name: "createAuthHook",
14730
+ signature: "(options?: AuthHookOptions) => Handle",
14731
+ description: "Create a SvelteKit handle function for server-side authentication",
14732
+ example: "// src/hooks.server.ts\nimport { createAuthHook } from '@classic-homes/auth/svelte';\nimport { sequence } from '@sveltejs/kit/hooks';\n\nconst authHook = createAuthHook({\n loginPath: '/auth/login',\n publicRoutes: [/^\\/auth\\//, /^\\/api\\/health/],\n cookieName: 'my_app_auth',\n});\n\nexport const handle = sequence(authHook);"
14733
+ },
14734
+ {
14735
+ name: "matchesRoute",
14736
+ signature: "(pathname: string, patterns: RegExp[]) => boolean",
14737
+ description: "Helper to check if a pathname matches any pattern in a list"
14738
+ },
14739
+ {
14740
+ name: "routePatterns",
14741
+ signature: "{ auth, api, apiAuth, public, admin, root, health, prefix, exact }",
14742
+ description: "Pre-built route patterns for common use cases",
14743
+ example: "import { createAuthHook, routePatterns } from '@classic-homes/auth/svelte';\n\nconst authHook = createAuthHook({\n publicRoutes: [\n routePatterns.auth, // /auth/*\n routePatterns.health, // /health, /healthz, /ready, /live\n routePatterns.exact('/about'), // exact /about\n routePatterns.prefix('/public'), // /public/*\n ],\n protectedRoutes: [\n routePatterns.admin, // /admin/*\n routePatterns.api, // /api/*\n ],\n});"
14744
+ }
14745
+ ],
14746
+ types: [
14747
+ {
14748
+ name: "AuthHookOptions",
14749
+ description: "Configuration options for the auth hook",
14750
+ properties: [
14751
+ { name: "loginPath", type: "string", required: false, description: "Path to redirect unauthenticated users (default: '/login')" },
14752
+ { name: "protectedRoutes", type: "RegExp[]", required: false, description: "Routes that require authentication. If set, only these routes need auth." },
14753
+ { name: "publicRoutes", type: "RegExp[]", required: false, description: "Routes that don't require auth (default: [/^\\/auth\\//, /^\\/api\\/auth\\//])" },
14754
+ { name: "cookieName", type: "string", required: false, description: "Cookie name for auth token (default: 'classic_auth')" },
14755
+ { name: "headerName", type: "string", required: false, description: "Alternative header name to check for auth token" },
14756
+ { name: "redirectParam", type: "string", required: false, description: "Query parameter for redirect URL (default: 'redirect')" },
14757
+ { name: "isAuthenticated", type: "(event: RequestEvent) => boolean | Promise<boolean>", required: false, description: "Custom function to determine if request is authenticated" },
14758
+ { name: "onUnauthenticated", type: "(event: RequestEvent) => Response | Promise<Response>", required: false, description: "Custom handler for unauthenticated requests" },
14759
+ { name: "onAuthCheck", type: "(event: RequestEvent, isAuthenticated: boolean) => void", required: false, description: "Callback for auth check logging/analytics" }
14760
+ ]
14761
+ }
14762
+ ]
14763
+ },
14764
+ utils: {
14765
+ description: "Navigation filtering utilities based on user roles and permissions",
14766
+ functions: [
14767
+ {
14768
+ name: "filterByAccess",
14769
+ signature: "<T extends RoleRestrictedItem>(items: T[], user: User | null, options?: NavFilterOptions) => T[]",
14770
+ description: "Filter navigation items based on user roles and permissions",
14771
+ example: "import { filterByAccess } from '@classic-homes/auth/svelte';\n\nconst navItems = [\n { id: 'dashboard', label: 'Dashboard' },\n { id: 'users', label: 'Users', roles: ['admin', 'manager'] },\n { id: 'settings', label: 'Settings', permissions: ['settings:read'] },\n];\n\nconst filtered = filterByAccess(navItems, user);\n// Returns items the user can see based on their roles/permissions"
14772
+ },
14773
+ {
14774
+ name: "filterNavSections",
14775
+ signature: "<TItem, TSection>(sections: TSection[], user: User | null, options?: NavFilterOptions) => TSection[]",
14776
+ description: "Filter navigation sections with nested items, removing empty sections",
14777
+ example: "import { filterNavSections } from '@classic-homes/auth/svelte';\n\nconst sections = [\n {\n title: 'Main',\n items: [\n { id: 'dashboard', label: 'Dashboard' },\n { id: 'analytics', label: 'Analytics', roles: ['admin'] },\n ],\n },\n {\n title: 'Admin',\n items: [\n { id: 'users', label: 'Users', roles: ['admin'] },\n ],\n },\n];\n\nconst filtered = filterNavSections(sections, user);\n// Admin section removed entirely if user isn't admin"
14778
+ },
14779
+ {
14780
+ name: "canAccess",
14781
+ signature: "(item: RoleRestrictedItem, user: User | null, options?: NavFilterOptions) => boolean",
14782
+ description: "Check if a user can access a specific item",
14783
+ example: "import { canAccess } from '@classic-homes/auth/svelte';\n\nconst adminItem = { id: 'admin', roles: ['admin'] };\n\nif (canAccess(adminItem, user)) {\n // Show admin link\n}"
14784
+ },
14785
+ {
14786
+ name: "createNavFilter",
14787
+ signature: "(defaultOptions?: NavFilterOptions) => FilterFunction",
14788
+ description: "Create a pre-configured filter function with fixed options",
14789
+ example: "import { createNavFilter } from '@classic-homes/auth/svelte';\n\n// In a config file\nexport const filterNav = createNavFilter({ requireAllRoles: false });\n\n// In components\nconst filtered = filterNav(items, user);"
14790
+ }
14791
+ ],
14792
+ types: [
14793
+ {
14794
+ name: "RoleRestrictedItem",
14795
+ description: "Interface for items that can be filtered by role/permission",
14796
+ properties: [
14797
+ { name: "id", type: "string", required: false, description: "Optional item identifier" },
14798
+ { name: "roles", type: "string[]", required: false, description: "Roles that can see this item (any by default)" },
14799
+ { name: "permissions", type: "string[]", required: false, description: "Permissions that can see this item (any by default)" }
14800
+ ]
14801
+ },
14802
+ {
14803
+ name: "NavFilterOptions",
14804
+ description: "Options for navigation filtering behavior",
14805
+ properties: [
14806
+ { name: "requireAllRoles", type: "boolean", required: false, description: "Require ALL specified roles (default: false = any role)" },
14807
+ { name: "requireAllPermissions", type: "boolean", required: false, description: "Require ALL specified permissions (default: false = any permission)" },
14808
+ { name: "hideUnrestrictedForGuests", type: "boolean", required: false, description: "Hide unrestricted items for unauthenticated users (default: false)" }
14809
+ ]
14810
+ }
14811
+ ]
14579
14812
  }
14580
14813
  }
14581
14814
  },
@@ -15279,7 +15512,7 @@ function registerAuthResources(server) {
15279
15512
  ]
15280
15513
  }));
15281
15514
  server.resource(
15282
- "Auth Module",
15515
+ "Auth Core Module",
15283
15516
  new ResourceTemplate3("auth://core/{module}", { list: void 0 }),
15284
15517
  async (uri, params) => {
15285
15518
  const moduleName = params.module;
@@ -15293,7 +15526,40 @@ function registerAuthResources(server) {
15293
15526
  uri: uri.href,
15294
15527
  mimeType: "application/json",
15295
15528
  text: JSON.stringify({
15296
- error: `Module "${moduleName}" not found`,
15529
+ error: `Module "${moduleName}" not found in core`,
15530
+ availableModules
15531
+ })
15532
+ }
15533
+ ]
15534
+ };
15535
+ }
15536
+ return {
15537
+ contents: [
15538
+ {
15539
+ uri: uri.href,
15540
+ mimeType: "application/json",
15541
+ text: JSON.stringify(module, null, 2)
15542
+ }
15543
+ ]
15544
+ };
15545
+ }
15546
+ );
15547
+ server.resource(
15548
+ "Auth Svelte Module",
15549
+ new ResourceTemplate3("auth://svelte/{module}", { list: void 0 }),
15550
+ async (uri, params) => {
15551
+ const moduleName = params.module;
15552
+ const modules = catalog2.subpackages.svelte.modules;
15553
+ const module = modules[moduleName];
15554
+ if (!module) {
15555
+ const availableModules = Object.keys(modules);
15556
+ return {
15557
+ contents: [
15558
+ {
15559
+ uri: uri.href,
15560
+ mimeType: "application/json",
15561
+ text: JSON.stringify({
15562
+ error: `Module "${moduleName}" not found in svelte`,
15297
15563
  availableModules
15298
15564
  })
15299
15565
  }
@@ -15323,6 +15589,10 @@ function registerAuthResources(server) {
15323
15589
  code: "import { initAuth } from '@classic-homes/auth/core';\n\ninitAuth({ baseUrl: 'https://api.example.com' });",
15324
15590
  description: "Initialize the auth system with your API base URL"
15325
15591
  },
15592
+ createAuthClient: {
15593
+ code: "import { createAuthClient } from '@classic-homes/auth/svelte';\n\nexport const { authStore, authActions, authService, isAuthenticated, currentUser } = createAuthClient({\n baseUrl: 'https://api.example.com',\n onSessionExpired: (path) => goto(`/login?redirect=${path}`),\n});",
15594
+ description: "One-liner setup that bundles initialization, stores, and services"
15595
+ },
15326
15596
  login: {
15327
15597
  code: "import { authApi, isMfaChallengeResponse } from '@classic-homes/auth/core';\n\nconst response = await authApi.login({ username: 'user@example.com', password: 'password' });\nif (isMfaChallengeResponse(response)) {\n // Handle MFA\n}",
15328
15598
  description: "Login with username and password, handling MFA if required"
@@ -15332,9 +15602,25 @@ function registerAuthResources(server) {
15332
15602
  description: "Use reactive Svelte stores for auth state"
15333
15603
  },
15334
15604
  routeProtection: {
15335
- code: "import { requireAuth, requireRole } from '@classic-homes/auth/svelte';\n\n// In +page.ts or +layout.ts\nexport const load = requireAuth();\n// or\nexport const load = requireRole('admin');",
15605
+ code: "import { requireAuth, requireRole } from '@classic-homes/auth/svelte';\nimport { redirect } from '@sveltejs/kit';\n\n// In +page.ts\nexport function load() {\n const result = requireAuth();\n if (!result.allowed) throw redirect(302, result.redirectTo ?? '/login');\n}",
15336
15606
  description: "Protect SvelteKit routes with auth guards"
15337
15607
  },
15608
+ serverSideHooks: {
15609
+ code: "// hooks.server.ts\nimport { createAuthHook, routePatterns } from '@classic-homes/auth/svelte';\nimport { sequence } from '@sveltejs/kit/hooks';\n\nconst authHook = createAuthHook({\n publicRoutes: [routePatterns.auth, routePatterns.health],\n});\n\nexport const handle = sequence(authHook);",
15610
+ description: "Server-side authentication middleware for SvelteKit"
15611
+ },
15612
+ navigationFiltering: {
15613
+ code: "import { filterByAccess } from '@classic-homes/auth/svelte';\n\nconst navItems = [\n { id: 'dashboard', label: 'Dashboard' },\n { id: 'admin', label: 'Admin', roles: ['admin'] },\n];\n\nconst filtered = filterByAccess(navItems, user);",
15614
+ description: "Filter navigation items based on user roles/permissions"
15615
+ },
15616
+ userDisplay: {
15617
+ code: "import { getDisplayName, getUserInitials, getGreeting } from '@classic-homes/auth/core';\n\ngetDisplayName(user); // 'John Doe'\ngetUserInitials(user); // 'JD'\ngetGreeting(user); // 'Good morning, John'",
15618
+ description: "User display utilities for UI"
15619
+ },
15620
+ roleValidation: {
15621
+ code: "import { authService, RoleDeniedError } from '@classic-homes/auth/core';\n\ntry {\n await authService.login(credentials, { allowedRoles: ['admin', 'agent'] });\n} catch (e) {\n if (e instanceof RoleDeniedError) {\n // User authenticated but lacks role\n }\n}",
15622
+ description: "Validate roles during login and handle access denial"
15623
+ },
15338
15624
  testing: {
15339
15625
  code: "import { setupTestAuth, mockUser, assertAuthenticated } from '@classic-homes/auth/testing';\n\nconst ctx = setupTestAuth();\n// Run tests\nctx.cleanup();",
15340
15626
  description: "Set up mocks for testing auth flows"