@jmruthers/pace-core 0.5.115 → 0.5.117

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 (235) hide show
  1. package/dist/{AuthService-CVgsgtaZ.d.ts → AuthService-D4646R4b.d.ts} +9 -4
  2. package/dist/{DataTable-H5KJCAIS.js → DataTable-ZOAKQ3SU.js} +10 -9
  3. package/dist/{UnifiedAuthProvider-KZZUO27W.js → UnifiedAuthProvider-YFN7YGVN.js} +4 -3
  4. package/dist/{api-PKU4PUBO.js → api-TNIBJWLM.js} +3 -3
  5. package/dist/{audit-H4YJJF7R.js → audit-T36HM7IM.js} +2 -2
  6. package/dist/{chunk-SYXOZQ4P.js → chunk-2GJ5GL77.js} +1 -1
  7. package/dist/chunk-2GJ5GL77.js.map +1 -0
  8. package/dist/{chunk-XYRZV7R5.js → chunk-2LM4QQGH.js} +30 -34
  9. package/dist/chunk-2LM4QQGH.js.map +1 -0
  10. package/dist/{chunk-3OGQLOJM.js → chunk-3DBFLLLU.js} +30 -1
  11. package/dist/chunk-3DBFLLLU.js.map +1 -0
  12. package/dist/{chunk-KTHLNIMA.js → chunk-ECOVPXYS.js} +13 -62
  13. package/dist/chunk-ECOVPXYS.js.map +1 -0
  14. package/dist/{chunk-HKWQN44G.js → chunk-IZXS7RZK.js} +15 -15
  15. package/dist/{chunk-OO3V7W4H.js → chunk-KA3PSVNV.js} +87 -40
  16. package/dist/chunk-KA3PSVNV.js.map +1 -0
  17. package/dist/{chunk-L36JW4KV.js → chunk-LFS45U62.js} +2 -2
  18. package/dist/{chunk-BUN7NMV7.js → chunk-O3FTRYEU.js} +2 -2
  19. package/dist/{chunk-F6QB26OS.js → chunk-P3PUOL6B.js} +80 -8
  20. package/dist/chunk-P3PUOL6B.js.map +1 -0
  21. package/dist/{chunk-ZPXWJA4H.js → chunk-PHDAXDHB.js} +131 -5
  22. package/dist/chunk-PHDAXDHB.js.map +1 -0
  23. package/dist/chunk-UJI6WSMD.js +201 -0
  24. package/dist/{chunk-5CDJCTOO.js.map → chunk-UJI6WSMD.js.map} +1 -1
  25. package/dist/{chunk-OUU3SP6I.js → chunk-UKZWNQMB.js} +50 -7
  26. package/dist/{chunk-OUU3SP6I.js.map → chunk-UKZWNQMB.js.map} +1 -1
  27. package/dist/{chunk-7H75SHXZ.js → chunk-VN3OOE35.js} +2 -2
  28. package/dist/{chunk-QKIVSZ2O.js → chunk-WP5I5GLN.js} +2 -2
  29. package/dist/{chunk-NEONKMTU.js → chunk-XN2LYHDI.js} +47 -6
  30. package/dist/chunk-XN2LYHDI.js.map +1 -0
  31. package/dist/components.d.ts +1 -1
  32. package/dist/components.js +12 -11
  33. package/dist/components.js.map +1 -1
  34. package/dist/hooks.d.ts +1 -1
  35. package/dist/hooks.js +10 -9
  36. package/dist/hooks.js.map +1 -1
  37. package/dist/index.d.ts +4 -4
  38. package/dist/index.js +19 -16
  39. package/dist/index.js.map +1 -1
  40. package/dist/providers.d.ts +2 -2
  41. package/dist/providers.js +3 -2
  42. package/dist/rbac/index.d.ts +82 -1
  43. package/dist/rbac/index.js +13 -10
  44. package/dist/{useToast-DVT4dMtf.d.ts → useToast-Cs_g32bg.d.ts} +1 -1
  45. package/dist/utils.js +6 -4
  46. package/dist/utils.js.map +1 -1
  47. package/dist/validation.js +3 -1
  48. package/dist/validation.js.map +1 -1
  49. package/docs/README.md +4 -0
  50. package/docs/api/classes/ColumnFactory.md +1 -1
  51. package/docs/api/classes/ErrorBoundary.md +1 -1
  52. package/docs/api/classes/InvalidScopeError.md +1 -1
  53. package/docs/api/classes/MissingUserContextError.md +1 -1
  54. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  55. package/docs/api/classes/PermissionDeniedError.md +1 -1
  56. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  57. package/docs/api/classes/RBACAuditManager.md +35 -12
  58. package/docs/api/classes/RBACCache.md +1 -1
  59. package/docs/api/classes/RBACEngine.md +1 -1
  60. package/docs/api/classes/RBACError.md +1 -1
  61. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  62. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  63. package/docs/api/classes/StorageUtils.md +1 -1
  64. package/docs/api/enums/FileCategory.md +1 -1
  65. package/docs/api/interfaces/AggregateConfig.md +1 -1
  66. package/docs/api/interfaces/ButtonProps.md +1 -1
  67. package/docs/api/interfaces/CardProps.md +1 -1
  68. package/docs/api/interfaces/ColorPalette.md +1 -1
  69. package/docs/api/interfaces/ColorShade.md +1 -1
  70. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  71. package/docs/api/interfaces/DataRecord.md +1 -1
  72. package/docs/api/interfaces/DataTableAction.md +1 -1
  73. package/docs/api/interfaces/DataTableColumn.md +1 -1
  74. package/docs/api/interfaces/DataTableProps.md +1 -1
  75. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  76. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  77. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  78. package/docs/api/interfaces/EventAppRoleData.md +71 -0
  79. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  80. package/docs/api/interfaces/FileMetadata.md +1 -1
  81. package/docs/api/interfaces/FileReference.md +1 -1
  82. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  83. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  84. package/docs/api/interfaces/FileUploadProps.md +1 -1
  85. package/docs/api/interfaces/FooterProps.md +1 -1
  86. package/docs/api/interfaces/GrantEventAppRoleParams.md +122 -0
  87. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  88. package/docs/api/interfaces/InputProps.md +1 -1
  89. package/docs/api/interfaces/LabelProps.md +1 -1
  90. package/docs/api/interfaces/LoginFormProps.md +1 -1
  91. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  92. package/docs/api/interfaces/NavigationContextType.md +1 -1
  93. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  94. package/docs/api/interfaces/NavigationItem.md +1 -1
  95. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  96. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  97. package/docs/api/interfaces/Organisation.md +1 -1
  98. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  99. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  100. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  101. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  102. package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
  103. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  104. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  105. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  106. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  107. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  108. package/docs/api/interfaces/PaletteData.md +1 -1
  109. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  110. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  111. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  112. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  113. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  114. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  115. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  116. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  117. package/docs/api/interfaces/RBACConfig.md +1 -1
  118. package/docs/api/interfaces/RBACLogger.md +1 -1
  119. package/docs/api/interfaces/RevokeEventAppRoleParams.md +100 -0
  120. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  121. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  122. package/docs/api/interfaces/RoleManagementResult.md +52 -0
  123. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  124. package/docs/api/interfaces/RouteConfig.md +1 -1
  125. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  126. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  127. package/docs/api/interfaces/StorageConfig.md +1 -1
  128. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  129. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  130. package/docs/api/interfaces/StorageListOptions.md +1 -1
  131. package/docs/api/interfaces/StorageListResult.md +1 -1
  132. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  133. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  134. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  135. package/docs/api/interfaces/StyleImport.md +1 -1
  136. package/docs/api/interfaces/SwitchProps.md +1 -1
  137. package/docs/api/interfaces/ToastActionElement.md +1 -1
  138. package/docs/api/interfaces/ToastProps.md +1 -1
  139. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  140. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  141. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  142. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  143. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  144. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  145. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  146. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  147. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  148. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  149. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  150. package/docs/api/interfaces/UserEventAccess.md +1 -1
  151. package/docs/api/interfaces/UserMenuProps.md +1 -1
  152. package/docs/api/interfaces/UserProfile.md +1 -1
  153. package/docs/api/modules.md +41 -14
  154. package/docs/architecture/rpc-function-standards.md +193 -0
  155. package/package.json +1 -1
  156. package/src/__tests__/TEST_STANDARD.md +244 -2
  157. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +46 -16
  158. package/src/components/DataTable/__tests__/keyboard.test.tsx +276 -217
  159. package/src/components/DataTable/components/DataTableCore.tsx +29 -2
  160. package/src/components/DataTable/components/DataTableToolbar.tsx +3 -2
  161. package/src/components/DataTable/components/EditableRow.tsx +18 -1
  162. package/src/components/DataTable/components/ViewRowModal.tsx +1 -1
  163. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +735 -0
  164. package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +572 -0
  165. package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +708 -0
  166. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +451 -0
  167. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +456 -0
  168. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +454 -0
  169. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +462 -0
  170. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +423 -0
  171. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +393 -0
  172. package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +617 -0
  173. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +734 -0
  174. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +412 -0
  175. package/src/components/DataTable/hooks/useTableHandlers.ts +4 -0
  176. package/src/components/EventSelector/EventSelector.tsx +5 -25
  177. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +12 -7
  178. package/src/components/PaceAppLayout/PaceAppLayout.tsx +4 -0
  179. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +7 -2
  180. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +13 -8
  181. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +109 -100
  182. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +18 -13
  183. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +17 -12
  184. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +2 -0
  185. package/src/components/PaceLoginPage/PaceLoginPage.tsx +11 -1
  186. package/src/components/PasswordReset/PasswordChangeForm.test.tsx +2 -2
  187. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +648 -0
  188. package/src/components/ProtectedRoute/ProtectedRoute.tsx +10 -7
  189. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +4 -12
  190. package/src/components/Select/Select.tsx +8 -0
  191. package/src/components/Toast/Toast.tsx +1 -1
  192. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +367 -3
  193. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +916 -0
  194. package/src/hooks/useEventTheme.ts +49 -18
  195. package/src/hooks/usePermissionCache.ts +5 -3
  196. package/src/hooks/useSecureDataAccess.ts +56 -3
  197. package/src/hooks/useToast.ts +1 -1
  198. package/src/providers/services/EventServiceProvider.tsx +15 -8
  199. package/src/rbac/__tests__/cache-invalidation.test.ts +385 -0
  200. package/src/rbac/audit.test.ts +206 -0
  201. package/src/rbac/audit.ts +37 -2
  202. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +26 -23
  203. package/src/rbac/errors.test.ts +340 -0
  204. package/src/rbac/hooks/index.ts +9 -0
  205. package/src/rbac/hooks/useResolvedScope.test.ts +1063 -0
  206. package/src/rbac/hooks/useRoleManagement.test.ts +908 -0
  207. package/src/rbac/hooks/useRoleManagement.ts +255 -0
  208. package/src/services/AuthService.ts +10 -0
  209. package/src/services/EventService.ts +111 -50
  210. package/src/services/__tests__/AuthService.test.ts +1 -1
  211. package/src/services/__tests__/EventService.test.ts +60 -45
  212. package/src/services/interfaces/IEventService.ts +1 -1
  213. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +320 -0
  214. package/src/utils/__tests__/logger.unit.test.ts +398 -0
  215. package/src/utils/__tests__/validation.unit.test.ts +225 -1
  216. package/src/utils/file-reference.test.ts +214 -0
  217. package/dist/chunk-3OGQLOJM.js.map +0 -1
  218. package/dist/chunk-5CDJCTOO.js +0 -190
  219. package/dist/chunk-F6QB26OS.js.map +0 -1
  220. package/dist/chunk-KTHLNIMA.js.map +0 -1
  221. package/dist/chunk-NEONKMTU.js.map +0 -1
  222. package/dist/chunk-OO3V7W4H.js.map +0 -1
  223. package/dist/chunk-SYXOZQ4P.js.map +0 -1
  224. package/dist/chunk-XYRZV7R5.js.map +0 -1
  225. package/dist/chunk-ZPXWJA4H.js.map +0 -1
  226. package/src/rbac/audit-enhanced.ts +0 -351
  227. /package/dist/{DataTable-H5KJCAIS.js.map → DataTable-ZOAKQ3SU.js.map} +0 -0
  228. /package/dist/{UnifiedAuthProvider-KZZUO27W.js.map → UnifiedAuthProvider-YFN7YGVN.js.map} +0 -0
  229. /package/dist/{api-PKU4PUBO.js.map → api-TNIBJWLM.js.map} +0 -0
  230. /package/dist/{audit-H4YJJF7R.js.map → audit-T36HM7IM.js.map} +0 -0
  231. /package/dist/{chunk-HKWQN44G.js.map → chunk-IZXS7RZK.js.map} +0 -0
  232. /package/dist/{chunk-L36JW4KV.js.map → chunk-LFS45U62.js.map} +0 -0
  233. /package/dist/{chunk-BUN7NMV7.js.map → chunk-O3FTRYEU.js.map} +0 -0
  234. /package/dist/{chunk-7H75SHXZ.js.map → chunk-VN3OOE35.js.map} +0 -0
  235. /package/dist/{chunk-QKIVSZ2O.js.map → chunk-WP5I5GLN.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/validation/sanitization.ts","../src/validation/csrf.ts","../src/validation/sqlInjectionProtection.ts","../src/validation/passwordSchema.ts"],"sourcesContent":["\n/**\n * @file Input sanitization and validation schemas\n * @description Enhanced validation schemas with security features\n */\n\nimport { z } from 'zod';\n\n/**\n * Enhanced email schema with security checks\n */\nexport const secureEmailSchema = z\n .string()\n .min(1, 'Email is required')\n .email('Invalid email format')\n .max(254, 'Email too long')\n .refine(\n (email) => {\n if (!email || typeof email !== 'string') return false;\n // Basic domain validation\n const domain = email.split('@')[1];\n return domain && domain.includes('.') && domain.length > 3;\n },\n 'Invalid email domain'\n )\n .transform((email) => sanitizeEmail(email));\n\n/**\n * Basic email schema for common use\n */\nexport const emailSchema = z\n .string()\n .min(1, 'Email is required')\n .email('Invalid email format');\n\n/**\n * Name validation schema\n */\nexport const nameSchema = z\n .string()\n .min(1, 'Name is required')\n .max(100, 'Name too long')\n .regex(/^[a-zA-Z\\s'-]+$/, 'Name contains invalid characters');\n\n/**\n * Phone validation schema\n */\nexport const phoneSchema = z\n .string()\n .regex(/^[\\+]?[1-9][\\d]{0,15}$/, 'Invalid phone number format');\n\n/**\n * URL validation schema\n */\nexport const urlSchema = z\n .string()\n .url('Invalid URL format');\n\n/**\n * Date validation schema\n */\nexport const dateSchema = z\n .string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Invalid date format (YYYY-MM-DD)');\n\n/**\n * Secure login schema\n */\nexport const secureLoginSchema = z.object({\n email: secureEmailSchema,\n password: z.string().min(1, 'Password is required'),\n});\n\n/**\n * Sanitize email input\n */\nexport function sanitizeEmail(email: string): string {\n if (!email || typeof email !== 'string') {\n return '';\n }\n return email.toLowerCase().trim();\n}\n\n/**\n * Sanitize string input\n */\nexport function sanitizeString(input: string): string {\n if (!input || typeof input !== 'string') {\n return '';\n }\n return input\n .replace(/[<>]/g, '') // Remove angle brackets\n .replace(/javascript:/gi, '') // Remove javascript: protocol\n .replace(/on\\w+=/gi, '') // Remove event handlers\n .trim();\n}\n","/**\n * @file CSRF Protection Implementation\n * @description Session-based CSRF token management with security enhancements\n */\n\nimport { secureStorage } from '../utils/secureStorage';\n\nexport interface CSRFTokenData {\n token: string;\n sessionId: string;\n timestamp: number;\n used: boolean;\n}\n\nclass CSRFManager {\n private tokenCache = new Map<string, CSRFTokenData>();\n private readonly TOKEN_EXPIRY = 30 * 60 * 1000; // 30 minutes\n private readonly MAX_TOKENS_PER_SESSION = 10;\n\n /**\n * Generate a new CSRF token for the current session\n */\n async generateToken(sessionId: string): Promise<string> {\n try {\n // Clean up expired tokens\n await this.cleanupExpiredTokens();\n\n // Limit tokens per session\n const sessionTokens = Array.from(this.tokenCache.values())\n .filter(data => data.sessionId === sessionId && !data.used);\n \n if (sessionTokens.length >= this.MAX_TOKENS_PER_SESSION) {\n // Remove oldest token\n const oldest = sessionTokens.sort((a, b) => a.timestamp - b.timestamp)[0];\n this.tokenCache.delete(oldest.token);\n }\n\n // Generate cryptographically secure token\n const tokenBytes = new Uint8Array(32);\n crypto.getRandomValues(tokenBytes);\n const token = Array.from(tokenBytes, byte => \n byte.toString(16).padStart(2, '0')\n ).join('');\n\n const tokenData: CSRFTokenData = {\n token,\n sessionId,\n timestamp: Date.now(),\n used: false,\n };\n\n // Store in memory and secure storage\n this.tokenCache.set(token, tokenData);\n await this.persistTokens();\n\n return token;\n } catch (error) {\n throw new Error('CSRF token generation failed');\n }\n }\n\n /**\n * Validate and consume a CSRF token\n */\n async validateToken(token: string, sessionId: string): Promise<boolean> {\n try {\n // Load tokens from storage if cache is empty\n if (this.tokenCache.size === 0) {\n await this.loadTokens();\n }\n\n const tokenData = this.tokenCache.get(token);\n \n if (!tokenData) {\n return false;\n }\n\n // Check if token belongs to the session\n if (tokenData.sessionId !== sessionId) {\n return false;\n }\n\n // Check if token is already used\n if (tokenData.used) {\n return false;\n }\n\n // Check if token is expired\n if (Date.now() - tokenData.timestamp > this.TOKEN_EXPIRY) {\n this.tokenCache.delete(token);\n await this.persistTokens();\n return false;\n }\n\n // Mark token as used (one-time use)\n tokenData.used = true;\n this.tokenCache.set(token, tokenData);\n await this.persistTokens();\n\n return true;\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Get current valid token for session\n */\n async getCurrentToken(sessionId: string): Promise<string | null> {\n // Load tokens from storage if needed\n if (this.tokenCache.size === 0) {\n await this.loadTokens();\n }\n\n // Find valid unused token for session\n for (const [token, data] of this.tokenCache.entries()) {\n if (\n data.sessionId === sessionId &&\n !data.used &&\n (Date.now() - data.timestamp) < this.TOKEN_EXPIRY\n ) {\n return token;\n }\n }\n\n // Generate new token if none found\n return await this.generateToken(sessionId);\n }\n\n /**\n * Clean up expired and used tokens\n */\n private async cleanupExpiredTokens(): Promise<void> {\n const now = Date.now();\n const expiredTokens: string[] = [];\n\n for (const [token, data] of this.tokenCache.entries()) {\n if (data.used || (now - data.timestamp) > this.TOKEN_EXPIRY) {\n expiredTokens.push(token);\n }\n }\n\n expiredTokens.forEach(token => this.tokenCache.delete(token));\n \n if (expiredTokens.length > 0) {\n await this.persistTokens();\n }\n }\n\n /**\n * Persist tokens to secure storage\n */\n private async persistTokens(): Promise<void> {\n try {\n const tokensArray = Array.from(this.tokenCache.entries());\n await secureStorage.setItem(\n 'csrf_tokens',\n JSON.stringify(tokensArray),\n { encrypt: true, expiry: this.TOKEN_EXPIRY }\n );\n } catch (error) {\n // Silent fail - tokens will be regenerated if needed\n }\n }\n\n /**\n * Load tokens from secure storage\n */\n private async loadTokens(): Promise<void> {\n try {\n const tokensData = await secureStorage.getItem('csrf_tokens');\n if (tokensData) {\n const tokensArray = JSON.parse(tokensData);\n this.tokenCache = new Map(tokensArray);\n // Clean up on load\n await this.cleanupExpiredTokens();\n }\n } catch (error) {\n this.tokenCache.clear();\n }\n }\n\n /**\n * Clear all tokens for session\n */\n async clearSession(sessionId: string): Promise<void> {\n const tokensToRemove: string[] = [];\n \n for (const [token, data] of this.tokenCache.entries()) {\n if (data.sessionId === sessionId) {\n tokensToRemove.push(token);\n }\n }\n \n tokensToRemove.forEach(token => this.tokenCache.delete(token));\n await this.persistTokens();\n }\n}\n\n// Export singleton instance\nexport const csrfManager = new CSRFManager();\n\n// Convenience functions\nexport async function generateCSRFToken(sessionId: string): Promise<string> {\n return csrfManager.generateToken(sessionId);\n}\n\nexport async function validateCSRFToken(token: string, sessionId: string): Promise<boolean> {\n return csrfManager.validateToken(token, sessionId);\n}\n\nexport async function getCSRFToken(sessionId: string): Promise<string | null> {\n return csrfManager.getCurrentToken(sessionId);\n}\n","\n/**\n * @file SQL Injection Protection\n * @description Utilities to prevent SQL injection attacks in dynamic queries\n */\n\nimport { z } from 'zod';\n\n// Common SQL injection patterns\nconst SQL_INJECTION_PATTERNS = [\n /(\\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|EXECUTE|UNION|SCRIPT|JAVASCRIPT)\\b)/i,\n /(\\'|(\\\\\\')|(\\'\\')|(\\\"|(\\\\\\\")|(\\\\\")))|(\\\\x)|(\\\\u)/i,\n /((%27)|(')|(%6F)|o|(%4F)|(%72)|r|(%52))/i, // '|%27|' OR\n /((%27)|(')|(%55)|u|(%55)|(%4E)|n|(%4E)|(%49)|i|(%49)|(%4F)|o|(%4F)|(%4E)|n|(%4E))/i, // '|%27|' UNION\n /((%3D)|(=))[^\\n]*((%27)|(')|((\\\\x27))|((\\\\x2D))|((\\\\x23)))/i,\n /(w*((%27)|(')|(%6F)|o|(%4F)|(%72)|r|(%52)))/i,\n /((%27)|(')|(''))+union/i,\n /exec(\\+|\\s)+(s|x)p\\w+/i,\n /\\b(and|or)\\b.+?(=|<|>|\\bin\\b|\\blike\\b)/i,\n /\\bunion\\b.+?\\bselect\\b/i,\n /\\bdrop\\b.+?\\btable\\b/i,\n /\\binsert\\b.+?\\binto\\b/i,\n /\\bdelete\\b.+?\\bfrom\\b/i,\n /\\bupdate\\b.+?\\bset\\b/i,\n /(;|(\\\\x3B)).+?(drop|create|alter|exec|execute|insert|update|delete)/i,\n /(%3B|;).+?(%44|%64|d)(%52|%72|r)(%4F|%6F|o)(%50|%70|p)/i\n];\n\n// Characters that should be escaped or removed\nconst DANGEROUS_CHARS = /[';\\\"\\\\%]/g;\n\n/**\n * Schema for validating and sanitizing search queries\n */\nexport const searchQuerySchema = z\n .string()\n .max(500, 'Search query too long')\n .refine(\n (query) => {\n return !SQL_INJECTION_PATTERNS.some(pattern => pattern.test(query));\n },\n 'Invalid characters detected in search query'\n )\n .transform((query) => sanitizeSearchQuery(query));\n\n/**\n * Schema for validating table/column names\n */\nexport const sqlIdentifierSchema = z\n .string()\n .min(1, 'Identifier cannot be empty')\n .max(63, 'Identifier too long') // PostgreSQL limit\n .regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, 'Invalid identifier format')\n .refine(\n (identifier) => {\n const reservedWords = [\n 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'CREATE', 'ALTER',\n 'FROM', 'WHERE', 'JOIN', 'UNION', 'ORDER', 'GROUP', 'HAVING'\n ];\n return !reservedWords.includes(identifier.toUpperCase());\n },\n 'Identifier cannot be a reserved SQL keyword'\n );\n\n/**\n * Schema for validating order by clauses\n */\nexport const orderBySchema = z\n .string()\n .regex(/^[a-zA-Z_][a-zA-Z0-9_]*(\\s+(ASC|DESC|asc|desc))?$/, 'Invalid order by format');\n\n/**\n * Schema for validating limit/offset values\n */\nexport const limitOffsetSchema = z\n .number()\n .int('Must be an integer')\n .min(0, 'Must be non-negative')\n .max(1000, 'Limit too large'); // Reasonable maximum\n\n/**\n * Sanitize search query by removing dangerous characters\n */\nexport function sanitizeSearchQuery(query: string): string {\n return query\n .replace(DANGEROUS_CHARS, '') // Remove dangerous characters\n .replace(/\\s+/g, ' ') // Normalize whitespace\n .trim()\n .slice(0, 500); // Enforce length limit\n}\n\n/**\n * Escape special characters for LIKE queries\n */\nexport function escapeLikeQuery(query: string): string {\n return query\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n .replace(/%/g, '\\\\%') // Escape percent signs\n .replace(/_/g, '\\\\_'); // Escape underscores\n}\n\n/**\n * Validate and sanitize a dynamic filter object\n */\nexport function sanitizeFilters(filters: Record<string, unknown>): Record<string, unknown> {\n const sanitized: Record<string, unknown> = {};\n \n for (const [key, value] of Object.entries(filters)) {\n // Validate the key (column name)\n const keyValidation = sqlIdentifierSchema.safeParse(key);\n if (!keyValidation.success) {\n // Log warning for invalid filter keys\n console.warn(`[SECURITY] Invalid filter key detected and removed: ${key}`);\n continue;\n }\n \n // Sanitize the value based on type\n if (typeof value === 'string') {\n const valueValidation = searchQuerySchema.safeParse(value);\n if (valueValidation.success) {\n sanitized[key] = valueValidation.data;\n }\n } else if (typeof value === 'number') {\n if (Number.isFinite(value)) {\n sanitized[key] = value;\n }\n } else if (typeof value === 'boolean') {\n sanitized[key] = value;\n } else if (Array.isArray(value)) {\n // For IN queries, validate each item\n const sanitizedArray = value\n .filter(item => typeof item === 'string' || typeof item === 'number')\n .map(item => typeof item === 'string' ? sanitizeSearchQuery(item) : item)\n .slice(0, 100); // Limit array size\n \n if (sanitizedArray.length > 0) {\n sanitized[key] = sanitizedArray;\n }\n }\n }\n \n return sanitized;\n}\n\n/**\n * Build safe query parameters for Supabase\n */\nexport interface SafeQueryParams {\n select?: string;\n filters?: Record<string, unknown>;\n orderBy?: string;\n limit?: number;\n offset?: number;\n search?: string;\n}\n\nexport function buildSafeQueryParams(params: SafeQueryParams): SafeQueryParams {\n const safe: SafeQueryParams = {};\n \n // Validate select clause\n if (params.select) {\n const selectFields = params.select.split(',').map(field => field.trim());\n const validFields = selectFields.filter(field => {\n return sqlIdentifierSchema.safeParse(field).success;\n });\n \n if (validFields.length > 0) {\n safe.select = validFields.join(', ');\n }\n }\n \n // Sanitize filters\n if (params.filters) {\n safe.filters = sanitizeFilters(params.filters);\n }\n \n // Validate order by\n if (params.orderBy) {\n const orderByValidation = orderBySchema.safeParse(params.orderBy);\n if (orderByValidation.success) {\n safe.orderBy = orderByValidation.data;\n }\n }\n \n // Validate limit and offset\n if (params.limit !== undefined) {\n const limitValidation = limitOffsetSchema.safeParse(params.limit);\n if (limitValidation.success) {\n safe.limit = limitValidation.data;\n }\n }\n \n if (params.offset !== undefined) {\n const offsetValidation = limitOffsetSchema.safeParse(params.offset);\n if (offsetValidation.success) {\n safe.offset = offsetValidation.data;\n }\n }\n \n // Sanitize search query\n if (params.search) {\n const searchValidation = searchQuerySchema.safeParse(params.search);\n if (searchValidation.success) {\n safe.search = searchValidation.data;\n }\n }\n \n return safe;\n}\n\n/**\n * Detect potential SQL injection attempts\n */\nexport function detectSQLInjection(input: string): {\n isSuspicious: boolean;\n patterns: string[];\n riskLevel: 'low' | 'medium' | 'high' | 'critical';\n} {\n const detectedPatterns: string[] = [];\n let maxRisk: 'low' | 'medium' | 'high' | 'critical' = 'low';\n \n SQL_INJECTION_PATTERNS.forEach((pattern, index) => {\n if (pattern.test(input)) {\n detectedPatterns.push(`Pattern ${index + 1}`);\n \n // Assign risk levels based on pattern severity\n if (index < 3) { // Most dangerous patterns first\n maxRisk = 'critical';\n } else if (index < 7 && maxRisk !== 'critical') {\n maxRisk = 'high';\n } else if (index < 12 && !['critical', 'high'].includes(maxRisk)) {\n maxRisk = 'medium';\n }\n }\n });\n \n return {\n isSuspicious: detectedPatterns.length > 0,\n patterns: detectedPatterns,\n riskLevel: maxRisk\n };\n}\n","\n/**\n * @file Enhanced Password Schema with Security Validations\n * @description Comprehensive password validation with security checks\n */\n\nimport { z } from 'zod';\n\n// Common weak passwords to check against\nconst COMMON_PASSWORDS = new Set([\n 'password', '123456', '123456789', 'qwerty', 'abc123', 'password123',\n 'admin', 'letmein', 'welcome', 'monkey', '1234567890', 'password1'\n]);\n\n// Common password patterns to avoid\nconst WEAK_PATTERNS = [\n /^(.)\\1+$/, // All same character\n /^(012|123|234|345|456|567|678|789|890|987|876|765|654|543|432|321|210)+/, // Sequential numbers\n /^(abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz)+/i, // Sequential letters\n];\n\n/**\n * Enhanced password validation schema with security checks\n */\nexport const securePasswordSchema = z\n .string()\n .min(8, 'Password must be at least 8 characters long')\n .max(128, 'Password must not exceed 128 characters')\n .refine(\n (password) => /[a-z]/.test(password),\n 'Password must contain at least one lowercase letter'\n )\n .refine(\n (password) => /[A-Z]/.test(password),\n 'Password must contain at least one uppercase letter'\n )\n .refine(\n (password) => /\\d/.test(password),\n 'Password must contain at least one number'\n )\n .refine(\n (password) => /[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]/.test(password),\n 'Password must contain at least one special character'\n )\n .refine(\n (password) => !COMMON_PASSWORDS.has(password.toLowerCase()),\n 'Password is too common. Please choose a stronger password'\n )\n .refine(\n (password) => !WEAK_PATTERNS.some(pattern => pattern.test(password)),\n 'Password contains weak patterns. Please choose a more complex password'\n )\n .refine(\n (password) => {\n // Check for keyboard patterns (qwerty, asdf, etc.)\n const keyboardPatterns = ['qwerty', 'asdfgh', 'zxcvbn', '1234567890'];\n return !keyboardPatterns.some(pattern => \n password.toLowerCase().includes(pattern)\n );\n },\n 'Password contains keyboard patterns. Please choose a more secure password'\n );\n\n/**\n * Basic password schema for less strict requirements\n */\nexport const passwordSchema = z\n .string()\n .min(6, 'Password must be at least 6 characters long')\n .max(128, 'Password must not exceed 128 characters');\n\n/**\n * Password strength calculator\n */\nexport function calculatePasswordStrength(password: string): {\n score: number;\n feedback: string[];\n level: 'very-weak' | 'weak' | 'fair' | 'good' | 'strong';\n} {\n let score = 0;\n const feedback: string[] = [];\n\n // Length check\n if (password.length >= 8) score += 20;\n else if (password.length >= 6) score += 10;\n else feedback.push('Use at least 8 characters');\n\n // Character variety\n if (/[a-z]/.test(password)) score += 15;\n else feedback.push('Add lowercase letters');\n\n if (/[A-Z]/.test(password)) score += 15;\n else feedback.push('Add uppercase letters');\n\n if (/\\d/.test(password)) score += 15;\n else feedback.push('Add numbers');\n\n if (/[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]/.test(password)) score += 15;\n else feedback.push('Add special characters');\n\n // Additional complexity\n if (password.length >= 12) score += 10;\n if (/[^a-zA-Z0-9]/.test(password)) score += 10;\n\n // Penalties\n if (COMMON_PASSWORDS.has(password.toLowerCase())) {\n score -= 30;\n feedback.push('Avoid common passwords');\n }\n\n if (WEAK_PATTERNS.some(pattern => pattern.test(password))) {\n score -= 20;\n feedback.push('Avoid predictable patterns');\n }\n\n // Determine level\n let level: 'very-weak' | 'weak' | 'fair' | 'good' | 'strong';\n if (score < 30) level = 'very-weak';\n else if (score < 50) level = 'weak';\n else if (score < 70) level = 'fair';\n else if (score < 90) level = 'good';\n else level = 'strong';\n\n return { score: Math.max(0, Math.min(100, score)), feedback, level };\n}\n"],"mappings":"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","names":["emailSchema","nameSchema","phoneSchema","urlSchema","dateSchema","secureLoginSchema","z","z","securePasswordSchema","passwordSchema"]}
1
+ {"version":3,"sources":["../src/validation/sanitization.ts","../src/validation/csrf.ts","../src/validation/sqlInjectionProtection.ts","../src/validation/passwordSchema.ts"],"sourcesContent":["\n/**\n * @file Input sanitization and validation schemas\n * @description Enhanced validation schemas with security features\n */\n\nimport { z } from 'zod';\n\n/**\n * Enhanced email schema with security checks\n */\nexport const secureEmailSchema = z\n .string()\n .min(1, 'Email is required')\n .email('Invalid email format')\n .max(254, 'Email too long')\n .refine(\n (email) => {\n if (!email || typeof email !== 'string') return false;\n // Basic domain validation\n const domain = email.split('@')[1];\n return domain && domain.includes('.') && domain.length > 3;\n },\n 'Invalid email domain'\n )\n .transform((email) => sanitizeEmail(email));\n\n/**\n * Basic email schema for common use\n */\nexport const emailSchema = z\n .string()\n .min(1, 'Email is required')\n .email('Invalid email format');\n\n/**\n * Name validation schema\n */\nexport const nameSchema = z\n .string()\n .min(1, 'Name is required')\n .max(100, 'Name too long')\n .regex(/^[a-zA-Z\\s'-]+$/, 'Name contains invalid characters');\n\n/**\n * Phone validation schema\n */\nexport const phoneSchema = z\n .string()\n .regex(/^[\\+]?[1-9][\\d]{0,15}$/, 'Invalid phone number format');\n\n/**\n * URL validation schema\n */\nexport const urlSchema = z\n .string()\n .url('Invalid URL format');\n\n/**\n * Date validation schema\n */\nexport const dateSchema = z\n .string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Invalid date format (YYYY-MM-DD)');\n\n/**\n * Secure login schema\n */\nexport const secureLoginSchema = z.object({\n email: secureEmailSchema,\n password: z.string().min(1, 'Password is required'),\n});\n\n/**\n * Sanitize email input\n */\nexport function sanitizeEmail(email: string): string {\n if (!email || typeof email !== 'string') {\n return '';\n }\n return email.toLowerCase().trim();\n}\n\n/**\n * Sanitize string input\n */\nexport function sanitizeString(input: string): string {\n if (!input || typeof input !== 'string') {\n return '';\n }\n return input\n .replace(/[<>]/g, '') // Remove angle brackets\n .replace(/javascript:/gi, '') // Remove javascript: protocol\n .replace(/on\\w+=/gi, '') // Remove event handlers\n .trim();\n}\n","/**\n * @file CSRF Protection Implementation\n * @description Session-based CSRF token management with security enhancements\n */\n\nimport { secureStorage } from '../utils/secureStorage';\n\nexport interface CSRFTokenData {\n token: string;\n sessionId: string;\n timestamp: number;\n used: boolean;\n}\n\nclass CSRFManager {\n private tokenCache = new Map<string, CSRFTokenData>();\n private readonly TOKEN_EXPIRY = 30 * 60 * 1000; // 30 minutes\n private readonly MAX_TOKENS_PER_SESSION = 10;\n\n /**\n * Generate a new CSRF token for the current session\n */\n async generateToken(sessionId: string): Promise<string> {\n try {\n // Clean up expired tokens\n await this.cleanupExpiredTokens();\n\n // Limit tokens per session\n const sessionTokens = Array.from(this.tokenCache.values())\n .filter(data => data.sessionId === sessionId && !data.used);\n \n if (sessionTokens.length >= this.MAX_TOKENS_PER_SESSION) {\n // Remove oldest token\n const oldest = sessionTokens.sort((a, b) => a.timestamp - b.timestamp)[0];\n this.tokenCache.delete(oldest.token);\n }\n\n // Generate cryptographically secure token\n const tokenBytes = new Uint8Array(32);\n crypto.getRandomValues(tokenBytes);\n const token = Array.from(tokenBytes, byte => \n byte.toString(16).padStart(2, '0')\n ).join('');\n\n const tokenData: CSRFTokenData = {\n token,\n sessionId,\n timestamp: Date.now(),\n used: false,\n };\n\n // Store in memory and secure storage\n this.tokenCache.set(token, tokenData);\n await this.persistTokens();\n\n return token;\n } catch (error) {\n throw new Error('CSRF token generation failed');\n }\n }\n\n /**\n * Validate and consume a CSRF token\n */\n async validateToken(token: string, sessionId: string): Promise<boolean> {\n try {\n // Load tokens from storage if cache is empty\n if (this.tokenCache.size === 0) {\n await this.loadTokens();\n }\n\n const tokenData = this.tokenCache.get(token);\n \n if (!tokenData) {\n return false;\n }\n\n // Check if token belongs to the session\n if (tokenData.sessionId !== sessionId) {\n return false;\n }\n\n // Check if token is already used\n if (tokenData.used) {\n return false;\n }\n\n // Check if token is expired\n if (Date.now() - tokenData.timestamp > this.TOKEN_EXPIRY) {\n this.tokenCache.delete(token);\n await this.persistTokens();\n return false;\n }\n\n // Mark token as used (one-time use)\n tokenData.used = true;\n this.tokenCache.set(token, tokenData);\n await this.persistTokens();\n\n return true;\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Get current valid token for session\n */\n async getCurrentToken(sessionId: string): Promise<string | null> {\n // Load tokens from storage if needed\n if (this.tokenCache.size === 0) {\n await this.loadTokens();\n }\n\n // Find valid unused token for session\n for (const [token, data] of this.tokenCache.entries()) {\n if (\n data.sessionId === sessionId &&\n !data.used &&\n (Date.now() - data.timestamp) < this.TOKEN_EXPIRY\n ) {\n return token;\n }\n }\n\n // Generate new token if none found\n return await this.generateToken(sessionId);\n }\n\n /**\n * Clean up expired and used tokens\n */\n private async cleanupExpiredTokens(): Promise<void> {\n const now = Date.now();\n const expiredTokens: string[] = [];\n\n for (const [token, data] of this.tokenCache.entries()) {\n if (data.used || (now - data.timestamp) > this.TOKEN_EXPIRY) {\n expiredTokens.push(token);\n }\n }\n\n expiredTokens.forEach(token => this.tokenCache.delete(token));\n \n if (expiredTokens.length > 0) {\n await this.persistTokens();\n }\n }\n\n /**\n * Persist tokens to secure storage\n */\n private async persistTokens(): Promise<void> {\n try {\n const tokensArray = Array.from(this.tokenCache.entries());\n await secureStorage.setItem(\n 'csrf_tokens',\n JSON.stringify(tokensArray),\n { encrypt: true, expiry: this.TOKEN_EXPIRY }\n );\n } catch (error) {\n // Silent fail - tokens will be regenerated if needed\n }\n }\n\n /**\n * Load tokens from secure storage\n */\n private async loadTokens(): Promise<void> {\n try {\n const tokensData = await secureStorage.getItem('csrf_tokens');\n if (tokensData) {\n const tokensArray = JSON.parse(tokensData);\n this.tokenCache = new Map(tokensArray);\n // Clean up on load\n await this.cleanupExpiredTokens();\n }\n } catch (error) {\n this.tokenCache.clear();\n }\n }\n\n /**\n * Clear all tokens for session\n */\n async clearSession(sessionId: string): Promise<void> {\n const tokensToRemove: string[] = [];\n \n for (const [token, data] of this.tokenCache.entries()) {\n if (data.sessionId === sessionId) {\n tokensToRemove.push(token);\n }\n }\n \n tokensToRemove.forEach(token => this.tokenCache.delete(token));\n await this.persistTokens();\n }\n}\n\n// Export singleton instance\nexport const csrfManager = new CSRFManager();\n\n// Convenience functions\nexport async function generateCSRFToken(sessionId: string): Promise<string> {\n return csrfManager.generateToken(sessionId);\n}\n\nexport async function validateCSRFToken(token: string, sessionId: string): Promise<boolean> {\n return csrfManager.validateToken(token, sessionId);\n}\n\nexport async function getCSRFToken(sessionId: string): Promise<string | null> {\n return csrfManager.getCurrentToken(sessionId);\n}\n","\n/**\n * @file SQL Injection Protection\n * @description Utilities to prevent SQL injection attacks in dynamic queries\n */\n\nimport { z } from 'zod';\n\n// Common SQL injection patterns\nconst SQL_INJECTION_PATTERNS = [\n /(\\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|EXECUTE|UNION|SCRIPT|JAVASCRIPT)\\b)/i,\n /(\\'|(\\\\\\')|(\\'\\')|(\\\"|(\\\\\\\")|(\\\\\")))|(\\\\x)|(\\\\u)/i,\n /((%27)|(')|(%6F)|o|(%4F)|(%72)|r|(%52))/i, // '|%27|' OR\n /((%27)|(')|(%55)|u|(%55)|(%4E)|n|(%4E)|(%49)|i|(%49)|(%4F)|o|(%4F)|(%4E)|n|(%4E))/i, // '|%27|' UNION\n /((%3D)|(=))[^\\n]*((%27)|(')|((\\\\x27))|((\\\\x2D))|((\\\\x23)))/i,\n /(w*((%27)|(')|(%6F)|o|(%4F)|(%72)|r|(%52)))/i,\n /((%27)|(')|(''))+union/i,\n /exec(\\+|\\s)+(s|x)p\\w+/i,\n /\\b(and|or)\\b.+?(=|<|>|\\bin\\b|\\blike\\b)/i,\n /\\bunion\\b.+?\\bselect\\b/i,\n /\\bdrop\\b.+?\\btable\\b/i,\n /\\binsert\\b.+?\\binto\\b/i,\n /\\bdelete\\b.+?\\bfrom\\b/i,\n /\\bupdate\\b.+?\\bset\\b/i,\n /(;|(\\\\x3B)).+?(drop|create|alter|exec|execute|insert|update|delete)/i,\n /(%3B|;).+?(%44|%64|d)(%52|%72|r)(%4F|%6F|o)(%50|%70|p)/i\n];\n\n// Characters that should be escaped or removed\nconst DANGEROUS_CHARS = /[';\\\"\\\\%]/g;\n\n/**\n * Schema for validating and sanitizing search queries\n */\nexport const searchQuerySchema = z\n .string()\n .max(500, 'Search query too long')\n .refine(\n (query) => {\n return !SQL_INJECTION_PATTERNS.some(pattern => pattern.test(query));\n },\n 'Invalid characters detected in search query'\n )\n .transform((query) => sanitizeSearchQuery(query));\n\n/**\n * Schema for validating table/column names\n */\nexport const sqlIdentifierSchema = z\n .string()\n .min(1, 'Identifier cannot be empty')\n .max(63, 'Identifier too long') // PostgreSQL limit\n .regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, 'Invalid identifier format')\n .refine(\n (identifier) => {\n const reservedWords = [\n 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'CREATE', 'ALTER',\n 'FROM', 'WHERE', 'JOIN', 'UNION', 'ORDER', 'GROUP', 'HAVING'\n ];\n return !reservedWords.includes(identifier.toUpperCase());\n },\n 'Identifier cannot be a reserved SQL keyword'\n );\n\n/**\n * Schema for validating order by clauses\n */\nexport const orderBySchema = z\n .string()\n .regex(/^[a-zA-Z_][a-zA-Z0-9_]*(\\s+(ASC|DESC|asc|desc))?$/, 'Invalid order by format');\n\n/**\n * Schema for validating limit/offset values\n */\nexport const limitOffsetSchema = z\n .number()\n .int('Must be an integer')\n .min(0, 'Must be non-negative')\n .max(1000, 'Limit too large'); // Reasonable maximum\n\n/**\n * Sanitize search query by removing dangerous characters\n */\nexport function sanitizeSearchQuery(query: string): string {\n return query\n .replace(DANGEROUS_CHARS, '') // Remove dangerous characters\n .replace(/\\s+/g, ' ') // Normalize whitespace\n .trim()\n .slice(0, 500); // Enforce length limit\n}\n\n/**\n * Escape special characters for LIKE queries\n */\nexport function escapeLikeQuery(query: string): string {\n return query\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n .replace(/%/g, '\\\\%') // Escape percent signs\n .replace(/_/g, '\\\\_'); // Escape underscores\n}\n\n/**\n * Validate and sanitize a dynamic filter object\n */\nexport function sanitizeFilters(filters: Record<string, unknown>): Record<string, unknown> {\n const sanitized: Record<string, unknown> = {};\n \n for (const [key, value] of Object.entries(filters)) {\n // Validate the key (column name)\n const keyValidation = sqlIdentifierSchema.safeParse(key);\n if (!keyValidation.success) {\n // Log warning for invalid filter keys\n console.warn(`[SECURITY] Invalid filter key detected and removed: ${key}`);\n continue;\n }\n \n // Sanitize the value based on type\n if (typeof value === 'string') {\n const valueValidation = searchQuerySchema.safeParse(value);\n if (valueValidation.success) {\n sanitized[key] = valueValidation.data;\n }\n } else if (typeof value === 'number') {\n if (Number.isFinite(value)) {\n sanitized[key] = value;\n }\n } else if (typeof value === 'boolean') {\n sanitized[key] = value;\n } else if (Array.isArray(value)) {\n // For IN queries, validate each item\n const sanitizedArray = value\n .filter(item => typeof item === 'string' || typeof item === 'number')\n .map(item => typeof item === 'string' ? sanitizeSearchQuery(item) : item)\n .slice(0, 100); // Limit array size\n \n if (sanitizedArray.length > 0) {\n sanitized[key] = sanitizedArray;\n }\n }\n }\n \n return sanitized;\n}\n\n/**\n * Build safe query parameters for Supabase\n */\nexport interface SafeQueryParams {\n select?: string;\n filters?: Record<string, unknown>;\n orderBy?: string;\n limit?: number;\n offset?: number;\n search?: string;\n}\n\nexport function buildSafeQueryParams(params: SafeQueryParams): SafeQueryParams {\n const safe: SafeQueryParams = {};\n \n // Validate select clause\n if (params.select) {\n const selectFields = params.select.split(',').map(field => field.trim());\n const validFields = selectFields.filter(field => {\n return sqlIdentifierSchema.safeParse(field).success;\n });\n \n if (validFields.length > 0) {\n safe.select = validFields.join(', ');\n }\n }\n \n // Sanitize filters\n if (params.filters) {\n safe.filters = sanitizeFilters(params.filters);\n }\n \n // Validate order by\n if (params.orderBy) {\n const orderByValidation = orderBySchema.safeParse(params.orderBy);\n if (orderByValidation.success) {\n safe.orderBy = orderByValidation.data;\n }\n }\n \n // Validate limit and offset\n if (params.limit !== undefined) {\n const limitValidation = limitOffsetSchema.safeParse(params.limit);\n if (limitValidation.success) {\n safe.limit = limitValidation.data;\n }\n }\n \n if (params.offset !== undefined) {\n const offsetValidation = limitOffsetSchema.safeParse(params.offset);\n if (offsetValidation.success) {\n safe.offset = offsetValidation.data;\n }\n }\n \n // Sanitize search query\n if (params.search) {\n const searchValidation = searchQuerySchema.safeParse(params.search);\n if (searchValidation.success) {\n safe.search = searchValidation.data;\n }\n }\n \n return safe;\n}\n\n/**\n * Detect potential SQL injection attempts\n */\nexport function detectSQLInjection(input: string): {\n isSuspicious: boolean;\n patterns: string[];\n riskLevel: 'low' | 'medium' | 'high' | 'critical';\n} {\n const detectedPatterns: string[] = [];\n let maxRisk: 'low' | 'medium' | 'high' | 'critical' = 'low';\n \n SQL_INJECTION_PATTERNS.forEach((pattern, index) => {\n if (pattern.test(input)) {\n detectedPatterns.push(`Pattern ${index + 1}`);\n \n // Assign risk levels based on pattern severity\n if (index < 3) { // Most dangerous patterns first\n maxRisk = 'critical';\n } else if (index < 7 && maxRisk !== 'critical') {\n maxRisk = 'high';\n } else if (index < 12 && !['critical', 'high'].includes(maxRisk)) {\n maxRisk = 'medium';\n }\n }\n });\n \n return {\n isSuspicious: detectedPatterns.length > 0,\n patterns: detectedPatterns,\n riskLevel: maxRisk\n };\n}\n","\n/**\n * @file Enhanced Password Schema with Security Validations\n * @description Comprehensive password validation with security checks\n */\n\nimport { z } from 'zod';\n\n// Common weak passwords to check against\nconst COMMON_PASSWORDS = new Set([\n 'password', '123456', '123456789', 'qwerty', 'abc123', 'password123',\n 'admin', 'letmein', 'welcome', 'monkey', '1234567890', 'password1'\n]);\n\n// Common password patterns to avoid\nconst WEAK_PATTERNS = [\n /^(.)\\1+$/, // All same character\n /^(012|123|234|345|456|567|678|789|890|987|876|765|654|543|432|321|210)+/, // Sequential numbers\n /^(abc|bcd|cde|def|efg|fgh|ghi|hij|ijk|jkl|klm|lmn|mno|nop|opq|pqr|qrs|rst|stu|tuv|uvw|vwx|wxy|xyz)+/i, // Sequential letters\n];\n\n/**\n * Enhanced password validation schema with security checks\n */\nexport const securePasswordSchema = z\n .string()\n .min(8, 'Password must be at least 8 characters long')\n .max(128, 'Password must not exceed 128 characters')\n .refine(\n (password) => /[a-z]/.test(password),\n 'Password must contain at least one lowercase letter'\n )\n .refine(\n (password) => /[A-Z]/.test(password),\n 'Password must contain at least one uppercase letter'\n )\n .refine(\n (password) => /\\d/.test(password),\n 'Password must contain at least one number'\n )\n .refine(\n (password) => /[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]/.test(password),\n 'Password must contain at least one special character'\n )\n .refine(\n (password) => !COMMON_PASSWORDS.has(password.toLowerCase()),\n 'Password is too common. Please choose a stronger password'\n )\n .refine(\n (password) => !WEAK_PATTERNS.some(pattern => pattern.test(password)),\n 'Password contains weak patterns. Please choose a more complex password'\n )\n .refine(\n (password) => {\n // Check for keyboard patterns (qwerty, asdf, etc.)\n const keyboardPatterns = ['qwerty', 'asdfgh', 'zxcvbn', '1234567890'];\n return !keyboardPatterns.some(pattern => \n password.toLowerCase().includes(pattern)\n );\n },\n 'Password contains keyboard patterns. Please choose a more secure password'\n );\n\n/**\n * Basic password schema for less strict requirements\n */\nexport const passwordSchema = z\n .string()\n .min(6, 'Password must be at least 6 characters long')\n .max(128, 'Password must not exceed 128 characters');\n\n/**\n * Password strength calculator\n */\nexport function calculatePasswordStrength(password: string): {\n score: number;\n feedback: string[];\n level: 'very-weak' | 'weak' | 'fair' | 'good' | 'strong';\n} {\n let score = 0;\n const feedback: string[] = [];\n\n // Length check\n if (password.length >= 8) score += 20;\n else if (password.length >= 6) score += 10;\n else feedback.push('Use at least 8 characters');\n\n // Character variety\n if (/[a-z]/.test(password)) score += 15;\n else feedback.push('Add lowercase letters');\n\n if (/[A-Z]/.test(password)) score += 15;\n else feedback.push('Add uppercase letters');\n\n if (/\\d/.test(password)) score += 15;\n else feedback.push('Add numbers');\n\n if (/[!@#$%^&*()_+\\-=\\[\\]{};':\"\\\\|,.<>\\/?]/.test(password)) score += 15;\n else feedback.push('Add special characters');\n\n // Additional complexity\n if (password.length >= 12) score += 10;\n if (/[^a-zA-Z0-9]/.test(password)) score += 10;\n\n // Penalties\n if (COMMON_PASSWORDS.has(password.toLowerCase())) {\n score -= 30;\n feedback.push('Avoid common passwords');\n }\n\n if (WEAK_PATTERNS.some(pattern => pattern.test(password))) {\n score -= 20;\n feedback.push('Avoid predictable patterns');\n }\n\n // Determine level\n let level: 'very-weak' | 'weak' | 'fair' | 'good' | 'strong';\n if (score < 30) level = 'very-weak';\n else if (score < 50) level = 'weak';\n else if (score < 70) level = 'fair';\n else if (score < 90) level = 'good';\n else level = 'strong';\n\n return { score: Math.max(0, Math.min(100, score)), feedback, level };\n}\n"],"mappings":"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","names":["emailSchema","nameSchema","phoneSchema","urlSchema","dateSchema","secureLoginSchema","z","z","securePasswordSchema","passwordSchema"]}
package/docs/README.md CHANGED
@@ -119,6 +119,10 @@ const columns = [
119
119
  data={[{ id: 'evt-1', name: 'Conference', status: 'published' }]}
120
120
  columns={columns}
121
121
  features={{ search: true, pagination: true, sorting: true }}
122
+ rbac={{
123
+ resource: 'events',
124
+ actions: []
125
+ }}
122
126
  />;
123
127
  ```
124
128
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / ColumnFactory
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / ColumnFactory
2
2
 
3
3
  # Class: ColumnFactory\<TData\>
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / ErrorBoundary
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / ErrorBoundary
2
2
 
3
3
  # Class: ErrorBoundary
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / InvalidScopeError
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / InvalidScopeError
2
2
 
3
3
  # Class: InvalidScopeError
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / MissingUserContextError
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / MissingUserContextError
2
2
 
3
3
  # Class: MissingUserContextError
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / OrganisationContextRequiredError
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / OrganisationContextRequiredError
2
2
 
3
3
  # Class: OrganisationContextRequiredError
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / PermissionDeniedError
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / PermissionDeniedError
2
2
 
3
3
  # Class: PermissionDeniedError
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / PublicErrorBoundary
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / PublicErrorBoundary
2
2
 
3
3
  # Class: PublicErrorBoundary
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / RBACAuditManager
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / RBACAuditManager
2
2
 
3
3
  # Class: RBACAuditManager
4
4
 
@@ -16,6 +16,7 @@ Handles emission of structured audit events for all RBAC operations.
16
16
 
17
17
  - [setEnabled](RBACAuditManager.md#setenabled)
18
18
  - [isEnabled](RBACAuditManager.md#isenabled)
19
+ - [setFallbackEnabled](RBACAuditManager.md#setfallbackenabled)
19
20
  - [emitEvent](RBACAuditManager.md#emitevent)
20
21
  - [emitPermissionCheck](RBACAuditManager.md#emitpermissioncheck)
21
22
  - [emitPermissionDenied](RBACAuditManager.md#emitpermissiondenied)
@@ -43,7 +44,7 @@ Handles emission of structured audit events for all RBAC operations.
43
44
 
44
45
  #### Defined in
45
46
 
46
- [packages/core/src/rbac/audit.ts:112](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L112)
47
+ [packages/core/src/rbac/audit.ts:113](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L113)
47
48
 
48
49
  ## Methods
49
50
 
@@ -65,7 +66,7 @@ Enable or disable audit logging
65
66
 
66
67
  #### Defined in
67
68
 
68
- [packages/core/src/rbac/audit.ts:121](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L121)
69
+ [packages/core/src/rbac/audit.ts:122](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L122)
69
70
 
70
71
  ___
71
72
 
@@ -83,7 +84,29 @@ True if audit logging is enabled
83
84
 
84
85
  #### Defined in
85
86
 
86
- [packages/core/src/rbac/audit.ts:130](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L130)
87
+ [packages/core/src/rbac/audit.ts:131](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L131)
88
+
89
+ ___
90
+
91
+ ### setFallbackEnabled
92
+
93
+ ▸ **setFallbackEnabled**(`enabled`): `void`
94
+
95
+ Enable or disable fallback logging (console logging when database fails)
96
+
97
+ #### Parameters
98
+
99
+ | Name | Type | Description |
100
+ | :------ | :------ | :------ |
101
+ | `enabled` | `boolean` | Whether to enable fallback logging |
102
+
103
+ #### Returns
104
+
105
+ `void`
106
+
107
+ #### Defined in
108
+
109
+ [packages/core/src/rbac/audit.ts:140](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L140)
87
110
 
88
111
  ___
89
112
 
@@ -107,7 +130,7 @@ Promise that resolves when event is logged
107
130
 
108
131
  #### Defined in
109
132
 
110
- [packages/core/src/rbac/audit.ts:140](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L140)
133
+ [packages/core/src/rbac/audit.ts:150](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L150)
111
134
 
112
135
  ___
113
136
 
@@ -129,7 +152,7 @@ Emit a permission check audit event
129
152
 
130
153
  #### Defined in
131
154
 
132
- [packages/core/src/rbac/audit.ts:234](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L234)
155
+ [packages/core/src/rbac/audit.ts:269](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L269)
133
156
 
134
157
  ___
135
158
 
@@ -151,7 +174,7 @@ Emit a permission denied audit event
151
174
 
152
175
  #### Defined in
153
176
 
154
- [packages/core/src/rbac/audit.ts:246](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L246)
177
+ [packages/core/src/rbac/audit.ts:281](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L281)
155
178
 
156
179
  ___
157
180
 
@@ -173,7 +196,7 @@ Emit a role granted audit event
173
196
 
174
197
  #### Defined in
175
198
 
176
- [packages/core/src/rbac/audit.ts:258](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L258)
199
+ [packages/core/src/rbac/audit.ts:293](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L293)
177
200
 
178
201
  ___
179
202
 
@@ -195,7 +218,7 @@ Emit a role revoked audit event
195
218
 
196
219
  #### Defined in
197
220
 
198
- [packages/core/src/rbac/audit.ts:270](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L270)
221
+ [packages/core/src/rbac/audit.ts:305](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L305)
199
222
 
200
223
  ___
201
224
 
@@ -217,7 +240,7 @@ Emit an RLS denied audit event
217
240
 
218
241
  #### Defined in
219
242
 
220
- [packages/core/src/rbac/audit.ts:282](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L282)
243
+ [packages/core/src/rbac/audit.ts:317](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L317)
221
244
 
222
245
  ___
223
246
 
@@ -242,7 +265,7 @@ Promise resolving to audit events
242
265
 
243
266
  #### Defined in
244
267
 
245
- [packages/core/src/rbac/audit.ts:296](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L296)
268
+ [packages/core/src/rbac/audit.ts:331](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L331)
246
269
 
247
270
  ___
248
271
 
@@ -267,4 +290,4 @@ Promise resolving to audit events
267
290
 
268
291
  #### Defined in
269
292
 
270
- [packages/core/src/rbac/audit.ts:318](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L318)
293
+ [packages/core/src/rbac/audit.ts:353](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/audit.ts#L353)
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / RBACCache
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / RBACCache
2
2
 
3
3
  # Class: RBACCache
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / RBACEngine
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / RBACEngine
2
2
 
3
3
  # Class: RBACEngine
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / RBACError
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / RBACError
2
2
 
3
3
  # Class: RBACError
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / RBACNotInitializedError
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / RBACNotInitializedError
2
2
 
3
3
  # Class: RBACNotInitializedError
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / SecureSupabaseClient
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / SecureSupabaseClient
2
2
 
3
3
  # Class: SecureSupabaseClient
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / StorageUtils
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / StorageUtils
2
2
 
3
3
  # Class: StorageUtils
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / FileCategory
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / FileCategory
2
2
 
3
3
  # Enumeration: FileCategory
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / AggregateConfig
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / AggregateConfig
2
2
 
3
3
  # Interface: AggregateConfig
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / ButtonProps
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / ButtonProps
2
2
 
3
3
  # Interface: ButtonProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / CardProps
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / CardProps
2
2
 
3
3
  # Interface: CardProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / ColorPalette
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / ColorPalette
2
2
 
3
3
  # Interface: ColorPalette
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / ColorShade
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / ColorShade
2
2
 
3
3
  # Interface: ColorShade
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / DataAccessRecord
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / DataAccessRecord
2
2
 
3
3
  # Interface: DataAccessRecord
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / DataRecord
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / DataRecord
2
2
 
3
3
  # Interface: DataRecord
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / DataTableAction
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / DataTableAction
2
2
 
3
3
  # Interface: DataTableAction\<TData\>
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / DataTableColumn
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / DataTableColumn
2
2
 
3
3
  # Interface: DataTableColumn\<TData\>
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / DataTableProps
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / DataTableProps
2
2
 
3
3
  # Interface: DataTableProps\<TData\>
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / DataTableToolbarButton
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / DataTableToolbarButton
2
2
 
3
3
  # Interface: DataTableToolbarButton
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / EmptyStateConfig
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / EmptyStateConfig
2
2
 
3
3
  # Interface: EmptyStateConfig
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / EnhancedNavigationMenuProps
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / EnhancedNavigationMenuProps
2
2
 
3
3
  # Interface: EnhancedNavigationMenuProps
4
4
 
@@ -0,0 +1,71 @@
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / EventAppRoleData
2
+
3
+ # Interface: EventAppRoleData
4
+
5
+ ## Hierarchy
6
+
7
+ - **`EventAppRoleData`**
8
+
9
+ ↳ [`RevokeEventAppRoleParams`](RevokeEventAppRoleParams.md)
10
+
11
+ ↳ [`GrantEventAppRoleParams`](GrantEventAppRoleParams.md)
12
+
13
+ ## Table of contents
14
+
15
+ ### Properties
16
+
17
+ - [user\_id](EventAppRoleData.md#user_id)
18
+ - [organisation\_id](EventAppRoleData.md#organisation_id)
19
+ - [event\_id](EventAppRoleData.md#event_id)
20
+ - [app\_id](EventAppRoleData.md#app_id)
21
+ - [role](EventAppRoleData.md#role)
22
+
23
+ ## Properties
24
+
25
+ ### user\_id
26
+
27
+ • **user\_id**: `string`
28
+
29
+ #### Defined in
30
+
31
+ [packages/core/src/rbac/hooks/useRoleManagement.ts:44](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/hooks/useRoleManagement.ts#L44)
32
+
33
+ ___
34
+
35
+ ### organisation\_id
36
+
37
+ • **organisation\_id**: `string`
38
+
39
+ #### Defined in
40
+
41
+ [packages/core/src/rbac/hooks/useRoleManagement.ts:45](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/hooks/useRoleManagement.ts#L45)
42
+
43
+ ___
44
+
45
+ ### event\_id
46
+
47
+ • **event\_id**: `string`
48
+
49
+ #### Defined in
50
+
51
+ [packages/core/src/rbac/hooks/useRoleManagement.ts:46](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/hooks/useRoleManagement.ts#L46)
52
+
53
+ ___
54
+
55
+ ### app\_id
56
+
57
+ • **app\_id**: `string`
58
+
59
+ #### Defined in
60
+
61
+ [packages/core/src/rbac/hooks/useRoleManagement.ts:47](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/hooks/useRoleManagement.ts#L47)
62
+
63
+ ___
64
+
65
+ ### role
66
+
67
+ • **role**: ``"viewer"`` \| ``"participant"`` \| ``"planner"`` \| ``"event_admin"``
68
+
69
+ #### Defined in
70
+
71
+ [packages/core/src/rbac/hooks/useRoleManagement.ts:48](https://github.com/jmruthers/pace-core/blob/main/packages/core/src/rbac/hooks/useRoleManagement.ts#L48)
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / FileDisplayProps
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / FileDisplayProps
2
2
 
3
3
  # Interface: FileDisplayProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / FileMetadata
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / FileMetadata
2
2
 
3
3
  # Interface: FileMetadata
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / FileReference
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / FileReference
2
2
 
3
3
  # Interface: FileReference
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / FileSizeLimits
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / FileSizeLimits
2
2
 
3
3
  # Interface: FileSizeLimits
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / FileUploadOptions
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / FileUploadOptions
2
2
 
3
3
  # Interface: FileUploadOptions
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / FileUploadProps
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / FileUploadProps
2
2
 
3
3
  # Interface: FileUploadProps
4
4
 
@@ -1,4 +1,4 @@
1
- [@jmruthers/pace-core - v0.5.115](../README.md) / [Exports](../modules.md) / FooterProps
1
+ [@jmruthers/pace-core - v0.5.117](../README.md) / [Exports](../modules.md) / FooterProps
2
2
 
3
3
  # Interface: FooterProps
4
4