@jmruthers/pace-core 0.5.181 → 0.5.183
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +1 -1
- package/README.md +16 -2
- package/dist/{AuthService-DYuQPJj6.d.ts → AuthService-B-cd2MA4.d.ts} +9 -11
- package/dist/{DataTable-CWAZZcXC.d.ts → DataTable-Bz8ffqyA.d.ts} +1 -1
- package/dist/{DataTable-UA6CL4JI.js → DataTable-QAB34V6K.js} +14 -15
- package/dist/UnifiedAuthProvider-7F6T4B6K.js +13 -0
- package/dist/{UnifiedAuthProvider-DJxGTftH.d.ts → UnifiedAuthProvider-F86d7dSi.d.ts} +5 -6
- package/dist/{api-45XYYO2A.js → api-ROMBCNKU.js} +5 -5
- package/dist/{audit-64X3VJXB.js → audit-WRS3KJKI.js} +4 -4
- package/dist/auth-BZOJqrdd.d.ts +49 -0
- package/dist/{chunk-CX5M4ZAG.js → chunk-5DRSZLL2.js} +1 -1
- package/dist/chunk-5DRSZLL2.js.map +1 -0
- package/dist/{chunk-BESYRHQM.js → chunk-6C4YBBJM.js} +10 -7
- package/dist/chunk-6C4YBBJM.js.map +1 -0
- package/dist/{chunk-PLDDJCW6.js → chunk-7D4SUZUM.js} +2 -13
- package/dist/{chunk-HRO5HWN2.js → chunk-CSOFYHAG.js} +55 -162
- package/dist/chunk-CSOFYHAG.js.map +1 -0
- package/dist/{chunk-ANBQRTPX.js → chunk-E66EQZE6.js} +3 -5
- package/dist/{chunk-ANBQRTPX.js.map → chunk-E66EQZE6.js.map} +1 -1
- package/dist/{chunk-Q5QRDWKI.js → chunk-F2IMUDXZ.js} +4 -6
- package/dist/chunk-F2IMUDXZ.js.map +1 -0
- package/dist/{chunk-SBVILCCA.js → chunk-FSFQFJCU.js} +28 -6
- package/dist/chunk-FSFQFJCU.js.map +1 -0
- package/dist/chunk-FUEYYMX5.js +2296 -0
- package/dist/chunk-FUEYYMX5.js.map +1 -0
- package/dist/{chunk-FFKNH6U5.js → chunk-HKIT6O7W.js} +3 -5
- package/dist/{chunk-FFKNH6U5.js.map → chunk-HKIT6O7W.js.map} +1 -1
- package/dist/chunk-KQCRWDSA.js +1 -0
- package/dist/{chunk-S5OFRT4M.js → chunk-KUEN3HFB.js} +6 -6
- package/dist/chunk-KUEN3HFB.js.map +1 -0
- package/dist/chunk-LMC26NLJ.js +84 -0
- package/dist/chunk-LMC26NLJ.js.map +1 -0
- package/dist/{chunk-BVYWGZVV.js → chunk-M7W4CP3M.js} +52 -19
- package/dist/chunk-M7W4CP3M.js.map +1 -0
- package/dist/{chunk-HZLDFOE4.js → chunk-MI7HBHN3.js} +164 -243
- package/dist/chunk-MI7HBHN3.js.map +1 -0
- package/dist/{chunk-PPMP5J6T.js → chunk-PWAHJW4G.js} +180 -29
- package/dist/chunk-PWAHJW4G.js.map +1 -0
- package/dist/chunk-PWLANIRT.js +127 -0
- package/dist/{chunk-XDNLUEXI.js.map → chunk-PWLANIRT.js.map} +1 -1
- package/dist/chunk-QCDXODCA.js +75 -0
- package/dist/chunk-QCDXODCA.js.map +1 -0
- package/dist/{chunk-D7LCGMVS.js → chunk-QETLRQI6.js} +526 -887
- package/dist/chunk-QETLRQI6.js.map +1 -0
- package/dist/{chunk-5MT24GKJ.js → chunk-QUVSNGIP.js} +264 -262
- package/dist/chunk-QUVSNGIP.js.map +1 -0
- package/dist/chunk-QXHPKYJV.js +113 -0
- package/dist/chunk-QXHPKYJV.js.map +1 -0
- package/dist/{chunk-OWAG3GSU.js → chunk-R77UEZ4E.js} +11 -1
- package/dist/chunk-R77UEZ4E.js.map +1 -0
- package/dist/{chunk-ZYTYSTO5.js → chunk-RA3JUFMW.js} +314 -161
- package/dist/chunk-RA3JUFMW.js.map +1 -0
- package/dist/{chunk-ERISIBYU.js → chunk-SQGMNID3.js} +3 -8
- package/dist/chunk-SQGMNID3.js.map +1 -0
- package/dist/{chunk-XJ2HZOBU.js → chunk-UHNYIBXL.js} +1 -1
- package/dist/chunk-UHNYIBXL.js.map +1 -0
- package/{src/utils/secureStorage.ts → dist/chunk-VBXEHIUJ.js} +113 -88
- package/dist/{chunk-7QCC6MCP.js.map → chunk-VBXEHIUJ.js.map} +1 -1
- package/dist/{chunk-VZ4VDGTB.js → chunk-W22JP75J.js} +5 -13
- package/dist/{chunk-VZ4VDGTB.js.map → chunk-W22JP75J.js.map} +1 -1
- package/dist/components.d.ts +12 -93
- package/dist/components.js +23 -106
- package/dist/components.js.map +1 -1
- package/dist/core-CUElvH_C.d.ts +164 -0
- package/dist/database.generated-CBmg2950.d.ts +8284 -0
- package/dist/event-CW5YB_2p.d.ts +239 -0
- package/dist/{file-reference-C6Gkn77H.d.ts → file-reference-D06mEEWW.d.ts} +7 -5
- package/dist/functions-D_kgHktt.d.ts +208 -0
- package/dist/hooks.d.ts +54 -7
- package/dist/hooks.js +204 -17
- package/dist/hooks.js.map +1 -1
- package/dist/{EventLogo-B3V3otev.d.ts → index-Bl--n7-T.d.ts} +387 -397
- package/dist/index.d.ts +94 -261
- package/dist/index.js +314 -126
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +7 -8
- package/dist/providers.js +6 -13
- package/dist/rbac/index.d.ts +171 -101
- package/dist/rbac/index.js +23 -17
- package/dist/styles/index.d.ts +1 -3
- package/dist/styles/index.js +2 -17
- package/dist/theming/runtime.js +3 -3
- package/dist/types-UU913iLA.d.ts +102 -0
- package/dist/{types-Dfz9dmVH.d.ts → types-_x1f4QBF.d.ts} +6 -6
- package/dist/types.d.ts +88 -227
- package/dist/types.js +64 -112
- package/dist/types.js.map +1 -1
- package/dist/{usePublicRouteParams-B7PabvuH.d.ts → usePublicRouteParams-JJczomYq.d.ts} +203 -6
- package/dist/utils.d.ts +299 -13
- package/dist/utils.js +481 -55
- package/dist/utils.js.map +1 -1
- package/dist/validation-643vUDZW.d.ts +177 -0
- package/docs/DOCUMENTATION_REVIEW_TRACKER.md +511 -0
- package/docs/README.md +9 -8
- package/docs/api/README.md +16 -2
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +4 -4
- package/docs/api/classes/MissingUserContextError.md +4 -4
- package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
- package/docs/api/classes/PermissionDeniedError.md +4 -4
- package/docs/api/classes/RBACAuditManager.md +14 -14
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +2 -2
- package/docs/api/classes/RBACError.md +4 -4
- package/docs/api/classes/RBACNotInitializedError.md +4 -4
- package/docs/api/classes/SecureSupabaseClient.md +29 -9
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +17 -17
- package/docs/api/enums/RBACErrorCode.md +228 -0
- package/docs/api/enums/RPCFunction.md +118 -0
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +2 -2
- package/docs/api/interfaces/CalendarProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +29 -3
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +2 -2
- package/docs/api/interfaces/DataTableColumn.md +6 -6
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +2 -2
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/ExportColumn.md +5 -5
- package/docs/api/interfaces/ExportOptions.md +4 -4
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +13 -13
- package/docs/api/interfaces/FileReference.md +12 -12
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +10 -10
- package/docs/api/interfaces/FileUploadProps.md +19 -19
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +166 -0
- package/docs/api/interfaces/FormProps.md +113 -0
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +8 -8
- package/docs/api/interfaces/InputProps.md +2 -2
- package/docs/api/interfaces/LabelProps.md +8 -8
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +17 -73
- package/docs/api/interfaces/NavigationMenuProps.md +38 -53
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +13 -13
- package/docs/api/interfaces/OrganisationContextType.md +21 -21
- package/docs/api/interfaces/OrganisationMembership.md +15 -15
- package/docs/api/interfaces/OrganisationProviderProps.md +59 -2
- package/docs/api/interfaces/OrganisationSecurityError.md +5 -5
- package/docs/api/interfaces/PaceAppLayoutProps.md +26 -39
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProgressProps.md +50 -0
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
- package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
- package/docs/api/interfaces/PublicPageLayoutProps.md +15 -15
- package/docs/api/interfaces/RBACAccessValidateParams.md +52 -0
- package/docs/api/interfaces/RBACAccessValidateResult.md +41 -0
- package/docs/api/interfaces/RBACAuditLogParams.md +85 -0
- package/docs/api/interfaces/RBACAuditLogResult.md +52 -0
- package/docs/api/interfaces/RBACConfig.md +2 -2
- package/docs/api/interfaces/RBACContext.md +52 -0
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +74 -0
- package/docs/api/interfaces/RBACPermissionCheckParams.md +74 -0
- package/docs/api/interfaces/RBACPermissionCheckResult.md +52 -0
- package/docs/api/interfaces/RBACPermissionsGetParams.md +63 -0
- package/docs/api/interfaces/RBACPermissionsGetResult.md +63 -0
- package/docs/api/interfaces/RBACResult.md +58 -0
- package/docs/api/interfaces/RBACRoleGrantParams.md +63 -0
- package/docs/api/interfaces/RBACRoleGrantResult.md +52 -0
- package/docs/api/interfaces/RBACRoleRevokeParams.md +63 -0
- package/docs/api/interfaces/RBACRoleRevokeResult.md +52 -0
- package/docs/api/interfaces/RBACRoleValidateParams.md +52 -0
- package/docs/api/interfaces/RBACRoleValidateResult.md +63 -0
- package/docs/api/interfaces/RBACRolesListParams.md +52 -0
- package/docs/api/interfaces/RBACRolesListResult.md +74 -0
- package/docs/api/interfaces/RBACSessionTrackParams.md +74 -0
- package/docs/api/interfaces/RBACSessionTrackResult.md +52 -0
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +15 -2
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +43 -2
- package/docs/api/interfaces/TextareaProps.md +2 -2
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +61 -61
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +87 -0
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +81 -0
- package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
- package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +4 -4
- package/docs/api/interfaces/UserProfile.md +7 -7
- package/docs/api/modules.md +484 -462
- package/docs/api-reference/components.md +186 -15
- package/docs/api-reference/deprecated.md +376 -0
- package/docs/api-reference/hooks.md +149 -19
- package/docs/api-reference/providers.md +61 -6
- package/docs/api-reference/rpc-functions.md +397 -0
- package/docs/api-reference/types.md +135 -78
- package/docs/api-reference/utilities.md +51 -380
- package/docs/architecture/README.md +49 -3
- package/docs/architecture/database-schema-requirements.md +40 -3
- package/docs/architecture/rbac-security-architecture.md +41 -4
- package/docs/architecture/services.md +127 -42
- package/docs/best-practices/README.md +51 -5
- package/docs/best-practices/accessibility.md +32 -3
- package/docs/best-practices/common-patterns.md +50 -3
- package/docs/best-practices/deployment.md +50 -4
- package/docs/best-practices/performance.md +50 -3
- package/docs/best-practices/security.md +94 -41
- package/docs/best-practices/testing.md +33 -4
- package/docs/core-concepts/authentication.md +5 -5
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +3 -3
- package/docs/core-concepts/permissions.md +3 -3
- package/docs/core-concepts/rbac-system.md +5 -5
- package/docs/documentation-index.md +30 -8
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +7 -5
- package/docs/getting-started/examples/basic-auth-app.md +3 -0
- package/docs/getting-started/examples/full-featured-app.md +5 -3
- package/docs/getting-started/faq.md +6 -6
- package/docs/getting-started/installation-guide.md +192 -13
- package/docs/getting-started/local-development.md +303 -0
- package/docs/getting-started/quick-reference.md +3 -3
- package/docs/getting-started/quick-start.md +517 -0
- package/docs/implementation-guides/app-layout.md +45 -3
- package/docs/implementation-guides/authentication.md +66 -7
- package/docs/implementation-guides/component-styling.md +53 -3
- package/docs/implementation-guides/data-tables.md +76 -7
- package/docs/implementation-guides/datatable-filtering.md +1 -2
- package/docs/implementation-guides/datatable-rbac-usage.md +0 -1
- package/docs/implementation-guides/dynamic-colors.md +155 -4
- package/docs/implementation-guides/file-reference-system.md +72 -3
- package/docs/implementation-guides/file-upload-storage.md +72 -3
- package/docs/implementation-guides/forms.md +53 -3
- package/docs/implementation-guides/inactivity-tracking.md +53 -3
- package/docs/implementation-guides/large-datasets.md +1 -1
- package/docs/implementation-guides/navigation.md +55 -5
- package/docs/implementation-guides/organisation-security.md +72 -3
- package/docs/implementation-guides/performance.md +57 -1
- package/docs/implementation-guides/permission-enforcement.md +81 -8
- package/docs/implementation-guides/public-pages.md +560 -14
- package/docs/migration/MIGRATION_GUIDE.md +409 -50
- package/docs/migration/README.md +37 -3
- package/docs/migration/organisation-context-timing-fix.md +39 -4
- package/docs/migration/quick-migration-guide.md +41 -5
- package/docs/migration/rbac-migration.md +59 -3
- package/docs/migration/service-architecture.md +77 -14
- package/docs/rbac/README.md +79 -3
- package/docs/rbac/advanced-patterns.md +47 -3
- package/docs/rbac/api-reference.md +77 -8
- package/docs/rbac/event-based-apps.md +50 -5
- package/docs/rbac/examples/rbac-rls-integration-example.md +3 -3
- package/docs/rbac/examples.md +39 -3
- package/docs/rbac/getting-started.md +63 -4
- package/docs/rbac/quick-start.md +57 -5
- package/docs/rbac/rbac-rls-integration.md +68 -6
- package/docs/rbac/super-admin-guide.md +47 -3
- package/docs/rbac/troubleshooting.md +3 -3
- package/docs/security/README.md +68 -3
- package/docs/security/checklist.md +50 -3
- package/docs/standards/01-architecture-standard.md +39 -0
- package/docs/standards/02-api-and-rpc-standard.md +39 -0
- package/docs/standards/03-component-standard.md +32 -0
- package/docs/standards/04-code-style-standard.md +32 -0
- package/docs/standards/05-security-standard.md +30 -0
- package/docs/standards/06-testing-and-docs-standard.md +29 -0
- package/docs/standards/README.md +35 -0
- package/docs/styles/README.md +89 -8
- package/docs/testing/README.md +175 -24
- package/docs/troubleshooting/README.md +50 -3
- package/docs/troubleshooting/common-issues.md +271 -5
- package/docs/troubleshooting/debugging.md +54 -1
- package/docs/troubleshooting/migration.md +54 -1
- package/docs/troubleshooting/organisation-context-setup.md +29 -3
- package/docs/troubleshooting/styling-issues.md +246 -4
- package/{src/components/DataTable/examples → examples/DataTable}/GroupingAggregationExample.tsx +1 -1
- package/examples/{components 2/DataTable/HierarchicalActionsExample.tsx → DataTable/HierarchicalActionsExample.tsx} +7 -6
- package/{src/components/DataTable/examples → examples/DataTable}/HierarchicalExample.tsx +8 -6
- package/examples/{components 2/DataTable/PerformanceExample.tsx → DataTable/PerformanceExample.tsx} +2 -2
- package/examples/{components 2/DataTable/index.ts → DataTable/index.ts} +1 -0
- package/{src/components/Dialog/examples → examples/Dialog}/HtmlDialogExample.tsx +3 -3
- package/examples/{components 2/Dialog/ScrollableDialogExample.tsx → Dialog/ScrollableDialogExample.tsx} +1 -1
- package/{src/components/Dialog/examples → examples/Dialog}/SmartDialogExample.tsx +1 -1
- package/examples/{components 2/Dialog/index.ts → Dialog/index.ts} +0 -3
- package/examples/{features/public-pages → PublicPages}/CorrectPublicPageImplementation.tsx +52 -17
- package/examples/{features/public-pages → PublicPages}/PublicEventPage.tsx +65 -35
- package/examples/{features/public-pages → PublicPages}/PublicPageApp.tsx +52 -18
- package/examples/{features/public-pages → PublicPages}/PublicPageUsageExample.tsx +28 -15
- package/examples/README.md +81 -33
- package/examples/index.ts +14 -12
- package/examples/{RBAC → rbac}/CompleteRBACExample.tsx +1 -1
- package/examples/{features/rbac → rbac}/EventBasedApp.tsx +4 -4
- package/examples/{features/rbac → rbac}/PermissionExample.tsx +5 -3
- package/package.json +21 -27
- package/src/__tests__/helpers/test-utils.tsx +29 -3
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +7 -5
- package/src/components/Alert/Alert.test.tsx +2 -2
- package/src/components/Alert/Alert.tsx +4 -4
- package/src/components/Avatar/Avatar.test.tsx +17 -6
- package/src/components/Badge/Badge.test.tsx +1 -1
- package/src/components/Badge/Badge.tsx +2 -2
- package/src/components/Button/Button.test.tsx +2 -2
- package/src/components/Button/Button.tsx +11 -7
- package/src/components/Calendar/Calendar.test.tsx +41 -8
- package/src/components/Calendar/Calendar.tsx +39 -36
- package/src/components/Card/Card.tsx +51 -13
- package/src/components/Checkbox/Checkbox.test.tsx +36 -12
- package/src/components/DataTable/DataTable.test.tsx +1 -1
- package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +13 -7
- package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +14 -42
- package/src/components/DataTable/__tests__/DataTable.export.test.tsx +13 -10
- package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +14 -11
- package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +4 -2
- package/src/components/DataTable/__tests__/DataTable.test.tsx +13 -7
- package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +13 -10
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +15 -11
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +12 -6
- package/src/components/DataTable/__tests__/keyboard.test.tsx +12 -6
- package/src/components/DataTable/__tests__/pagination.modes.test.tsx +10 -6
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +1 -1
- package/src/components/DataTable/components/DataTableBody.tsx +10 -25
- package/src/components/DataTable/components/DataTableCore.tsx +1 -1
- package/src/components/DataTable/components/FilterRow.tsx +3 -1
- package/src/components/DataTable/components/ImportModal.tsx +1 -1
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +9 -9
- package/src/components/DataTable/core/ColumnFactory.ts +6 -6
- package/src/components/DataTable/core/DataTableContext.tsx +14 -10
- package/src/components/DataTable/core/LocalDataAdapter.ts +2 -1
- package/src/components/DataTable/core/PluginRegistry.ts +3 -3
- package/src/components/DataTable/core/StateManager.ts +12 -11
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +104 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +101 -0
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +84 -0
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +102 -0
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +104 -0
- package/src/components/DataTable/core/interfaces.ts +17 -17
- package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +124 -0
- package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +117 -0
- package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +102 -0
- package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +53 -0
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +0 -2
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +9 -8
- package/src/components/DataTable/types.ts +5 -5
- package/src/components/DataTable/utils/aggregationUtils.ts +4 -4
- package/src/components/DataTable/utils/columnUtils.ts +3 -2
- package/src/components/DataTable/utils/debugTools.ts +1 -1
- package/src/components/DataTable/utils/exportUtils.ts +6 -6
- package/src/components/DataTable/utils/hierarchicalSorting.ts +6 -6
- package/src/components/DataTable/utils/hierarchicalUtils.ts +0 -8
- package/src/components/DataTable/utils/index.ts +0 -1
- package/src/components/DataTable/utils/performanceUtils.ts +9 -4
- package/src/components/Dialog/Dialog.test.tsx +49 -27
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +13 -8
- package/src/components/EventSelector/EventSelector.test.tsx +60 -12
- package/src/components/EventSelector/EventSelector.tsx +38 -15
- package/src/components/EventSelector/index.ts +2 -2
- package/src/components/FileDisplay/FileDisplay.test.tsx +143 -85
- package/src/components/FileDisplay/FileDisplay.tsx +1 -0
- package/src/components/FileUpload/FileUpload.test.tsx +532 -152
- package/src/components/FileUpload/FileUpload.tsx +43 -8
- package/src/components/Footer/Footer.test.tsx +19 -14
- package/src/components/Form/Form.test.tsx +96 -14
- package/src/components/Form/Form.tsx +210 -1
- package/src/components/Form/index.ts +3 -7
- package/src/components/Header/Header.test.tsx +24 -17
- package/src/components/Header/Header.tsx +3 -1
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -4
- package/src/components/Input/Input.test.tsx +61 -36
- package/src/components/Label/{__tests__/Label.test.tsx → Label.test.tsx} +2 -2
- package/src/components/Label/Label.tsx +2 -3
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +6 -5
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +6 -2
- package/src/components/LoginForm/LoginForm.test.tsx +14 -13
- package/src/components/LoginForm/LoginForm.tsx +1 -1
- package/src/components/LoginForm/index.ts +7 -0
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +233 -20
- package/src/components/NavigationMenu/NavigationMenu.tsx +191 -55
- package/src/components/NavigationMenu/index.ts +1 -1
- package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +20 -11
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +1 -1
- package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.integration.test.tsx → PaceAppLayout.integration.test.tsx} +272 -79
- package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.performance.test.tsx → PaceAppLayout.performance.test.tsx} +155 -32
- package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.security.test.tsx → PaceAppLayout.security.test.tsx} +211 -65
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +498 -210
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +63 -64
- package/src/components/PaceAppLayout/test-setup.tsx +192 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +193 -39
- package/src/components/{PasswordReset → PasswordChange}/PasswordChangeForm.test.tsx +2 -2
- package/src/components/{PasswordReset → PasswordChange}/PasswordChangeForm.tsx +10 -4
- package/src/components/PasswordChange/index.ts +2 -0
- package/src/components/Progress/Progress.test.tsx +11 -0
- package/src/components/Progress/Progress.tsx +1 -1
- package/src/components/Progress/index.ts +10 -0
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +2 -1
- package/src/components/PublicLayout/PublicLayout.test.tsx +1210 -0
- package/src/components/PublicLayout/PublicPageLayout.tsx +190 -36
- package/src/components/PublicLayout/PublicPageProvider.tsx +8 -7
- package/src/components/PublicLayout/index.ts +10 -28
- package/src/components/Select/Select.test.tsx +7 -7
- package/src/components/Select/Select.tsx +277 -11
- package/src/components/Select/index.ts +1 -2
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +232 -0
- package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +40 -19
- package/src/components/Table/{__tests__/Table.test.tsx → Table.test.tsx} +94 -41
- package/src/components/Tabs/Tabs.test.tsx +10 -9
- package/src/components/Tabs/Tabs.tsx +61 -33
- package/src/components/Textarea/Textarea.test.tsx +31 -18
- package/src/components/Toast/Toast.tsx +2 -2
- package/src/components/Tooltip/Tooltip.test.tsx +1 -1
- package/src/components/UserMenu/UserMenu.test.tsx +7 -6
- package/src/components/UserMenu/UserMenu.tsx +2 -2
- package/src/components/index.ts +5 -4
- package/src/constants/performance.ts +19 -8
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +21 -22
- package/src/hooks/__tests__/useEvents.unit.test.ts +5 -4
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +2 -2
- package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -0
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +16 -11
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +1 -3
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +1 -3
- package/src/hooks/__tests__/useRBAC.unit.test.ts +24 -2
- package/src/hooks/index.ts +4 -0
- package/src/hooks/public/index.ts +2 -0
- package/src/hooks/public/usePublicEvent.ts +4 -6
- package/src/hooks/public/usePublicEventLogo.test.ts +147 -0
- package/src/hooks/public/usePublicRouteParams.ts +1 -1
- package/src/hooks/services/useAuth.ts +2 -4
- package/src/hooks/services/useCurrentEvent.ts +1 -1
- package/src/hooks/useAppConfig.ts +1 -1
- package/src/hooks/useDataTablePerformance.ts +2 -2
- package/src/hooks/useEventTheme.ts +1 -1
- package/src/hooks/useEvents.ts +51 -10
- package/src/hooks/useOrganisationPermissions.test.ts +3 -3
- package/src/hooks/useOrganisationPermissions.ts +1 -1
- package/src/hooks/useOrganisationSecurity.ts +2 -2
- package/src/hooks/usePermissionCache.test.ts +9 -9
- package/src/hooks/usePermissionCache.ts +2 -2
- package/src/index.ts +19 -12
- package/src/providers/OrganisationProvider.tsx +73 -9
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +113 -13
- package/src/providers/__tests__/AuthProvider.test.tsx +2 -1
- package/src/providers/__tests__/EventProvider.test.tsx +24 -15
- package/src/providers/__tests__/OrganisationProvider.test.tsx +87 -36
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +80 -24
- package/src/providers/index.ts +0 -3
- package/src/providers/services/AuthServiceProvider.tsx +2 -17
- package/src/providers/services/EventServiceProvider.tsx +11 -16
- package/src/providers/services/InactivityServiceProvider.tsx +9 -12
- package/src/providers/services/OrganisationServiceProvider.tsx +9 -12
- package/src/providers/services/UnifiedAuthProvider.tsx +85 -18
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +11 -4
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +105 -21
- package/src/rbac/adapters.tsx +1 -1
- package/src/rbac/api.ts +20 -4
- package/src/rbac/audit-enhanced.ts +47 -2
- package/src/rbac/audit.ts +47 -2
- package/src/rbac/components/NavigationGuard.tsx +1 -1
- package/src/rbac/components/NavigationProvider.test.tsx +7 -6
- package/src/rbac/components/NavigationProvider.tsx +1 -1
- package/src/rbac/components/PagePermissionGuard.tsx +1 -1
- package/src/rbac/components/PagePermissionProvider.test.tsx +7 -6
- package/src/rbac/components/PagePermissionProvider.tsx +1 -1
- package/src/rbac/components/PermissionEnforcer.tsx +1 -1
- package/src/rbac/components/RoleBasedRouter.tsx +1 -1
- package/src/rbac/components/SecureDataProvider.test.tsx +7 -6
- package/src/rbac/components/SecureDataProvider.tsx +1 -1
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +6 -6
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +11 -10
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +10 -11
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +19 -15
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +13 -12
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +19 -15
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +18 -18
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +11 -10
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +8 -7
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +10 -11
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +48 -19
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +476 -0
- package/src/rbac/hooks/index.ts +3 -0
- package/src/rbac/hooks/usePermissions.ts +31 -85
- package/src/rbac/hooks/useRBAC.test.ts +13 -1
- package/src/rbac/hooks/useRBAC.ts +13 -67
- package/src/rbac/hooks/useResolvedScope.ts +11 -0
- package/src/rbac/hooks/useSecureSupabase.ts +308 -0
- package/src/rbac/index.ts +3 -0
- package/src/rbac/secureClient.ts +53 -6
- package/src/rbac/security.ts +37 -1
- package/src/{types/rbac-functions.ts → rbac/types/functions.ts} +30 -30
- package/src/rbac/types.ts +3 -2
- package/src/services/AuthService.ts +33 -25
- package/src/services/EventService.ts +56 -44
- package/src/services/InactivityService.ts +33 -53
- package/src/services/OrganisationService.ts +36 -40
- package/src/services/__tests__/AuthService.restoreSession.test.ts +6 -2
- package/src/services/__tests__/EventService.test.ts +67 -33
- package/src/services/interfaces/IEventService.ts +1 -1
- package/src/styles/core.css +2 -2
- package/src/styles/index.test.ts +21 -0
- package/src/styles/index.ts +1 -5
- package/src/types/__tests__/guards.test.ts +1 -1
- package/src/types/__tests__/organisation.roles.test.ts +55 -0
- package/src/types/__tests__/type-validation.test.ts +0 -1
- package/src/types/auth.ts +42 -2
- package/src/types/core.ts +251 -0
- package/src/types/database.ts +11 -496
- package/src/types/event.ts +102 -0
- package/src/types/file-reference.ts +6 -4
- package/src/types/guards.ts +2 -1
- package/src/types/index.ts +48 -14
- package/src/types/lodash.debounce.d.ts +15 -0
- package/src/types/organisation.ts +14 -10
- package/src/types/supabase.ts +15 -17
- package/src/utils/__tests__/secureErrors.unit.test.ts +1 -1
- package/src/utils/__tests__/validationUtils.unit.test.ts +0 -29
- package/src/utils/app/appNameResolver.ts +1 -1
- package/src/utils/audit/audit.test.ts +65 -0
- package/src/utils/device/deviceFingerprint.test.ts +171 -0
- package/src/utils/dynamic/dynamicUtils.ts +3 -2
- package/src/utils/file-reference/index.ts +25 -6
- package/src/utils/security/secureErrors.ts +1 -1
- package/src/utils/validation/__tests__/validationUtils.test.ts +72 -0
- package/src/utils/validation/index.ts +6 -12
- package/src/utils/validation/validationUtils.ts +0 -13
- package/dist/UnifiedAuthProvider-B37ATQHE.js +0 -16
- package/dist/auth-DReDSLq9.d.ts +0 -16
- package/dist/chunk-3JI76CYK.js +0 -2444
- package/dist/chunk-3JI76CYK.js.map +0 -1
- package/dist/chunk-56XJ3TU6.js +0 -11
- package/dist/chunk-56XJ3TU6.js.map +0 -1
- package/dist/chunk-5MT24GKJ.js.map +0 -1
- package/dist/chunk-7QCC6MCP.js +0 -288
- package/dist/chunk-BESYRHQM.js.map +0 -1
- package/dist/chunk-BJPBT3CU.js +0 -21
- package/dist/chunk-BJPBT3CU.js.map +0 -1
- package/dist/chunk-BVYWGZVV.js.map +0 -1
- package/dist/chunk-CX5M4ZAG.js.map +0 -1
- package/dist/chunk-D7LCGMVS.js.map +0 -1
- package/dist/chunk-EGI6MUL6.js +0 -27
- package/dist/chunk-EGI6MUL6.js.map +0 -1
- package/dist/chunk-ERISIBYU.js.map +0 -1
- package/dist/chunk-HRO5HWN2.js.map +0 -1
- package/dist/chunk-HZLDFOE4.js.map +0 -1
- package/dist/chunk-JISYG63F.js +0 -70
- package/dist/chunk-JISYG63F.js.map +0 -1
- package/dist/chunk-LIMSTKYD.js +0 -61
- package/dist/chunk-LIMSTKYD.js.map +0 -1
- package/dist/chunk-OWAG3GSU.js.map +0 -1
- package/dist/chunk-PPMP5J6T.js.map +0 -1
- package/dist/chunk-Q5QRDWKI.js.map +0 -1
- package/dist/chunk-S5OFRT4M.js.map +0 -1
- package/dist/chunk-SBVILCCA.js.map +0 -1
- package/dist/chunk-TUMEWN34.js +0 -15
- package/dist/chunk-TUMEWN34.js.map +0 -1
- package/dist/chunk-XDNLUEXI.js +0 -138
- package/dist/chunk-XJ2HZOBU.js.map +0 -1
- package/dist/chunk-ZYTYSTO5.js.map +0 -1
- package/dist/chunk-ZZ2SS7NI.js +0 -237
- package/dist/chunk-ZZ2SS7NI.js.map +0 -1
- package/dist/database-C6jy7EOu.d.ts +0 -500
- package/dist/organisation-D6qRDtbF.d.ts +0 -93
- package/dist/schema-DTDZQe2u.d.ts +0 -28
- package/dist/unified-DQ4VcT7H.d.ts +0 -198
- package/dist/useInactivityTracker-TO6ZOF35.js +0 -11
- package/dist/validation.d.ts +0 -47
- package/dist/validation.js +0 -24
- package/dist/validation.js.map +0 -1
- package/docs/DOCUMENTATION_AUDIT.md +0 -172
- package/docs/DOCUMENTATION_STANDARD.md +0 -137
- package/docs/api/classes/PublicErrorBoundary.md +0 -132
- package/docs/api/interfaces/EventLogoProps.md +0 -152
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +0 -94
- package/docs/api/interfaces/PublicErrorBoundaryState.md +0 -68
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +0 -86
- package/docs/architecture/rpc-function-standards.md +0 -1106
- package/docs/getting-started/consuming-app-vite-config.md +0 -239
- package/docs/implementation-guides/event-theming-summary.md +0 -226
- package/docs/implementation-guides/public-pages-advanced.md +0 -1038
- package/docs/migration/v0.4.15-tailwind-scanning.md +0 -278
- package/docs/migration/v0.4.16-css-first-approach.md +0 -312
- package/docs/migration/v0.4.17-source-path-fix.md +0 -235
- package/docs/rbac/RBAC_EVENT_CONTEXT_LOADING.md +0 -222
- package/docs/rbac/RBAC_LOGIN_SAFETY_FIX.md +0 -95
- package/docs/rbac/RBAC_V0.5.147_FIX.md +0 -117
- package/docs/rbac/README-rbac-rls-integration.md +0 -374
- package/docs/styles/usage.md +0 -227
- package/docs/testing/visual-testing.md +0 -120
- package/docs/troubleshooting/DEBUG_NETWORK_ERROR.md +0 -152
- package/docs/troubleshooting/FIX_SUPABASE_CORS.md +0 -184
- package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +0 -193
- package/docs/troubleshooting/database-view-compatibility.md +0 -125
- package/docs/troubleshooting/react-hooks-issue-analysis.md +0 -172
- package/docs/troubleshooting/tailwind-content-scanning.md +0 -219
- package/examples/RBAC/EventBasedApp.tsx +0 -239
- package/examples/RBAC/PermissionExample.tsx +0 -151
- package/examples/STRUCTURE.md +0 -125
- package/examples/components 2/DataTable/HierarchicalExample.tsx +0 -475
- package/examples/components 2/Dialog/BasicHtmlTest.tsx +0 -55
- package/examples/components 2/Dialog/DebugHtmlExample.tsx +0 -68
- package/examples/components 2/Dialog/HtmlDialogExample.tsx +0 -202
- package/examples/components 2/Dialog/SimpleHtmlTest.tsx +0 -61
- package/examples/components 2/Dialog/SmartDialogExample.tsx +0 -322
- package/examples/components 2/index.ts +0 -11
- package/examples/features/index.ts +0 -12
- package/examples/features/rbac/CompleteRBACExample.tsx +0 -324
- package/examples/features/rbac/index.ts +0 -13
- package/examples/public-pages/CorrectPublicPageImplementation.tsx +0 -301
- package/examples/public-pages/PublicEventPage.tsx +0 -274
- package/examples/public-pages/PublicPageApp.tsx +0 -308
- package/examples/public-pages/PublicPageUsageExample.tsx +0 -216
- package/examples/public-pages/index.ts +0 -14
- package/src/__tests__/TEST_STANDARD.md +0 -1008
- package/src/components/Checkbox/__mocks__/Checkbox.tsx +0 -2
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +0 -421
- package/src/components/DataTable/examples/InitialPageSizeExample.tsx +0 -177
- package/src/components/DataTable/examples/PerformanceExample.tsx +0 -506
- package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +0 -316
- package/src/components/DataTable/examples/__tests__/HierarchicalExample.test.tsx +0 -45
- package/src/components/DataTable/examples/__tests__/InitialPageSizeExample.test.tsx +0 -211
- package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +0 -126
- package/src/components/Dialog/README.md +0 -804
- package/src/components/Dialog/examples/BasicHtmlTest.tsx +0 -55
- package/src/components/Dialog/examples/DebugHtmlExample.tsx +0 -68
- package/src/components/Dialog/examples/ScrollableDialogExample.tsx +0 -290
- package/src/components/Dialog/examples/SimpleHtmlTest.tsx +0 -61
- package/src/components/Dialog/examples/__tests__/HtmlDialogExample.test.tsx +0 -71
- package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +0 -122
- package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +0 -147
- package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +0 -611
- package/src/components/Dialog/utils/safeHtml.ts +0 -185
- package/src/components/EventSelector/types.ts +0 -79
- package/src/components/Form/FormErrorSummary.tsx +0 -113
- package/src/components/Form/FormField.tsx +0 -249
- package/src/components/Form/FormFieldset.tsx +0 -127
- package/src/components/Form/FormLiveRegion.tsx +0 -198
- package/src/components/Input/__mocks__/Input.tsx +0 -2
- package/src/components/NavigationMenu/types.ts +0 -85
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +0 -326
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -1078
- package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
- package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
- package/src/components/PasswordReset/index.ts +0 -2
- package/src/components/ProtectedRoute/README.md +0 -164
- package/src/components/PublicLayout/EventLogo.tsx +0 -175
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +0 -282
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +0 -216
- package/src/components/PublicLayout/PublicPageContextChecker.tsx +0 -131
- package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
- package/src/components/PublicLayout/PublicPageFooter.tsx +0 -124
- package/src/components/PublicLayout/PublicPageHeader.tsx +0 -209
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +0 -449
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +0 -393
- package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +0 -192
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +0 -351
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +0 -402
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +0 -460
- package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +0 -313
- package/src/components/Select/hooks.ts +0 -289
- package/src/hooks/useCounter.test.ts +0 -131
- package/src/hooks/useDebounce.test.ts +0 -375
- package/src/providers/AuthProvider.tsx +0 -15
- package/src/providers/EventProvider.tsx +0 -16
- package/src/providers/InactivityProvider.tsx +0 -15
- package/src/providers/OrganisationProvider.context.test.tsx +0 -169
- package/src/providers/UnifiedAuthProvider.tsx +0 -15
- package/src/types/theme.ts +0 -6
- package/src/types/unified.ts +0 -265
- package/src/utils/appConfig.ts +0 -47
- package/src/utils/appIdResolver.test.ts +0 -499
- package/src/utils/appIdResolver.ts +0 -130
- package/src/utils/appNameResolver.simple.test.ts +0 -212
- package/src/utils/appNameResolver.test.ts +0 -121
- package/src/utils/appNameResolver.ts +0 -191
- package/src/utils/audit.ts +0 -127
- package/src/utils/auth-utils.ts +0 -96
- package/src/utils/bundleAnalysis.ts +0 -129
- package/src/utils/debugLogger.ts +0 -67
- package/src/utils/deviceFingerprint.ts +0 -215
- package/src/utils/dynamicUtils.ts +0 -105
- package/src/utils/file-reference.test.ts +0 -788
- package/src/utils/file-reference.ts +0 -519
- package/src/utils/formatDate.test.ts +0 -237
- package/src/utils/formatting.ts +0 -170
- package/src/utils/lazyLoad.tsx +0 -44
- package/src/utils/logger.ts +0 -179
- package/src/utils/organisationContext.test.ts +0 -322
- package/src/utils/organisationContext.ts +0 -153
- package/src/utils/performanceBenchmark.ts +0 -64
- package/src/utils/performanceBudgets.ts +0 -110
- package/src/utils/permissionTypes.ts +0 -37
- package/src/utils/permissionUtils.test.ts +0 -393
- package/src/utils/permissionUtils.ts +0 -34
- package/src/utils/sanitization.ts +0 -264
- package/src/utils/schemaUtils.ts +0 -37
- package/src/utils/secureDataAccess.test.ts +0 -711
- package/src/utils/secureDataAccess.ts +0 -377
- package/src/utils/secureErrors.ts +0 -79
- package/src/utils/security.ts +0 -156
- package/src/utils/securityMonitor.ts +0 -45
- package/src/utils/sessionTracking.ts +0 -126
- package/src/utils/validation.ts +0 -111
- package/src/utils/validationUtils.ts +0 -120
- package/src/validation/index.ts +0 -12
- /package/dist/{DataTable-UA6CL4JI.js.map → DataTable-QAB34V6K.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-B37ATQHE.js.map → UnifiedAuthProvider-7F6T4B6K.js.map} +0 -0
- /package/dist/{api-45XYYO2A.js.map → api-ROMBCNKU.js.map} +0 -0
- /package/dist/{audit-64X3VJXB.js.map → audit-WRS3KJKI.js.map} +0 -0
- /package/dist/{chunk-PLDDJCW6.js.map → chunk-7D4SUZUM.js.map} +0 -0
- /package/dist/{useInactivityTracker-TO6ZOF35.js.map → chunk-KQCRWDSA.js.map} +0 -0
- /package/examples/{components 2/DataTable → DataTable}/InitialPageSizeExample.tsx +0 -0
- /package/examples/{features/public-pages → PublicPages}/index.ts +0 -0
- /package/examples/{RBAC → rbac}/index.ts +0 -0
package/src/rbac/hooks/index.ts
CHANGED
|
@@ -73,31 +73,17 @@ export function usePermissions(
|
|
|
73
73
|
// Normalize organisationId to empty string if undefined
|
|
74
74
|
const orgId = organisationId || '';
|
|
75
75
|
|
|
76
|
-
//
|
|
77
|
-
// This helps us see if React is calling the hook with updated scope
|
|
78
|
-
logger.warn('[usePermissions] Hook called with scope', {
|
|
79
|
-
userId,
|
|
80
|
-
organisationId: orgId,
|
|
81
|
-
eventId,
|
|
82
|
-
appId,
|
|
83
|
-
hasAppId: !!appId,
|
|
84
|
-
hasOrganisationId: !!orgId
|
|
85
|
-
});
|
|
86
|
-
|
|
87
|
-
// Log when scope changes to verify React detects the change
|
|
88
|
-
React.useEffect(() => {
|
|
89
|
-
logger.warn('[usePermissions] Scope changed (useEffect)', {
|
|
90
|
-
userId,
|
|
91
|
-
organisationId,
|
|
92
|
-
eventId,
|
|
93
|
-
appId,
|
|
94
|
-
hasAppId: !!appId,
|
|
95
|
-
hasOrganisationId: !!organisationId
|
|
96
|
-
});
|
|
97
|
-
}, [userId, organisationId, eventId, appId]);
|
|
76
|
+
// Removed excessive logging - only log when scope actually changes (not on every render)
|
|
98
77
|
|
|
99
78
|
// Add timeout for missing organisation context (3 seconds)
|
|
79
|
+
// OPTIMIZATION: Skip timeout if userId is null/undefined (indicates pre-filtered mode)
|
|
100
80
|
useEffect(() => {
|
|
81
|
+
// If userId is null/undefined, skip the timeout - this indicates items are pre-filtered
|
|
82
|
+
// and we don't need to wait for organisation context
|
|
83
|
+
if (!userId) {
|
|
84
|
+
return; // Skip timeout when userId is null (pre-filtered mode)
|
|
85
|
+
}
|
|
86
|
+
|
|
101
87
|
if (!orgId || orgId === null || (typeof orgId === 'string' && orgId.trim() === '')) {
|
|
102
88
|
const timeoutId = setTimeout(() => {
|
|
103
89
|
setError(new Error('Organisation context is required for permission checks'));
|
|
@@ -110,7 +96,7 @@ export function usePermissions(
|
|
|
110
96
|
if (error?.message === 'Organisation context is required for permission checks') {
|
|
111
97
|
setError(null);
|
|
112
98
|
}
|
|
113
|
-
}, [organisationId, error]);
|
|
99
|
+
}, [userId, organisationId, error]);
|
|
114
100
|
|
|
115
101
|
// CRITICAL: Detect parameter changes imperatively and trigger fetch
|
|
116
102
|
// This bypasses React's useEffect dependency tracking which is failing to detect appId changes
|
|
@@ -121,15 +107,13 @@ export function usePermissions(
|
|
|
121
107
|
prevValuesRef.current.appId !== appId;
|
|
122
108
|
|
|
123
109
|
if (paramsChanged) {
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
appIdChanged: prevValuesRef.current.appId !== appId
|
|
132
|
-
});
|
|
110
|
+
// Only log significant changes (appId changes are most important)
|
|
111
|
+
if (prevValuesRef.current.appId !== appId) {
|
|
112
|
+
logger.debug('[usePermissions] AppId changed - triggering fetch', {
|
|
113
|
+
prevAppId: prevValuesRef.current.appId,
|
|
114
|
+
newAppId: appId
|
|
115
|
+
});
|
|
116
|
+
}
|
|
133
117
|
prevValuesRef.current = { userId, organisationId, eventId, appId };
|
|
134
118
|
// Increment counter to force useEffect to run
|
|
135
119
|
setFetchTrigger(prev => prev + 1);
|
|
@@ -137,30 +121,12 @@ export function usePermissions(
|
|
|
137
121
|
|
|
138
122
|
useEffect(() => {
|
|
139
123
|
const fetchPermissions = async () => {
|
|
140
|
-
logger.warn('[usePermissions] Fetch useEffect triggered', {
|
|
141
|
-
userId,
|
|
142
|
-
orgId,
|
|
143
|
-
eventId,
|
|
144
|
-
appId,
|
|
145
|
-
hasAppId: !!appId,
|
|
146
|
-
isFetching: isFetchingRef.current
|
|
147
|
-
});
|
|
148
|
-
|
|
149
124
|
// Prevent multiple simultaneous fetches
|
|
150
125
|
if (isFetchingRef.current) {
|
|
151
|
-
logger.warn('[usePermissions] Skipping fetch - already fetching', {
|
|
152
|
-
userId,
|
|
153
|
-
scope: {
|
|
154
|
-
organisationId: orgId,
|
|
155
|
-
eventId: eventId,
|
|
156
|
-
appId: appId
|
|
157
|
-
}
|
|
158
|
-
});
|
|
159
126
|
return;
|
|
160
127
|
}
|
|
161
128
|
|
|
162
129
|
if (!userId) {
|
|
163
|
-
logger.warn('[usePermissions] Skipping fetch - no userId');
|
|
164
130
|
setPermissions({} as PermissionMap);
|
|
165
131
|
setIsLoading(false);
|
|
166
132
|
return;
|
|
@@ -169,39 +135,21 @@ export function usePermissions(
|
|
|
169
135
|
// Don't fetch permissions if scope is invalid (e.g., organisationId is null/empty)
|
|
170
136
|
// Wait for organisation context to resolve
|
|
171
137
|
// IMPORTANT: Don't clear existing permissions here - keep them until we have new ones
|
|
138
|
+
// OPTIMIZATION: If userId is null/undefined, immediately set loading to false
|
|
139
|
+
// This indicates pre-filtered mode where we don't need to wait for organisation context
|
|
140
|
+
if (!userId) {
|
|
141
|
+
setPermissions({} as PermissionMap);
|
|
142
|
+
setIsLoading(false);
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
|
|
172
146
|
if (!orgId || orgId === null || (typeof orgId === 'string' && orgId.trim() === '')) {
|
|
173
|
-
logger.warn('[usePermissions] Skipping fetch - no orgId', {
|
|
174
|
-
orgId,
|
|
175
|
-
hasOrgId: !!orgId
|
|
176
|
-
});
|
|
177
147
|
// Keep existing permissions, just mark as loading
|
|
178
148
|
setIsLoading(true);
|
|
179
149
|
setError(null);
|
|
180
150
|
return;
|
|
181
151
|
}
|
|
182
152
|
|
|
183
|
-
// Note: getPermissionMap can work without appId, but will return limited permissions
|
|
184
|
-
// In test environments, appId might be undefined, so we still attempt the fetch
|
|
185
|
-
// If appId is missing in production, it will return an empty map which is acceptable
|
|
186
|
-
if (!appId) {
|
|
187
|
-
logger.warn('[usePermissions] Fetching permissions without appId (may return limited permissions)', {
|
|
188
|
-
userId,
|
|
189
|
-
organisationId: orgId,
|
|
190
|
-
eventId: eventId,
|
|
191
|
-
hasAppId: false
|
|
192
|
-
});
|
|
193
|
-
// Continue with fetch - don't block on appId
|
|
194
|
-
}
|
|
195
|
-
logger.warn('[usePermissions] Fetching permissions', {
|
|
196
|
-
userId,
|
|
197
|
-
scope: {
|
|
198
|
-
organisationId: orgId,
|
|
199
|
-
eventId: eventId,
|
|
200
|
-
appId: appId
|
|
201
|
-
},
|
|
202
|
-
hasAppId: !!appId
|
|
203
|
-
});
|
|
204
|
-
|
|
205
153
|
try {
|
|
206
154
|
isFetchingRef.current = true;
|
|
207
155
|
setIsLoading(true);
|
|
@@ -217,15 +165,13 @@ export function usePermissions(
|
|
|
217
165
|
// Fetch new permissions - don't clear old ones until we have new ones
|
|
218
166
|
const permissionMap = await getPermissionMap({ userId, scope });
|
|
219
167
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
organisationId: orgId,
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
}
|
|
228
|
-
});
|
|
168
|
+
// Only log if there's a significant change or error
|
|
169
|
+
const permissionCount = Object.keys(permissionMap).length;
|
|
170
|
+
if (permissionCount === 0 && Object.keys(permissions).length > 0) {
|
|
171
|
+
logger.warn('[usePermissions] Permissions fetched but returned empty map', {
|
|
172
|
+
scope: { organisationId: orgId, eventId, appId }
|
|
173
|
+
});
|
|
174
|
+
}
|
|
229
175
|
|
|
230
176
|
// Only update permissions if fetch was successful
|
|
231
177
|
setPermissions(permissionMap);
|
|
@@ -152,6 +152,9 @@ describe('useRBAC', () => {
|
|
|
152
152
|
selectedEvent: null,
|
|
153
153
|
eventLoading: false,
|
|
154
154
|
});
|
|
155
|
+
mockResolveAppContext.mockResolvedValue({ appId: 'app-123' as any, hasAccess: true });
|
|
156
|
+
mockGetPermissionMap.mockResolvedValue({});
|
|
157
|
+
mockGetAccessLevel.mockResolvedValue('viewer');
|
|
155
158
|
mockGetRoleContext.mockResolvedValue({
|
|
156
159
|
globalRole: 'super_admin',
|
|
157
160
|
organisationRole: null,
|
|
@@ -160,8 +163,17 @@ describe('useRBAC', () => {
|
|
|
160
163
|
|
|
161
164
|
const { result } = renderHook(() => useRBAC());
|
|
162
165
|
|
|
163
|
-
await waitFor(() =>
|
|
166
|
+
await waitFor(() => {
|
|
167
|
+
expect(mockResolveAppContext).toHaveBeenCalled();
|
|
168
|
+
expect(mockGetRoleContext).toHaveBeenCalled();
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
await waitFor(() => {
|
|
172
|
+
expect(result.current.isLoading).toBe(false);
|
|
173
|
+
expect(result.current.globalRole).toBe('super_admin');
|
|
174
|
+
});
|
|
164
175
|
|
|
176
|
+
expect(result.current.globalRole).toBe('super_admin');
|
|
165
177
|
expect(result.current.isSuperAdmin).toBe(true);
|
|
166
178
|
expect(result.current.hasGlobalPermission('any')).toBe(true);
|
|
167
179
|
});
|
|
@@ -69,28 +69,7 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
69
69
|
// This prevents premature loading when appConfig hasn't loaded yet
|
|
70
70
|
const requiresEvent = appConfig?.requires_event ?? (appConfig === null ? true : false);
|
|
71
71
|
|
|
72
|
-
//
|
|
73
|
-
// Log hook initialization for debugging (use warn level so it's always visible)
|
|
74
|
-
// Also use direct console.log as fallback to ensure visibility
|
|
75
|
-
if (user && session) {
|
|
76
|
-
const hookInitLog = {
|
|
77
|
-
appName,
|
|
78
|
-
requiresEvent,
|
|
79
|
-
appConfig: appConfig ? JSON.stringify(appConfig) : 'null',
|
|
80
|
-
hasUser: !!user,
|
|
81
|
-
hasSession: !!session,
|
|
82
|
-
hasSelectedEvent: !!selectedEvent,
|
|
83
|
-
eventLoading,
|
|
84
|
-
selectedEventId: selectedEvent?.event_id,
|
|
85
|
-
hasSelectedOrganisation: !!selectedOrganisation,
|
|
86
|
-
organisationId: selectedOrganisation?.id,
|
|
87
|
-
orgContextReady,
|
|
88
|
-
orgLoading
|
|
89
|
-
};
|
|
90
|
-
logger.warn('[useRBAC] Hook initialized', hookInitLog);
|
|
91
|
-
// Direct console.log as fallback to ensure we can see if hook is called
|
|
92
|
-
console.warn('[useRBAC] Hook initialized (direct log)', hookInitLog);
|
|
93
|
-
}
|
|
72
|
+
// Removed excessive logging - hook initialization logged only on first mount or significant changes
|
|
94
73
|
|
|
95
74
|
const [globalRole, setGlobalRole] = useState<GlobalRole | null>(null);
|
|
96
75
|
const [organisationRole, setOrganisationRole] = useState<OrganisationRole | null>(null);
|
|
@@ -120,13 +99,6 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
120
99
|
// This is critical - without organisation ID, RPC calls can't resolve permissions
|
|
121
100
|
if (orgLoading || !orgContextReady || !selectedOrganisation?.id) {
|
|
122
101
|
setIsLoading(true);
|
|
123
|
-
logger.warn('[useRBAC] Waiting for organisation context before loading RBAC context', {
|
|
124
|
-
orgLoading,
|
|
125
|
-
orgContextReady,
|
|
126
|
-
hasSelectedOrganisation: !!selectedOrganisation,
|
|
127
|
-
organisationId: selectedOrganisation?.id,
|
|
128
|
-
appName
|
|
129
|
-
});
|
|
130
102
|
return;
|
|
131
103
|
}
|
|
132
104
|
|
|
@@ -138,13 +110,6 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
138
110
|
// This prevents premature RPC calls that can cause NetworkError
|
|
139
111
|
// Set loading state so React knows we're waiting
|
|
140
112
|
setIsLoading(true);
|
|
141
|
-
logger.warn('[useRBAC] Waiting for event context before loading RBAC context', {
|
|
142
|
-
eventLoading,
|
|
143
|
-
hasSelectedEvent: !!selectedEvent,
|
|
144
|
-
appName,
|
|
145
|
-
selectedEventId: selectedEvent?.event_id,
|
|
146
|
-
organisationId: selectedOrganisation?.id
|
|
147
|
-
});
|
|
148
113
|
return;
|
|
149
114
|
}
|
|
150
115
|
}
|
|
@@ -152,7 +117,9 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
152
117
|
setIsLoading(true);
|
|
153
118
|
setError(null);
|
|
154
119
|
|
|
155
|
-
|
|
120
|
+
// Only log at debug level - loading RBAC context is normal operation
|
|
121
|
+
// Changed from warn to debug to reduce console noise
|
|
122
|
+
logger.debug('[useRBAC] Loading RBAC context', {
|
|
156
123
|
appName,
|
|
157
124
|
requiresEvent,
|
|
158
125
|
hasSelectedEvent: !!selectedEvent,
|
|
@@ -195,15 +162,6 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
195
162
|
appId,
|
|
196
163
|
};
|
|
197
164
|
|
|
198
|
-
// Log scope to verify it's built correctly
|
|
199
|
-
logger.warn('[useRBAC] Building scope for RBAC context', {
|
|
200
|
-
organisationId: scope.organisationId,
|
|
201
|
-
eventId: scope.eventId,
|
|
202
|
-
appId: scope.appId,
|
|
203
|
-
hasOrganisationId: !!scope.organisationId,
|
|
204
|
-
hasEventId: !!scope.eventId
|
|
205
|
-
});
|
|
206
|
-
|
|
207
165
|
setCurrentScope(scope);
|
|
208
166
|
|
|
209
167
|
const [map, roleContext, accessLevel] = await Promise.all([
|
|
@@ -217,13 +175,15 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
217
175
|
setOrganisationRole(roleContext.organisationRole);
|
|
218
176
|
setEventAppRole(roleContext.eventAppRole || mapAccessLevelToEventRole(accessLevel));
|
|
219
177
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
178
|
+
// Only log on first successful load or if there's an issue
|
|
179
|
+
const permissionCount = Object.keys(map).length;
|
|
180
|
+
if (permissionCount === 0) {
|
|
181
|
+
logger.warn('[useRBAC] RBAC context loaded but returned 0 permissions', {
|
|
182
|
+
appName,
|
|
183
|
+
organisationId: selectedOrganisation.id,
|
|
184
|
+
eventId: selectedEvent?.event_id
|
|
185
|
+
});
|
|
186
|
+
}
|
|
227
187
|
} catch (err) {
|
|
228
188
|
const handledError = err instanceof Error ? err : new Error('Failed to load RBAC context');
|
|
229
189
|
logger.error('[useRBAC] Error loading RBAC context:', handledError);
|
|
@@ -260,20 +220,6 @@ export function useRBAC(pageId?: string): UserRBACContext {
|
|
|
260
220
|
const canManageEvent = useMemo(() => isSuperAdmin || eventAppRole === 'event_admin', [isSuperAdmin, eventAppRole]);
|
|
261
221
|
|
|
262
222
|
useEffect(() => {
|
|
263
|
-
// Log when effect runs to help debug
|
|
264
|
-
logger.warn('[useRBAC] useEffect triggered - calling loadRBACContext', {
|
|
265
|
-
appName,
|
|
266
|
-
requiresEvent,
|
|
267
|
-
eventLoading,
|
|
268
|
-
hasSelectedEvent: !!selectedEvent,
|
|
269
|
-
selectedEventId: selectedEvent?.event_id,
|
|
270
|
-
hasUser: !!user,
|
|
271
|
-
hasSession: !!session,
|
|
272
|
-
hasSelectedOrganisation: !!selectedOrganisation,
|
|
273
|
-
organisationId: selectedOrganisation?.id,
|
|
274
|
-
orgContextReady,
|
|
275
|
-
orgLoading
|
|
276
|
-
});
|
|
277
223
|
loadRBACContext();
|
|
278
224
|
}, [loadRBACContext, appName, requiresEvent, eventLoading, selectedEvent?.event_id, user, session, selectedOrganisation?.id, orgContextReady, orgLoading]);
|
|
279
225
|
|
|
@@ -108,6 +108,17 @@ export function useResolvedScope({
|
|
|
108
108
|
let cancelled = false;
|
|
109
109
|
|
|
110
110
|
const resolveScope = async () => {
|
|
111
|
+
// OPTIMIZATION: If all inputs are null/undefined, immediately return empty scope
|
|
112
|
+
// This indicates pre-filtered mode where we don't need to resolve scope
|
|
113
|
+
if (!supabase && !selectedOrganisationId && !selectedEventId) {
|
|
114
|
+
if (!cancelled) {
|
|
115
|
+
setResolvedScope(null);
|
|
116
|
+
setIsLoading(false);
|
|
117
|
+
setError(null);
|
|
118
|
+
}
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
|
|
111
122
|
setIsLoading(true);
|
|
112
123
|
setError(null);
|
|
113
124
|
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Secure Supabase Client Hook
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module RBAC/Hooks
|
|
5
|
+
* @since 1.0.0
|
|
6
|
+
*
|
|
7
|
+
* React hook for getting a secure Supabase client with automatic context injection
|
|
8
|
+
* and caching to prevent multiple client instances.
|
|
9
|
+
*
|
|
10
|
+
* ## Overview
|
|
11
|
+
*
|
|
12
|
+
* This hook provides a secure Supabase client that automatically injects
|
|
13
|
+
* organisation and event context for all database operations, while preventing
|
|
14
|
+
* the creation of multiple Supabase client instances (which causes the
|
|
15
|
+
* "Multiple GoTrueClient instances" warning).
|
|
16
|
+
*
|
|
17
|
+
* ## Features
|
|
18
|
+
*
|
|
19
|
+
* - **Automatic Context Injection**: Organisation, event, and app context are
|
|
20
|
+
* automatically injected into all database queries
|
|
21
|
+
* - **Client Instance Caching**: Prevents creating duplicate Supabase clients
|
|
22
|
+
* for the same context, eliminating the "Multiple GoTrueClient instances" warning
|
|
23
|
+
* - **Automatic Fallback**: Falls back to base client when context is unavailable
|
|
24
|
+
* - **Type-Safe**: Full TypeScript support with proper type inference
|
|
25
|
+
*
|
|
26
|
+
* ## Usage
|
|
27
|
+
*
|
|
28
|
+
* ### Basic Usage
|
|
29
|
+
*
|
|
30
|
+
* ```tsx
|
|
31
|
+
* import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
|
|
32
|
+
*
|
|
33
|
+
* function MyComponent() {
|
|
34
|
+
* const supabase = useSecureSupabase();
|
|
35
|
+
*
|
|
36
|
+
* if (!supabase) {
|
|
37
|
+
* return <div>Loading context...</div>;
|
|
38
|
+
* }
|
|
39
|
+
*
|
|
40
|
+
* const fetchData = async () => {
|
|
41
|
+
* const { data, error } = await supabase
|
|
42
|
+
* .from('users')
|
|
43
|
+
* .select('*');
|
|
44
|
+
* // Organisation context is automatically injected
|
|
45
|
+
* };
|
|
46
|
+
*
|
|
47
|
+
* return <div>...</div>;
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*
|
|
51
|
+
* ### With Base Client Fallback
|
|
52
|
+
*
|
|
53
|
+
* ```tsx
|
|
54
|
+
* import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
|
|
55
|
+
* import { supabase } from './lib/supabase';
|
|
56
|
+
*
|
|
57
|
+
* function MyComponent() {
|
|
58
|
+
* // Provide base client as fallback
|
|
59
|
+
* const secureSupabase = useSecureSupabase(supabase);
|
|
60
|
+
*
|
|
61
|
+
* // secureSupabase will be the secure client when context is available,
|
|
62
|
+
* // or the base client when context is unavailable
|
|
63
|
+
* }
|
|
64
|
+
* ```
|
|
65
|
+
*
|
|
66
|
+
* ## How It Works
|
|
67
|
+
*
|
|
68
|
+
* 1. **Context Resolution**: The hook uses `useResolvedScope` to get the current
|
|
69
|
+
* organisation, event, and app context
|
|
70
|
+
* 2. **Client Caching**: Clients are cached by context key (organisationId-eventId-appId)
|
|
71
|
+
* to prevent duplicate instances
|
|
72
|
+
* 3. **Automatic Injection**: The secure client automatically injects context headers
|
|
73
|
+
* into all database operations
|
|
74
|
+
* 4. **Fallback Behavior**: When context is unavailable or event is loading, the hook
|
|
75
|
+
* returns the base client (or null if no base client provided)
|
|
76
|
+
*
|
|
77
|
+
* ## Security
|
|
78
|
+
*
|
|
79
|
+
* - **Organisation Context Enforcement**: All queries automatically include organisation
|
|
80
|
+
* context, preventing cross-organisation data access
|
|
81
|
+
* - **Event Context Injection**: Event context is automatically included when available
|
|
82
|
+
* - **App Context Support**: App context is included when resolved from scope
|
|
83
|
+
*
|
|
84
|
+
* ## Performance
|
|
85
|
+
*
|
|
86
|
+
* - **Client Instance Caching**: Prevents creating multiple Supabase clients for the
|
|
87
|
+
* same context, reducing memory usage and eliminating the "Multiple GoTrueClient
|
|
88
|
+
* instances" warning
|
|
89
|
+
* - **Cache Management**: Automatically cleans up old cache entries (keeps last 5)
|
|
90
|
+
* to prevent memory leaks
|
|
91
|
+
* - **Stable References**: Returns stable client references to prevent unnecessary
|
|
92
|
+
* re-renders in consuming components
|
|
93
|
+
*
|
|
94
|
+
* ## Requirements
|
|
95
|
+
*
|
|
96
|
+
* - Must be used within `UnifiedAuthProvider` context
|
|
97
|
+
* - Requires `useOrganisations` and `useEvents` hooks to be available
|
|
98
|
+
* - Environment variables `VITE_SUPABASE_URL` and `VITE_SUPABASE_ANON_KEY` must be set
|
|
99
|
+
* (or `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY` for Next.js)
|
|
100
|
+
*
|
|
101
|
+
* ## See Also
|
|
102
|
+
*
|
|
103
|
+
* - {@link SecureSupabaseClient} - The underlying secure client class
|
|
104
|
+
* - {@link createSecureClient} - Function to create secure clients manually
|
|
105
|
+
* - {@link useResolvedScope} - Hook for resolving RBAC scope
|
|
106
|
+
*
|
|
107
|
+
* @security
|
|
108
|
+
* - Enforces organisation context on all queries
|
|
109
|
+
* - Prevents cross-organisation data access
|
|
110
|
+
* - Automatic context injection
|
|
111
|
+
*
|
|
112
|
+
* @performance
|
|
113
|
+
* - Client instance caching prevents duplicate creation
|
|
114
|
+
* - Reuses cached clients for same context
|
|
115
|
+
* - Automatic cache cleanup
|
|
116
|
+
*/
|
|
117
|
+
|
|
118
|
+
import { useMemo, useRef } from 'react';
|
|
119
|
+
import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
|
|
120
|
+
import { useOrganisations } from '../../hooks/useOrganisations';
|
|
121
|
+
import { useEvents } from '../../hooks/useEvents';
|
|
122
|
+
import { useResolvedScope } from './useResolvedScope';
|
|
123
|
+
import { createSecureClient, SecureSupabaseClient } from '../secureClient';
|
|
124
|
+
import type { Database } from '../../types/database';
|
|
125
|
+
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
126
|
+
import { logger } from '../../utils/core/logger';
|
|
127
|
+
|
|
128
|
+
// Cache secure clients by context to prevent creating multiple instances
|
|
129
|
+
// This prevents the "Multiple GoTrueClient instances" warning
|
|
130
|
+
const secureClientCache = new Map<string, SecureSupabaseClient>();
|
|
131
|
+
|
|
132
|
+
// Maximum cache size to prevent memory leaks
|
|
133
|
+
const MAX_CACHE_SIZE = 5;
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* Get cache key for secure client based on context
|
|
137
|
+
*/
|
|
138
|
+
function getCacheKey(
|
|
139
|
+
organisationId: string,
|
|
140
|
+
eventId: string | undefined,
|
|
141
|
+
appId: string | undefined
|
|
142
|
+
): string {
|
|
143
|
+
return `${organisationId}-${eventId || 'no-event'}-${appId || 'no-app'}`;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Get Supabase URL and key from environment
|
|
148
|
+
*/
|
|
149
|
+
function getSupabaseConfig(): { url: string; key: string } | null {
|
|
150
|
+
// Try to get from environment variables
|
|
151
|
+
const getEnvVar = (key: string): string | undefined => {
|
|
152
|
+
if (typeof import.meta !== 'undefined' && (import.meta as any).env) {
|
|
153
|
+
return (import.meta as any).env[key];
|
|
154
|
+
}
|
|
155
|
+
if (typeof process !== 'undefined' && process.env) {
|
|
156
|
+
return process.env[key];
|
|
157
|
+
}
|
|
158
|
+
return undefined;
|
|
159
|
+
};
|
|
160
|
+
|
|
161
|
+
const supabaseUrl = getEnvVar('VITE_SUPABASE_URL') ||
|
|
162
|
+
getEnvVar('NEXT_PUBLIC_SUPABASE_URL') ||
|
|
163
|
+
null;
|
|
164
|
+
|
|
165
|
+
const supabaseKey = getEnvVar('VITE_SUPABASE_ANON_KEY') ||
|
|
166
|
+
getEnvVar('NEXT_PUBLIC_SUPABASE_ANON_KEY') ||
|
|
167
|
+
null;
|
|
168
|
+
|
|
169
|
+
if (!supabaseUrl || !supabaseKey) {
|
|
170
|
+
return null;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return { url: supabaseUrl, key: supabaseKey };
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
/**
|
|
177
|
+
* Hook to get a secure Supabase client with automatic context injection
|
|
178
|
+
*
|
|
179
|
+
* Returns a secure client when organisation context is available,
|
|
180
|
+
* otherwise returns null. The client automatically injects organisation
|
|
181
|
+
* and event context into all database operations.
|
|
182
|
+
*
|
|
183
|
+
* Uses caching to prevent creating multiple Supabase client instances,
|
|
184
|
+
* which causes the "Multiple GoTrueClient instances" warning.
|
|
185
|
+
*
|
|
186
|
+
* @param baseClient - Optional base Supabase client to use as fallback
|
|
187
|
+
* @returns Secure Supabase client or null if context is not available
|
|
188
|
+
*
|
|
189
|
+
* @example
|
|
190
|
+
* ```tsx
|
|
191
|
+
* import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
|
|
192
|
+
*
|
|
193
|
+
* function MyComponent() {
|
|
194
|
+
* const supabase = useSecureSupabase();
|
|
195
|
+
*
|
|
196
|
+
* if (!supabase) {
|
|
197
|
+
* return <div>Loading context...</div>;
|
|
198
|
+
* }
|
|
199
|
+
*
|
|
200
|
+
* // Use supabase client - organisation context is automatically injected
|
|
201
|
+
* const { data } = await supabase.from('users').select('*');
|
|
202
|
+
* }
|
|
203
|
+
* ```
|
|
204
|
+
*/
|
|
205
|
+
export function useSecureSupabase(
|
|
206
|
+
baseClient?: SupabaseClient<Database> | null
|
|
207
|
+
): SupabaseClient<Database> | null {
|
|
208
|
+
const { user, supabase: authSupabase } = useUnifiedAuth();
|
|
209
|
+
const { selectedOrganisation } = useOrganisations();
|
|
210
|
+
const eventsContext = useEvents();
|
|
211
|
+
const { selectedEvent } = eventsContext;
|
|
212
|
+
const eventLoading = 'eventLoading' in eventsContext ? eventsContext.eventLoading : false;
|
|
213
|
+
|
|
214
|
+
// Resolve scope to get appId
|
|
215
|
+
const { resolvedScope } = useResolvedScope({
|
|
216
|
+
supabase: authSupabase || null,
|
|
217
|
+
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
218
|
+
selectedEventId: selectedEvent?.event_id || null
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
// Track previous context to detect changes
|
|
222
|
+
const prevContextRef = useRef<{
|
|
223
|
+
organisationId: string | undefined;
|
|
224
|
+
eventId: string | undefined;
|
|
225
|
+
appId: string | undefined;
|
|
226
|
+
}>({
|
|
227
|
+
organisationId: undefined,
|
|
228
|
+
eventId: undefined,
|
|
229
|
+
appId: undefined
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
return useMemo(() => {
|
|
233
|
+
// If event is loading, return base client or null to avoid recreating client unnecessarily
|
|
234
|
+
if (eventLoading) {
|
|
235
|
+
return baseClient || authSupabase || null;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// If we have organisation context, create or reuse a secure client
|
|
239
|
+
if (selectedOrganisation?.id && user?.id) {
|
|
240
|
+
const organisationId = selectedOrganisation.id;
|
|
241
|
+
const eventId = selectedEvent?.event_id;
|
|
242
|
+
|
|
243
|
+
// Get appId from resolved scope if available
|
|
244
|
+
const appId = resolvedScope?.appId;
|
|
245
|
+
|
|
246
|
+
// Update previous context
|
|
247
|
+
prevContextRef.current = { organisationId, eventId, appId };
|
|
248
|
+
|
|
249
|
+
// Check cache first
|
|
250
|
+
const cacheKey = getCacheKey(organisationId, eventId, appId);
|
|
251
|
+
const cachedClient = secureClientCache.get(cacheKey);
|
|
252
|
+
|
|
253
|
+
if (cachedClient) {
|
|
254
|
+
// Reuse cached client - prevents creating multiple instances
|
|
255
|
+
return cachedClient.getClient();
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
// Get Supabase configuration
|
|
259
|
+
const config = getSupabaseConfig();
|
|
260
|
+
if (!config || !config.url || !config.key) {
|
|
261
|
+
logger.warn('useSecureSupabase', 'Missing Supabase environment variables. Falling back to base client.', {
|
|
262
|
+
note: 'Ensure VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY are set in your environment.'
|
|
263
|
+
});
|
|
264
|
+
return baseClient || authSupabase || null;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
try {
|
|
268
|
+
const secureClient = createSecureClient(
|
|
269
|
+
config.url,
|
|
270
|
+
config.key,
|
|
271
|
+
organisationId as any, // organisationId is string, UUID is string alias
|
|
272
|
+
eventId,
|
|
273
|
+
appId as any // appId is string | undefined, UUID is string alias
|
|
274
|
+
);
|
|
275
|
+
|
|
276
|
+
// Cache the client for reuse
|
|
277
|
+
secureClientCache.set(cacheKey, secureClient);
|
|
278
|
+
|
|
279
|
+
// Clean up old cache entries to prevent memory leaks
|
|
280
|
+
if (secureClientCache.size > MAX_CACHE_SIZE) {
|
|
281
|
+
const firstKey = secureClientCache.keys().next().value;
|
|
282
|
+
if (firstKey) {
|
|
283
|
+
secureClientCache.delete(firstKey);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
// Return the underlying client for compatibility
|
|
288
|
+
return secureClient.getClient();
|
|
289
|
+
} catch (error) {
|
|
290
|
+
logger.error('useSecureSupabase', 'Failed to create secure client', error);
|
|
291
|
+
// Fallback to base client
|
|
292
|
+
return baseClient || authSupabase || null;
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Fallback to base client when context is not available
|
|
297
|
+
return baseClient || authSupabase || null;
|
|
298
|
+
}, [
|
|
299
|
+
selectedOrganisation?.id,
|
|
300
|
+
selectedEvent?.event_id,
|
|
301
|
+
user?.id,
|
|
302
|
+
eventLoading,
|
|
303
|
+
resolvedScope?.appId,
|
|
304
|
+
baseClient,
|
|
305
|
+
authSupabase
|
|
306
|
+
]);
|
|
307
|
+
}
|
|
308
|
+
|