@jmruthers/pace-core 0.5.68 → 0.5.69
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{DataTable-4IUY7BXB.js → DataTable-MPBSXUC6.js} +5 -6
- package/dist/{PublicLoadingSpinner-DdKXTkCZ.d.ts → PublicLoadingSpinner-BOdyU3u-.d.ts} +1 -1
- package/dist/{chunk-PXWEDX7Y.js → chunk-2ARQW6VX.js} +3 -3
- package/dist/{chunk-MOJXHWDE.js → chunk-6JILXFEA.js} +335 -5
- package/dist/chunk-6JILXFEA.js.map +1 -0
- package/dist/{chunk-D7ARGIA3.js → chunk-6RBH67W7.js} +23 -6
- package/dist/chunk-6RBH67W7.js.map +1 -0
- package/dist/{chunk-ZMS23NS5.js → chunk-FJTAWPAQ.js} +3 -5
- package/dist/{chunk-ZMS23NS5.js.map → chunk-FJTAWPAQ.js.map} +1 -1
- package/dist/{chunk-OPCWH3A4.js → chunk-NO5QHMDX.js} +7 -6
- package/dist/chunk-NO5QHMDX.js.map +1 -0
- package/dist/{chunk-ZPK5656W.js → chunk-O3NWNXDY.js} +4 -5
- package/dist/chunk-O3NWNXDY.js.map +1 -0
- package/dist/{chunk-UYA6U6H7.js → chunk-Q2UP3ZWQ.js} +4 -4
- package/dist/{chunk-KRCRNXPD.js → chunk-RVYGJPOD.js} +79 -18
- package/dist/chunk-RVYGJPOD.js.map +1 -0
- package/dist/{chunk-NN45OBIS.js → chunk-UCMHBF7Y.js} +3 -5
- package/dist/{chunk-NN45OBIS.js.map → chunk-UCMHBF7Y.js.map} +1 -1
- package/dist/{chunk-ZPG4XPV5.js → chunk-V3QO3LL7.js} +5 -7
- package/dist/chunk-V3QO3LL7.js.map +1 -0
- package/dist/{chunk-U6GPOF6J.js → chunk-ZXJGZLLO.js} +17 -17
- package/dist/{chunk-U6GPOF6J.js.map → chunk-ZXJGZLLO.js.map} +1 -1
- package/dist/components.d.ts +1 -1
- package/dist/components.js +8 -9
- package/dist/components.js.map +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +9 -6
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +16 -16
- package/dist/index.js.map +1 -1
- package/dist/providers.js +5 -7
- package/dist/rbac/index.js +5 -6
- package/dist/{usePublicRouteParams-CdoFxnJK.d.ts → usePublicRouteParams-Ua1Vz-HG.d.ts} +35 -1
- package/dist/utils.d.ts +4 -1
- package/dist/utils.js +3 -3
- package/docs/DOCUMENTATION_CHECKLIST.md +281 -0
- package/docs/README.md +22 -10
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- 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/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventContextType.md +1 -1
- package/docs/api/interfaces/EventLogoProps.md +1 -1
- package/docs/api/interfaces/EventProviderProps.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- 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/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +2 -2
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACContextType.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACProviderProps.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.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/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/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +39 -14
- package/docs/architecture/services.md +374 -0
- package/docs/best-practices/README.md +1 -1
- package/docs/best-practices/testing.md +1 -1
- package/docs/breaking-changes.md +182 -0
- package/docs/common-patterns.md +445 -0
- package/docs/core-concepts/authentication.md +26 -11
- package/docs/core-concepts/events.md +2 -0
- package/docs/core-concepts/organisations.md +2 -0
- package/docs/core-concepts/permissions.md +2 -0
- package/docs/{INDEX.md → documentation-index.md} +26 -38
- package/docs/faq.md +286 -0
- package/docs/{FILE_REFERENCE_SYSTEM.md → file-reference-system.md} +1 -1
- package/docs/getting-started/installation-guide.md +284 -0
- package/docs/getting-started/quick-start.md +8 -1
- package/docs/implementation-guides/app-layout.md +3 -1
- package/docs/implementation-guides/data-tables.md +2 -0
- package/docs/implementation-guides/dynamic-colors.md +47 -2
- package/docs/implementation-guides/event-theming-summary.md +220 -0
- package/docs/implementation-guides/forms.md +9 -7
- package/docs/implementation-guides/navigation.md +2 -0
- package/docs/migration/service-architecture.md +351 -0
- package/docs/rbac/README-rbac-rls-integration.md +2 -2
- package/docs/rbac/README.md +1 -1
- package/docs/rbac/examples/rbac-rls-integration-example.md +3 -3
- package/docs/rbac/quick-start.md +2 -0
- package/docs/rbac/rbac-rls-integration.md +2 -2
- package/docs/style-guide.md +136 -1
- package/docs/testing/README.md +1 -1
- package/docs/troubleshooting/authentication-issues.md +334 -0
- package/docs/troubleshooting/common-issues.md +2 -0
- package/docs/troubleshooting/styling-issues.md +199 -144
- package/docs/usage.md +23 -2
- package/package.json +1 -1
- package/src/__tests__/{TESTING_GUIDELINES.md → TEST_GUIDE_CURSOR.md} +20 -0
- package/src/__tests__/TEST_GUIDE_HUMAN.md +103 -0
- package/src/__tests__/fixtures/test-data.ts +90 -0
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +260 -0
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +224 -0
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +273 -0
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +98 -0
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +436 -0
- package/src/__tests__/helpers/__tests__/timer-utils.test.ts +371 -0
- package/src/__tests__/helpers/component-test-utils.tsx +14 -4
- package/src/__tests__/helpers/optimized-test-setup.ts +68 -0
- package/src/__tests__/helpers/test-providers.tsx +329 -0
- package/src/__tests__/helpers/test-utils.tsx +91 -45
- package/src/__tests__/helpers/timer-utils.ts +71 -0
- package/src/__tests__/hooks/usePermissions.test.ts +1 -5
- package/src/__tests__/integration/UserProfile.test.tsx +1 -5
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +42 -12
- package/src/__tests__/setup.ts +34 -28
- package/src/components/Alert/Alert.test.tsx +1 -5
- package/src/components/Avatar/Avatar.test.tsx +1 -5
- package/src/components/Button/Button.test.tsx +4 -20
- package/src/components/Card/Card.test.tsx +1 -5
- package/src/components/Checkbox/Checkbox.test.tsx +1 -5
- package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +1 -5
- package/src/components/DataTable/__tests__/DataTable.test.tsx +45 -49
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +1 -5
- package/src/components/DataTable/__tests__/styles.test.ts +382 -0
- package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +409 -0
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +634 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +519 -0
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +714 -0
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +592 -0
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +354 -0
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +539 -0
- package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +1 -5
- package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +1 -8
- package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +34 -38
- package/src/components/Footer/Footer.test.tsx +1 -5
- package/src/components/Form/Form.test.tsx +22 -35
- package/src/components/Header/Header.test.tsx +1 -9
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +1 -5
- package/src/components/Input/Input.test.tsx +2 -10
- package/src/components/LoginForm/LoginForm.test.tsx +1 -5
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +24 -24
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +1 -6
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +6 -16
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +1 -5
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +1 -5
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +1 -7
- package/src/components/PasswordReset/PasswordChangeForm.test.tsx +1 -9
- package/src/components/PasswordReset/PasswordResetForm.test.tsx +1 -9
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +4 -5
- package/src/components/PublicLayout/PublicPageHeader.tsx +13 -9
- package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +666 -0
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +457 -0
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +393 -0
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +351 -0
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +374 -0
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +388 -0
- package/src/components/Select/Select.bug-test.tsx +69 -0
- package/src/components/Select/Select.refactored.tsx +497 -0
- package/src/components/Select/Select.test.tsx +42 -49
- package/src/components/Select/Select.tsx +5 -2
- package/src/components/Select/hooks.ts +254 -0
- package/src/components/Switch/Switch.test.tsx +1 -5
- package/src/components/Table/__tests__/Table.test.tsx +775 -0
- package/src/components/Toast/Toast.test.tsx +15 -8
- package/src/components/Tooltip/Tooltip.test.tsx +1 -5
- package/src/components/UserMenu/UserMenu.test.tsx +3 -15
- package/src/components/__tests__/FileDisplay.test.tsx +575 -0
- package/src/components/__tests__/FileUpload.test.tsx +446 -0
- package/src/components/__tests__/SuperAdminGuard.test.tsx +422 -354
- package/src/hooks/__tests__/ServiceHooks.test.tsx +613 -0
- package/src/hooks/__tests__/hooks.integration.test.tsx +1 -10
- package/src/hooks/__tests__/useApiFetch.unit.test.ts +10 -14
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +307 -0
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +1 -6
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +1 -5
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +6 -9
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +321 -0
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
- package/src/hooks/__tests__/usePublicEventLogo.unit.test.ts +640 -0
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +435 -0
- package/src/hooks/__tests__/useRBAC.unit.test.ts +10 -10
- package/src/hooks/__tests__/useStorage.unit.test.ts +751 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/public/usePublicEvent.ts +30 -9
- package/src/hooks/public/usePublicRouteParams.ts +13 -3
- package/src/hooks/services/useAuth.ts +50 -0
- package/src/hooks/services/useAuthService.ts +30 -0
- package/src/hooks/services/useCurrentEvent.ts +36 -0
- package/src/hooks/services/useCurrentOrganisation.ts +52 -0
- package/src/hooks/services/useEventService.ts +30 -0
- package/src/hooks/services/useInactivityService.ts +30 -0
- package/src/hooks/services/useOrganisationService.ts +30 -0
- package/src/hooks/services/usePermissions.ts +70 -0
- package/src/hooks/services/useRBACService.ts +30 -0
- package/src/hooks/useCounter.test.ts +1 -5
- package/src/hooks/useEventTheme.ts +86 -0
- package/src/hooks/useOrganisationPermissions.test.ts +2 -5
- package/src/hooks/useOrganisationSecurity.test.ts +1 -5
- package/src/hooks/usePermissionCache.test.ts +1 -5
- package/src/hooks/usePermissionCheck.ts +150 -0
- package/src/hooks/useSecureDataAccess.test.ts +1 -5
- package/src/index.ts +1 -0
- package/src/providers/OrganisationProvider.test.tsx +1 -5
- package/src/providers/OrganisationProvider.tsx +56 -4
- package/src/providers/UnifiedAuthProvider.test.tsx +1 -5
- package/src/providers/__tests__/AuthProvider.test.tsx +105 -439
- package/src/providers/__tests__/AuthProvider.test.tsx.backup +771 -0
- package/src/providers/__tests__/EventProvider.test.tsx +211 -110
- package/src/providers/__tests__/EventProvider.test.tsx.backup +824 -0
- package/src/providers/__tests__/InactivityProvider.test.tsx +1 -5
- package/src/providers/__tests__/OrganisationProvider.test.tsx +97 -261
- package/src/providers/__tests__/OrganisationProvider.test.tsx.backup +820 -0
- package/src/providers/__tests__/ServiceProviders.test.tsx +477 -0
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +72 -504
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup +911 -0
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup2 +166 -0
- package/src/providers/services/AuthServiceProvider.tsx +65 -0
- package/src/providers/services/EventServiceProvider.tsx +83 -0
- package/src/providers/services/InactivityServiceProvider.tsx +83 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +77 -0
- package/src/providers/services/RBACServiceProvider.tsx +79 -0
- package/src/providers/services/UnifiedAuthProvider.tsx +368 -0
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +210 -0
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +269 -0
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +892 -0
- package/src/rbac/__tests__/engine.comprehensive.test.ts +954 -0
- package/src/rbac/__tests__/integration.authflow.test.tsx +1 -5
- package/src/rbac/__tests__/integration.navigation.test.tsx +1 -4
- package/src/rbac/__tests__/rbac-core.test.tsx +2 -7
- package/src/rbac/__tests__/rbac-functions.test.ts +1 -9
- package/src/rbac/__tests__/rbac-integration.test.ts +1 -9
- package/src/rbac/api.test.ts +1 -9
- package/src/rbac/cache.test.ts +10 -8
- package/src/rbac/cli/__tests__/policy-manager.test.ts +339 -0
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +1 -5
- package/src/rbac/components/NavigationProvider.test.tsx +1 -5
- package/src/rbac/components/PagePermissionProvider.test.tsx +1 -5
- package/src/rbac/components/SecureDataProvider.test.tsx +1 -5
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +25 -29
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +27 -30
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +23 -27
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +18 -22
- package/src/rbac/config.test.ts +1 -5
- package/src/rbac/hooks/useCan.test.ts +262 -9
- package/src/rbac/hooks/usePermissions.test.ts +246 -6
- package/src/rbac/hooks/useRBAC.simple.test.ts +1 -5
- package/src/rbac/hooks/useRBAC.test.ts +472 -198
- package/src/rbac/providers/__tests__/RBACProvider.test.tsx +1 -9
- package/src/services/AuthService.ts +416 -0
- package/src/services/EventService.ts +366 -0
- package/src/services/InactivityService.ts +388 -0
- package/src/services/OrganisationService.ts +592 -0
- package/src/services/RBACService.ts +522 -0
- package/src/services/__tests__/AuthService.test.ts +356 -0
- package/src/services/__tests__/BaseService.test.ts +314 -0
- package/src/services/__tests__/EventService.test.ts +489 -0
- package/src/services/__tests__/InactivityService.test.ts +403 -0
- package/src/services/__tests__/OrganisationService.test.ts +660 -0
- package/src/services/__tests__/RBACService.test.ts +492 -0
- package/src/services/base/BaseService.ts +87 -0
- package/src/services/interfaces/IAuthService.ts +39 -0
- package/src/services/interfaces/IEventService.ts +30 -0
- package/src/services/interfaces/IInactivityService.ts +31 -0
- package/src/services/interfaces/IOrganisationService.ts +41 -0
- package/src/services/interfaces/IRBACService.ts +62 -0
- package/src/theming/__tests__/runtime.test.ts +540 -0
- package/src/types/__tests__/file-reference.test.ts +447 -0
- package/src/types/__tests__/organisation.test.ts +1133 -0
- package/src/types/__tests__/theme.test.ts +830 -0
- package/src/types/__tests__/type-validation.test.ts +527 -0
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +1 -5
- package/src/utils/__tests__/debugLogger.test.ts +417 -0
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -6
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -5
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +35 -35
- package/src/utils/__tests__/organisationContext.unit.test.ts +1 -5
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +5 -11
- package/src/utils/__tests__/secureErrors.unit.test.ts +1 -6
- package/src/utils/__tests__/secureStorage.unit.test.ts +1 -5
- package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -5
- package/src/utils/__tests__/sessionTracking.unit.test.ts +1 -5
- package/src/utils/appIdResolver.test.ts +6 -10
- package/src/utils/appNameResolver.simple.test.ts +142 -0
- package/src/utils/appNameResolver.test.ts +31 -458
- package/src/utils/appNameResolver.test.ts.backup +494 -0
- package/src/utils/debugLogger.ts +26 -5
- package/src/utils/formatDate.test.ts +1 -5
- package/src/utils/organisationContext.test.ts +1 -5
- package/src/utils/performanceBudgets.ts +3 -4
- package/src/utils/secureDataAccess.test.ts +1 -5
- package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -5
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +1 -5
- package/dist/chunk-D7ARGIA3.js.map +0 -1
- package/dist/chunk-IPCH4YPT.js +0 -315
- package/dist/chunk-IPCH4YPT.js.map +0 -1
- package/dist/chunk-KRCRNXPD.js.map +0 -1
- package/dist/chunk-MOJXHWDE.js.map +0 -1
- package/dist/chunk-OPCWH3A4.js.map +0 -1
- package/dist/chunk-ZPG4XPV5.js.map +0 -1
- package/dist/chunk-ZPK5656W.js.map +0 -1
- package/docs/getting-started/installation.md +0 -269
- package/src/__tests__/REBUILD_PLAN.md +0 -223
- /package/dist/{DataTable-4IUY7BXB.js.map → DataTable-MPBSXUC6.js.map} +0 -0
- /package/dist/{chunk-PXWEDX7Y.js.map → chunk-2ARQW6VX.js.map} +0 -0
- /package/dist/{chunk-UYA6U6H7.js.map → chunk-Q2UP3ZWQ.js.map} +0 -0
|
@@ -0,0 +1,494 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file App Name Resolver Tests
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Utils/AppNameResolver
|
|
5
|
+
* @since 1.0.0
|
|
6
|
+
*
|
|
7
|
+
* Comprehensive tests for app name resolution utility functions covering all critical functionality.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
11
|
+
import {
|
|
12
|
+
getAppNameFromPackageJson,
|
|
13
|
+
getAppNameFromBuildTime,
|
|
14
|
+
getAppNameFromGlobal,
|
|
15
|
+
getAppNameFromEnvironment,
|
|
16
|
+
getCurrentAppName,
|
|
17
|
+
setRBACAppName
|
|
18
|
+
} from './appNameResolver';
|
|
19
|
+
|
|
20
|
+
// Mock Node.js modules
|
|
21
|
+
const mockFs = {
|
|
22
|
+
existsSync: vi.fn(),
|
|
23
|
+
readFileSync: vi.fn()
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
const mockPath = {
|
|
27
|
+
join: vi.fn()
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
vi.mock('fs', () => mockFs);
|
|
31
|
+
vi.mock('path', () => mockPath);
|
|
32
|
+
|
|
33
|
+
describe('App Name Resolver', () => {
|
|
34
|
+
beforeEach(() => {
|
|
35
|
+
vi.clearAllMocks();
|
|
36
|
+
// Reset global variables
|
|
37
|
+
delete (globalThis as any).__RBAC_APP_NAME__;
|
|
38
|
+
delete (globalThis as any).RBAC_APP_NAME;
|
|
39
|
+
delete (globalThis as any).process;
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
afterEach(() => {
|
|
43
|
+
vi.restoreAllMocks();
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
describe('getAppNameFromPackageJson', () => {
|
|
47
|
+
it('reads app name from package.json in Node.js environment', () => {
|
|
48
|
+
// Mock Node.js environment
|
|
49
|
+
Object.defineProperty(global, 'window', { value: undefined, writable: true });
|
|
50
|
+
Object.defineProperty(global, 'require', { value: vi.fn(), writable: true });
|
|
51
|
+
|
|
52
|
+
mockPath.join.mockReturnValue('/path/to/package.json');
|
|
53
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
54
|
+
mockFs.readFileSync.mockReturnValue(JSON.stringify({ name: '@org/my-app' }));
|
|
55
|
+
|
|
56
|
+
const result = getAppNameFromPackageJson();
|
|
57
|
+
|
|
58
|
+
expect(result).toBe('my-app');
|
|
59
|
+
expect(mockPath.join).toHaveBeenCalledWith(expect.any(String), 'package.json');
|
|
60
|
+
expect(mockFs.existsSync).toHaveBeenCalledWith('/path/to/package.json');
|
|
61
|
+
expect(mockFs.readFileSync).toHaveBeenCalledWith('/path/to/package.json', 'utf8');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('handles scoped packages correctly', () => {
|
|
65
|
+
Object.defineProperty(global, 'window', { value: undefined, writable: true });
|
|
66
|
+
Object.defineProperty(global, 'require', { value: vi.fn(), writable: true });
|
|
67
|
+
|
|
68
|
+
mockPath.join.mockReturnValue('/path/to/package.json');
|
|
69
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
70
|
+
mockFs.readFileSync.mockReturnValue(JSON.stringify({ name: '@myorg/super-app' }));
|
|
71
|
+
|
|
72
|
+
const result = getAppNameFromPackageJson();
|
|
73
|
+
|
|
74
|
+
expect(result).toBe('super-app');
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it('handles non-scoped packages correctly', () => {
|
|
78
|
+
Object.defineProperty(global, 'window', { value: undefined, writable: true });
|
|
79
|
+
Object.defineProperty(global, 'require', { value: vi.fn(), writable: true });
|
|
80
|
+
|
|
81
|
+
mockPath.join.mockReturnValue('/path/to/package.json');
|
|
82
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
83
|
+
mockFs.readFileSync.mockReturnValue(JSON.stringify({ name: 'my-app' }));
|
|
84
|
+
|
|
85
|
+
const result = getAppNameFromPackageJson();
|
|
86
|
+
|
|
87
|
+
expect(result).toBe('my-app');
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('tries multiple package.json paths', () => {
|
|
91
|
+
Object.defineProperty(global, 'window', { value: undefined, writable: true });
|
|
92
|
+
Object.defineProperty(global, 'require', { value: vi.fn(), writable: true });
|
|
93
|
+
|
|
94
|
+
mockPath.join
|
|
95
|
+
.mockReturnValueOnce('/path/to/package.json')
|
|
96
|
+
.mockReturnValueOnce('/path/to/../../package.json')
|
|
97
|
+
.mockReturnValueOnce('/path/to/../../../package.json');
|
|
98
|
+
|
|
99
|
+
mockFs.existsSync
|
|
100
|
+
.mockReturnValueOnce(false)
|
|
101
|
+
.mockReturnValueOnce(false)
|
|
102
|
+
.mockReturnValueOnce(true);
|
|
103
|
+
|
|
104
|
+
mockFs.readFileSync.mockReturnValue(JSON.stringify({ name: 'my-app' }));
|
|
105
|
+
|
|
106
|
+
const result = getAppNameFromPackageJson();
|
|
107
|
+
|
|
108
|
+
expect(result).toBe('my-app');
|
|
109
|
+
expect(mockPath.join).toHaveBeenCalledTimes(3);
|
|
110
|
+
expect(mockFs.existsSync).toHaveBeenCalledTimes(3);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it('returns null in browser environment', () => {
|
|
114
|
+
Object.defineProperty(global, 'window', { value: {}, writable: true });
|
|
115
|
+
|
|
116
|
+
const result = getAppNameFromPackageJson();
|
|
117
|
+
|
|
118
|
+
expect(result).toBeNull();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('handles missing package.json gracefully', () => {
|
|
122
|
+
Object.defineProperty(global, 'window', { value: undefined, writable: true });
|
|
123
|
+
Object.defineProperty(global, 'require', { value: vi.fn(), writable: true });
|
|
124
|
+
|
|
125
|
+
mockPath.join.mockReturnValue('/path/to/package.json');
|
|
126
|
+
mockFs.existsSync.mockReturnValue(false);
|
|
127
|
+
|
|
128
|
+
const result = getAppNameFromPackageJson();
|
|
129
|
+
|
|
130
|
+
expect(result).toBeNull();
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it('handles invalid JSON gracefully', () => {
|
|
134
|
+
Object.defineProperty(global, 'window', { value: undefined, writable: true });
|
|
135
|
+
Object.defineProperty(global, 'require', { value: vi.fn(), writable: true });
|
|
136
|
+
|
|
137
|
+
mockPath.join.mockReturnValue('/path/to/package.json');
|
|
138
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
139
|
+
mockFs.readFileSync.mockReturnValue('invalid json');
|
|
140
|
+
|
|
141
|
+
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
142
|
+
|
|
143
|
+
const result = getAppNameFromPackageJson();
|
|
144
|
+
|
|
145
|
+
expect(result).toBeNull();
|
|
146
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
147
|
+
'[RBAC] Could not read app name from package.json:',
|
|
148
|
+
expect.any(Error)
|
|
149
|
+
);
|
|
150
|
+
|
|
151
|
+
consoleSpy.mockRestore();
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('handles missing name field in package.json', () => {
|
|
155
|
+
Object.defineProperty(global, 'window', { value: undefined, writable: true });
|
|
156
|
+
Object.defineProperty(global, 'require', { value: vi.fn(), writable: true });
|
|
157
|
+
|
|
158
|
+
mockPath.join.mockReturnValue('/path/to/package.json');
|
|
159
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
160
|
+
mockFs.readFileSync.mockReturnValue(JSON.stringify({ version: '1.0.0' }));
|
|
161
|
+
|
|
162
|
+
const result = getAppNameFromPackageJson();
|
|
163
|
+
|
|
164
|
+
expect(result).toBeNull();
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('getAppNameFromBuildTime', () => {
|
|
169
|
+
it('reads app name from build-time injected variable', () => {
|
|
170
|
+
(globalThis as any).__RBAC_APP_NAME__ = 'my-app';
|
|
171
|
+
|
|
172
|
+
const result = getAppNameFromBuildTime();
|
|
173
|
+
|
|
174
|
+
expect(result).toBe('my-app');
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it('trims whitespace from build-time variable', () => {
|
|
178
|
+
(globalThis as any).__RBAC_APP_NAME__ = ' my-app ';
|
|
179
|
+
|
|
180
|
+
const result = getAppNameFromBuildTime();
|
|
181
|
+
|
|
182
|
+
expect(result).toBe('my-app');
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
it('returns null when build-time variable is not set', () => {
|
|
186
|
+
const result = getAppNameFromBuildTime();
|
|
187
|
+
|
|
188
|
+
expect(result).toBeNull();
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
it('returns null when build-time variable is empty', () => {
|
|
192
|
+
(globalThis as any).__RBAC_APP_NAME__ = '';
|
|
193
|
+
|
|
194
|
+
const result = getAppNameFromBuildTime();
|
|
195
|
+
|
|
196
|
+
expect(result).toBeNull();
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
it('handles errors gracefully', () => {
|
|
200
|
+
// Mock globalThis access to throw error
|
|
201
|
+
Object.defineProperty(globalThis, '__RBAC_APP_NAME__', {
|
|
202
|
+
get: () => { throw new Error('Access denied'); }
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const result = getAppNameFromBuildTime();
|
|
206
|
+
|
|
207
|
+
expect(result).toBeNull();
|
|
208
|
+
});
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
describe('getAppNameFromGlobal', () => {
|
|
212
|
+
it('reads app name from global variable', () => {
|
|
213
|
+
(globalThis as any).RBAC_APP_NAME = 'my-app';
|
|
214
|
+
|
|
215
|
+
const result = getAppNameFromGlobal();
|
|
216
|
+
|
|
217
|
+
expect(result).toBe('my-app');
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
it('trims whitespace from global variable', () => {
|
|
221
|
+
(globalThis as any).RBAC_APP_NAME = ' my-app ';
|
|
222
|
+
|
|
223
|
+
const result = getAppNameFromGlobal();
|
|
224
|
+
|
|
225
|
+
expect(result).toBe('my-app');
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
it('returns null when global variable is not set', () => {
|
|
229
|
+
const result = getAppNameFromGlobal();
|
|
230
|
+
|
|
231
|
+
expect(result).toBeNull();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('returns null when global variable is empty', () => {
|
|
235
|
+
(globalThis as any).RBAC_APP_NAME = '';
|
|
236
|
+
|
|
237
|
+
const result = getAppNameFromGlobal();
|
|
238
|
+
|
|
239
|
+
expect(result).toBeNull();
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('handles errors gracefully', () => {
|
|
243
|
+
// Mock globalThis access to throw error
|
|
244
|
+
Object.defineProperty(globalThis, 'RBAC_APP_NAME', {
|
|
245
|
+
get: () => { throw new Error('Access denied'); }
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
const result = getAppNameFromGlobal();
|
|
249
|
+
|
|
250
|
+
expect(result).toBeNull();
|
|
251
|
+
});
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
describe('getAppNameFromEnvironment', () => {
|
|
255
|
+
it('reads app name from environment variable', () => {
|
|
256
|
+
const originalEnv = process.env;
|
|
257
|
+
process.env = { ...originalEnv, RBAC_APP_NAME: 'my-app' };
|
|
258
|
+
|
|
259
|
+
const result = getAppNameFromEnvironment();
|
|
260
|
+
|
|
261
|
+
expect(result).toBe('my-app');
|
|
262
|
+
|
|
263
|
+
process.env = originalEnv;
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
it('trims whitespace from environment variable', () => {
|
|
267
|
+
const originalEnv = process.env;
|
|
268
|
+
process.env = { ...originalEnv, RBAC_APP_NAME: ' my-app ' };
|
|
269
|
+
|
|
270
|
+
const result = getAppNameFromEnvironment();
|
|
271
|
+
|
|
272
|
+
expect(result).toBe('my-app');
|
|
273
|
+
|
|
274
|
+
process.env = originalEnv;
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('returns null when environment variable is not set', () => {
|
|
278
|
+
const originalEnv = process.env;
|
|
279
|
+
process.env = { ...originalEnv };
|
|
280
|
+
delete process.env.RBAC_APP_NAME;
|
|
281
|
+
|
|
282
|
+
const result = getAppNameFromEnvironment();
|
|
283
|
+
|
|
284
|
+
expect(result).toBeNull();
|
|
285
|
+
|
|
286
|
+
process.env = originalEnv;
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('returns null when environment variable is empty', () => {
|
|
290
|
+
const originalEnv = process.env;
|
|
291
|
+
process.env = { ...originalEnv, RBAC_APP_NAME: '' };
|
|
292
|
+
|
|
293
|
+
const result = getAppNameFromEnvironment();
|
|
294
|
+
|
|
295
|
+
expect(result).toBeNull();
|
|
296
|
+
|
|
297
|
+
process.env = originalEnv;
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
describe('getCurrentAppName', () => {
|
|
302
|
+
it('returns app name from build-time variable (highest priority)', () => {
|
|
303
|
+
(globalThis as any).__RBAC_APP_NAME__ = 'build-time-app';
|
|
304
|
+
(globalThis as any).RBAC_APP_NAME = 'global-app';
|
|
305
|
+
|
|
306
|
+
const originalEnv = process.env;
|
|
307
|
+
process.env = { ...originalEnv, RBAC_APP_NAME: 'env-app' };
|
|
308
|
+
|
|
309
|
+
const result = getCurrentAppName();
|
|
310
|
+
|
|
311
|
+
expect(result).toBe('build-time-app');
|
|
312
|
+
|
|
313
|
+
process.env = originalEnv;
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
it('falls back to global variable when build-time is not available', () => {
|
|
317
|
+
(globalThis as any).RBAC_APP_NAME = 'global-app';
|
|
318
|
+
|
|
319
|
+
const originalEnv = process.env;
|
|
320
|
+
process.env = { ...originalEnv, RBAC_APP_NAME: 'env-app' };
|
|
321
|
+
|
|
322
|
+
const result = getCurrentAppName();
|
|
323
|
+
|
|
324
|
+
expect(result).toBe('global-app');
|
|
325
|
+
|
|
326
|
+
process.env = originalEnv;
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
it('falls back to environment variable when others are not available', () => {
|
|
330
|
+
const originalEnv = process.env;
|
|
331
|
+
process.env = { ...originalEnv, RBAC_APP_NAME: 'env-app' };
|
|
332
|
+
|
|
333
|
+
const result = getCurrentAppName();
|
|
334
|
+
|
|
335
|
+
expect(result).toBe('env-app');
|
|
336
|
+
|
|
337
|
+
process.env = originalEnv;
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('falls back to package.json when others are not available', () => {
|
|
341
|
+
Object.defineProperty(global, 'window', { value: undefined, writable: true });
|
|
342
|
+
Object.defineProperty(global, 'require', { value: vi.fn(), writable: true });
|
|
343
|
+
|
|
344
|
+
mockPath.join.mockReturnValue('/path/to/package.json');
|
|
345
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
346
|
+
mockFs.readFileSync.mockReturnValue(JSON.stringify({ name: 'package-app' }));
|
|
347
|
+
|
|
348
|
+
const result = getCurrentAppName();
|
|
349
|
+
|
|
350
|
+
expect(result).toBe('package-app');
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('returns fallback when all methods fail', () => {
|
|
354
|
+
const result = getCurrentAppName();
|
|
355
|
+
|
|
356
|
+
expect(result).toBe('pace-core');
|
|
357
|
+
});
|
|
358
|
+
});
|
|
359
|
+
|
|
360
|
+
describe('setRBACAppName', () => {
|
|
361
|
+
it('sets global app name variable', () => {
|
|
362
|
+
setRBACAppName('my-app');
|
|
363
|
+
|
|
364
|
+
expect((globalThis as any).RBAC_APP_NAME).toBe('my-app');
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
it('trims whitespace when setting app name', () => {
|
|
368
|
+
setRBACAppName(' my-app ');
|
|
369
|
+
|
|
370
|
+
expect((globalThis as any).RBAC_APP_NAME).toBe('my-app');
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
it('handles null/undefined app name', () => {
|
|
374
|
+
setRBACAppName(null as any);
|
|
375
|
+
setRBACAppName(undefined as any);
|
|
376
|
+
|
|
377
|
+
expect((globalThis as any).RBAC_APP_NAME).toBeUndefined();
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it('handles empty app name', () => {
|
|
381
|
+
setRBACAppName('');
|
|
382
|
+
|
|
383
|
+
expect((globalThis as any).RBAC_APP_NAME).toBe('');
|
|
384
|
+
});
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
describe('Integration Tests', () => {
|
|
388
|
+
it('works with real-world scenarios', () => {
|
|
389
|
+
// Test build-time injection
|
|
390
|
+
(globalThis as any).__RBAC_APP_NAME__ = 'production-app';
|
|
391
|
+
expect(getCurrentAppName()).toBe('production-app');
|
|
392
|
+
|
|
393
|
+
// Test global variable fallback
|
|
394
|
+
delete (globalThis as any).__RBAC_APP_NAME__;
|
|
395
|
+
(globalThis as any).RBAC_APP_NAME = 'development-app';
|
|
396
|
+
expect(getCurrentAppName()).toBe('development-app');
|
|
397
|
+
|
|
398
|
+
// Test environment variable fallback
|
|
399
|
+
delete (globalThis as any).RBAC_APP_NAME__;
|
|
400
|
+
const originalEnv = process.env;
|
|
401
|
+
process.env = { ...originalEnv, RBAC_APP_NAME: 'test-app' };
|
|
402
|
+
expect(getCurrentAppName()).toBe('test-app');
|
|
403
|
+
|
|
404
|
+
process.env = originalEnv;
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
it('handles complex app name patterns', () => {
|
|
408
|
+
const appNames = [
|
|
409
|
+
'my-app',
|
|
410
|
+
'my_app',
|
|
411
|
+
'MyApp',
|
|
412
|
+
'myapp',
|
|
413
|
+
'@org/my-app',
|
|
414
|
+
'my-app-v2',
|
|
415
|
+
'my-app@1.0.0'
|
|
416
|
+
];
|
|
417
|
+
|
|
418
|
+
appNames.forEach(appName => {
|
|
419
|
+
setRBACAppName(appName);
|
|
420
|
+
expect(getCurrentAppName()).toBe(appName);
|
|
421
|
+
});
|
|
422
|
+
});
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
describe('Error Handling', () => {
|
|
426
|
+
it('handles file system errors gracefully', () => {
|
|
427
|
+
Object.defineProperty(global, 'window', { value: undefined, writable: true });
|
|
428
|
+
Object.defineProperty(global, 'require', { value: vi.fn(), writable: true });
|
|
429
|
+
|
|
430
|
+
mockPath.join.mockReturnValue('/path/to/package.json');
|
|
431
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
432
|
+
mockFs.readFileSync.mockImplementation(() => {
|
|
433
|
+
throw new Error('Permission denied');
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
437
|
+
|
|
438
|
+
const result = getAppNameFromPackageJson();
|
|
439
|
+
|
|
440
|
+
expect(result).toBeNull();
|
|
441
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
442
|
+
'[RBAC] Could not read app name from package.json:',
|
|
443
|
+
expect.any(Error)
|
|
444
|
+
);
|
|
445
|
+
|
|
446
|
+
consoleSpy.mockRestore();
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
it('handles JSON parsing errors gracefully', () => {
|
|
450
|
+
Object.defineProperty(global, 'window', { value: undefined, writable: true });
|
|
451
|
+
Object.defineProperty(global, 'require', { value: vi.fn(), writable: true });
|
|
452
|
+
|
|
453
|
+
mockPath.join.mockReturnValue('/path/to/package.json');
|
|
454
|
+
mockFs.existsSync.mockReturnValue(true);
|
|
455
|
+
mockFs.readFileSync.mockReturnValue('{ "name": "my-app" }'); // Valid JSON but missing closing brace
|
|
456
|
+
|
|
457
|
+
const consoleSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
|
|
458
|
+
|
|
459
|
+
const result = getAppNameFromPackageJson();
|
|
460
|
+
|
|
461
|
+
expect(result).toBeNull();
|
|
462
|
+
expect(consoleSpy).toHaveBeenCalledWith(
|
|
463
|
+
'[RBAC] Could not read app name from package.json:',
|
|
464
|
+
expect.any(Error)
|
|
465
|
+
);
|
|
466
|
+
|
|
467
|
+
consoleSpy.mockRestore();
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
|
|
471
|
+
describe('Performance', () => {
|
|
472
|
+
it('caches results efficiently', () => {
|
|
473
|
+
const startTime = Date.now();
|
|
474
|
+
|
|
475
|
+
// Call multiple times
|
|
476
|
+
for (let i = 0; i < 1000; i++) {
|
|
477
|
+
getCurrentAppName();
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
const endTime = Date.now();
|
|
481
|
+
|
|
482
|
+
expect(endTime - startTime).toBeLessThan(100); // Should be very fast
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
it('handles large app names efficiently', () => {
|
|
486
|
+
const largeAppName = 'a'.repeat(1000);
|
|
487
|
+
setRBACAppName(largeAppName);
|
|
488
|
+
|
|
489
|
+
const result = getCurrentAppName();
|
|
490
|
+
|
|
491
|
+
expect(result).toBe(largeAppName);
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
});
|
package/src/utils/debugLogger.ts
CHANGED
|
@@ -10,14 +10,23 @@
|
|
|
10
10
|
* Only logs in development mode to prevent production console spam
|
|
11
11
|
*/
|
|
12
12
|
export class DebugLogger {
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Check if we're in development mode
|
|
15
|
+
*/
|
|
16
|
+
private static get isDevelopment(): boolean {
|
|
17
|
+
return import.meta.env.MODE === 'development';
|
|
18
|
+
}
|
|
14
19
|
|
|
15
20
|
/**
|
|
16
21
|
* Log debug information only in development mode
|
|
17
22
|
*/
|
|
18
23
|
static log(component: string, message: string, ...args: any[]): void {
|
|
19
24
|
if (this.isDevelopment) {
|
|
20
|
-
|
|
25
|
+
try {
|
|
26
|
+
console.log(`[${component}] ${message}`, ...args);
|
|
27
|
+
} catch (e) {
|
|
28
|
+
// Gracefully handle console method errors
|
|
29
|
+
}
|
|
21
30
|
}
|
|
22
31
|
}
|
|
23
32
|
|
|
@@ -25,14 +34,22 @@ export class DebugLogger {
|
|
|
25
34
|
* Log error information (always logged)
|
|
26
35
|
*/
|
|
27
36
|
static error(component: string, message: string, ...args: any[]): void {
|
|
28
|
-
|
|
37
|
+
try {
|
|
38
|
+
console.error(`[${component}] ${message}`, ...args);
|
|
39
|
+
} catch (e) {
|
|
40
|
+
// Gracefully handle console method errors
|
|
41
|
+
}
|
|
29
42
|
}
|
|
30
43
|
|
|
31
44
|
/**
|
|
32
45
|
* Log warning information (always logged)
|
|
33
46
|
*/
|
|
34
47
|
static warn(component: string, message: string, ...args: any[]): void {
|
|
35
|
-
|
|
48
|
+
try {
|
|
49
|
+
console.warn(`[${component}] ${message}`, ...args);
|
|
50
|
+
} catch (e) {
|
|
51
|
+
// Gracefully handle console method errors
|
|
52
|
+
}
|
|
36
53
|
}
|
|
37
54
|
|
|
38
55
|
/**
|
|
@@ -40,7 +57,11 @@ export class DebugLogger {
|
|
|
40
57
|
*/
|
|
41
58
|
static info(component: string, message: string, ...args: any[]): void {
|
|
42
59
|
if (this.isDevelopment) {
|
|
43
|
-
|
|
60
|
+
try {
|
|
61
|
+
console.info(`[${component}] ${message}`, ...args);
|
|
62
|
+
} catch (e) {
|
|
63
|
+
// Gracefully handle console method errors
|
|
64
|
+
}
|
|
44
65
|
}
|
|
45
66
|
}
|
|
46
67
|
}
|
|
@@ -16,11 +16,7 @@ describe('formatDate Utility', () => {
|
|
|
16
16
|
originalTimezone = Intl.DateTimeFormat().resolvedOptions().timeZone;
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
vi.restoreAllMocks();
|
|
21
|
-
});
|
|
22
|
-
|
|
23
|
-
describe('Date Object Input', () => {
|
|
19
|
+
describe('Date Object Input', () => {
|
|
24
20
|
it('formats a Date object correctly', () => {
|
|
25
21
|
const date = new Date('2024-01-15T10:30:00.000Z');
|
|
26
22
|
const result = formatDate(date);
|
|
@@ -28,11 +28,7 @@ describe('Organisation Context', () => {
|
|
|
28
28
|
mockSupabase = createMockSupabaseClient();
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
vi.restoreAllMocks();
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
describe('setOrganisationContext', () => {
|
|
31
|
+
describe('setOrganisationContext', () => {
|
|
36
32
|
it('sets organisation context successfully', async () => {
|
|
37
33
|
mockSupabase.rpc.mockResolvedValue({
|
|
38
34
|
data: null,
|
|
@@ -39,7 +39,7 @@ class PerformanceBudgetMonitor {
|
|
|
39
39
|
|
|
40
40
|
// In production, this would send to a proper logging service
|
|
41
41
|
// For now, we'll log to console for testing purposes
|
|
42
|
-
if (import.meta.env.MODE === 'development' || import.meta.env.MODE === 'test') {
|
|
42
|
+
if (import.meta.env.MODE === 'development' || import.meta.env.MODE === 'test' || process.env.NODE_ENV === 'test') {
|
|
43
43
|
console.log('📊 Performance Metric: ' + metric + ' = ' + value, metadata);
|
|
44
44
|
}
|
|
45
45
|
|
|
@@ -56,8 +56,7 @@ class PerformanceBudgetMonitor {
|
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
setBudget(metric: string, budget: number, threshold: 'error' | 'warning' | 'info' = 'warning'): void {
|
|
59
|
-
|
|
60
|
-
this.budgets.push({ metric, budget, actual, threshold });
|
|
59
|
+
this.budgets.push({ metric, budget, actual: 0, threshold });
|
|
61
60
|
}
|
|
62
61
|
|
|
63
62
|
checkBudgets(): PerformanceBudget[] {
|
|
@@ -72,7 +71,7 @@ class PerformanceBudgetMonitor {
|
|
|
72
71
|
|
|
73
72
|
// In production, this would send to a proper logging service
|
|
74
73
|
// For now, we'll log to console for testing purposes
|
|
75
|
-
if (import.meta.env.MODE === 'development' || import.meta.env.MODE === 'test') {
|
|
74
|
+
if (import.meta.env.MODE === 'development' || import.meta.env.MODE === 'test' || process.env.NODE_ENV === 'test') {
|
|
76
75
|
if (budget.threshold === 'error') {
|
|
77
76
|
console.error('❌ Performance budget exceeded: ' + budget.metric + ' (' + actual + ' > ' + budget.budget + ')');
|
|
78
77
|
} else if (budget.threshold === 'warning') {
|
|
@@ -66,11 +66,7 @@ describe('secureDataAccess', () => {
|
|
|
66
66
|
mockSupabaseClient.from = vi.fn().mockReturnValue(mockQueryBuilder);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
-
|
|
70
|
-
vi.restoreAllMocks();
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe('createSecureDataAccess', () => {
|
|
69
|
+
describe('createSecureDataAccess', () => {
|
|
74
70
|
describe('Regular User (Non-Super Admin)', () => {
|
|
75
71
|
beforeEach(() => {
|
|
76
72
|
secureDataAccess = createSecureDataAccess(mockSupabaseClient, mockOrganisationId, false);
|
|
@@ -156,11 +156,7 @@ describe('Storage Helpers', () => {
|
|
|
156
156
|
});
|
|
157
157
|
|
|
158
158
|
describe('uploadFile', () => {
|
|
159
|
-
|
|
160
|
-
vi.clearAllMocks();
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
it('should upload file successfully', async () => {
|
|
159
|
+
it('should upload file successfully', async () => {
|
|
164
160
|
const file = createMockFile('test.jpg', 'image/jpeg', 1024);
|
|
165
161
|
const mockUpload = vi.fn().mockResolvedValue({ data: { path: 'org-123/documents/test.jpg' }, error: null });
|
|
166
162
|
const mockGetPublicUrl = vi.fn().mockReturnValue({ data: { publicUrl: 'https://example.com/file.jpg' } });
|
|
@@ -19,11 +19,7 @@ import {
|
|
|
19
19
|
} from '../sqlInjectionProtection';
|
|
20
20
|
|
|
21
21
|
describe('SQL Injection Protection', () => {
|
|
22
|
-
|
|
23
|
-
vi.clearAllMocks();
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
describe('detectSQLInjection', () => {
|
|
22
|
+
describe('detectSQLInjection', () => {
|
|
27
23
|
it('should detect basic SQL injection patterns', () => {
|
|
28
24
|
const maliciousInputs = [
|
|
29
25
|
"'; DROP TABLE users; --",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/debugLogger.ts","../src/utils/cn.ts","../src/utils/organisationContext.ts"],"sourcesContent":["/**\n * @file Debug Logger Utility\n * @package @jmruthers/pace-core\n * @module Utils/DebugLogger\n * @since 0.4.76\n */\n\n/**\n * Debug logger that respects environment settings\n * Only logs in development mode to prevent production console spam\n */\nexport class DebugLogger {\n private static isDevelopment = import.meta.env.MODE === 'development';\n\n /**\n * Log debug information only in development mode\n */\n static log(component: string, message: string, ...args: any[]): void {\n if (this.isDevelopment) {\n console.log(`[${component}] ${message}`, ...args);\n }\n }\n\n /**\n * Log error information (always logged)\n */\n static error(component: string, message: string, ...args: any[]): void {\n console.error(`[${component}] ${message}`, ...args);\n }\n\n /**\n * Log warning information (always logged)\n */\n static warn(component: string, message: string, ...args: any[]): void {\n console.warn(`[${component}] ${message}`, ...args);\n }\n\n /**\n * Log info information only in development mode\n */\n static info(component: string, message: string, ...args: any[]): void {\n if (this.isDevelopment) {\n console.info(`[${component}] ${message}`, ...args);\n }\n }\n}\n","\nimport { type ClassValue, clsx } from \"clsx\";\nimport { twMerge } from \"tailwind-merge\";\n\nexport function cn(...inputs: ClassValue[]) {\n return twMerge(clsx(inputs));\n}","/**\n * @file Organisation Context Utility\n * @package @jmruthers/pace-core\n * @module Utils/OrganisationContext\n * @since 0.4.0\n *\n * Utility functions for managing organisation context in database sessions.\n * Provides fallback mechanisms for when database functions are not available.\n */\n\nimport type { SupabaseClient } from '@supabase/supabase-js';\n\n/**\n * Set organisation context in the database session\n * \n * This function attempts to set the organisation context using a database function.\n * If the function is not available, it falls back gracefully without throwing errors.\n * \n * @param supabase - Supabase client instance\n * @param organisationId - The organisation ID to set as context\n * @returns Promise that resolves when context is set (or falls back gracefully)\n */\nexport async function setOrganisationContext(\n supabase: SupabaseClient,\n organisationId: string\n): Promise<void> {\n if (!supabase || !organisationId) {\n // TODO: Replace with proper logging service integration\n return;\n }\n\n try {\n // Try to call the database function to set organisation context\n const { error } = await supabase.rpc('rbac_audit_log', {\n p_event_type: 'organisation_switched',\n p_organisation_id: organisationId,\n p_metadata: { action: 'set_context' }\n });\n\n if (error) {\n // Function might not exist yet - this is expected during migration\n // Silent fail - will fall back to client-side filtering\n // TODO: Replace with proper logging service integration\n } else {\n // TODO: Replace with proper logging service integration\n }\n } catch (error) {\n // Handle any other errors gracefully\n // Silent fail - will fall back to client-side filtering\n // TODO: Replace with proper logging service integration\n }\n}\n\n/**\n * Clear organisation context from the database session\n * \n * @param supabase - Supabase client instance\n * @returns Promise that resolves when context is cleared\n */\nexport async function clearOrganisationContext(\n supabase: SupabaseClient\n): Promise<void> {\n if (!supabase) {\n // TODO: Replace with proper logging service integration\n return;\n }\n\n try {\n const { error } = await supabase.rpc('rbac_audit_log', {\n p_event_type: 'organisation_switched',\n p_metadata: { action: 'clear_context' }\n });\n \n if (error) {\n // Silent fail - function not available\n // TODO: Replace with proper logging service integration\n } else {\n // TODO: Replace with proper logging service integration\n }\n } catch (error) {\n // Silent fail - error occurred\n // TODO: Replace with proper logging service integration\n }\n}\n\n/**\n * Get current organisation context from the database session\n * \n * @param supabase - Supabase client instance\n * @returns Promise that resolves to the current organisation ID or null\n */\nexport async function getOrganisationContext(\n supabase: SupabaseClient\n): Promise<string | null> {\n if (!supabase) {\n // TODO: Replace with proper logging service integration\n return null;\n }\n\n try {\n // For now, return null since we're not using database context\n // This will be replaced with proper context management\n const data = null;\n const error = null;\n \n if (error) {\n // TODO: Replace with proper logging service integration\n return null;\n }\n \n // Validate that data is a string (allow empty strings)\n if (typeof data === 'string') {\n return data;\n }\n \n // Return null for invalid data formats\n return null;\n } catch (error) {\n // TODO: Replace with proper logging service integration\n return null;\n }\n}\n\n/**\n * Check if organisation context functions are available in the database\n * \n * @param supabase - Supabase client instance\n * @returns Promise that resolves to true if functions are available\n */\nexport async function isOrganisationContextAvailable(\n supabase: SupabaseClient\n): Promise<boolean> {\n if (!supabase) {\n return false;\n }\n\n try {\n const { error } = await supabase.rpc('get_organisation_context');\n \n if (error) {\n return false;\n }\n \n return true;\n } catch (error) {\n return false;\n }\n} "],"mappings":";;;;;AAAA,IAWa;AAXb;AAAA;AAAA;AAWO,IAAM,cAAN,MAAkB;AAAA;AAAA;AAAA;AAAA,MAMvB,OAAO,IAAI,WAAmB,YAAoB,MAAmB;AACnE,YAAI,KAAK,eAAe;AACtB,kBAAQ,IAAI,IAAI,SAAS,KAAK,OAAO,IAAI,GAAG,IAAI;AAAA,QAClD;AAAA,MACF;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,MAAM,WAAmB,YAAoB,MAAmB;AACrE,gBAAQ,MAAM,IAAI,SAAS,KAAK,OAAO,IAAI,GAAG,IAAI;AAAA,MACpD;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,KAAK,WAAmB,YAAoB,MAAmB;AACpE,gBAAQ,KAAK,IAAI,SAAS,KAAK,OAAO,IAAI,GAAG,IAAI;AAAA,MACnD;AAAA;AAAA;AAAA;AAAA,MAKA,OAAO,KAAK,WAAmB,YAAoB,MAAmB;AACpE,YAAI,KAAK,eAAe;AACtB,kBAAQ,KAAK,IAAI,SAAS,KAAK,OAAO,IAAI,GAAG,IAAI;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAjCE,IADW,YACI,gBAAgB,YAAY,IAAI,SAAS;AAAA;AAAA;;;ACX1D,SAA0B,YAAY;AACtC,SAAS,eAAe;AAEjB,SAAS,MAAM,QAAsB;AAC1C,SAAO,QAAQ,KAAK,MAAM,CAAC;AAC7B;AANA;AAAA;AAAA;AAAA;AAAA;;;ACsBA,eAAsB,uBACpB,UACA,gBACe;AACf,MAAI,CAAC,YAAY,CAAC,gBAAgB;AAEhC;AAAA,EACF;AAEA,MAAI;AAEF,UAAM,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,kBAAkB;AAAA,MACrD,cAAc;AAAA,MACd,mBAAmB;AAAA,MACnB,YAAY,EAAE,QAAQ,cAAc;AAAA,IACtC,CAAC;AAED,QAAI,OAAO;AAAA,IAIX,OAAO;AAAA,IAEP;AAAA,EACF,SAAS,OAAO;AAAA,EAIhB;AACF;AAQA,eAAsB,yBACpB,UACe;AACf,MAAI,CAAC,UAAU;AAEb;AAAA,EACF;AAEA,MAAI;AACF,UAAM,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,kBAAkB;AAAA,MACrD,cAAc;AAAA,MACd,YAAY,EAAE,QAAQ,gBAAgB;AAAA,IACxC,CAAC;AAED,QAAI,OAAO;AAAA,IAGX,OAAO;AAAA,IAEP;AAAA,EACF,SAAS,OAAO;AAAA,EAGhB;AACF;AAQA,eAAsB,uBACpB,UACwB;AACxB,MAAI,CAAC,UAAU;AAEb,WAAO;AAAA,EACT;AAEA,MAAI;AAGF,UAAM,OAAO;AACb,UAAM,QAAQ;AAEd,QAAI,OAAO;AAET,aAAO;AAAA,IACT;AAGA,QAAI,OAAO,SAAS,UAAU;AAC5B,aAAO;AAAA,IACT;AAGA,WAAO;AAAA,EACT,SAAS,OAAO;AAEd,WAAO;AAAA,EACT;AACF;AAQA,eAAsB,+BACpB,UACkB;AAClB,MAAI,CAAC,UAAU;AACb,WAAO;AAAA,EACT;AAEA,MAAI;AACF,UAAM,EAAE,MAAM,IAAI,MAAM,SAAS,IAAI,0BAA0B;AAE/D,QAAI,OAAO;AACT,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,EACT,SAAS,OAAO;AACd,WAAO;AAAA,EACT;AACF;AAnJA;AAAA;AAAA;AAAA;AAAA;","names":[]}
|