@jmruthers/pace-core 0.5.183 → 0.5.185

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 (307) hide show
  1. package/CHANGELOG.md +38 -0
  2. package/README.md +60 -1
  3. package/core-usage-manifest.json +312 -0
  4. package/dist/{DataTable-QAB34V6K.js → DataTable-IX2NBUTP.js} +6 -6
  5. package/dist/{DataTable-Bz8ffqyA.d.ts → DataTable-Z9NLVJh0.d.ts} +1 -1
  6. package/dist/{index-Bl--n7-T.d.ts → PublicPageProvider-BABf6JCh.d.ts} +21 -10
  7. package/dist/{UnifiedAuthProvider-7F6T4B6K.js → UnifiedAuthProvider-A4BCQRJY.js} +4 -2
  8. package/dist/{UnifiedAuthProvider-F86d7dSi.d.ts → UnifiedAuthProvider-BG0AL5eE.d.ts} +2 -1
  9. package/dist/{api-ROMBCNKU.js → api-BMFCXVQX.js} +2 -2
  10. package/dist/{chunk-RA3JUFMW.js → chunk-445GEP27.js} +154 -4
  11. package/dist/{chunk-RA3JUFMW.js.map → chunk-445GEP27.js.map} +1 -1
  12. package/dist/{chunk-CSOFYHAG.js → chunk-AISXLWGZ.js} +374 -60
  13. package/dist/chunk-AISXLWGZ.js.map +1 -0
  14. package/dist/{chunk-FUEYYMX5.js → chunk-FXFJRTKI.js} +24 -3
  15. package/dist/chunk-FXFJRTKI.js.map +1 -0
  16. package/dist/{chunk-QETLRQI6.js → chunk-HC67NW5K.js} +380 -360
  17. package/dist/chunk-HC67NW5K.js.map +1 -0
  18. package/dist/chunk-HESYZWZW.js +388 -0
  19. package/dist/chunk-HESYZWZW.js.map +1 -0
  20. package/dist/{chunk-QUVSNGIP.js → chunk-HGPQUCBC.js} +34 -9
  21. package/dist/{chunk-QUVSNGIP.js.map → chunk-HGPQUCBC.js.map} +1 -1
  22. package/dist/{chunk-UHNYIBXL.js → chunk-IXSNYUCT.js} +1 -1
  23. package/dist/chunk-IXSNYUCT.js.map +1 -0
  24. package/dist/{chunk-MI7HBHN3.js → chunk-MX3EIJGQ.js} +4 -3
  25. package/dist/{chunk-MI7HBHN3.js.map → chunk-MX3EIJGQ.js.map} +1 -1
  26. package/dist/{chunk-PWAHJW4G.js → chunk-OKI34GZD.js} +86 -33
  27. package/dist/chunk-OKI34GZD.js.map +1 -0
  28. package/dist/{chunk-W22JP75J.js → chunk-STTZQK2I.js} +3 -3
  29. package/dist/chunk-THRPYOFK.js +215 -0
  30. package/dist/chunk-THRPYOFK.js.map +1 -0
  31. package/dist/{chunk-M7W4CP3M.js → chunk-U6WNSFX5.js} +2 -1
  32. package/dist/chunk-U6WNSFX5.js.map +1 -0
  33. package/dist/{chunk-QCDXODCA.js → chunk-XAUHJD3L.js} +2 -2
  34. package/dist/components.d.ts +182 -6
  35. package/dist/components.js +157 -11
  36. package/dist/components.js.map +1 -1
  37. package/dist/eslint-rules/pace-core-compliance.cjs +406 -0
  38. package/dist/{file-reference-D06mEEWW.d.ts → file-reference-BjR39ktt.d.ts} +7 -1
  39. package/dist/hooks.d.ts +7 -14
  40. package/dist/hooks.js +10 -22
  41. package/dist/hooks.js.map +1 -1
  42. package/dist/index.d.ts +11 -11
  43. package/dist/index.js +79 -16
  44. package/dist/index.js.map +1 -1
  45. package/dist/providers.d.ts +1 -1
  46. package/dist/providers.js +3 -1
  47. package/dist/rbac/index.d.ts +205 -14
  48. package/dist/rbac/index.js +28 -6
  49. package/dist/timezone-_pgH8qrY.d.ts +530 -0
  50. package/dist/{types-_x1f4QBF.d.ts → types-DUyCRSTj.d.ts} +1 -1
  51. package/dist/types.d.ts +1 -1
  52. package/dist/types.js +1 -1
  53. package/dist/{usePublicRouteParams-JJczomYq.d.ts → usePublicRouteParams-CvnC3d-e.d.ts} +113 -2
  54. package/dist/utils.d.ts +109 -151
  55. package/dist/utils.js +128 -138
  56. package/dist/utils.js.map +1 -1
  57. package/docs/api/README.md +60 -1
  58. package/docs/api/classes/ColumnFactory.md +1 -1
  59. package/docs/api/classes/ErrorBoundary.md +1 -1
  60. package/docs/api/classes/InvalidScopeError.md +1 -1
  61. package/docs/api/classes/Logger.md +178 -0
  62. package/docs/api/classes/MissingUserContextError.md +1 -1
  63. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  64. package/docs/api/classes/PermissionDeniedError.md +1 -1
  65. package/docs/api/classes/RBACAuditManager.md +2 -2
  66. package/docs/api/classes/RBACCache.md +1 -1
  67. package/docs/api/classes/RBACEngine.md +2 -2
  68. package/docs/api/classes/RBACError.md +1 -1
  69. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  70. package/docs/api/classes/SecureSupabaseClient.md +5 -5
  71. package/docs/api/classes/StorageUtils.md +1 -1
  72. package/docs/api/enums/FileCategory.md +1 -1
  73. package/docs/api/enums/LogLevel.md +54 -0
  74. package/docs/api/enums/RBACErrorCode.md +1 -1
  75. package/docs/api/enums/RPCFunction.md +1 -1
  76. package/docs/api/interfaces/AggregateConfig.md +1 -1
  77. package/docs/api/interfaces/BadgeProps.md +1 -1
  78. package/docs/api/interfaces/ButtonProps.md +1 -1
  79. package/docs/api/interfaces/CalendarProps.md +18 -2
  80. package/docs/api/interfaces/CardProps.md +1 -1
  81. package/docs/api/interfaces/ColorPalette.md +1 -1
  82. package/docs/api/interfaces/ColorShade.md +1 -1
  83. package/docs/api/interfaces/ComplianceResult.md +30 -0
  84. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  85. package/docs/api/interfaces/DataRecord.md +1 -1
  86. package/docs/api/interfaces/DataTableAction.md +1 -1
  87. package/docs/api/interfaces/DataTableColumn.md +1 -1
  88. package/docs/api/interfaces/DataTableProps.md +1 -1
  89. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  90. package/docs/api/interfaces/DatabaseComplianceResult.md +85 -0
  91. package/docs/api/interfaces/DatabaseIssue.md +41 -0
  92. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  93. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  94. package/docs/api/interfaces/EventAppRoleData.md +6 -6
  95. package/docs/api/interfaces/ExportColumn.md +1 -1
  96. package/docs/api/interfaces/ExportOptions.md +1 -1
  97. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  98. package/docs/api/interfaces/FileMetadata.md +1 -1
  99. package/docs/api/interfaces/FileReference.md +1 -1
  100. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  101. package/docs/api/interfaces/FileUploadOptions.md +24 -8
  102. package/docs/api/interfaces/FileUploadProps.md +24 -13
  103. package/docs/api/interfaces/FooterProps.md +1 -1
  104. package/docs/api/interfaces/FormFieldProps.md +1 -1
  105. package/docs/api/interfaces/FormProps.md +1 -1
  106. package/docs/api/interfaces/GrantEventAppRoleParams.md +9 -9
  107. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  108. package/docs/api/interfaces/InputProps.md +1 -1
  109. package/docs/api/interfaces/LabelProps.md +1 -1
  110. package/docs/api/interfaces/LoggerConfig.md +62 -0
  111. package/docs/api/interfaces/LoginFormProps.md +1 -1
  112. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  113. package/docs/api/interfaces/NavigationContextType.md +1 -1
  114. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  115. package/docs/api/interfaces/NavigationItem.md +1 -1
  116. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  117. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  118. package/docs/api/interfaces/Organisation.md +1 -1
  119. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  120. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  121. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  122. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  123. package/docs/api/interfaces/PaceAppLayoutProps.md +36 -23
  124. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  125. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  126. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  127. package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
  128. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  129. package/docs/api/interfaces/PaletteData.md +1 -1
  130. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  131. package/docs/api/interfaces/ProgressProps.md +1 -1
  132. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  133. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  134. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  135. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  136. package/docs/api/interfaces/QuickFix.md +52 -0
  137. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  138. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  139. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  140. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  141. package/docs/api/interfaces/RBACConfig.md +4 -4
  142. package/docs/api/interfaces/RBACContext.md +1 -1
  143. package/docs/api/interfaces/RBACLogger.md +1 -1
  144. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  145. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  146. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  147. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  148. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  149. package/docs/api/interfaces/RBACResult.md +1 -1
  150. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  151. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  152. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  153. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  154. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  155. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  156. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  157. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  158. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  159. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  160. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  161. package/docs/api/interfaces/RevokeEventAppRoleParams.md +7 -7
  162. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  163. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  164. package/docs/api/interfaces/RoleManagementResult.md +5 -5
  165. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  166. package/docs/api/interfaces/RouteConfig.md +1 -1
  167. package/docs/api/interfaces/RuntimeComplianceResult.md +55 -0
  168. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  169. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  170. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  171. package/docs/api/interfaces/SetupIssue.md +41 -0
  172. package/docs/api/interfaces/StorageConfig.md +1 -1
  173. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  174. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  175. package/docs/api/interfaces/StorageListOptions.md +1 -1
  176. package/docs/api/interfaces/StorageListResult.md +1 -1
  177. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  178. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  179. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  180. package/docs/api/interfaces/StyleImport.md +1 -1
  181. package/docs/api/interfaces/SwitchProps.md +1 -1
  182. package/docs/api/interfaces/TabsContentProps.md +1 -1
  183. package/docs/api/interfaces/TabsListProps.md +1 -1
  184. package/docs/api/interfaces/TabsProps.md +1 -1
  185. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  186. package/docs/api/interfaces/TextareaProps.md +1 -1
  187. package/docs/api/interfaces/ToastActionElement.md +1 -1
  188. package/docs/api/interfaces/ToastProps.md +1 -1
  189. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  190. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  191. package/docs/api/interfaces/UseFormDialogOptions.md +62 -0
  192. package/docs/api/interfaces/UseFormDialogReturn.md +117 -0
  193. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  194. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  195. package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
  196. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  197. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  198. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  199. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  200. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  201. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  202. package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
  203. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  204. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  205. package/docs/api/interfaces/UserEventAccess.md +1 -1
  206. package/docs/api/interfaces/UserMenuProps.md +1 -1
  207. package/docs/api/interfaces/UserProfile.md +1 -1
  208. package/docs/api/modules.md +738 -42
  209. package/docs/api-reference/hooks.md +111 -0
  210. package/docs/api-reference/rpc-functions.md +1 -1
  211. package/docs/api-reference/utilities.md +184 -0
  212. package/docs/getting-started/installation-guide.md +75 -16
  213. package/docs/getting-started/quick-start.md +61 -11
  214. package/docs/implementation-guides/authentication.md +88 -12
  215. package/docs/implementation-guides/file-reference-system.md +2 -1
  216. package/docs/implementation-guides/file-upload-storage.md +21 -0
  217. package/docs/rbac/README.md +1 -0
  218. package/docs/rbac/compliance/compliance-guide.md +544 -0
  219. package/docs/rbac/getting-started.md +158 -33
  220. package/docs/standards/pace-core-compliance.md +432 -0
  221. package/eslint-config-pace-core.cjs +93 -0
  222. package/package.json +15 -3
  223. package/scripts/analyze-bundle.js +232 -0
  224. package/scripts/build-css.js +56 -0
  225. package/scripts/build-docs-incremental.js +1015 -0
  226. package/scripts/check-pace-core-compliance.cjs +2353 -0
  227. package/scripts/generate-docs.js +157 -0
  228. package/scripts/setup-build-cache.js +73 -0
  229. package/scripts/utils/command-runner.js +131 -0
  230. package/scripts/utils/env.js +33 -0
  231. package/scripts/utils/index.js +10 -0
  232. package/scripts/utils/logger.js +88 -0
  233. package/scripts/utils/path-helpers.js +37 -0
  234. package/scripts/validate-formats.js +133 -0
  235. package/scripts/validate-master.js +155 -0
  236. package/scripts/validate-pre-publish.js +140 -0
  237. package/scripts/validate-theme.js +142 -0
  238. package/src/components/Calendar/Calendar.tsx +8 -1
  239. package/src/components/Card/Card.tsx +47 -8
  240. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +314 -0
  241. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +126 -0
  242. package/src/components/DatePickerWithTimezone/README.md +135 -0
  243. package/src/components/DatePickerWithTimezone/index.ts +10 -0
  244. package/src/components/DateTimeField/DateTimeField.test.tsx +358 -0
  245. package/src/components/DateTimeField/DateTimeField.tsx +232 -0
  246. package/src/components/DateTimeField/README.md +148 -0
  247. package/src/components/DateTimeField/index.ts +10 -0
  248. package/src/components/FileUpload/FileUpload.tsx +3 -0
  249. package/src/components/Header/Header.test.tsx +47 -18
  250. package/src/components/Header/Header.tsx +24 -6
  251. package/src/components/PaceAppLayout/PaceAppLayout.tsx +29 -20
  252. package/src/components/PaceAppLayout/README.md +9 -0
  253. package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -1
  254. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +37 -8
  255. package/src/components/ProtectedRoute/ProtectedRoute.tsx +12 -4
  256. package/src/components/index.ts +8 -0
  257. package/src/eslint-rules/pace-core-compliance.cjs +406 -0
  258. package/src/eslint-rules/pace-core-compliance.js +640 -0
  259. package/src/hooks/__tests__/useFormDialog.test.ts +478 -0
  260. package/src/hooks/index.ts +2 -0
  261. package/src/hooks/useFileReference.test.ts +1 -0
  262. package/src/hooks/useFormDialog.ts +147 -0
  263. package/src/index.ts +27 -0
  264. package/src/providers/services/OrganisationServiceProvider.tsx +6 -5
  265. package/src/providers/services/UnifiedAuthProvider.tsx +24 -3
  266. package/src/rbac/__tests__/scenarios.user-role.test.tsx +3 -0
  267. package/src/rbac/compliance/database-validator.ts +165 -0
  268. package/src/rbac/compliance/index.ts +38 -0
  269. package/src/rbac/compliance/quick-fix-suggestions.ts +209 -0
  270. package/src/rbac/compliance/runtime-compliance.ts +77 -0
  271. package/src/rbac/compliance/setup-validator.ts +131 -0
  272. package/src/rbac/components/PagePermissionGuard.tsx +8 -64
  273. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +35 -21
  274. package/src/rbac/docs/event-based-apps.md +285 -0
  275. package/src/rbac/errors.ts +11 -0
  276. package/src/rbac/hooks/useRoleManagement.ts +292 -12
  277. package/src/rbac/index.ts +30 -0
  278. package/src/services/OrganisationService.ts +4 -0
  279. package/src/types/file-reference.ts +6 -0
  280. package/src/utils/__tests__/timezone.test.ts +345 -0
  281. package/src/utils/file-reference/__tests__/file-reference.test.ts +2 -0
  282. package/src/utils/file-reference/index.ts +1 -0
  283. package/src/utils/formatting/formatDateTimeTimezone.test.ts +167 -0
  284. package/src/utils/formatting/formatting.ts +179 -0
  285. package/src/utils/index.ts +27 -1
  286. package/src/utils/location/index.ts +16 -0
  287. package/src/utils/location/location.test.ts +286 -0
  288. package/src/utils/location/location.ts +175 -0
  289. package/src/utils/timezone/index.ts +17 -0
  290. package/src/utils/timezone/timezone.test.ts +349 -0
  291. package/src/utils/timezone/timezone.ts +281 -0
  292. package/dist/chunk-CSOFYHAG.js.map +0 -1
  293. package/dist/chunk-FUEYYMX5.js.map +0 -1
  294. package/dist/chunk-HKIT6O7W.js +0 -198
  295. package/dist/chunk-HKIT6O7W.js.map +0 -1
  296. package/dist/chunk-KUEN3HFB.js +0 -94
  297. package/dist/chunk-KUEN3HFB.js.map +0 -1
  298. package/dist/chunk-M7W4CP3M.js.map +0 -1
  299. package/dist/chunk-PWAHJW4G.js.map +0 -1
  300. package/dist/chunk-QETLRQI6.js.map +0 -1
  301. package/dist/chunk-UHNYIBXL.js.map +0 -1
  302. package/dist/formatting-5wETwiGF.d.ts +0 -162
  303. /package/dist/{DataTable-QAB34V6K.js.map → DataTable-IX2NBUTP.js.map} +0 -0
  304. /package/dist/{UnifiedAuthProvider-7F6T4B6K.js.map → UnifiedAuthProvider-A4BCQRJY.js.map} +0 -0
  305. /package/dist/{api-ROMBCNKU.js.map → api-BMFCXVQX.js.map} +0 -0
  306. /package/dist/{chunk-W22JP75J.js.map → chunk-STTZQK2I.js.map} +0 -0
  307. /package/dist/{chunk-QCDXODCA.js.map → chunk-XAUHJD3L.js.map} +0 -0
@@ -8,7 +8,7 @@
8
8
  * Note: RBAC functionality is available via useRBAC() hook from '@jmruthers/pace-core/rbac'
9
9
  */
10
10
 
11
- import React, { createContext, useContext, useMemo, useCallback, useRef, useEffect, useState } from 'react';
11
+ import React, { createContext, useContext, useMemo, useCallback, useRef, useEffect, useState, useReducer } from 'react';
12
12
  import { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';
13
13
  import { AuthServiceProvider } from './AuthServiceProvider';
14
14
  import { OrganisationServiceProvider } from './OrganisationServiceProvider';
@@ -114,7 +114,7 @@ export interface UnifiedAuthContextType {
114
114
  sessionRestorationTimeoutMs: number;
115
115
  }
116
116
 
117
- const UnifiedAuthContext = createContext<UnifiedAuthContextType | undefined>(undefined);
117
+ export const UnifiedAuthContext = createContext<UnifiedAuthContextType | undefined>(undefined);
118
118
 
119
119
  export const useUnifiedAuth = () => {
120
120
  const context = useContext(UnifiedAuthContext);
@@ -179,13 +179,15 @@ function UnifiedAuthContextProvider({
179
179
  eventService = useEventService();
180
180
  } catch (error) {
181
181
  // EventService not available - provide fallback implementation
182
+ // Include subscribe method to match BaseService interface
182
183
  eventService = {
183
184
  getEvents: () => [],
184
185
  getSelectedEvent: () => null,
185
186
  isLoading: () => false,
186
187
  getError: () => null,
187
188
  setSelectedEvent: () => {},
188
- refreshEvents: async () => {}
189
+ refreshEvents: async () => {},
190
+ subscribe: () => () => {} // No-op subscribe/unsubscribe for fallback
189
191
  };
190
192
  }
191
193
 
@@ -256,6 +258,25 @@ function UnifiedAuthContextProvider({
256
258
  }
257
259
  }, [isAuth, currentUser?.id, supabase, appName, appId]);
258
260
 
261
+ // Subscribe to service state changes to trigger re-renders
262
+ // Use useReducer to force updates when services notify
263
+ const [, forceUpdate] = useReducer(x => x + 1, 0);
264
+
265
+ useEffect(() => {
266
+ // Subscribe to all service changes
267
+ const unsubscribeAuth = authService.subscribe(() => forceUpdate());
268
+ const unsubscribeOrg = organisationService.subscribe(() => forceUpdate());
269
+ const unsubscribeEvent = eventService.subscribe(() => forceUpdate());
270
+ const unsubscribeInactivity = inactivityService.subscribe(() => forceUpdate());
271
+
272
+ return () => {
273
+ unsubscribeAuth();
274
+ unsubscribeOrg();
275
+ unsubscribeEvent();
276
+ unsubscribeInactivity();
277
+ };
278
+ }, [authService, organisationService, eventService, inactivityService]);
279
+
259
280
  // Get loading states - these will trigger re-renders when services change
260
281
  const authLoading = authService.isLoading();
261
282
  const orgLoading = organisationService.isLoading();
@@ -30,6 +30,7 @@ vi.mock('../../hooks/services/useAuthService', () => ({
30
30
  resetPassword: vi.fn(),
31
31
  updatePassword: vi.fn(),
32
32
  refreshSession: vi.fn(),
33
+ subscribe: vi.fn(() => () => {}), // Subscribe method that returns unsubscribe function
33
34
  }),
34
35
  }));
35
36
 
@@ -41,6 +42,7 @@ vi.mock('../../hooks/services/useEventService', () => ({
41
42
  getError: vi.fn(() => null),
42
43
  setSelectedEvent: vi.fn(),
43
44
  refreshEvents: vi.fn(),
45
+ subscribe: vi.fn(() => () => {}), // Subscribe method that returns unsubscribe function
44
46
  }),
45
47
  }));
46
48
 
@@ -56,6 +58,7 @@ vi.mock('../../hooks/services/useInactivityService', () => ({
56
58
  startTracking: vi.fn(),
57
59
  stopTracking: vi.fn(),
58
60
  handleIdleLogout: vi.fn(),
61
+ subscribe: vi.fn(() => () => {}), // Subscribe method that returns unsubscribe function
59
62
  }),
60
63
  }));
61
64
 
@@ -0,0 +1,165 @@
1
+ /**
2
+ * Database Configuration Validator
3
+ * @package @jmruthers/pace-core
4
+ * @module RBAC/Compliance/DatabaseValidator
5
+ * @since 1.0.0
6
+ *
7
+ * This module provides utilities to validate database configuration for RBAC.
8
+ */
9
+
10
+ import { SupabaseClient } from '@supabase/supabase-js';
11
+ import { Database } from '../../types/database';
12
+
13
+ export interface DatabaseIssue {
14
+ type: 'app-not-configured' | 'app-name-mismatch' | 'pages-not-configured' | 'permissions-not-configured' | 'rls-not-active' | 'roles-not-configured';
15
+ message: string;
16
+ recommendation: string;
17
+ }
18
+
19
+ export interface DatabaseComplianceResult {
20
+ appConfigured: boolean;
21
+ pagesConfigured: boolean;
22
+ permissionsConfigured: boolean;
23
+ rlsPoliciesActive: boolean;
24
+ rolesConfigured: boolean;
25
+ issues: DatabaseIssue[];
26
+ recommendations: string[];
27
+ }
28
+
29
+ /**
30
+ * Validate database configuration
31
+ *
32
+ * @param supabase - Supabase client
33
+ * @param appName - Application name to validate
34
+ * @returns Database compliance result
35
+ */
36
+ export async function validateDatabaseConfiguration(
37
+ supabase: SupabaseClient<Database>,
38
+ appName: string
39
+ ): Promise<DatabaseComplianceResult> {
40
+ const issues: DatabaseIssue[] = [];
41
+ const recommendations: string[] = [];
42
+
43
+ let appConfigured = false;
44
+ let pagesConfigured = false;
45
+ let permissionsConfigured = false;
46
+ let rlsPoliciesActive = false;
47
+ let rolesConfigured = false;
48
+
49
+ try {
50
+ // Check if app exists in rbac_apps
51
+ const { data: app, error: appError } = await supabase
52
+ .from('rbac_apps')
53
+ .select('id, name')
54
+ .eq('name', appName)
55
+ .single();
56
+
57
+ if (appError || !app) {
58
+ issues.push({
59
+ type: 'app-not-configured',
60
+ message: `App '${appName}' not found in rbac_apps table.`,
61
+ recommendation: `Register your app in the rbac_apps table with name '${appName}' (case-sensitive).`
62
+ });
63
+ } else {
64
+ appConfigured = true;
65
+
66
+ // Check if app name matches exactly
67
+ if (app.name !== appName) {
68
+ issues.push({
69
+ type: 'app-name-mismatch',
70
+ message: `App name mismatch. Database has '${app.name}', but environment variable has '${appName}'.`,
71
+ recommendation: `Ensure VITE_APP_NAME (or NEXT_PUBLIC_APP_NAME) matches the app name in rbac_apps table exactly (case-sensitive).`
72
+ });
73
+ }
74
+
75
+ // Check if pages are configured
76
+ const { data: pages, error: pagesError } = await supabase
77
+ .from('rbac_app_pages')
78
+ .select('id')
79
+ .eq('app_id', app.id)
80
+ .limit(1);
81
+
82
+ if (pagesError || !pages || pages.length === 0) {
83
+ issues.push({
84
+ type: 'pages-not-configured',
85
+ message: `No pages found for app '${appName}' in rbac_app_pages table.`,
86
+ recommendation: 'Register your app pages in the rbac_app_pages table. Each route/page should have an entry.'
87
+ });
88
+ } else {
89
+ pagesConfigured = true;
90
+
91
+ // Check if permissions are configured for pages
92
+ const { data: permissions, error: permissionsError } = await supabase
93
+ .from('rbac_page_permissions')
94
+ .select('id')
95
+ .in('page_id', pages.map(p => p.id))
96
+ .limit(1);
97
+
98
+ if (permissionsError || !permissions || permissions.length === 0) {
99
+ issues.push({
100
+ type: 'permissions-not-configured',
101
+ message: `No permissions found for app '${appName}' pages in rbac_page_permissions table.`,
102
+ recommendation: 'Configure permissions for your app pages in the rbac_page_permissions table. Each page should have permissions for different operations (read, create, update, delete).'
103
+ });
104
+ } else {
105
+ permissionsConfigured = true;
106
+ }
107
+ }
108
+ }
109
+
110
+ // Check if RLS is enabled on RBAC tables (basic check)
111
+ // Note: This is a simplified check - full RLS validation would require more complex queries
112
+ try {
113
+ // Type assertion needed because rbac_check_rls_status may not be in generated types yet
114
+ const { data: rbacTables, error: rlsError } = await (supabase.rpc as any)('rbac_check_rls_status');
115
+
116
+ if (rlsError) {
117
+ // RLS check function might not exist, which is okay
118
+ // We'll assume RLS is active if we can query the tables
119
+ rlsPoliciesActive = true;
120
+ recommendations.push('Consider adding an RLS status check function to validate RLS policies are active.');
121
+ } else {
122
+ rlsPoliciesActive = true;
123
+ }
124
+ } catch (error) {
125
+ // RLS check function might not exist or be available
126
+ // We'll assume RLS is active if we can query the tables
127
+ rlsPoliciesActive = true;
128
+ recommendations.push('Consider adding an RLS status check function to validate RLS policies are active.');
129
+ }
130
+
131
+ // Check if organisation roles exist (sample check)
132
+ const { data: orgRoles, error: rolesError } = await supabase
133
+ .from('rbac_organisation_roles')
134
+ .select('id')
135
+ .limit(1);
136
+
137
+ if (rolesError) {
138
+ issues.push({
139
+ type: 'roles-not-configured',
140
+ message: 'Unable to query rbac_organisation_roles table. RLS might be blocking access or table might not exist.',
141
+ recommendation: 'Ensure rbac_organisation_roles table exists and RLS policies allow read access for authenticated users.'
142
+ });
143
+ } else {
144
+ rolesConfigured = true;
145
+ }
146
+
147
+ } catch (error) {
148
+ issues.push({
149
+ type: 'app-not-configured',
150
+ message: `Error validating database configuration: ${error instanceof Error ? error.message : 'Unknown error'}`,
151
+ recommendation: 'Check your Supabase connection and ensure you have the necessary permissions to query RBAC tables.'
152
+ });
153
+ }
154
+
155
+ return {
156
+ appConfigured,
157
+ pagesConfigured,
158
+ permissionsConfigured,
159
+ rlsPoliciesActive,
160
+ rolesConfigured,
161
+ issues,
162
+ recommendations
163
+ };
164
+ }
165
+
@@ -0,0 +1,38 @@
1
+ /**
2
+ * RBAC Compliance Module
3
+ * @package @jmruthers/pace-core
4
+ * @module RBAC/Compliance
5
+ * @since 1.0.0
6
+ *
7
+ * This module provides compliance checking utilities for RBAC/auth setup.
8
+ */
9
+
10
+ export {
11
+ isRBACInitialized,
12
+ validateRBACSetup,
13
+ getSetupIssues,
14
+ type SetupIssue,
15
+ type ComplianceResult,
16
+ } from './setup-validator';
17
+
18
+ export {
19
+ checkRuntimeCompliance,
20
+ validateAndWarn,
21
+ type RuntimeComplianceResult,
22
+ } from './runtime-compliance';
23
+
24
+ export {
25
+ validateDatabaseConfiguration,
26
+ type DatabaseComplianceResult,
27
+ type DatabaseIssue,
28
+ } from './database-validator';
29
+
30
+ export {
31
+ getQuickFixes,
32
+ getCustomAuthCodeFixes,
33
+ getDuplicateConfigFixes,
34
+ getUnprotectedPageFixes,
35
+ getDirectSupabaseAuthFixes,
36
+ type QuickFix,
37
+ } from './quick-fix-suggestions';
38
+
@@ -0,0 +1,209 @@
1
+ /**
2
+ * Quick Fix Suggestions for RBAC/Auth Compliance
3
+ * @package @jmruthers/pace-core
4
+ * @module RBAC/Compliance/QuickFixSuggestions
5
+ * @since 1.0.0
6
+ *
7
+ * This module provides auto-suggest fixes for common RBAC/auth compliance issues.
8
+ */
9
+
10
+ export interface QuickFix {
11
+ issue: string;
12
+ suggestion: string;
13
+ codeExample?: string;
14
+ migrationSteps?: string[];
15
+ }
16
+
17
+ /**
18
+ * Get quick fix suggestions for custom auth code
19
+ */
20
+ export function getCustomAuthCodeFixes(customCodeName: string, type: 'hook' | 'component' | 'util'): QuickFix {
21
+ const fixes: Record<string, QuickFix> = {
22
+ 'useAuth': {
23
+ issue: `Custom ${type} '${customCodeName}' detected`,
24
+ suggestion: `Replace with useUnifiedAuth from pace-core`,
25
+ codeExample: `// Before
26
+ import { useAuth } from './hooks/useAuth';
27
+
28
+ // After
29
+ import { useUnifiedAuth } from '@jmruthers/pace-core';`,
30
+ migrationSteps: [
31
+ 'Remove custom useAuth hook',
32
+ 'Import useUnifiedAuth from @jmruthers/pace-core',
33
+ 'Update all usages to use useUnifiedAuth',
34
+ 'Ensure UnifiedAuthProvider wraps your app'
35
+ ]
36
+ },
37
+ 'usePermissions': {
38
+ issue: `Custom ${type} '${customCodeName}' detected`,
39
+ suggestion: `Replace with usePermissions from pace-core`,
40
+ codeExample: `// Before
41
+ import { usePermissions } from './hooks/usePermissions';
42
+
43
+ // After
44
+ import { usePermissions } from '@jmruthers/pace-core/rbac';`,
45
+ migrationSteps: [
46
+ 'Remove custom usePermissions hook',
47
+ 'Import usePermissions from @jmruthers/pace-core/rbac',
48
+ 'Update all usages - ensure setupRBAC() has been called',
49
+ 'Verify provider hierarchy is correct'
50
+ ]
51
+ },
52
+ 'PermissionGuard': {
53
+ issue: `Custom ${type} '${customCodeName}' detected`,
54
+ suggestion: `Replace with PagePermissionGuard from pace-core`,
55
+ codeExample: `// Before
56
+ import { PermissionGuard } from './components/PermissionGuard';
57
+
58
+ // After
59
+ import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';`,
60
+ migrationSteps: [
61
+ 'Remove custom PermissionGuard component',
62
+ 'Import PagePermissionGuard from @jmruthers/pace-core/rbac',
63
+ 'Wrap pages with PagePermissionGuard',
64
+ 'Use pageName and operation props instead of custom permission strings'
65
+ ]
66
+ },
67
+ 'checkPermission': {
68
+ issue: `Custom ${type} '${customCodeName}' detected`,
69
+ suggestion: `Replace with isPermitted from pace-core`,
70
+ codeExample: `// Before
71
+ import { checkPermission } from './utils/permissions';
72
+
73
+ // After
74
+ import { isPermitted } from '@jmruthers/pace-core/rbac';`,
75
+ migrationSteps: [
76
+ 'Remove custom checkPermission utility',
77
+ 'Import isPermitted from @jmruthers/pace-core/rbac',
78
+ 'Update all usages to use isPermitted with proper scope',
79
+ 'Ensure setupRBAC() has been called'
80
+ ]
81
+ }
82
+ };
83
+
84
+ return fixes[customCodeName] || {
85
+ issue: `Custom ${type} '${customCodeName}' detected`,
86
+ suggestion: `Use pace-core's equivalent instead. Check @jmruthers/pace-core documentation for the correct import.`,
87
+ migrationSteps: [
88
+ `Remove custom ${customCodeName} ${type}`,
89
+ 'Find equivalent in pace-core',
90
+ 'Import from @jmruthers/pace-core or @jmruthers/pace-core/rbac',
91
+ 'Update all usages'
92
+ ]
93
+ };
94
+ }
95
+
96
+ /**
97
+ * Get quick fix suggestions for duplicate Supabase config
98
+ */
99
+ export function getDuplicateConfigFixes(): QuickFix {
100
+ return {
101
+ issue: 'Multiple Supabase client instantiations found',
102
+ suggestion: 'Consolidate to a single Supabase client configuration',
103
+ codeExample: `// Before - Multiple createClient calls
104
+ // src/lib/supabase.ts
105
+ export const supabase = createClient(url, key);
106
+
107
+ // src/utils/api.ts
108
+ export const supabase = createClient(url, key);
109
+
110
+ // After - Single configuration
111
+ // src/lib/supabase.ts
112
+ export const supabase = createClient(
113
+ import.meta.env.VITE_SUPABASE_URL,
114
+ import.meta.env.VITE_SUPABASE_ANON_KEY
115
+ );
116
+
117
+ // src/utils/api.ts
118
+ import { supabase } from '../lib/supabase';`,
119
+ migrationSteps: [
120
+ 'Create a single supabase.ts file in a shared location (e.g., src/lib/supabase.ts)',
121
+ 'Move all Supabase client creation to this file',
122
+ 'Export the client instance',
123
+ 'Update all files to import from the shared location',
124
+ 'Remove duplicate createClient calls'
125
+ ]
126
+ };
127
+ }
128
+
129
+ /**
130
+ * Get quick fix suggestions for unprotected pages
131
+ */
132
+ export function getUnprotectedPageFixes(): QuickFix {
133
+ return {
134
+ issue: 'Route/page found without PagePermissionGuard',
135
+ suggestion: 'Wrap all routes with PagePermissionGuard',
136
+ codeExample: `// Before
137
+ <Route path="/dashboard" element={<Dashboard />} />
138
+
139
+ // After
140
+ <Route
141
+ path="/dashboard"
142
+ element={
143
+ <PagePermissionGuard pageName="dashboard" operation="read">
144
+ <Dashboard />
145
+ </PagePermissionGuard>
146
+ }
147
+ />`,
148
+ migrationSteps: [
149
+ 'Import PagePermissionGuard from @jmruthers/pace-core/rbac',
150
+ 'Wrap each route/page component with PagePermissionGuard',
151
+ 'Set pageName prop to match your page name in rbac_app_pages table',
152
+ 'Set operation prop (read, create, update, or delete)',
153
+ 'Ensure setupRBAC() has been called and providers are set up correctly'
154
+ ]
155
+ };
156
+ }
157
+
158
+ /**
159
+ * Get quick fix suggestions for direct Supabase auth usage
160
+ */
161
+ export function getDirectSupabaseAuthFixes(): QuickFix {
162
+ return {
163
+ issue: 'Direct Supabase auth usage detected',
164
+ suggestion: 'Use UnifiedAuthProvider and useUnifiedAuth from pace-core',
165
+ codeExample: `// Before
166
+ import { createClient } from '@supabase/supabase-js';
167
+ const supabase = createClient(url, key);
168
+ await supabase.auth.signInWithPassword({ email, password });
169
+
170
+ // After
171
+ import { useUnifiedAuth } from '@jmruthers/pace-core';
172
+ const { signIn } = useUnifiedAuth();
173
+ await signIn({ email, password });`,
174
+ migrationSteps: [
175
+ 'Remove direct Supabase auth calls',
176
+ 'Import useUnifiedAuth from @jmruthers/pace-core',
177
+ 'Use the auth methods from useUnifiedAuth hook',
178
+ 'Ensure UnifiedAuthProvider wraps your app',
179
+ 'Update all auth-related code to use pace-core hooks'
180
+ ]
181
+ };
182
+ }
183
+
184
+ /**
185
+ * Get all quick fix suggestions for a compliance issue
186
+ */
187
+ export function getQuickFixes(issueType: string, details?: Record<string, any>): QuickFix[] {
188
+ const fixes: QuickFix[] = [];
189
+
190
+ switch (issueType) {
191
+ case 'custom-auth-code':
192
+ if (details?.name && details?.type) {
193
+ fixes.push(getCustomAuthCodeFixes(details.name, details.type));
194
+ }
195
+ break;
196
+ case 'duplicate-config':
197
+ fixes.push(getDuplicateConfigFixes());
198
+ break;
199
+ case 'unprotected-pages':
200
+ fixes.push(getUnprotectedPageFixes());
201
+ break;
202
+ case 'direct-supabase-auth':
203
+ fixes.push(getDirectSupabaseAuthFixes());
204
+ break;
205
+ }
206
+
207
+ return fixes;
208
+ }
209
+
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Runtime Compliance Checking
3
+ * @package @jmruthers/pace-core
4
+ * @module RBAC/Compliance/RuntimeCompliance
5
+ * @since 1.0.0
6
+ *
7
+ * This module provides runtime compliance checking utilities.
8
+ */
9
+
10
+ import { validateRBACSetup, SetupIssue } from './setup-validator';
11
+ import { getRBACLogger } from '../config';
12
+
13
+ export interface RuntimeComplianceResult {
14
+ setup: {
15
+ isCompliant: boolean;
16
+ issues: SetupIssue[];
17
+ };
18
+ warnings: string[];
19
+ providerContext?: {
20
+ available: boolean;
21
+ message?: string;
22
+ };
23
+ }
24
+
25
+ /**
26
+ * Check runtime compliance
27
+ *
28
+ * This function checks if the RBAC system is properly set up and logs warnings
29
+ * to the console if issues are found. This is intended for development-time
30
+ * validation only.
31
+ *
32
+ * @returns Runtime compliance result
33
+ */
34
+ export function checkRuntimeCompliance(): RuntimeComplianceResult {
35
+ const logger = getRBACLogger();
36
+ const setupValidation = validateRBACSetup();
37
+ const warnings: string[] = [];
38
+
39
+ if (!setupValidation.isCompliant) {
40
+ setupValidation.issues.forEach(issue => {
41
+ const warning = `[RBAC Compliance] ${issue.message}\n Recommendation: ${issue.recommendation}`;
42
+ warnings.push(warning);
43
+ logger.warn(warning);
44
+ });
45
+ }
46
+
47
+ // Check for provider context issues
48
+ const providerContextIssues = setupValidation.issues.filter(
49
+ issue => issue.type === 'missing-provider-context' || issue.type === 'not-initialized'
50
+ );
51
+
52
+ const providerContext = providerContextIssues.length > 0 ? {
53
+ available: false,
54
+ message: 'UnifiedAuthProvider context may not be available. Ensure your app is wrapped with UnifiedAuthProvider from @jmruthers/pace-core.'
55
+ } : {
56
+ available: true
57
+ };
58
+
59
+ return {
60
+ setup: setupValidation,
61
+ warnings,
62
+ providerContext
63
+ };
64
+ }
65
+
66
+ /**
67
+ * Validate and warn about RBAC setup issues
68
+ *
69
+ * This is a convenience function that checks compliance and logs warnings.
70
+ * Call this in development mode to get early warnings about setup issues.
71
+ */
72
+ export function validateAndWarn(): void {
73
+ if (import.meta.env.MODE === 'development' || import.meta.env.DEV) {
74
+ checkRuntimeCompliance();
75
+ }
76
+ }
77
+