@jmruthers/pace-core 0.6.5 → 0.6.7
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 +104 -0
- package/README.md +5 -403
- package/audit-tool/00-dependencies.cjs +394 -0
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +5 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -35
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +185 -57
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/04-code-style-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/index.cjs +0 -223
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/components/DataTable/components/DataTableBody.tsx +0 -454
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
package/dist/hooks.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/hooks/useFocusManagement.ts","../src/hooks/useKeyboardShortcuts.ts","../src/hooks/useIsMobile.ts","../src/hooks/useDataTableState.ts","../src/hooks/usePerformanceMonitor.ts","../src/hooks/useFileUrlCache.ts","../src/hooks/useStorage.ts"],"sourcesContent":["\nimport { useRef, useCallback, useEffect } from 'react';\n\n/**\n * Options for the useFocusManagement hook.\n */\nexport interface FocusManagementOptions {\n trapFocus?: boolean;\n autoFocus?: boolean;\n restoreFocus?: boolean;\n onEscape?: () => void;\n onFocusFirst?: () => void;\n onFocusLast?: () => void;\n}\n\n/**\n * Return value of the useFocusManagement hook.\n * Provides focus management utilities for accessible components.\n */\nexport interface FocusManagementReturn {\n containerRef: React.RefObject<HTMLDivElement | null>;\n focusRef: React.RefObject<HTMLElement | null>;\n setFocus: (element: HTMLElement | null) => void;\n focusFirst: () => void;\n focusLast: () => void;\n trapFocus: () => void;\n releaseFocus: () => void;\n getFocusableElements: () => HTMLElement[];\n handleEscape: (callback: () => void) => () => void;\n}\n\n/**\n * Hook for managing focus in accessible components.\n * Provides focus trapping, restoration, and navigation utilities.\n * \n * @param options - Focus management configuration\n * @returns Focus management utilities and refs\n */\nexport function useFocusManagement(options: FocusManagementOptions = {}): FocusManagementReturn {\n const { \n trapFocus = false, \n autoFocus = false, \n restoreFocus = false,\n onEscape,\n onFocusFirst,\n onFocusLast \n } = options;\n\n const containerRef = useRef<HTMLDivElement>(null);\n const focusRef = useRef<HTMLElement | null>(null);\n const previousFocusRef = useRef<HTMLElement | null>(null);\n const trapFocusActiveRef = useRef<boolean>(false);\n\n const setFocus = useCallback((element: HTMLElement | null) => {\n focusRef.current = element;\n element?.focus();\n }, []);\n\n const getFocusableElements = useCallback((): HTMLElement[] => {\n if (!containerRef.current) return [];\n\n return Array.from(\n containerRef.current.querySelectorAll<HTMLElement>(\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\n )\n ).filter((el) => !el.hasAttribute('disabled') && !el.hasAttribute('hidden'));\n }, []);\n\n const focusFirst = useCallback(() => {\n const elements = getFocusableElements();\n if (elements.length > 0) {\n setFocus(elements[0]);\n onFocusFirst?.();\n }\n }, [getFocusableElements, setFocus, onFocusFirst]);\n\n const focusLast = useCallback(() => {\n const elements = getFocusableElements();\n if (elements.length > 0) {\n setFocus(elements[elements.length - 1]);\n onFocusLast?.();\n }\n }, [getFocusableElements, setFocus, onFocusLast]);\n\n const trapFocusMethod = useCallback(() => {\n trapFocusActiveRef.current = true;\n }, []);\n\n const releaseFocus = useCallback(() => {\n trapFocusActiveRef.current = false;\n }, []);\n\n const handleEscape = useCallback((callback: () => void) => {\n return () => {\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape') {\n callback();\n }\n };\n\n document.addEventListener('keydown', handleKeyDown);\n return () => document.removeEventListener('keydown', handleKeyDown);\n };\n }, []);\n\n // Handle focus trap\n useEffect(() => {\n if (!trapFocus || !containerRef.current) return;\n\n const handleKeyDown = (event: KeyboardEvent) => {\n if (event.key === 'Escape' && onEscape) {\n onEscape();\n return;\n }\n\n if (event.key !== 'Tab') return;\n\n const elements = getFocusableElements();\n if (elements.length === 0) return;\n\n const firstElement = elements[0];\n const lastElement = elements[elements.length - 1];\n\n if (event.shiftKey) {\n if (document.activeElement === firstElement) {\n event.preventDefault();\n lastElement.focus();\n }\n } else {\n if (document.activeElement === lastElement) {\n event.preventDefault();\n firstElement.focus();\n }\n }\n };\n\n const current = containerRef.current;\n current.addEventListener('keydown', handleKeyDown);\n return () => {\n current?.removeEventListener('keydown', handleKeyDown);\n };\n }, [trapFocus, onEscape, getFocusableElements]);\n\n // Handle auto focus\n useEffect(() => {\n if (autoFocus) {\n focusFirst();\n }\n }, [autoFocus, focusFirst]);\n\n // Handle focus restoration\n useEffect(() => {\n if (!restoreFocus) return;\n\n previousFocusRef.current = document.activeElement as HTMLElement;\n\n return () => {\n if (previousFocusRef.current) {\n previousFocusRef.current.focus();\n }\n };\n }, [restoreFocus]);\n\n return {\n containerRef,\n focusRef,\n setFocus,\n focusFirst,\n focusLast,\n trapFocus: trapFocusMethod,\n releaseFocus,\n getFocusableElements,\n handleEscape,\n };\n}\n","import { useEffect, useCallback } from 'react';\n\n/**\n * Keyboard shortcut definition.\n * Defines a key combination and its handler function.\n */\nexport interface KeyboardShortcut {\n /** Key combination (e.g., 'Escape', 'Enter', 'ArrowDown', 'ctrl+s') */\n key: string;\n /** Callback function to execute */\n handler: (event: KeyboardEvent) => void;\n /** Description for documentation/help */\n description?: string;\n /** Whether the shortcut is enabled */\n enabled?: boolean;\n /** Prevent default browser behavior */\n preventDefault?: boolean;\n /** Stop event propagation */\n stopPropagation?: boolean;\n}\n\nexport interface KeyboardShortcutsOptions {\n /** Element to attach listeners to (defaults to document) */\n element?: HTMLElement | Document;\n /** Whether shortcuts are globally enabled */\n enabled?: boolean;\n}\n\n/**\n * Parse key combination string into modifier and key parts\n */\nfunction parseKeyCombo(combo: string) {\n const parts = combo.toLowerCase().split('+');\n const key = parts.pop()!;\n const modifiers = {\n ctrl: parts.includes('ctrl') || parts.includes('control'),\n alt: parts.includes('alt'),\n shift: parts.includes('shift'),\n meta: parts.includes('meta') || parts.includes('cmd')\n };\n return { key, modifiers };\n}\n\n/**\n * Check if event matches the key combination\n */\nfunction matchesKeyCombo(event: KeyboardEvent, combo: string): boolean {\n const { key, modifiers } = parseKeyCombo(combo);\n \n // Check if the main key matches\n const eventKey = event.key.toLowerCase();\n const targetKey = key.toLowerCase();\n \n if (eventKey !== targetKey) {\n return false;\n }\n \n // Check modifiers\n return (\n event.ctrlKey === modifiers.ctrl &&\n event.altKey === modifiers.alt &&\n event.shiftKey === modifiers.shift &&\n event.metaKey === modifiers.meta\n );\n}\n\n/**\n * Hook for managing keyboard shortcuts\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const shortcuts = [\n * {\n * key: 'Escape',\n * handler: () => setIsOpen(false),\n * description: 'Close modal'\n * },\n * {\n * key: 'ctrl+s',\n * handler: (e) => handleSave(),\n * description: 'Save document',\n * preventDefault: true\n * }\n * ];\n * \n * useKeyboardShortcuts(shortcuts);\n * \n * return <main>Content</main>;\n * }\n * ```\n */\nexport function useKeyboardShortcuts(\n shortcuts: KeyboardShortcut[],\n options: KeyboardShortcutsOptions = {}\n): void {\n const { element = document, enabled = true } = options;\n\n const handleKeyDown = useCallback((event: KeyboardEvent) => {\n if (!enabled) return;\n\n for (const shortcut of shortcuts) {\n if (shortcut.enabled === false) continue;\n\n if (matchesKeyCombo(event, shortcut.key)) {\n if (shortcut.preventDefault) {\n event.preventDefault();\n }\n if (shortcut.stopPropagation) {\n event.stopPropagation();\n }\n \n shortcut.handler(event);\n break; // Only handle first matching shortcut\n }\n }\n }, [shortcuts, enabled]);\n\n useEffect(() => {\n if (!enabled) return;\n\n element.addEventListener('keydown', handleKeyDown as EventListener);\n return () => element.removeEventListener('keydown', handleKeyDown as EventListener);\n }, [element, enabled, handleKeyDown]);\n}\n\n/**\n * Hook for common accessibility keyboard shortcuts\n */\nexport function useAccessibilityShortcuts(handlers: {\n onEscape?: () => void;\n onEnter?: () => void;\n onSpace?: () => void;\n onArrowUp?: () => void;\n onArrowDown?: () => void;\n onArrowLeft?: () => void;\n onArrowRight?: () => void;\n onHome?: () => void;\n onEnd?: () => void;\n onTab?: () => void;\n onShiftTab?: () => void;\n}) {\n const shortcuts: KeyboardShortcut[] = [];\n\n if (handlers.onEscape) {\n shortcuts.push({\n key: 'Escape',\n handler: handlers.onEscape,\n description: 'Escape/Cancel'\n });\n }\n\n if (handlers.onEnter) {\n shortcuts.push({\n key: 'Enter',\n handler: handlers.onEnter,\n description: 'Activate/Submit'\n });\n }\n\n if (handlers.onSpace) {\n shortcuts.push({\n key: ' ',\n handler: handlers.onSpace,\n description: 'Activate',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowUp) {\n shortcuts.push({\n key: 'ArrowUp',\n handler: handlers.onArrowUp,\n description: 'Navigate up',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowDown) {\n shortcuts.push({\n key: 'ArrowDown',\n handler: handlers.onArrowDown,\n description: 'Navigate down',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowLeft) {\n shortcuts.push({\n key: 'ArrowLeft',\n handler: handlers.onArrowLeft,\n description: 'Navigate left',\n preventDefault: true\n });\n }\n\n if (handlers.onArrowRight) {\n shortcuts.push({\n key: 'ArrowRight',\n handler: handlers.onArrowRight,\n description: 'Navigate right',\n preventDefault: true\n });\n }\n\n if (handlers.onHome) {\n shortcuts.push({\n key: 'Home',\n handler: handlers.onHome,\n description: 'Go to first item',\n preventDefault: true\n });\n }\n\n if (handlers.onEnd) {\n shortcuts.push({\n key: 'End',\n handler: handlers.onEnd,\n description: 'Go to last item',\n preventDefault: true\n });\n }\n\n if (handlers.onTab) {\n shortcuts.push({\n key: 'Tab',\n handler: handlers.onTab,\n description: 'Navigate forward'\n });\n }\n\n if (handlers.onShiftTab) {\n shortcuts.push({\n key: 'shift+Tab',\n handler: handlers.onShiftTab,\n description: 'Navigate backward'\n });\n }\n\n useKeyboardShortcuts(shortcuts);\n}\n","/**\n * @file useIsMobile Hook\n * @description Hook for detecting mobile viewport using modern matchMedia API\n */\n\nimport { useState, useEffect } from 'react';\n\nconst MOBILE_BREAKPOINT = 768;\n\n/**\n * Hook to detect if the viewport is mobile-sized using matchMedia API.\n * More performant than window resize events.\n * @returns {boolean} True if mobile, false otherwise.\n */\nexport function useIsMobile(): boolean {\n const [isMobile, setIsMobile] = useState<boolean | undefined>(undefined);\n\n useEffect(() => {\n // Handle SSR case\n if (typeof window === 'undefined') {\n setIsMobile(false);\n return;\n }\n\n const mql = window.matchMedia(`(max-width: ${MOBILE_BREAKPOINT - 1}px)`);\n \n const onChange = () => {\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n };\n\n // Set initial value\n setIsMobile(window.innerWidth < MOBILE_BREAKPOINT);\n\n // Add event listener\n mql.addEventListener('change', onChange);\n\n // Cleanup\n return () => mql.removeEventListener('change', onChange);\n }, []);\n\n return !!isMobile;\n}\n","/**\n * @file useDataTableState Hook\n * @description Hook for managing DataTable state\n */\n\nimport { useState, useCallback } from 'react';\nimport type { SortingState, ColumnFiltersState, ExpandedState } from '@tanstack/react-table';\n\nexport interface DataTableState {\n sorting: SortingState;\n columnFilters: ColumnFiltersState;\n expanded: ExpandedState;\n pageSize: number;\n pageIndex: number;\n selectedRows: string[];\n}\n\nexport interface DataTableActions {\n setSorting: (sorting: SortingState) => void;\n setColumnFilters: (filters: ColumnFiltersState) => void;\n setExpanded: (expanded: ExpandedState) => void;\n setPageSize: (size: number) => void;\n setPageIndex: (index: number) => void;\n setSelectedRows: (rows: string[]) => void;\n resetState: () => void;\n}\n\nexport interface DataTableComputed {\n paginatedData: any[];\n totalPages: number;\n hasNextPage: boolean;\n hasPreviousPage: boolean;\n}\n\nexport interface UseDataTableStateOptions {\n initialPageSize?: number;\n data: any[];\n}\n\n/**\n * Hook for managing DataTable state\n * @param options Configuration options\n * @returns Object containing state, actions, and computed values\n */\nexport function useDataTableState(options: UseDataTableStateOptions) {\n const { initialPageSize = 10, data } = options;\n\n // State\n const [sorting, setSorting] = useState<SortingState>([]);\n const [columnFilters, setColumnFilters] = useState<ColumnFiltersState>([]);\n const [expanded, setExpanded] = useState<ExpandedState>({});\n const [pageSize, setPageSize] = useState(initialPageSize);\n const [pageIndex, setPageIndex] = useState(0);\n const [selectedRows, setSelectedRows] = useState<string[]>([]);\n\n // Actions\n const resetState = useCallback(() => {\n setSorting([]);\n setColumnFilters([]);\n setExpanded({});\n setPageSize(initialPageSize);\n setPageIndex(0);\n setSelectedRows([]);\n }, [initialPageSize]);\n\n // Computed values - React Compiler handles memoization automatically\n const start = pageIndex * pageSize;\n const end = start + pageSize;\n const paginatedData = data.slice(start, end);\n\n const totalPages = Math.ceil(data.length / pageSize);\n const hasNextPage = pageIndex < totalPages - 1;\n const hasPreviousPage = pageIndex > 0;\n\n return {\n state: {\n sorting,\n columnFilters,\n expanded,\n pageSize,\n pageIndex,\n selectedRows\n },\n actions: {\n setSorting,\n setColumnFilters,\n setExpanded,\n setPageSize,\n setPageIndex,\n setSelectedRows,\n resetState\n },\n computed: {\n paginatedData,\n totalPages,\n hasNextPage,\n hasPreviousPage\n }\n };\n}\n","\nimport { useEffect, useRef, useCallback } from 'react';\nimport { performanceBudgetMonitor, PERFORMANCE_BUDGETS } from '../utils/performance/performanceBudgets';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('usePerformanceMonitor');\n\n/**\n * Performance metrics interface.\n * Represents performance measurement data for components or operations.\n */\nexport interface PerformanceMetrics {\n renderTime: number;\n componentName: string;\n timestamp: number;\n}\n\n/**\n * Hook for monitoring component performance with budget validation\n * @param componentName - Name of the component being monitored\n * @param enabled - Whether performance monitoring is enabled\n * @param budgetName - Performance budget to validate against\n */\nexport function usePerformanceMonitor(\n componentName: string, \n enabled = import.meta.env.MODE === 'development',\n budgetName: string = 'COMPONENT_RENDER'\n) {\n const renderStartTime = useRef<number>(0);\n const metrics = useRef<PerformanceMetrics[]>([]);\n\n // Start performance measurement\n const startMeasurement = useCallback(() => {\n if (!enabled) return;\n renderStartTime.current = performance.now();\n }, [enabled]);\n\n // End performance measurement with budget validation\n const endMeasurement = useCallback(() => {\n if (!enabled || renderStartTime.current === 0) return;\n \n const renderTime = performance.now() - renderStartTime.current;\n const metric: PerformanceMetrics = {\n renderTime,\n componentName,\n timestamp: Date.now()\n };\n \n metrics.current.push(metric);\n \n // Keep only last 10 measurements\n if (metrics.current.length > 10) {\n metrics.current = metrics.current.slice(-10);\n }\n \n // Validate against performance budget\n const measurement = performanceBudgetMonitor.measure(budgetName, renderTime, {\n componentName,\n renderCount: metrics.current.length\n });\n \n // Log slow renders in development\n if (!measurement.passed) {\n log.warn(\n `Performance budget exceeded in ${componentName}: ${renderTime.toFixed(2)}ms ` +\n `(budget: ${PERFORMANCE_BUDGETS[budgetName]?.threshold}ms)`\n );\n }\n \n renderStartTime.current = 0;\n }, [enabled, componentName, budgetName]);\n\n // Get performance metrics\n const getMetrics = useCallback(() => {\n return metrics.current.slice();\n }, []);\n\n // Get average render time\n const getAverageRenderTime = useCallback(() => {\n if (metrics.current.length === 0) return 0;\n \n const total = metrics.current.reduce((sum, metric) => sum + metric.renderTime, 0);\n return total / metrics.current.length;\n }, []);\n\n // Get performance budget status\n const getBudgetStatus = useCallback(() => {\n const budget = PERFORMANCE_BUDGETS[budgetName];\n if (!budget) return null;\n\n const averageTime = getAverageRenderTime();\n return {\n budget: budget.threshold,\n average: averageTime,\n passed: averageTime <= budget.threshold,\n efficiency: budget.threshold > 0 ? (budget.threshold - averageTime) / budget.threshold : 0\n };\n }, [budgetName, getAverageRenderTime]);\n\n // Start measurement on every render\n useEffect(() => {\n startMeasurement();\n return endMeasurement;\n });\n\n return {\n getMetrics,\n getAverageRenderTime,\n getBudgetStatus,\n startMeasurement,\n endMeasurement\n };\n}\n\n// Hook for measuring specific operations\nexport function useOperationPerformance(operationName: string, budgetName?: string) {\n const measureOperation = useCallback(async <T>(\n operation: () => Promise<T> | T,\n context?: Record<string, any>\n ): Promise<T> => {\n const start = performance.now();\n const result = await operation();\n const duration = performance.now() - start;\n \n const budget = budgetName || 'COMPONENT_RENDER';\n performanceBudgetMonitor.measure(budget, duration, {\n operation: operationName,\n ...context\n });\n \n return result;\n }, [operationName, budgetName]);\n\n return { measureOperation };\n}\n","/**\n * @file File URL Cache Hook\n * @package @jmruthers/pace-core\n * @module Hooks\n *\n * Centralized caching hook for file URLs to prevent duplicate requests\n * and improve performance across components.\n *\n * Features:\n * - TTL-based caching matching signed URL expiration (3600s)\n * - Automatic cache cleanup\n * - Supports both public and signed URLs\n * - Thread-safe cache operations\n *\n * @example\n * ```tsx\n * import { useFileUrlCache } from '@jmruthers/pace-core';\n *\n * function MyComponent() {\n * const { getUrl, setUrl, clearCache } = useFileUrlCache();\n *\n * const url = await getUrl(fileReference, supabase, organisationId);\n * return <img src={url} alt=\"File\" />;\n * }\n * ```\n */\n\nimport { useRef, useCallback } from 'react';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport { FileReference } from '../types/file-reference';\nimport { getPublicUrl, getSignedUrl } from '../utils/storage/helpers';\n\ninterface CachedUrl {\n url: string;\n expiresAt: number; // Timestamp in milliseconds\n}\n\n// Global cache shared across all hook instances\nconst globalUrlCache = new Map<string, CachedUrl>();\n\n// Cache size limit to prevent memory leaks\nconst MAX_CACHE_SIZE = 500;\n\n// Default TTL matches signed URL expiration (3600 seconds = 1 hour)\nconst DEFAULT_TTL_MS = 3600 * 1000;\n\n/**\n * Generate cache key from file reference\n */\nfunction getCacheKey(fileReference: FileReference): string {\n return `file-url:${fileReference.id}:${fileReference.is_public ? 'public' : 'private'}`;\n}\n\n/**\n * Clean up expired entries and enforce size limit\n */\nfunction cleanupCache(): void {\n const now = Date.now();\n \n // Remove expired entries\n for (const [key, value] of globalUrlCache.entries()) {\n if (value.expiresAt < now) {\n globalUrlCache.delete(key);\n }\n }\n \n // Enforce size limit by removing oldest entries\n if (globalUrlCache.size > MAX_CACHE_SIZE) {\n const entries = Array.from(globalUrlCache.entries());\n // Sort by expiration time (oldest first)\n entries.sort((a, b) => a[1].expiresAt - b[1].expiresAt);\n \n // Remove oldest 20% of entries\n const toRemove = Math.floor(MAX_CACHE_SIZE * 0.2);\n for (let i = 0; i < toRemove && i < entries.length; i++) {\n globalUrlCache.delete(entries[i][0]);\n }\n }\n}\n\nexport interface UseFileUrlCacheReturn {\n /**\n * Get URL for a file reference, using cache if available\n * @param fileReference - File reference to get URL for\n * @param supabase - Supabase client instance\n * @param organisationId - Organisation ID for signed URLs\n * @param ttl - Time to live in milliseconds (default: 3600000 = 1 hour)\n * @returns Promise resolving to URL string or null\n */\n getUrl: (\n fileReference: FileReference,\n supabase: SupabaseClient,\n organisationId: string,\n ttl?: number\n ) => Promise<string | null>;\n \n /**\n * Set URL in cache\n * @param fileReference - File reference\n * @param url - URL to cache\n * @param ttl - Time to live in milliseconds (default: 3600000 = 1 hour)\n */\n setUrl: (fileReference: FileReference, url: string, ttl?: number) => void;\n \n /**\n * Get URL from cache without generating if missing\n * @param fileReference - File reference\n * @returns Cached URL or null if not in cache or expired\n */\n getCachedUrl: (fileReference: FileReference) => string | null;\n \n /**\n * Clear cache for a specific file reference\n * @param fileReference - File reference to clear\n */\n clearFile: (fileReference: FileReference) => void;\n \n /**\n * Clear all cached URLs\n */\n clearCache: () => void;\n \n /**\n * Get cache statistics\n */\n getCacheStats: () => { size: number; maxSize: number };\n}\n\n/**\n * Hook for centralized file URL caching\n * \n * This hook provides a shared cache for file URLs across all components,\n * preventing duplicate requests for the same file.\n * \n * @returns Cache operations and utilities\n */\nexport function useFileUrlCache(): UseFileUrlCacheReturn {\n // Use ref to ensure stable reference across renders\n const cleanupIntervalRef = useRef<number | null>(null);\n \n // Set up periodic cleanup (every 5 minutes)\n if (cleanupIntervalRef.current === null && typeof window !== 'undefined') {\n cleanupIntervalRef.current = window.setInterval(() => {\n cleanupCache();\n }, 5 * 60 * 1000); // 5 minutes\n }\n \n const getUrl = useCallback(async (\n fileReference: FileReference,\n supabase: SupabaseClient,\n organisationId: string,\n ttl: number = DEFAULT_TTL_MS\n ): Promise<string | null> => {\n const cacheKey = getCacheKey(fileReference);\n const cached = globalUrlCache.get(cacheKey);\n const now = Date.now();\n \n // Return cached URL if still valid\n if (cached && cached.expiresAt > now) {\n return cached.url;\n }\n \n // Generate new URL\n let url: string | null = null;\n \n try {\n if (fileReference.is_public) {\n // Public files: generate public URL (synchronous)\n url = getPublicUrl(supabase, fileReference.file_path, true);\n } else {\n // Private files: generate signed URL (async)\n const signedUrlResult = await getSignedUrl(supabase, fileReference.file_path, {\n appName: 'pace-core',\n orgId: organisationId,\n expiresIn: Math.floor(ttl / 1000) // Convert ms to seconds\n });\n url = signedUrlResult?.url || null;\n }\n \n // Cache the URL if generated successfully\n if (url) {\n globalUrlCache.set(cacheKey, {\n url,\n expiresAt: now + ttl\n });\n cleanupCache(); // Clean up after adding\n }\n \n return url;\n } catch (error) {\n console.error('Failed to generate file URL:', error);\n return null;\n }\n }, []);\n \n const setUrl = useCallback((\n fileReference: FileReference,\n url: string,\n ttl: number = DEFAULT_TTL_MS\n ): void => {\n const cacheKey = getCacheKey(fileReference);\n globalUrlCache.set(cacheKey, {\n url,\n expiresAt: Date.now() + ttl\n });\n cleanupCache();\n }, []);\n \n const getCachedUrl = useCallback((fileReference: FileReference): string | null => {\n const cacheKey = getCacheKey(fileReference);\n const cached = globalUrlCache.get(cacheKey);\n const now = Date.now();\n \n if (cached && cached.expiresAt > now) {\n return cached.url;\n }\n \n return null;\n }, []);\n \n const clearFile = useCallback((fileReference: FileReference): void => {\n const cacheKey = getCacheKey(fileReference);\n globalUrlCache.delete(cacheKey);\n }, []);\n \n const clearCache = useCallback((): void => {\n globalUrlCache.clear();\n }, []);\n \n const getCacheStats = useCallback(() => {\n return {\n size: globalUrlCache.size,\n maxSize: MAX_CACHE_SIZE\n };\n }, []);\n \n return {\n getUrl,\n setUrl,\n getCachedUrl,\n clearFile,\n clearCache,\n getCacheStats\n };\n}\n\n","/**\n * React hook for storage operations\n */\n\nimport { useState, useCallback } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { \n StorageUploadOptions, \n StorageUploadResult, \n StorageFileInfo,\n StorageListOptions,\n StorageListResult,\n uploadFile,\n getPublicUrl,\n getSignedUrl,\n deleteFile,\n listFiles,\n archiveFile\n} from '../utils/storage';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('useStorage');\n\nexport interface UseStorageOptions {\n supabase: SupabaseClient;\n appName: string;\n orgId: string;\n}\n\n/**\n * Return value of the useStorage hook.\n * Provides storage operations including upload, URL generation, file management, and listing.\n */\nexport interface UseStorageReturn {\n // Upload\n uploadFile: (file: File, options?: Partial<StorageUploadOptions>) => Promise<StorageUploadResult>;\n isUploading: boolean;\n uploadError: string | null;\n \n // URLs\n getPublicUrl: (path: string) => string;\n getSignedUrl: (path: string, expiresIn?: number) => Promise<string | null>;\n getFileUrl: (path: string) => string; // Alias for getPublicUrl\n \n // File management\n deleteFile: (path: string) => Promise<{ success: boolean; error?: string }>;\n archiveFile: (path: string) => Promise<{ success: boolean; error?: string }>;\n \n // Listing\n listFiles: (options?: Partial<StorageListOptions>) => Promise<StorageListResult>;\n isListing: boolean;\n listError: string | null;\n isLoading: boolean; // Alias for isListing\n error: string | null; // Alias for listError\n \n // State\n files: StorageFileInfo[];\n refreshFiles: () => Promise<void>;\n}\n\n/**\n * Hook for storage operations with app and organisation context\n */\nexport function useStorage({ supabase, appName, orgId }: UseStorageOptions): UseStorageReturn {\n const [isUploading, setIsUploading] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n const [isListing, setIsListing] = useState(false);\n const [listError, setListError] = useState<string | null>(null);\n const [files, setFiles] = useState<StorageFileInfo[]>([]);\n\n // Upload file\n const handleUploadFile = useCallback(async (\n file: File, \n options: Partial<StorageUploadOptions> = {}\n ): Promise<StorageUploadResult> => {\n setIsUploading(true);\n setUploadError(null);\n\n try {\n const uploadOptions: StorageUploadOptions = {\n appName,\n orgId,\n isPublic: false,\n ...options\n };\n\n const result = await uploadFile(supabase, file, uploadOptions);\n \n if (result.success) {\n // Refresh file list\n await refreshFiles();\n } else {\n setUploadError(result.error || 'Upload failed');\n }\n\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Upload failed';\n setUploadError(errorMessage);\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsUploading(false);\n }\n }, [supabase, appName, orgId]);\n\n // Get public URL\n const handleGetPublicUrl = useCallback((path: string): string => {\n return getPublicUrl(supabase, path);\n }, [supabase]);\n\n // Get signed URL\n const handleGetSignedUrl = useCallback(async (\n path: string, \n expiresIn?: number\n ): Promise<string | null> => {\n try {\n const result = await getSignedUrl(supabase, path, {\n appName,\n orgId,\n expiresIn\n });\n return result?.url || null;\n } catch (error) {\n log.error('Failed to get signed URL:', error);\n return null;\n }\n }, [supabase, appName, orgId]);\n\n // Delete file\n const handleDeleteFile = useCallback(async (path: string) => {\n try {\n const result = await deleteFile(supabase, path);\n if (result.success) {\n await refreshFiles();\n }\n return result;\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Delete failed'\n };\n }\n }, [supabase]);\n\n // Archive file\n const handleArchiveFile = useCallback(async (path: string) => {\n try {\n const result = await archiveFile(supabase, path, { appName, orgId });\n if (result.success) {\n await refreshFiles();\n }\n return result;\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : 'Archive failed'\n };\n }\n }, [supabase, appName, orgId]);\n\n // List files\n const handleListFiles = useCallback(async (\n options: Partial<StorageListOptions> = {}\n ): Promise<StorageListResult> => {\n setIsListing(true);\n setListError(null);\n\n try {\n const listOptions: StorageListOptions = {\n appName,\n orgId,\n ...options\n };\n\n const result = await listFiles(supabase, listOptions);\n setFiles(result.files);\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'List failed';\n setListError(errorMessage);\n return { files: [], totalCount: 0, hasMore: false };\n } finally {\n setIsListing(false);\n }\n }, [supabase, appName, orgId]);\n\n // Refresh files\n const refreshFiles = useCallback(async () => {\n await handleListFiles();\n }, [handleListFiles]);\n\n return {\n // Upload\n uploadFile: handleUploadFile,\n isUploading,\n uploadError,\n \n // URLs\n getPublicUrl: handleGetPublicUrl,\n getSignedUrl: handleGetSignedUrl,\n getFileUrl: handleGetPublicUrl, // Alias for getPublicUrl\n \n // File management\n deleteFile: handleDeleteFile,\n archiveFile: handleArchiveFile,\n \n // Listing\n listFiles: handleListFiles,\n isListing,\n listError,\n isLoading: isListing, // Alias for isListing\n error: listError, // Alias for listError\n \n // State\n files,\n refreshFiles\n };\n}\n\n/**\n * Hook for file upload with progress tracking\n */\nexport function useFileUpload({ supabase, appName, orgId }: UseStorageOptions) {\n const [uploadProgress, setUploadProgress] = useState(0);\n const [isUploading, setIsUploading] = useState(false);\n const [uploadError, setUploadError] = useState<string | null>(null);\n\n const uploadWithProgress = useCallback(async (\n file: File,\n options: Partial<StorageUploadOptions> = {}\n ): Promise<StorageUploadResult> => {\n setIsUploading(true);\n setUploadProgress(0);\n setUploadError(null);\n\n try {\n // Simulate progress (Supabase doesn't provide real progress)\n const progressInterval = setInterval(() => {\n setUploadProgress(prev => Math.min(prev + 10, 90));\n }, 100);\n\n const uploadOptions: StorageUploadOptions = {\n appName,\n orgId,\n isPublic: false,\n ...options\n };\n\n const result = await uploadFile(supabase, file, uploadOptions);\n \n clearInterval(progressInterval);\n setUploadProgress(100);\n\n if (!result.success) {\n setUploadError(result.error || 'Upload failed');\n }\n\n return result;\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : 'Upload failed';\n setUploadError(errorMessage);\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsUploading(false);\n setTimeout(() => setUploadProgress(0), 1000);\n }\n }, [supabase, appName, orgId]);\n\n return {\n uploadWithProgress,\n uploadProgress,\n isUploading,\n uploadError\n };\n}\n"],"mappings":"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","names":["useEffect","useCallback","useEffect","useState","useCallback","useEffect","useRef","useCallback","useRef","useCallback","useEffect","useRef","useCallback","useRef","useCallback","useState","useCallback","log","useState","useCallback"]}
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/providers/OrganisationProvider.tsx","../src/components/InactivityWarningModal/InactivityWarningModal.tsx","../src/hooks/useInactivityTracker.ts","../src/index.ts","../src/utils/security/secureDataAccess.ts"],"sourcesContent":["/**\n * @file Organisation Provider\n * @package @jmruthers/pace-core\n * @module Providers\n * @since 0.1.0\n *\n * React provider for organisation context.\n * This is a convenience wrapper around OrganisationServiceProvider that\n * automatically gets auth context from UnifiedAuthProvider.\n * \n * Note: If you're using UnifiedAuthProvider, it already includes\n * OrganisationServiceProvider internally, so this component is mainly\n * for backward compatibility or standalone usage.\n */\n\nimport React from 'react';\nimport { useUnifiedAuth } from '../providers/services/UnifiedAuthProvider';\nimport { OrganisationServiceProvider } from './services/OrganisationServiceProvider';\nimport type { OrganisationProviderProps as BaseOrganisationProviderProps } from '../types/organisation';\n\nexport interface OrganisationProviderProps extends BaseOrganisationProviderProps {\n children: React.ReactNode;\n requireOrganisationContext?: boolean;\n autoSelectPrimaryOrganisation?: boolean;\n onOrganisationChange?: (organisation: any) => void;\n}\n\n/**\n * OrganisationProvider component\n * \n * Wraps OrganisationServiceProvider and automatically gets auth context.\n * \n * @example\n * ```tsx\n * <UnifiedAuthProvider supabaseClient={supabase} appName=\"my-app\">\n * <OrganisationProvider>\n * <App />\n * </OrganisationProvider>\n * </UnifiedAuthProvider>\n * ```\n */\nexport function OrganisationProvider({ \n children,\n requireOrganisationContext,\n autoSelectPrimaryOrganisation,\n onOrganisationChange\n}: OrganisationProviderProps) {\n // Get auth context from UnifiedAuthProvider\n const authContext = useUnifiedAuth();\n \n // If we're inside UnifiedAuthProvider, it already includes OrganisationServiceProvider\n // So we can just pass through the children\n // However, if the auth context is not available, we need to handle that\n if (!authContext) {\n // If no auth context, we can't provide organisation service\n // This might happen if used outside UnifiedAuthProvider\n // In that case, we should probably throw an error or show a message\n console.warn('OrganisationProvider: No auth context available. Make sure OrganisationProvider is used inside UnifiedAuthProvider.');\n return <>{children}</>;\n }\n\n const { supabase, user, session } = authContext;\n\n // Wrap with OrganisationServiceProvider\n // Note: The props like requireOrganisationContext, autoSelectPrimaryOrganisation\n // are handled by the OrganisationService internally, not by the provider\n // Note: supabase is mapped to supabaseClient for OrganisationServiceProvider\n if (!supabase) {\n console.warn('OrganisationProvider: No supabase client available.');\n return <>{children}</>;\n }\n\n return (\n <OrganisationServiceProvider\n supabaseClient={supabase}\n user={user}\n session={session}\n >\n {children}\n </OrganisationServiceProvider>\n );\n}\n\n","/**\n * @file Inactivity Warning Modal\n * @package @jmruthers/pace-core\n * @module Components/InactivityWarningModal\n * @since 0.1.0\n *\n * A modal dialog that warns users about impending auto-logout due to inactivity.\n * Provides a countdown timer and action buttons to either stay signed in or sign out immediately.\n *\n * Features:\n * - Accessible modal dialog with focus management\n * - Live countdown timer with 1-second updates\n * - Clear action buttons (Stay Signed In / Sign Out Now)\n * - Keyboard navigation support (Escape to stay signed in)\n * - Cross-tab awareness and synchronization\n * - Tailwind v4 styling with pace-core theme tokens\n * - Production-safe with no arbitrary bracket classes\n *\n * @example\n * ```tsx\n * <InactivityWarningModal\n * isOpen={showWarning}\n * timeRemaining={45}\n * onStaySignedIn={() => setShowWarning(false)}\n * onSignOutNow={() => signOut()}\n * />\n * ```\n *\n * @accessibility\n * - WCAG 2.1 AA compliant\n * - Focus trap within modal content\n * - Screen reader announcements for countdown changes\n * - Keyboard navigation support\n * - Clear visual hierarchy and contrast\n * - Escape key to stay signed in (safe default)\n *\n * @performance\n * - Efficient countdown updates (1-second intervals)\n * - Minimal re-renders with stable references\n * - Memory leak prevention with cleanup\n * - Optimized timer management\n *\n * @dependencies\n * - React 19+ - Hooks and effects\n * - Dialog components - Modal functionality\n * - Tailwind CSS v4 - Styling\n */\n\nimport React, { useEffect, useState, useCallback } from 'react';\nimport { Dialog, DialogContent, DialogHeader } from '../Dialog/Dialog';\nimport { Button } from '../Button/Button';\nimport { Clock, AlertTriangle } from 'lucide-react';\nimport { cn } from '../../utils/core/cn';\nimport { Card } from '../Card/Card';\n\nexport interface InactivityWarningModalProps {\n /** Whether the modal is open */\n isOpen: boolean;\n /** Time remaining in seconds before auto-logout */\n timeRemaining: number;\n /** Callback when user chooses to stay signed in */\n onStaySignedIn: () => void;\n /** Callback when user chooses to sign out immediately */\n onSignOutNow: () => void;\n /** Optional custom title */\n title?: string;\n /** Optional custom description */\n description?: string;\n /** Optional custom className */\n className?: string;\n}\n\nexport function InactivityWarningModal({\n isOpen,\n timeRemaining,\n onStaySignedIn,\n onSignOutNow,\n title = \"Session Timeout Warning\",\n description = \"You've been inactive for a while. Your session will expire soon for security reasons.\",\n className\n}: InactivityWarningModalProps) {\n const [displayTime, setDisplayTime] = useState(timeRemaining);\n\n // Update display time when timeRemaining prop changes\n useEffect(() => {\n setDisplayTime(timeRemaining);\n }, [timeRemaining]);\n\n // Format time for display (MM:SS)\n const formatTime = useCallback((seconds: number) => {\n const mins = Math.floor(seconds / 60);\n const secs = seconds % 60;\n return `${mins.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;\n }, []);\n\n return (\n <Dialog open={isOpen} onOpenChange={(open) => !open && onStaySignedIn()}>\n <DialogContent\n className={cn(\"sm:max-w-md\", className)}\n preventCloseOnEscape={false}\n preventCloseOnOutsideClick={true}\n data-testid=\"inactivity-warning-modal\"\n title={title}\n description={description}\n >\n <DialogHeader className=\"grid place-items-center text-center size-full\">\n <AlertTriangle className=\"size-6 text-acc-600\" />\n <h2>{title}</h2>\n <p className=\"text-main-700 mt-2\">{description}</p>\n </DialogHeader>\n\n\n {/* Countdown Timer */}\n <Card className=\"text-center\">\n <Clock className=\"inline-block size-5 text-acc-600 mr-2\" />\n <span className=\"text-2xl font-mono font-bold text-acc-700\">\n {formatTime(displayTime)}\n </span>\n <small>\n Time remaining before automatic logout\n </small>\n </Card>\n\n {/* Action Buttons */}\n\n <Button\n onClick={onStaySignedIn}\n className=\"flex-1 bg-main-600 hover:bg-main-700 text-main-50\"\n size=\"lg\"\n >\n Stay Signed In\n </Button>\n <Button\n onClick={onSignOutNow}\n variant=\"outline\"\n size=\"lg\"\n >\n Sign Out Now\n </Button>\n\n {/* Additional Info */}\n <small>\n For security reasons, you'll be automatically signed out after 30 minutes of inactivity.\n </small>\n </DialogContent>\n </Dialog>\n );\n}\n","/**\n * @file Inactivity Tracker Hook\n * @package @jmruthers/pace-core\n * @module Hooks/useInactivityTracker\n * @since 0.1.0\n *\n * A custom hook that tracks user inactivity and provides cross-tab synchronization.\n * Monitors various user interactions and manages inactivity timers with persistence.\n *\n * Features:\n * - Cross-tab synchronization using BroadcastChannel and localStorage\n * - Monitors keyboard, mouse, touch, scroll, and focus events\n * - Throttled event handling for performance\n * - Persistence of last activity time across page reloads\n * - SSR-safe implementation with proper cleanup\n * - Configurable timeout and warning thresholds\n * - Production-safe with dev-only escape hatches\n *\n * @example\n * ```tsx\n * const {\n * isIdle,\n * timeRemaining,\n * showWarning,\n * resetActivity,\n * startTracking,\n * stopTracking\n * } = useInactivityTracker({\n * idleTimeoutMs: 30 * 60 * 1000, // 30 minutes\n * warnBeforeMs: 60 * 1000, // 1 minute\n * onIdle: () => console.log('User is idle'),\n * onWarning: () => console.log('Warning should show'),\n * onActivity: () => console.log('User is active')\n * });\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (utility hook)\n * - Enables accessible inactivity warnings\n * - Supports screen reader friendly countdowns\n * - Maintains focus management during warnings\n *\n * @performance\n * - Throttled event handling (100ms intervals)\n * - Efficient timer management with cleanup\n * - Minimal re-renders with stable references\n * - Memory leak prevention\n * - Cross-tab optimization\n *\n * @dependencies\n * - React 19+ - Hooks and effects\n * - Browser APIs - BroadcastChannel, localStorage, timers\n */\n\nimport { useState, useEffect, useCallback, useRef } from 'react';\nimport { logger } from '../utils/core/logger';\n\n/**\n * Options for the useInactivityTracker hook.\n */\nexport interface UseInactivityTrackerOptions {\n /** Timeout in milliseconds before user is considered idle (default: 30 minutes) */\n idleTimeoutMs?: number;\n /** Time in milliseconds before idle timeout to show warning (default: 60 seconds) */\n warnBeforeMs?: number;\n /** Callback when user becomes idle */\n onIdle?: () => void;\n /** Callback when warning should be shown */\n onWarning?: () => void;\n /** Callback when user becomes active again */\n onActivity?: () => void;\n /** Whether tracking is enabled (default: true) */\n enabled?: boolean;\n /** Storage key for persistence (default: 'pace-core-inactivity') */\n storageKey?: string;\n /** Broadcast channel name for cross-tab sync (default: 'pace-core-inactivity') */\n channelName?: string;\n}\n\nexport interface UseInactivityTrackerReturn {\n /** Whether the user is currently idle */\n isIdle: boolean;\n /** Time remaining in milliseconds before idle timeout */\n timeRemaining: number;\n /** Whether warning should be shown */\n showWarning: boolean;\n /** Reset the activity timer */\n resetActivity: () => void;\n /** Start tracking inactivity */\n startTracking: () => void;\n /** Stop tracking inactivity */\n stopTracking: () => void;\n /** Whether tracking is currently active */\n isTracking: boolean;\n}\n\n// Events that indicate user activity\nconst ACTIVITY_EVENTS = [\n 'mousedown',\n 'mousemove',\n 'mouseup',\n 'click',\n 'scroll',\n 'wheel',\n 'touchstart',\n 'touchmove',\n 'touchend',\n 'keydown',\n 'keyup',\n 'keypress',\n 'focus',\n 'blur',\n 'visibilitychange'\n] as const;\n\n// Throttle function to limit event handler frequency\nfunction throttle<T extends (...args: any[]) => void>(\n func: T,\n limit: number\n): (...args: Parameters<T>) => void {\n let inThrottle: boolean;\n return function (this: any, ...args: Parameters<T>) {\n if (!inThrottle) {\n func.apply(this, args);\n inThrottle = true;\n setTimeout(() => (inThrottle = false), limit);\n }\n };\n}\n\nexport function useInactivityTracker({\n idleTimeoutMs = 30 * 60 * 1000, // 30 minutes\n warnBeforeMs = 60 * 1000, // 1 minute\n onIdle,\n onWarning,\n onActivity,\n enabled = true,\n storageKey = 'pace-core-inactivity',\n channelName = 'pace-core-inactivity'\n}: UseInactivityTrackerOptions = {}): UseInactivityTrackerReturn {\n const [isIdle, setIsIdle] = useState(false);\n const [timeRemaining, setTimeRemaining] = useState(idleTimeoutMs);\n const [showWarning, setShowWarning] = useState(false);\n const [isTracking, setIsTracking] = useState(false);\n\n // Reset tracking state when enabled changes\n useEffect(() => {\n if (!enabled) {\n setIsTracking(false);\n setIsIdle(false);\n setShowWarning(false);\n setTimeRemaining(idleTimeoutMs);\n }\n }, [enabled, idleTimeoutMs]);\n\n const timeoutRef = useRef<NodeJS.Timeout | null>(null);\n const warningTimeoutRef = useRef<NodeJS.Timeout | null>(null);\n const countdownIntervalRef = useRef<NodeJS.Timeout | null>(null);\n const lastActivityRef = useRef<number>(Date.now());\n const channelRef = useRef<BroadcastChannel | null>(null);\n const throttledResetActivityRef = useRef<((event: Event) => void) | null>(null);\n const onIdleRef = useRef(onIdle);\n const onWarningRef = useRef(onWarning);\n const onActivityRef = useRef(onActivity);\n\n useEffect(() => {\n onIdleRef.current = onIdle;\n onWarningRef.current = onWarning;\n onActivityRef.current = onActivity;\n }, [onIdle, onWarning, onActivity]);\n\n // Clear all timers\n const clearTimers = useCallback(() => {\n if (timeoutRef.current) {\n clearTimeout(timeoutRef.current);\n timeoutRef.current = null;\n }\n if (warningTimeoutRef.current) {\n clearTimeout(warningTimeoutRef.current);\n warningTimeoutRef.current = null;\n }\n if (countdownIntervalRef.current) {\n clearInterval(countdownIntervalRef.current);\n countdownIntervalRef.current = null;\n }\n }, []);\n\n // Reset activity and restart timers\n const resetActivity = useCallback((skipActivityCallback = false) => {\n if (!enabled) return;\n\n const now = Date.now();\n lastActivityRef.current = now;\n\n // Clear existing timers\n clearTimers();\n\n // Reset state\n setIsIdle(false);\n setShowWarning(false);\n setTimeRemaining(idleTimeoutMs);\n\n // Notify activity callback (unless skipped for initial setup)\n if (!skipActivityCallback) {\n onActivityRef.current?.();\n }\n\n // Set up warning timer\n const warningTime = idleTimeoutMs - warnBeforeMs;\n if (warningTime > 0) {\n warningTimeoutRef.current = setTimeout(() => {\n setShowWarning(true);\n onWarningRef.current?.();\n }, warningTime);\n }\n\n // Set up idle timeout\n timeoutRef.current = setTimeout(() => {\n setIsIdle(true);\n onIdleRef.current?.();\n }, idleTimeoutMs);\n\n // Start countdown interval for time remaining\n countdownIntervalRef.current = setInterval(() => {\n const elapsed = Date.now() - lastActivityRef.current;\n const remaining = Math.max(0, idleTimeoutMs - elapsed);\n setTimeRemaining(remaining);\n\n if (remaining === 0) {\n clearTimers();\n }\n }, 1000);\n\n // Persist activity time\n try {\n localStorage.setItem(storageKey, now.toString());\n } catch (error) {\n logger.warn('useInactivityTracker', 'Failed to persist activity time:', error);\n }\n\n // Broadcast activity to other tabs\n try {\n if (channelRef.current) {\n channelRef.current.postMessage({ type: 'activity', timestamp: now });\n }\n } catch (error) {\n logger.warn('useInactivityTracker', 'Failed to broadcast activity:', error);\n }\n }, [enabled, idleTimeoutMs, warnBeforeMs, storageKey, clearTimers]);\n\n // Start tracking\n const startTracking = useCallback(() => {\n if (!enabled) return;\n\n // Always reset state and start fresh\n setIsTracking(false);\n setIsIdle(false);\n setShowWarning(false);\n setTimeRemaining(idleTimeoutMs);\n \n // Clear any existing timers\n clearTimers();\n \n setIsTracking(true);\n\n // Set up cross-tab communication\n try {\n if (typeof BroadcastChannel !== 'undefined') {\n channelRef.current = new BroadcastChannel(channelName);\n channelRef.current.onmessage = (event) => {\n if (event.data.type === 'activity') {\n lastActivityRef.current = event.data.timestamp;\n resetActivity();\n }\n };\n }\n } catch (error) {\n logger.warn('useInactivityTracker', 'Failed to set up cross-tab communication:', error);\n }\n\n // Check for persisted activity time\n try {\n const persistedTime = localStorage.getItem(storageKey);\n if (persistedTime) {\n const persistedTimestamp = parseInt(persistedTime, 10);\n const elapsed = Date.now() - persistedTimestamp;\n \n if (elapsed < idleTimeoutMs) {\n // User was active recently, continue from where we left off\n lastActivityRef.current = persistedTimestamp;\n const remaining = idleTimeoutMs - elapsed;\n setTimeRemaining(remaining);\n \n if (remaining <= warnBeforeMs) {\n setShowWarning(true);\n onWarningRef.current?.();\n }\n \n if (remaining <= 0) {\n setIsIdle(true);\n onIdleRef.current?.();\n return;\n }\n }\n }\n } catch (error) {\n logger.warn('useInactivityTracker', 'Failed to check persisted activity time:', error);\n }\n\n // Clean up any existing throttled handler and event listeners first\n if (throttledResetActivityRef.current) {\n ACTIVITY_EVENTS.forEach(event => {\n document.removeEventListener(event, throttledResetActivityRef.current!);\n });\n }\n\n // Set up throttled activity handler - store in ref for proper cleanup\n throttledResetActivityRef.current = throttle((event) => {\n resetActivity();\n }, 100);\n\n // Add event listeners\n ACTIVITY_EVENTS.forEach(event => {\n document.addEventListener(event, throttledResetActivityRef.current!, { passive: true });\n });\n\n // Start the timer (skip activity callback for initial setup)\n resetActivity(true);\n\n // Cleanup function\n return () => {\n // Remove event listeners using the stored ref\n if (throttledResetActivityRef.current) {\n ACTIVITY_EVENTS.forEach(event => {\n document.removeEventListener(event, throttledResetActivityRef.current!);\n });\n throttledResetActivityRef.current = null;\n }\n clearTimers();\n if (channelRef.current) {\n channelRef.current.close();\n channelRef.current = null;\n }\n };\n }, [enabled, channelName, storageKey, idleTimeoutMs, warnBeforeMs, resetActivity, clearTimers]);\n\n // Stop tracking\n const stopTracking = useCallback(() => {\n setIsTracking(false);\n clearTimers();\n \n // Remove event listeners\n if (throttledResetActivityRef.current) {\n ACTIVITY_EVENTS.forEach(event => {\n document.removeEventListener(event, throttledResetActivityRef.current!);\n });\n throttledResetActivityRef.current = null;\n }\n \n if (channelRef.current) {\n channelRef.current.close();\n channelRef.current = null;\n }\n }, [clearTimers]);\n\n // Effect to start/stop tracking based on enabled state\n useEffect(() => {\n if (enabled) {\n const cleanup = startTracking();\n return cleanup;\n } else {\n stopTracking();\n return undefined;\n }\n }, [enabled, idleTimeoutMs, warnBeforeMs, startTracking, stopTracking]);\n\n // Cleanup on unmount\n useEffect(() => {\n return () => {\n clearTimers();\n if (channelRef.current) {\n channelRef.current.close();\n }\n };\n }, [clearTimers]);\n\n return {\n isIdle,\n timeRemaining,\n showWarning,\n resetActivity,\n startTracking,\n stopTracking,\n isTracking\n };\n}\n","/**\n * @file Complete Component Library Export\n * @package @jmruthers/pace-core\n * @module Core\n * @since 0.1.0\n * \n * This file exports the primary components, hooks, and utilities from the PACE Core library.\n * It is the main entry point for developers using the library.\n * \n * @example\n * // Import common components\n * import { Button, Card, useUnifiedAuth } from '@jmruthers/pace-core';\n * \n * // For specialized components, use the complete library import:\n * import { Dialog, NavigationMenu } from '@jmruthers/pace-core/components';\n */\n\n// AUTHENTICATION & AUTHORIZATION\n// Note: Providers are now service-based architecture for better testability and maintainability\nexport { UnifiedAuthProvider, useUnifiedAuth } from './providers/services/UnifiedAuthProvider';\nexport type { UnifiedAuthProviderProps, UnifiedAuthContextType, UserEventAccess } from './providers/services/UnifiedAuthProvider';\n\n// Session tracking utility (for manual use if needed)\nexport { useSessionTracking } from './utils/context/sessionTracking';\n\n// Provider components (using service architecture)\nexport { EventServiceProvider } from './providers/services/EventServiceProvider';\nexport { OrganisationServiceProvider } from './providers/services/OrganisationServiceProvider';\nexport { InactivityServiceProvider } from './providers/services/InactivityServiceProvider';\n\n// Convenience provider wrapper (backward compatibility)\nexport { OrganisationProvider } from './providers/OrganisationProvider';\nexport type { OrganisationProviderProps } from './providers/OrganisationProvider';\n\n// Convenience hooks\nexport { useEvents } from './hooks/useEvents';\nexport { useOrganisations } from './hooks/useOrganisations';\n\n// Service hooks for advanced usage (better performance)\nexport { useEventService } from './hooks/services/useEventService';\nexport { useOrganisationService } from './hooks/services/useOrganisationService';\nexport { useAuthService } from './hooks/services/useAuthService';\nexport { useInactivityService } from './hooks/services/useInactivityService';\nexport { useSessionRestoration } from './hooks/useSessionRestoration';\n\nexport type { \n Organisation, \n OrganisationMembership, \n OrganisationContextType, \n OrganisationSecurityError \n} from './types/organisation';\n\n// INACTIVITY TRACKING\nexport { InactivityWarningModal } from './components/InactivityWarningModal/InactivityWarningModal';\nexport type { InactivityWarningModalProps } from './components/InactivityWarningModal/InactivityWarningModal';\nexport { useInactivityTracker } from './hooks/useInactivityTracker';\nexport type { UseInactivityTrackerOptions, UseInactivityTrackerReturn } from './hooks/useInactivityTracker';\n\n// RBAC SYSTEM - Consolidated RBAC module\nexport * from './rbac';\n\n// BASIC UI COMPONENTS\nexport { Button } from './components/Button/Button';\nexport type { ButtonProps } from './components/Button/Button';\n\nexport { \n Card, \n CardHeader, \n CardFooter, \n CardTitle, \n CardDescription, \n CardContent,\n CardActions\n} from './components/Card/Card';\nexport type { CardProps } from './components/Card/Card';\n\nexport { Input } from './components/Input/Input';\nexport type { InputProps } from './components/Input/Input';\nexport { AddressField } from './components/AddressField';\nexport type { AddressFieldProps, AddressFieldRef, ParsedAddress, AutocompleteOptions } from './components/AddressField';\nexport { Label } from './components/Label/Label';\nexport type { LabelProps } from './components/Label/Label';\n\nexport { Textarea } from './components/Textarea/Textarea';\nexport type { TextareaProps } from './components/Textarea/Textarea';\n\nexport { Alert, AlertTitle, AlertDescription } from './components/Alert/Alert';\nexport { Avatar } from './components/Avatar/Avatar';\nexport type { AvatarProps } from './components/Avatar/Avatar';\n\nexport { Badge } from './components/Badge/Badge';\nexport type { BadgeProps, BadgeVariant } from './components/Badge/Badge';\n\nexport { Checkbox } from './components/Checkbox/Checkbox';\nexport { Switch } from './components/Switch/Switch';\nexport type { SwitchProps } from './components/Switch/Switch';\nexport { Progress } from './components/Progress';\nexport type { ProgressProps } from './components/Progress';\n\n// ADVANCED UI COMPONENTS\nexport {\n Dialog,\n DialogPortal,\n DialogTrigger,\n DialogClose,\n DialogContent,\n DialogHeader,\n DialogBody,\n DialogFooter,\n DialogTitle,\n DialogDescription,\n} from './components/Dialog/Dialog';\nexport type {\n DialogProps,\n DialogTriggerProps,\n DialogContentProps,\n DialogPortalProps,\n DialogCloseProps,\n DialogHeaderProps,\n DialogFooterProps,\n DialogBodyProps,\n DialogSize\n} from './components/Dialog/Dialog';\n\n// Dropdown Menu exports\n// DropdownMenu components have been merged into Select components\n\n// Select exports\nexport {\n Select,\n SelectGroup,\n SelectValue,\n SelectTrigger,\n SelectContent,\n SelectLabel,\n SelectItem,\n SelectSeparator,\n} from './components/Select';\n\n// Tabs exports\nexport { Tabs, TabsList, TabsTrigger, TabsContent } from './components/Tabs/Tabs';\nexport type { TabsProps, TabsListProps, TabsTriggerProps, TabsContentProps } from './components/Tabs/Tabs';\n\n// Calendar exports\nexport { Calendar } from './components/Calendar/Calendar';\nexport type { CalendarProps } from './components/Calendar/Calendar';\n\n// Modal functionality is provided by Dialog components\n\nexport {\n Toast,\n Toaster,\n ToastAction,\n ToastProvider,\n ToastViewport,\n ToastTitle,\n ToastDescription,\n ToastClose,\n} from './components/Toast/Toast';\nexport { useToast } from './hooks/useToast';\nexport type { ToastActionElement, ToastProps } from './components/Toast/Toast';\n\nexport { Tooltip, TooltipTrigger, TooltipContent, TooltipProvider, TooltipRoot } from './components/Tooltip/Tooltip';\n\n// DATA DISPLAY COMPONENTS\nexport {\n DataTable,\n type DataTableProps,\n type DataTableColumn,\n type DataTableAction,\n type DataTableToolbarButton,\n type AggregateConfig,\n type EmptyStateConfig,\n type GetRowId,\n type DataTableFeatureConfig,\n ColumnFactory\n} from './components/DataTable';\n\n// Re-export types from DataTable types\nexport type { DataRecord, ExportOptions } from './components/DataTable/types';\n\n// Export DataTable utility functions\nexport {\n exportToCSV,\n exportToCSVWithTableRows,\n generateCSVContent,\n type ExportColumn\n} from './components/DataTable/utils/exportUtils';\n\n// Export DataTable aggregation utilities\nexport {\n sum,\n average,\n count,\n min,\n max\n} from './components/DataTable/utils/aggregationUtils';\n\n// FORM COMPONENTS\nexport { Form, FormField } from './components/Form/Form';\nexport type { FormProps, FormFieldProps } from './components/Form/Form';\nexport { LoginForm } from './components/LoginForm';\nexport type { LoginFormProps } from './components/LoginForm';\n\n// FORM HOOKS\nexport { useZodForm } from './hooks/useZodForm';\nexport { useFormDialog } from './hooks/useFormDialog';\nexport type { UseFormDialogOptions, UseFormDialogReturn } from './hooks/useFormDialog';\n\n// VALIDATION - Re-export zod for schema creation\nexport { z } from 'zod';\n// Common validation schemas\nexport { emailSchema, nameSchema, phoneSchema, urlSchema } from './utils/validation/common';\nexport { passwordSchema } from './utils/validation/passwordSchema';\n\n// LAYOUT COMPONENTS\nexport { Header } from './components/Header/Header';\nexport { Footer } from './components/Footer/Footer';\nexport type { FooterProps } from './components/Footer/Footer';\n\n// NAVIGATION COMPONENTS\nexport { NavigationMenu } from './components/NavigationMenu/NavigationMenu';\nexport type { NavigationMenuProps, NavigationItem, NavigationMode } from './components/NavigationMenu/NavigationMenu';\nexport { UserMenu } from './components/UserMenu/UserMenu';\nexport type { UserMenuProps } from './components/UserMenu/UserMenu';\n\n// Reusable Page/Layout Components\nexport { PaceAppLayout } from './components/PaceAppLayout/PaceAppLayout';\nexport type { PaceAppLayoutProps } from './components/PaceAppLayout/PaceAppLayout';\nexport { PaceLoginPage } from './components/PaceLoginPage/PaceLoginPage';\nexport type { PaceLoginPageProps } from './components/PaceLoginPage/PaceLoginPage';\n\nexport { ProtectedRoute } from './components/ProtectedRoute/ProtectedRoute';\nexport type { ProtectedRouteProps } from './components/ProtectedRoute/ProtectedRoute';\n\n// UTILITY COMPONENTS\nexport { ErrorBoundary, ErrorBoundaryProvider } from './components/ErrorBoundary';\nexport type { ErrorBoundaryProps, ErrorBoundaryState, ErrorBoundaryProviderProps, GlobalErrorHandler } from './components/ErrorBoundary';\nexport { LoadingSpinner } from './components/LoadingSpinner/LoadingSpinner';\nexport { SessionRestorationLoader } from './components/SessionRestorationLoader/SessionRestorationLoader';\nexport type { SessionRestorationLoaderProps } from './components/SessionRestorationLoader/SessionRestorationLoader';\n\n// CONTEXT SELECTION\n// Unified context selector (shows all accessible orgs and events)\nexport { ContextSelector } from './components/ContextSelector/ContextSelector';\nexport type { ContextSelectorProps } from './components/ContextSelector/ContextSelector';\nexport { useOrganisationPermissions } from './hooks/useOrganisationPermissions';\nexport { useOrganisationSecurity } from './hooks/useOrganisationSecurity';\nexport { createSecureDataAccess } from './utils/security/secureDataAccess';\n\n// TYPES\nexport type { UserProfile } from './types/organisation';\n\n// AUTHENTICATION FORMS\nexport { PasswordChangeForm } from './components/PasswordChange/PasswordChangeForm';\n\n// UTILS & HOOKS\nexport { useAppConfig } from './hooks/useAppConfig';\nexport { useEventTheme } from './hooks/useEventTheme';\nexport { cn } from './utils/core/cn';\nexport { setAppConfig, getAppConfig, getCurrentAppName, getCurrentAppId } from './utils/app/appConfig';\n\n// LOGGING UTILITIES\nexport { Logger, logger, createLogger, LogLevel } from './utils/core/logger';\nexport type { LoggerConfig } from './utils/core/logger';\n\n// FORMATTING UTILITIES\nexport { \n formatDate,\n formatTime,\n formatDateTime,\n formatCurrency, \n formatNumber,\n formatPercent,\n formatCompactNumber,\n formatFileSize\n} from './utils/formatting/formatting';\n\n// TIMEZONE UTILITIES\nexport {\n formatInTimeZone,\n getTimezoneAbbreviation,\n formatTimeInTimeZone,\n getUserTimeZone,\n toZonedTime,\n fromZonedTime,\n roundToNearestMinutes,\n getTimeZoneDifference\n} from './utils/timezone';\n\n// STORAGE UTILITIES\nexport { FileUpload } from './components/FileUpload';\nexport type { FileUploadProps } from './components/FileUpload';\nexport { FileDisplay } from './components/FileDisplay';\nexport type { FileDisplayProps } from './components/FileDisplay';\nexport { FileCategory } from './types/file-reference';\nexport type { FileReference, FileMetadata, FileUploadOptions } from './types/file-reference';\nexport { \n useFileReference, \n useFileReferenceForRecord,\n useFileReferenceById,\n useFilesByCategory\n} from './hooks/useFileReference';\nexport type { \n UseFileReferenceOptions, \n UseFileReferenceReturn, \n UseFileReferenceForRecordReturn \n} from './hooks/useFileReference';\nexport * from './utils/storage';\n\n// Table components\nexport {\n Table,\n TableHeader,\n TableBody,\n TableCaption,\n TableCell,\n TableFooter,\n TableHead,\n TableRow,\n} from './components/Table/Table';\n\n// STYLES & THEMING\nexport * from './styles';\n// Direct export of theming utilities for convenience\nexport { parseAndNormalizeEventColours } from './theming/parseEventColours';\nexport { applyPalette, clearPalette } from './theming/runtime';\nexport type { PaletteData, ColorPalette, ColorShade } from './theming/runtime';\n\n// PUBLIC PAGES\nexport * from './hooks/public';\nexport * from './components/PublicLayout';\n","/**\n * @file Secure Data Access Utility\n * @package @jmruthers/pace-core\n * @module Utils/SecureDataAccess\n * @since 0.4.0\n *\n * Secure data access utilities that enforce organisation context for all database operations.\n * Prevents data leakage between organisations and ensures proper access validation.\n */\n\nimport type { SupabaseClient } from '@supabase/supabase-js';\n\n// Generic database record type\nexport interface DatabaseRecord {\n id: string;\n organisation_id: string;\n [key: string]: unknown;\n}\n\n// Generic data for insert/update operations\nexport interface DatabaseData {\n [key: string]: unknown;\n}\n\n// Generic filters for queries\nexport interface DatabaseFilters {\n [key: string]: unknown;\n}\n\n// Secure query options\nexport interface SecureQueryOptions {\n table: string;\n select: string;\n organisationId: string;\n filters?: DatabaseFilters;\n orderBy?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface SecureDataAccess {\n // Secure query methods\n secureQuery: <T extends DatabaseRecord = DatabaseRecord>(options: SecureQueryOptions) => Promise<T[]>;\n secureSingleQuery: <T extends DatabaseRecord = DatabaseRecord>(options: SecureQueryOptions) => Promise<T | null>;\n \n // Secure mutation methods\n secureInsert: <T extends DatabaseRecord = DatabaseRecord>(table: string, data: DatabaseData, organisationId: string) => Promise<T | null>;\n secureUpdate: <T extends DatabaseRecord = DatabaseRecord>(table: string, data: DatabaseData, filters: DatabaseFilters, organisationId: string) => Promise<T | null>;\n secureDelete: (table: string, filters: DatabaseFilters, organisationId: string) => Promise<boolean>;\n \n // Organisation-scoped queries\n queryByOrganisation: <T extends DatabaseRecord = DatabaseRecord>(table: string, select: string, organisationId: string, filters?: DatabaseFilters) => Promise<T[]>;\n \n // Validation helpers\n validateOrganisationContext: (organisationId: string) => void;\n ensureOrganisationColumn: (table: string) => boolean;\n}\n\nexport interface SecureQueryBuilder {\n table: string;\n select: string;\n organisationId: string;\n filters?: DatabaseFilters;\n orderBy?: string;\n limit?: number;\n offset?: number;\n}\n\n/**\n * Create a secure data access instance\n * @param supabase - Supabase client instance\n * @param organisationId - Current organisation context\n * @param isSuperAdmin - Whether user has super admin privileges\n * @returns Secure data access utilities\n */\nexport const createSecureDataAccess = (\n supabase: SupabaseClient,\n organisationId: string,\n isSuperAdmin: boolean = false\n): SecureDataAccess => {\n \n // Validate organisation context\n const validateOrganisationContext = (orgId: string): void => {\n if (!orgId) {\n throw new Error('Organisation context is required for secure data access');\n }\n \n if (!isSuperAdmin && !orgId) {\n throw new Error('Organisation context is mandatory for non-super admin users');\n }\n };\n\n // Check if table has organisation_id column\n const ensureOrganisationColumn = (table: string): boolean => {\n // This is a simplified check - in production you might want to cache this\n const tablesWithOrganisation = [\n 'core_events', 'organisation_settings',\n 'rbac_event_app_roles', 'rbac_organisation_roles',\n // SECURITY: Phase 2 additions - complete organisation table mapping\n 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',\n // SECURITY: Emergency additions for Phase 1 fixes\n 'cake_meal', 'cake_mealtype',\n // NOTE: core_person, pace_person, core_member, medi_profile, core_contact, core_consent, \n // core_identification, core_qualification are now person-scoped (not organisation-scoped) \n // and do NOT have organisation_id columns - removed from this list\n // SECURITY: Phase 3A additions - medical and personal data\n // NOTE: medi_condition, medi_diet, medi_action_plan, medi_profile_versions are now person-scoped\n // (via medi_profile) - removed from this list\n // core_identification_type remains organisation-scoped (lookup table)\n 'form_responses', 'form_response_values', 'forms',\n // SECURITY: Phase 3B additions - remaining critical tables\n 'invoice', 'line_item', 'credit_balance', 'payment_method',\n 'form_contexts', 'form_field_config', 'form_fields',\n 'cake_delivery', 'cake_diettype', 'cake_diner', 'cake_dish', 'cake_item', \n 'cake_logistics', 'cake_mealplan', 'cake_package', 'cake_recipe', 'cake_supplier', \n 'cake_supply', 'cake_unit', 'event_app_access', 'base_application', 'base_questions'\n ];\n \n return tablesWithOrganisation.includes(table);\n };\n\n // Build secure query with organisation context\n const buildSecureQuery = (options: SecureQueryBuilder) => {\n const { table, select, organisationId: orgId, filters, orderBy, limit, offset } = options;\n \n validateOrganisationContext(orgId);\n \n let query = supabase\n .from(table)\n .select(select);\n \n // Add organisation filter (unless super admin)\n if (!isSuperAdmin && ensureOrganisationColumn(table)) {\n query = query.eq('organisation_id', orgId);\n }\n \n // Add additional filters\n if (filters) {\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n // Handle qualified column names (e.g., 'users.role')\n const columnName = key.includes('.') ? key.split('.').pop()! : key;\n query = query.eq(columnName, value);\n }\n });\n }\n \n // Add ordering\n if (orderBy) {\n // Only use the column name, not a qualified name\n const orderByColumn = orderBy.split('.').pop();\n if (orderByColumn) {\n query = query.order(orderByColumn);\n }\n }\n \n // Add pagination\n if (limit) {\n query = query.limit(limit);\n }\n \n if (offset) {\n query = query.range(offset, offset + (limit || 10) - 1);\n }\n \n return query;\n };\n\n // Secure query for multiple results\n const secureQuery = async <T extends DatabaseRecord = DatabaseRecord>(options: SecureQueryOptions): Promise<T[]> => {\n const { table, select, organisationId: orgId, filters, orderBy, limit, offset } = options;\n \n try {\n const query = buildSecureQuery({\n table,\n select,\n organisationId: orgId,\n filters,\n orderBy,\n limit,\n offset\n });\n \n const { data, error } = await query;\n \n if (error) {\n throw error;\n }\n \n // Ensure data is an array and not an error type\n if (Array.isArray(data)) {\n return data as unknown as T[];\n }\n \n return [];\n } catch (error) {\n throw error;\n }\n };\n\n // Secure query for single result\n const secureSingleQuery = async <T extends DatabaseRecord = DatabaseRecord>(options: SecureQueryOptions): Promise<T | null> => {\n const { table, select, organisationId: orgId, filters, orderBy, limit, offset } = options;\n \n try {\n const query = buildSecureQuery({\n table,\n select,\n organisationId: orgId,\n filters,\n orderBy,\n limit,\n offset\n });\n \n const { data, error } = await query.single();\n \n if (error) {\n if (error.code === 'PGRST116') {\n // No rows returned\n return null;\n }\n throw error;\n }\n \n // Ensure data is not an error type\n if (data && typeof data === 'object' && !('code' in data)) {\n return data as unknown as T;\n }\n \n return null;\n } catch (error) {\n throw error;\n }\n };\n\n // Secure insert with organisation context\n const secureInsert = async <T extends DatabaseRecord = DatabaseRecord>(\n table: string, \n data: DatabaseData, \n organisationId: string\n ): Promise<T | null> => {\n validateOrganisationContext(organisationId);\n \n try {\n const insertData = {\n ...data,\n organisation_id: organisationId\n };\n \n const { data: result, error } = await supabase\n .from(table)\n .insert(insertData)\n .select()\n .single();\n \n if (error) {\n throw error;\n }\n \n return result;\n } catch (error) {\n throw error;\n }\n };\n\n // Secure update with organisation context\n const secureUpdate = async <T extends DatabaseRecord = DatabaseRecord>(\n table: string, \n data: DatabaseData, \n filters: DatabaseFilters, \n organisationId: string\n ): Promise<T | null> => {\n validateOrganisationContext(organisationId);\n \n try {\n let query = supabase\n .from(table)\n .update(data);\n \n // Add organisation filter (unless super admin)\n if (!isSuperAdmin && ensureOrganisationColumn(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n \n // Add additional filters\n if (filters) {\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n query = query.eq(key, value);\n }\n });\n }\n \n const { data: result, error } = await query.select().single();\n \n if (error) {\n throw error;\n }\n \n return result;\n } catch (error) {\n throw error;\n }\n };\n\n // Secure delete with organisation context\n const secureDelete = async (\n table: string, \n filters: DatabaseFilters, \n organisationId: string\n ): Promise<boolean> => {\n validateOrganisationContext(organisationId);\n \n try {\n let query = supabase\n .from(table)\n .delete();\n \n // Add organisation filter (unless super admin)\n if (!isSuperAdmin && ensureOrganisationColumn(table)) {\n query = query.eq('organisation_id', organisationId);\n }\n \n // Add additional filters\n if (filters) {\n Object.entries(filters).forEach(([key, value]) => {\n if (value !== undefined && value !== null) {\n query = query.eq(key, value);\n }\n });\n }\n \n const { error } = await query;\n \n if (error) {\n throw error;\n }\n \n return true;\n } catch (error) {\n throw error;\n }\n };\n\n // Organisation-scoped query helper\n const queryByOrganisation = async <T extends DatabaseRecord = DatabaseRecord>(\n table: string, \n select: string, \n organisationId: string, \n filters?: DatabaseFilters\n ): Promise<T[]> => {\n return secureQuery<T>({\n table,\n select,\n organisationId,\n filters\n });\n };\n\n return {\n secureQuery,\n secureSingleQuery,\n secureInsert,\n secureUpdate,\n secureDelete,\n queryByOrganisation,\n validateOrganisationContext,\n ensureOrganisationColumn\n };\n};\n\n/**\n * Hook for secure data access\n * @returns Secure data access utilities\n */\nexport const useSecureDataAccess = (): SecureDataAccess => {\n // This would typically get the context from providers\n // For now, we'll create a placeholder that can be used with explicit parameters\n throw new Error('useSecureDataAccess must be used with explicit parameters. Use createSecureDataAccess instead.');\n}; "],"mappings":"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","names":["jsx","formatTime","useState","useEffect","useCallback","useState","useEffect","useCallback","organisationId"]}
|
package/dist/providers.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/rbac/eslint-rules.js"],"sourcesContent":["/**\n * ESLint Rules for RBAC Enforcement\n * @package @jmruthers/pace-core\n * @module RBAC/ESLintRules\n * @since 1.0.0\n * \n * This module provides ESLint rules to enforce RBAC usage patterns.\n */\n\nmodule.exports = {\n rules: {\n /**\n * Ban direct @supabase/supabase-js imports outside secureClient\n */\n 'no-direct-supabase-import': {\n create(context) {\n return {\n ImportDeclaration(node) {\n if (node.source.value === '@supabase/supabase-js') {\n context.report({\n node,\n message: 'Use @jmruthers/pace-core/secureClient instead of direct Supabase imports. This ensures organisation context is properly enforced.',\n suggest: [{\n desc: 'Replace with secure client import',\n fix: function(fixer) {\n return fixer.replaceText(\n node,\n \"import { createSecureClient } from '@jmruthers/pace-core/secureClient';\"\n );\n }\n }]\n });\n }\n }\n };\n }\n },\n\n /**\n * Require withPermissionGuard for server handlers\n */\n 'require-permission-guard': {\n create(context) {\n const serverHandlerPatterns = [\n 'app.get',\n 'app.post',\n 'app.put',\n 'app.delete',\n 'app.patch',\n 'router.get',\n 'router.post',\n 'router.put',\n 'router.delete',\n 'router.patch',\n 'handler',\n 'middleware'\n ];\n\n return {\n CallExpression(node) {\n if (node.callee.type === 'MemberExpression') {\n const methodName = `${node.callee.object.name}.${node.callee.property.name}`;\n \n if (serverHandlerPatterns.includes(methodName)) {\n // Check if the handler is wrapped with permission guard\n const hasPermissionGuard = context.getAncestors().some(ancestor => \n ancestor.type === 'CallExpression' &&\n ancestor.callee.name === 'withPermissionGuard'\n );\n\n if (!hasPermissionGuard) {\n context.report({\n node,\n message: `Server handler '${methodName}' should be wrapped with withPermissionGuard to ensure proper permission checking.`,\n suggest: [{\n desc: 'Wrap with permission guard',\n fix: function(fixer) {\n const sourceCode = context.getSourceCode();\n const handlerText = sourceCode.getText(node);\n return fixer.replaceText(\n node,\n `withPermissionGuard({ permission: 'read:api' }, ${handlerText})`\n );\n }\n }]\n });\n }\n }\n }\n }\n };\n }\n },\n\n /**\n * Forbid inline permission strings (must import from permissions.ts)\n */\n 'forbid-inline-permissions': {\n create(context) {\n const permissionPattern = /^(read|create|update|delete|manage):[a-zA-Z0-9._-]+$/;\n\n return {\n Literal(node) {\n if (typeof node.value === 'string' && permissionPattern.test(node.value)) {\n // Check if this is a permission string\n const isPermissionString = context.getAncestors().some(ancestor => \n ancestor.type === 'Property' && \n (ancestor.key.name === 'permission' || ancestor.key.value === 'permission')\n ) || context.getAncestors().some(ancestor => \n ancestor.type === 'CallExpression' && \n ancestor.callee.name === 'isPermitted'\n );\n\n if (isPermissionString) {\n context.report({\n node,\n message: `Permission string '${node.value}' should be imported from a permissions constants file instead of using inline strings.`,\n suggest: [{\n desc: 'Import from permissions file',\n fix: function(fixer) {\n return fixer.replaceText(\n node,\n `PERMISSIONS.${node.value.replace(/[:.-]/g, '_').toUpperCase()}`\n );\n }\n }]\n });\n }\n }\n }\n };\n }\n },\n\n /**\n * Require organisation context in RBAC operations\n */\n 'require-organisation-context': {\n create(context) {\n const rbacFunctions = [\n 'isPermitted',\n 'getAccessLevel',\n 'getPermissionMap',\n 'useCan',\n 'usePermissions',\n 'useAccessLevel'\n ];\n\n return {\n CallExpression(node) {\n if (node.callee.name && rbacFunctions.includes(node.callee.name)) {\n // Check if scope parameter has organisationId\n const scopeArg = node.arguments.find(arg => \n arg.type === 'ObjectExpression' && \n arg.properties.some(prop => \n prop.key.name === 'scope' || prop.key.value === 'scope'\n )\n );\n\n if (scopeArg) {\n const scopeObject = scopeArg.properties.find(prop => \n prop.key.name === 'scope' || prop.key.value === 'scope'\n );\n\n if (scopeObject && scopeObject.value.type === 'ObjectExpression') {\n const hasOrganisationId = scopeObject.value.properties.some(prop => \n prop.key.name === 'organisationId' || prop.key.value === 'organisationId'\n );\n\n if (!hasOrganisationId) {\n context.report({\n node,\n message: `RBAC function '${node.callee.name}' requires organisationId in scope parameter for proper data isolation.`,\n suggest: [{\n desc: 'Add organisationId to scope',\n fix: function(fixer) {\n const sourceCode = context.getSourceCode();\n const scopeText = sourceCode.getText(scopeObject.value);\n return fixer.replaceText(\n scopeObject.value,\n `${scopeText.slice(0, -1)}, organisationId: 'your-org-id'${scopeText.slice(-1)}`\n );\n }\n }]\n });\n }\n }\n }\n }\n }\n };\n }\n },\n\n /**\n * Require error handling for RBAC operations\n */\n 'require-rbac-error-handling': {\n create(context) {\n const rbacHooks = ['useCan', 'usePermissions', 'useAccessLevel'];\n\n return {\n CallExpression(node) {\n if (node.callee.name && rbacHooks.includes(node.callee.name)) {\n // Check if the hook is used in a component that handles errors\n const component = context.getAncestors().find(ancestor => \n ancestor.type === 'FunctionDeclaration' || \n ancestor.type === 'FunctionExpression' ||\n ancestor.type === 'ArrowFunctionExpression'\n );\n\n if (component) {\n const componentBody = component.body;\n const hasErrorHandling = context.getSourceCode().getText(componentBody).includes('error');\n\n if (!hasErrorHandling) {\n context.report({\n node,\n message: `RBAC hook '${node.callee.name}' should be used with proper error handling to provide good user experience.`,\n suggest: [{\n desc: 'Add error handling',\n fix: function(fixer) {\n const sourceCode = context.getSourceCode();\n const hookText = sourceCode.getText(node);\n return fixer.insertTextAfter(\n node,\n `\\n if (error) {\\n console.error('RBAC error:', error);\\n return <div>Error loading permissions</div>;\\n }`\n );\n }\n }]\n });\n }\n }\n }\n }\n };\n }\n },\n\n /**\n * Require loading states for RBAC operations\n */\n 'require-rbac-loading-states': {\n create(context) {\n const rbacHooks = ['useCan', 'usePermissions', 'useAccessLevel'];\n\n return {\n CallExpression(node) {\n if (node.callee.name && rbacHooks.includes(node.callee.name)) {\n // Check if the hook is used in a component that handles loading\n const component = context.getAncestors().find(ancestor => \n ancestor.type === 'FunctionDeclaration' || \n ancestor.type === 'FunctionExpression' ||\n ancestor.type === 'ArrowFunctionExpression'\n );\n\n if (component) {\n const componentBody = component.body;\n const hasLoadingHandling = context.getSourceCode().getText(componentBody).includes('isLoading');\n\n if (!hasLoadingHandling) {\n context.report({\n node,\n message: `RBAC hook '${node.callee.name}' should be used with proper loading state handling for better user experience.`,\n suggest: [{\n desc: 'Add loading state handling',\n fix: function(fixer) {\n const sourceCode = context.getSourceCode();\n const hookText = sourceCode.getText(node);\n return fixer.insertTextAfter(\n node,\n `\\n if (isLoading) {\\n return <div>Loading permissions...</div>;\\n }`\n );\n }\n }]\n });\n }\n }\n }\n }\n };\n }\n }\n }\n};\n"],"mappings":"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","names":[]}
|
package/dist/rbac/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/styles/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/types.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/types/organisation.ts","../src/types/guards.ts"],"sourcesContent":["/**\n * @file Organisation Types\n * @package @jmruthers/pace-core\n * @module Types/Organisation\n * @since 1.0.0\n * \n * Type definitions for organisations, memberships, roles, and organisation context.\n */\n\nimport type { OrganisationId, UserId } from './core';\n\nexport interface Organisation {\n id: string;\n name: string;\n display_name: string;\n description?: string;\n parent_id?: string;\n subscription_tier: string;\n settings: Record<string, unknown>;\n is_active: boolean;\n created_at: string;\n updated_at: string;\n created_by?: string;\n updated_by?: string;\n}\n\nexport interface OrganisationMembership {\n id: string;\n user_id: UserId;\n organisation_id: OrganisationId;\n role: 'org_admin' | 'leader' | 'member' | 'supporter';\n status: 'active' | 'inactive' | 'suspended';\n granted_at: string;\n granted_by?: string;\n revoked_at?: string;\n revoked_by?: string;\n notes?: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface UserProfile {\n id: UserId;\n email: string;\n full_name?: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface OrganisationSettings {\n organisation_id: OrganisationId;\n logo_url?: string;\n primary_color?: string;\n secondary_color?: string;\n website_url?: string;\n contact_email?: string;\n phone?: string;\n address?: Record<string, unknown>;\n timezone?: string;\n date_format?: string;\n currency?: string;\n language?: string;\n custom_css?: string;\n email_templates?: Record<string, unknown>;\n notification_settings?: Record<string, unknown>;\n created_at: string;\n updated_at: string;\n created_by?: string;\n updated_by?: string;\n}\n\nexport interface OrganisationInvitation {\n id: string;\n organisation_id: OrganisationId;\n email: string;\n role: 'supporter' | 'member' | 'leader' | 'org_admin';\n invited_by?: string;\n expires_at: string;\n accepted_at?: string;\n created_at: string;\n updated_at: string;\n}\n\nexport interface OrganisationRoleDefinition {\n id: string;\n name: string;\n display_name: string;\n description?: string;\n permissions: Record<string, unknown>;\n is_active: boolean;\n created_at: string;\n updated_at: string;\n}\n\nexport interface SuperAdminContext {\n isSuperAdmin: boolean;\n hasGlobalAccess: boolean;\n canManageAllOrganisations: boolean;\n}\n\nexport interface OrganisationSecurityError extends Error {\n name: 'OrganisationSecurityError';\n code: string;\n organisationId?: string;\n userId?: string;\n}\n\nexport interface OrganisationContextType {\n // Current organisation context\n selectedOrganisation: Organisation | null;\n organisations: Organisation[];\n userMemberships: OrganisationMembership[];\n \n // Loading and error states\n isLoading: boolean;\n error: Error | null;\n hasValidOrganisationContext: boolean;\n isContextReady: boolean;\n \n // Organisation management\n setSelectedOrganisation: (org: Organisation | null) => void;\n switchOrganisation: (orgId: string) => Promise<void>;\n \n // Security helpers\n getUserRole: (orgId?: string) => string;\n validateOrganisationAccess: (orgId: string) => boolean;\n ensureOrganisationContext: () => Organisation;\n \n // Data management\n refreshOrganisations: () => Promise<void>;\n getPrimaryOrganisation: () => Organisation | null;\n isOrganisationSecure: () => boolean;\n \n // Enhanced security features\n getOrganisationHierarchy?: (orgId: string) => Promise<OrganisationHierarchy[]>;\n canAccessChildOrganisations?: (orgId: string) => boolean;\n validateUserAccess?: (userId: string, orgId: string) => Promise<boolean>;\n getUserPermissions?: (orgId?: string) => Promise<string[]>;\n logOrganisationAccess?: (action: string, details?: unknown) => Promise<void>;\n}\n\nexport interface OrganisationProviderProps {\n children: React.ReactNode;\n}\n\nexport interface OrganisationHierarchy {\n organisation: Organisation;\n children: OrganisationHierarchy[];\n parent?: Organisation;\n depth: number;\n}\n\n// Role permissions mapping - Updated for new consolidated role system\nexport const ORGANISATION_ROLE_PERMISSIONS = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings'],\n} as const;\n\nexport type OrganisationRole = keyof typeof ORGANISATION_ROLE_PERMISSIONS;\n\n// Define permission types based on the permissions used in the system\nexport type OrganisationPermission = \n | 'view_basic'\n | 'view_details'\n | 'moderate_content'\n | 'manage_events'\n | 'manage_members'\n | 'manage_settings'\n | '*';\n\n// Enhanced security types\nexport interface OrganisationAccessLog {\n id: string;\n user_id: UserId;\n organisation_id: OrganisationId;\n action: string;\n details: Record<string, unknown>;\n created_at: string;\n}\n\nexport interface SecureQueryOptions {\n table: string;\n select: string;\n filters?: Record<string, unknown>;\n organisationId: OrganisationId;\n userId?: UserId;\n} ","\n/**\n * @file Type Guards\n */\n\nimport { AuthErrorCode } from './core';\nimport type { User, Session } from './auth';\n\nexport function isAuthErrorCode(code: string): code is AuthErrorCode {\n return Object.values(AuthErrorCode).includes(code as AuthErrorCode);\n}\n\nexport function isUser(obj: unknown): obj is User {\n const candidate = obj as Partial<User> | null | undefined;\n return (\n candidate != null &&\n typeof candidate === 'object' &&\n typeof candidate.id === 'string' &&\n typeof candidate.created_at === 'string'\n );\n}\n\nexport function isSession(obj: unknown): obj is Session {\n const candidate = obj as Partial<Session> | null | undefined;\n return (\n candidate != null &&\n typeof candidate === 'object' &&\n typeof candidate.access_token === 'string' &&\n candidate.user != null &&\n typeof candidate.user === 'object'\n );\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAyJO,IAAM,gCAAgC;AAAA,EAC3C,WAAW,CAAC,YAAY;AAAA,EACxB,QAAQ,CAAC,cAAc,cAAc;AAAA,EACrC,QAAQ,CAAC,cAAc,gBAAgB,oBAAoB,eAAe;AAAA,EAC1E,WAAW,CAAC,cAAc,gBAAgB,oBAAoB,iBAAiB,kBAAkB,iBAAiB;AACpH;;;ACtJO,SAAS,gBAAgB,MAAqC;AACnE,SAAO,OAAO,OAAO,aAAa,EAAE,SAAS,IAAqB;AACpE;AAEO,SAAS,OAAO,KAA2B;AAChD,QAAM,YAAY;AAClB,SACE,aAAa,QACb,OAAO,cAAc,YACrB,OAAO,UAAU,OAAO,YACxB,OAAO,UAAU,eAAe;AAEpC;AAEO,SAAS,UAAU,KAA8B;AACtD,QAAM,YAAY;AAClB,SACE,aAAa,QACb,OAAO,cAAc,YACrB,OAAO,UAAU,iBAAiB,YAClC,UAAU,QAAQ,QAClB,OAAO,UAAU,SAAS;AAE9B;","names":[]}
|
package/dist/utils.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/utils/core/debugLogger.ts","../src/utils/validation/validation.ts","../src/utils/validation/validationUtils.ts","../src/utils/validation/sanitization.ts","../src/utils/validation/csrf.ts","../src/utils/validation/sqlInjectionProtection.ts","../src/utils/validation/user.ts","../src/utils/security/security.ts","../src/utils/security/securityMonitor.ts","../src/constants/performance.ts","../src/utils/performance/performanceBenchmark.ts","../src/utils/performance/bundleAnalysis.ts","../src/utils/dynamic/dynamicUtils.ts","../src/utils/dynamic/lazyLoad.tsx","../src/utils/permissions/permissionUtils.ts","../src/utils/permissions/permissionTypes.ts","../src/utils/audit/audit.ts","../src/utils/device/deviceFingerprint.ts","../src/utils/location/location.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 /**\n * Check if we're in development mode\n */\n private static get isDevelopment(): boolean {\n return import.meta.env.MODE === 'development';\n }\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 try {\n console.log(`[${component}] ${message}`, ...args);\n } catch (e) {\n // Gracefully handle console method errors\n }\n }\n }\n\n /**\n * Log error information (always logged)\n */\n static error(component: string, message: string, ...args: any[]): void {\n try {\n console.error(`[${component}] ${message}`, ...args);\n } catch (e) {\n // Gracefully handle console method errors\n }\n }\n\n /**\n * Log warning information (always logged)\n */\n static warn(component: string, message: string, ...args: any[]): void {\n try {\n console.warn(`[${component}] ${message}`, ...args);\n } catch (e) {\n // Gracefully handle console method errors\n }\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 try {\n console.info(`[${component}] ${message}`, ...args);\n } catch (e) {\n // Gracefully handle console method errors\n }\n }\n }\n}\n","/**\n * @file Internal utilities for validation module\n * @internal This file contains implementation details that should not be used directly\n */\n\n/**\n * Utility functions for validating data in the application\n */\n\n/**\n * Check if a string is a valid email\n */\nexport function isValidEmail(email: string): boolean {\n const emailPattern = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailPattern.test(email);\n}\n\n/**\n * Check if a string is empty (either null, undefined, or just whitespace)\n */\nexport function isEmpty(value: string | null | undefined): boolean {\n return value === null || value === undefined || value.trim() === '';\n}\n\n/**\n * Check if a password meets minimum requirements\n */\nexport function isStrongPassword(password: string): boolean {\n // Minimum 8 characters, at least one uppercase, one lowercase, one number\n const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$/;\n return passwordPattern.test(password);\n}\n\n/**\n * Check if a URL is valid\n */\nexport function isValidUrl(url: string): boolean {\n try {\n new URL(url);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if a date string is valid\n */\nexport function isValidDate(dateStr: string): boolean {\n const date = new Date(dateStr);\n return !isNaN(date.getTime());\n}\n\n/**\n * Check if a value is within a range\n */\nexport function isWithinRange(value: number, min: number, max: number): boolean {\n return value >= min && value <= max;\n}\n\n/**\n * Check if a value matches a specific pattern\n */\nexport function matchesPattern(value: string, pattern: RegExp): boolean {\n return pattern.test(value);\n}\n\n/**\n * Utility function to deep merge objects for schema combination\n * @internal\n */\nexport function deepMerge<T extends Record<string, unknown>>(\n target: T, \n source: Record<string, unknown>\n): T {\n const output = { ...target };\n \n if (isObject(target) && isObject(source)) {\n Object.keys(source).forEach(key => {\n if (isObject(source[key])) {\n if (!(key in target)) {\n Object.assign(output, { [key]: source[key] });\n } else {\n // Use a type assertion to safely handle the indexing\n const targetKey = key as keyof typeof target;\n const targetValue = target[targetKey];\n \n if (isObject(targetValue)) {\n // Safe cast using type assertion\n output[targetKey] = deepMerge(\n targetValue as Record<string, unknown>,\n source[key] as Record<string, unknown>\n ) as unknown as T[keyof T];\n }\n }\n } else {\n Object.assign(output, { [key]: source[key] });\n }\n });\n }\n \n return output as T;\n}\n\n/**\n * Type guard to check if a value is a plain object\n * @internal\n */\nexport function isObject(item: unknown): item is Record<string, unknown> {\n return item !== null && typeof item === 'object' && !Array.isArray(item);\n}\n","\n/**\n * @file Validation utilities\n * \n * Shared validation utilities with enhanced security\n */\n\nimport { z } from 'zod';\nimport { sanitizeUserInput, sanitizeFormData, type SanitizationOptions } from './sanitization';\n\n/**\n * Validates user input against a schema with automatic sanitization\n */\nexport function validateUserInput<T>(\n schema: z.ZodSchema<T>, \n data: unknown,\n sanitizationRules?: Record<string, SanitizationOptions>\n): { success: boolean; data?: T; error?: string } {\n return sanitizeFormData(data, schema, sanitizationRules);\n}\n\n/**\n * Enhanced email validation with sanitization\n */\nexport const emailSchema = z.string()\n .transform(email => email.toLowerCase().trim())\n .pipe(z.string().min(1, 'Email is required').email('Invalid email format').max(254, 'Email too long'));\n\n/**\n * Enhanced password validation\n */\nexport const passwordSchema = z.string()\n .min(8, 'Password must be at least 8 characters')\n .max(128, 'Password too long')\n .regex(/[A-Z]/, 'Password must contain at least one uppercase letter')\n .regex(/[a-z]/, 'Password must contain at least one lowercase letter')\n .regex(/[0-9]/, 'Password must contain at least one number')\n .regex(/[^A-Za-z0-9]/, 'Password must contain at least one special character');\n\n/**\n * Username validation with sanitization\n */\nexport const usernameSchema = z.string()\n .transform(username => username.toLowerCase().trim())\n .pipe(z.string().min(3, 'Username must be at least 3 characters').max(30, 'Username too long').regex(/^[a-zA-Z0-9_-]+$/, 'Username can only contain letters, numbers, hyphens, and underscores'));\n\n/**\n * Name validation with sanitization\n */\nexport const nameSchema = z.string()\n .min(1, 'Name is required')\n .max(100, 'Name too long')\n .refine(name => {\n // Check for XSS attempts and other invalid patterns\n const dangerousPatterns = [\n /<script/i,\n /<img/i,\n /on\\w+\\s*=/i,\n /javascript:/i,\n /data:/i,\n /vbscript:/i\n ];\n \n return !dangerousPatterns.some(pattern => pattern.test(name));\n }, 'Name contains invalid characters')\n .transform(name => sanitizeUserInput(name, { \n allowHtml: false, \n maxLength: 100, \n trim: true \n }));\n\n/**\n * Phone number validation with sanitization\n */\nexport const phoneSchema = z.string()\n .min(10, 'Phone number must be at least 10 digits')\n .max(20, 'Phone number too long')\n .regex(/^[\\+]?[0-9\\s\\-\\(\\)\\.]+$/, 'Invalid phone number format')\n .refine(phone => {\n // Remove all non-digit characters and check length\n const digitsOnly = phone.replace(/\\D/g, '');\n return digitsOnly.length >= 10 && digitsOnly.length <= 15;\n }, 'Phone number must be between 10 and 15 digits');\n\n/**\n * URL validation with sanitization\n */\nexport const urlSchema = z.string()\n .min(1, 'URL is required')\n .max(2048, 'URL too long')\n .refine(url => {\n try {\n const parsed = new URL(url);\n return ['http:', 'https:'].includes(parsed.protocol);\n } catch {\n return false;\n }\n }, 'Invalid URL format')\n .refine(url => {\n // Additional security checks\n const dangerousPatterns = [\n /javascript:/i,\n /data:/i,\n /vbscript:/i,\n /file:/i,\n /mailto:/i\n ];\n \n return !dangerousPatterns.some(pattern => pattern.test(url));\n }, 'URL contains invalid protocol');\n","/**\n * @file Input Sanitization Layer\n * @package @jmruthers/pace-core\n * @module Utils/Validation/Sanitization\n * @since 0.1.0\n * \n * Comprehensive input sanitization utilities to prevent XSS, injection attacks,\n * and other security vulnerabilities.\n */\n\nimport { z } from 'zod';\n\n/**\n * Sanitization options for different contexts\n */\nexport interface SanitizationOptions {\n allowHtml?: boolean;\n allowedTags?: string[];\n maxLength?: number;\n trim?: boolean;\n removeScripts?: boolean;\n removeEvents?: boolean;\n}\n\n/**\n * Default sanitization options\n */\nconst DEFAULT_OPTIONS: SanitizationOptions = {\n allowHtml: false,\n allowedTags: [],\n maxLength: 1000,\n trim: true,\n removeScripts: true,\n removeEvents: true\n};\n\n/**\n * Sanitizes user input by removing potentially dangerous characters and patterns\n */\nexport function sanitizeUserInput(input: string, options: SanitizationOptions = {}): string {\n if (typeof input !== 'string') {\n return '';\n }\n\n const opts = { ...DEFAULT_OPTIONS, ...options };\n let sanitized = input;\n\n // Trim whitespace if requested\n if (opts.trim) {\n sanitized = sanitized.trim();\n }\n\n // Enforce maximum length\n if (opts.maxLength && sanitized.length > opts.maxLength) {\n sanitized = sanitized.substring(0, opts.maxLength);\n }\n\n // Remove or escape HTML if not allowed\n if (!opts.allowHtml) {\n sanitized = sanitized\n .replace(/</g, '<')\n .replace(/>/g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(/\\//g, '/');\n } else if (opts.allowedTags && opts.allowedTags.length > 0) {\n // If HTML is allowed, only permit specific tags\n const allowedTagsRegex = new RegExp(`<(?!\\/?(?:${opts.allowedTags.join('|')})\\s*\\/?>)[^>]+>`, 'gi');\n sanitized = sanitized.replace(allowedTagsRegex, '');\n }\n\n // Remove script tags and javascript: protocols\n if (opts.removeScripts) {\n sanitized = sanitized\n .replace(/<script[^>]*>.*?<\\/script>/gi, '')\n .replace(/javascript:/gi, '')\n .replace(/vbscript:/gi, '')\n .replace(/data:/gi, '');\n }\n\n // Remove event handlers\n if (opts.removeEvents) {\n sanitized = sanitized.replace(/on\\w+\\s*=/gi, '');\n }\n\n return sanitized;\n}\n\n/**\n * Sanitizes email addresses\n */\nexport function sanitizeEmail(email: string): string {\n if (typeof email !== 'string') {\n return '';\n }\n\n return email\n .trim()\n .toLowerCase()\n .replace(/[^\\w@.-]/g, ''); // Only allow word characters, @, ., and -\n}\n\n/**\n * Sanitizes phone numbers\n */\nexport function sanitizePhoneNumber(phone: string): string {\n if (typeof phone !== 'string') {\n return '';\n }\n\n return phone.replace(/[^\\d+\\-\\s()]/g, '').trim();\n}\n\n/**\n * Sanitizes URLs\n */\nexport function sanitizeUrl(url: string): string {\n if (typeof url !== 'string') {\n return '';\n }\n\n const sanitized = url.trim();\n \n // Only allow http(s) and ftp protocols\n if (!/^https?:\\/\\/|^ftp:\\/\\//i.test(sanitized)) {\n return '';\n }\n\n // Remove javascript: and other dangerous protocols\n if (/javascript:|data:|vbscript:/i.test(sanitized)) {\n return '';\n }\n\n return sanitized;\n}\n\n/**\n * Sanitizes file names\n */\nexport function sanitizeFileName(fileName: string): string {\n if (typeof fileName !== 'string') {\n return '';\n }\n\n return fileName\n .trim()\n .replace(/[<>:\"/\\\\|?*]/g, '') // Remove invalid file name characters\n .replace(/\\.\\./g, '') // Remove directory traversal attempts\n .substring(0, 255); // Limit length\n}\n\n/**\n * Sanitizes SQL input to prevent injection\n */\nexport function sanitizeSqlInput(input: string): string {\n if (typeof input !== 'string') {\n return '';\n }\n\n return input\n .replace(/['\";\\\\]/g, '') // Remove SQL special characters\n .replace(/--.*$/gm, '') // Remove SQL comments\n .replace(/\\/\\*.*?\\*\\//g, '') // Remove SQL block comments\n .trim();\n}\n\n/**\n * Validates and sanitizes form data using Zod schemas\n */\nexport function sanitizeFormData<T>(\n data: unknown,\n schema: z.ZodSchema<T>,\n sanitizationRules?: Record<string, SanitizationOptions>\n): { success: boolean; data?: T; error?: string } {\n try {\n // First, sanitize string fields if rules are provided\n if (sanitizationRules && typeof data === 'object' && data !== null) {\n const sanitizedData = { ...data } as Record<string, unknown>;\n \n Object.entries(sanitizationRules).forEach(([field, options]) => {\n if (typeof sanitizedData[field] === 'string') {\n sanitizedData[field] = sanitizeUserInput(sanitizedData[field] as string, options);\n }\n });\n \n data = sanitizedData;\n }\n\n // Then validate with Zod schema\n const result = schema.parse(data);\n return { success: true, data: result };\n } catch (error) {\n if (error instanceof z.ZodError) {\n return { \n success: false, \n error: error.errors.map(e => e.message).join(', ') \n };\n }\n return { \n success: false, \n error: 'Validation failed' \n };\n }\n}\n\n// Re-export HTML sanitization from the consolidated module\n// The new implementation allows safe HTML tags while removing dangerous ones\nexport { sanitizeHtml } from './htmlSanitization';\n\n/**\n * Content Security Policy (CSP) utilities\n */\nexport const CSP_DIRECTIVES = {\n default: \"default-src 'self'\",\n script: \"script-src 'self' 'unsafe-inline'\",\n style: \"style-src 'self' 'unsafe-inline'\",\n img: \"img-src 'self' data: https:\",\n font: \"font-src 'self'\",\n connect: \"connect-src 'self'\",\n frame: \"frame-src 'none'\"\n};\n\nexport function generateCSPHeader(customDirectives?: Partial<typeof CSP_DIRECTIVES>): string {\n const directives = { ...CSP_DIRECTIVES, ...customDirectives };\n return Object.values(directives).join('; ');\n}\n\n/**\n * Rate limiting utilities\n */\nexport class RateLimiter {\n private attempts: Map<string, { count: number; resetTime: number }> = new Map();\n\n constructor(\n private maxAttempts: number = 5,\n private windowMs: number = 15 * 60 * 1000 // 15 minutes\n ) {}\n\n isAllowed(identifier: string): boolean {\n const now = Date.now();\n const record = this.attempts.get(identifier);\n\n if (!record || now > record.resetTime) {\n this.attempts.set(identifier, { count: 1, resetTime: now + this.windowMs });\n return true;\n }\n\n if (record.count >= this.maxAttempts) {\n return false;\n }\n\n record.count++;\n return true;\n }\n\n getRemainingAttempts(identifier: string): number {\n const record = this.attempts.get(identifier);\n if (!record || Date.now() > record.resetTime) {\n return this.maxAttempts;\n }\n return Math.max(0, this.maxAttempts - record.count);\n }\n\n reset(identifier: string): void {\n this.attempts.delete(identifier);\n }\n}\n\n// Validation schemas (kept from previous version)\n/**\n * Enhanced email schema with security checks\n */\nexport const secureEmailSchema = z\n .string()\n .min(1, 'Email is required')\n .email('Invalid email format')\n .max(254, 'Email too long')\n .refine(\n (email) => {\n if (!email || typeof email !== 'string') return false;\n // Basic domain validation\n const domain = email.split('@')[1];\n return domain && domain.includes('.') && domain.length > 3;\n },\n 'Invalid email domain'\n )\n .transform((email) => sanitizeEmail(email));\n\n/**\n * Basic email schema for common use\n */\nexport const emailSchema = z\n .string()\n .min(1, 'Email is required')\n .email('Invalid email format');\n\n/**\n * Name validation schema\n */\nexport const nameSchema = z\n .string()\n .min(1, 'Name is required')\n .max(100, 'Name too long')\n .regex(/^[a-zA-Z\\s'-]+$/, 'Name contains invalid characters');\n\n/**\n * Phone validation schema\n */\nexport const phoneSchema = z\n .string()\n .regex(/^[\\+]?[1-9][\\d]{0,15}$/, 'Invalid phone number format');\n\n/**\n * URL validation schema\n */\nexport const urlSchema = z\n .string()\n .url('Invalid URL format');\n\n/**\n * Date validation schema\n */\nexport const dateSchema = z\n .string()\n .regex(/^\\d{4}-\\d{2}-\\d{2}$/, 'Invalid date format (YYYY-MM-DD)');\n\n/**\n * Secure login schema\n */\nexport const secureLoginSchema = z.object({\n email: secureEmailSchema,\n password: z.string().min(1, 'Password is required'),\n});\n","/**\n * @file CSRF Protection Implementation\n * @description Session-based CSRF token management with security enhancements\n */\n\nimport { secureStorage } from '../security/secureStorage';\n\nexport interface CSRFTokenData {\n token: string;\n sessionId: string;\n timestamp: number;\n used: boolean;\n}\n\nclass CSRFManager {\n private tokenCache = new Map<string, CSRFTokenData>();\n private readonly TOKEN_EXPIRY = 30 * 60 * 1000; // 30 minutes\n private readonly MAX_TOKENS_PER_SESSION = 10;\n\n /**\n * Generate a new CSRF token for the current session\n */\n async generateToken(sessionId: string): Promise<string> {\n try {\n // Clean up expired tokens\n await this.cleanupExpiredTokens();\n\n // Limit tokens per session\n const sessionTokens = Array.from(this.tokenCache.values())\n .filter(data => data.sessionId === sessionId && !data.used);\n \n if (sessionTokens.length >= this.MAX_TOKENS_PER_SESSION) {\n // Remove oldest token\n const oldest = sessionTokens.sort((a, b) => a.timestamp - b.timestamp)[0];\n this.tokenCache.delete(oldest.token);\n }\n\n // Generate cryptographically secure token\n const tokenBytes = new Uint8Array(32);\n crypto.getRandomValues(tokenBytes);\n const token = Array.from(tokenBytes, byte => \n byte.toString(16).padStart(2, '0')\n ).join('');\n\n const tokenData: CSRFTokenData = {\n token,\n sessionId,\n timestamp: Date.now(),\n used: false,\n };\n\n // Store in memory and secure storage\n this.tokenCache.set(token, tokenData);\n await this.persistTokens();\n\n return token;\n } catch (error) {\n throw new Error('CSRF token generation failed');\n }\n }\n\n /**\n * Validate and consume a CSRF token\n */\n async validateToken(token: string, sessionId: string): Promise<boolean> {\n try {\n // Load tokens from storage if cache is empty\n if (this.tokenCache.size === 0) {\n await this.loadTokens();\n }\n\n const tokenData = this.tokenCache.get(token);\n \n if (!tokenData) {\n return false;\n }\n\n // Check if token belongs to the session\n if (tokenData.sessionId !== sessionId) {\n return false;\n }\n\n // Check if token is already used\n if (tokenData.used) {\n return false;\n }\n\n // Check if token is expired\n if (Date.now() - tokenData.timestamp > this.TOKEN_EXPIRY) {\n this.tokenCache.delete(token);\n await this.persistTokens();\n return false;\n }\n\n // Mark token as used (one-time use)\n tokenData.used = true;\n this.tokenCache.set(token, tokenData);\n await this.persistTokens();\n\n return true;\n } catch (error) {\n return false;\n }\n }\n\n /**\n * Get current valid token for session\n */\n async getCurrentToken(sessionId: string): Promise<string | null> {\n // Load tokens from storage if needed\n if (this.tokenCache.size === 0) {\n await this.loadTokens();\n }\n\n // Find valid unused token for session\n for (const [token, data] of this.tokenCache.entries()) {\n if (\n data.sessionId === sessionId &&\n !data.used &&\n (Date.now() - data.timestamp) < this.TOKEN_EXPIRY\n ) {\n return token;\n }\n }\n\n // Generate new token if none found\n return await this.generateToken(sessionId);\n }\n\n /**\n * Clean up expired and used tokens\n */\n private async cleanupExpiredTokens(): Promise<void> {\n const now = Date.now();\n const expiredTokens: string[] = [];\n\n for (const [token, data] of this.tokenCache.entries()) {\n if (data.used || (now - data.timestamp) > this.TOKEN_EXPIRY) {\n expiredTokens.push(token);\n }\n }\n\n expiredTokens.forEach(token => this.tokenCache.delete(token));\n \n if (expiredTokens.length > 0) {\n await this.persistTokens();\n }\n }\n\n /**\n * Persist tokens to secure storage\n */\n private async persistTokens(): Promise<void> {\n try {\n const tokensArray = Array.from(this.tokenCache.entries());\n await secureStorage.setItem(\n 'csrf_tokens',\n JSON.stringify(tokensArray),\n { encrypt: true, expiry: this.TOKEN_EXPIRY }\n );\n } catch (error) {\n // Silent fail - tokens will be regenerated if needed\n }\n }\n\n /**\n * Load tokens from secure storage\n */\n private async loadTokens(): Promise<void> {\n try {\n const tokensData = await secureStorage.getItem('csrf_tokens');\n if (tokensData) {\n const tokensArray = JSON.parse(tokensData);\n this.tokenCache = new Map(tokensArray);\n // Clean up on load\n await this.cleanupExpiredTokens();\n }\n } catch (error) {\n this.tokenCache.clear();\n }\n }\n\n /**\n * Clear all tokens for session\n */\n async clearSession(sessionId: string): Promise<void> {\n const tokensToRemove: string[] = [];\n \n for (const [token, data] of this.tokenCache.entries()) {\n if (data.sessionId === sessionId) {\n tokensToRemove.push(token);\n }\n }\n \n tokensToRemove.forEach(token => this.tokenCache.delete(token));\n await this.persistTokens();\n }\n}\n\n// Export singleton instance\nexport const csrfManager = new CSRFManager();\n\n// Convenience functions\nexport async function generateCSRFToken(sessionId: string): Promise<string> {\n return csrfManager.generateToken(sessionId);\n}\n\nexport async function validateCSRFToken(token: string, sessionId: string): Promise<boolean> {\n return csrfManager.validateToken(token, sessionId);\n}\n\nexport async function getCSRFToken(sessionId: string): Promise<string | null> {\n return csrfManager.getCurrentToken(sessionId);\n}\n","\n/**\n * @file SQL Injection Protection\n * @description Utilities to prevent SQL injection attacks in dynamic queries\n */\n\nimport { z } from 'zod';\n\n// Common SQL injection patterns\nconst SQL_INJECTION_PATTERNS = [\n /(\\b(SELECT|INSERT|UPDATE|DELETE|DROP|CREATE|ALTER|EXEC|EXECUTE|UNION|SCRIPT|JAVASCRIPT)\\b)/i,\n /(\\'|(\\\\\\')|(\\'\\')|(\\\"|(\\\\\\\")|(\\\\\")))|(\\\\x)|(\\\\u)/i,\n /((%27)|(')|(%6F)|o|(%4F)|(%72)|r|(%52))/i, // '|%27|' OR\n /((%27)|(')|(%55)|u|(%55)|(%4E)|n|(%4E)|(%49)|i|(%49)|(%4F)|o|(%4F)|(%4E)|n|(%4E))/i, // '|%27|' UNION\n /((%3D)|(=))[^\\n]*((%27)|(')|((\\\\x27))|((\\\\x2D))|((\\\\x23)))/i,\n /(w*((%27)|(')|(%6F)|o|(%4F)|(%72)|r|(%52)))/i,\n /((%27)|(')|(''))+union/i,\n /exec(\\+|\\s)+(s|x)p\\w+/i,\n /\\b(and|or)\\b.+?(=|<|>|\\bin\\b|\\blike\\b)/i,\n /\\bunion\\b.+?\\bselect\\b/i,\n /\\bdrop\\b.+?\\btable\\b/i,\n /\\binsert\\b.+?\\binto\\b/i,\n /\\bdelete\\b.+?\\bfrom\\b/i,\n /\\bupdate\\b.+?\\bset\\b/i,\n /(;|(\\\\x3B)).+?(drop|create|alter|exec|execute|insert|update|delete)/i,\n /(%3B|;).+?(%44|%64|d)(%52|%72|r)(%4F|%6F|o)(%50|%70|p)/i\n];\n\n// Characters that should be escaped or removed\nconst DANGEROUS_CHARS = /[';\\\"\\\\%]/g;\n\n/**\n * Schema for validating and sanitizing search queries\n */\nexport const searchQuerySchema = z\n .string()\n .max(500, 'Search query too long')\n .refine(\n (query) => {\n return !SQL_INJECTION_PATTERNS.some(pattern => pattern.test(query));\n },\n 'Invalid characters detected in search query'\n )\n .transform((query) => sanitizeSearchQuery(query));\n\n/**\n * Schema for validating table/column names\n */\nexport const sqlIdentifierSchema = z\n .string()\n .min(1, 'Identifier cannot be empty')\n .max(63, 'Identifier too long') // PostgreSQL limit\n .regex(/^[a-zA-Z_][a-zA-Z0-9_]*$/, 'Invalid identifier format')\n .refine(\n (identifier) => {\n const reservedWords = [\n 'SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'CREATE', 'ALTER',\n 'FROM', 'WHERE', 'JOIN', 'UNION', 'ORDER', 'GROUP', 'HAVING'\n ];\n return !reservedWords.includes(identifier.toUpperCase());\n },\n 'Identifier cannot be a reserved SQL keyword'\n );\n\n/**\n * Schema for validating order by clauses\n */\nexport const orderBySchema = z\n .string()\n .regex(/^[a-zA-Z_][a-zA-Z0-9_]*(\\s+(ASC|DESC|asc|desc))?$/, 'Invalid order by format');\n\n/**\n * Schema for validating limit/offset values\n */\nexport const limitOffsetSchema = z\n .number()\n .int('Must be an integer')\n .min(0, 'Must be non-negative')\n .max(1000, 'Limit too large'); // Reasonable maximum\n\n/**\n * Sanitize search query by removing dangerous characters\n */\nexport function sanitizeSearchQuery(query: string): string {\n return query\n .replace(DANGEROUS_CHARS, '') // Remove dangerous characters\n .replace(/\\s+/g, ' ') // Normalize whitespace\n .trim()\n .slice(0, 500); // Enforce length limit\n}\n\n/**\n * Escape special characters for LIKE queries\n */\nexport function escapeLikeQuery(query: string): string {\n return query\n .replace(/\\\\/g, '\\\\\\\\') // Escape backslashes\n .replace(/%/g, '\\\\%') // Escape percent signs\n .replace(/_/g, '\\\\_'); // Escape underscores\n}\n\n/**\n * Validate and sanitize a dynamic filter object\n */\nexport function sanitizeFilters(filters: Record<string, unknown>): Record<string, unknown> {\n const sanitized: Record<string, unknown> = {};\n \n for (const [key, value] of Object.entries(filters)) {\n // Validate the key (column name)\n const keyValidation = sqlIdentifierSchema.safeParse(key);\n if (!keyValidation.success) {\n // Log warning for invalid filter keys\n // Note: Using console.warn here is intentional for security events\n // This should eventually use the security audit system\n console.warn(`[SECURITY] Invalid filter key detected and removed: ${key}`);\n continue;\n }\n \n // Sanitize the value based on type\n if (typeof value === 'string') {\n const valueValidation = searchQuerySchema.safeParse(value);\n if (valueValidation.success) {\n sanitized[key] = valueValidation.data;\n }\n } else if (typeof value === 'number') {\n if (Number.isFinite(value)) {\n sanitized[key] = value;\n }\n } else if (typeof value === 'boolean') {\n sanitized[key] = value;\n } else if (Array.isArray(value)) {\n // For IN queries, validate each item\n const sanitizedArray = value\n .filter(item => typeof item === 'string' || typeof item === 'number')\n .map(item => typeof item === 'string' ? sanitizeSearchQuery(item) : item)\n .slice(0, 100); // Limit array size\n \n if (sanitizedArray.length > 0) {\n sanitized[key] = sanitizedArray;\n }\n }\n }\n \n return sanitized;\n}\n\n/**\n * Build safe query parameters for Supabase\n */\nexport interface SafeQueryParams {\n select?: string;\n filters?: Record<string, unknown>;\n orderBy?: string;\n limit?: number;\n offset?: number;\n search?: string;\n}\n\nexport function buildSafeQueryParams(params: SafeQueryParams): SafeQueryParams {\n const safe: SafeQueryParams = {};\n \n // Validate select clause\n if (params.select) {\n const selectFields = params.select.split(',').map(field => field.trim());\n const validFields = selectFields.filter(field => {\n return sqlIdentifierSchema.safeParse(field).success;\n });\n \n if (validFields.length > 0) {\n safe.select = validFields.join(', ');\n }\n }\n \n // Sanitize filters\n if (params.filters) {\n safe.filters = sanitizeFilters(params.filters);\n }\n \n // Validate order by\n if (params.orderBy) {\n const orderByValidation = orderBySchema.safeParse(params.orderBy);\n if (orderByValidation.success) {\n safe.orderBy = orderByValidation.data;\n }\n }\n \n // Validate limit and offset\n if (params.limit !== undefined) {\n const limitValidation = limitOffsetSchema.safeParse(params.limit);\n if (limitValidation.success) {\n safe.limit = limitValidation.data;\n }\n }\n \n if (params.offset !== undefined) {\n const offsetValidation = limitOffsetSchema.safeParse(params.offset);\n if (offsetValidation.success) {\n safe.offset = offsetValidation.data;\n }\n }\n \n // Sanitize search query\n if (params.search) {\n const searchValidation = searchQuerySchema.safeParse(params.search);\n if (searchValidation.success) {\n safe.search = searchValidation.data;\n }\n }\n \n return safe;\n}\n\n/**\n * Detect potential SQL injection attempts\n */\nexport function detectSQLInjection(input: string): {\n isSuspicious: boolean;\n patterns: string[];\n riskLevel: 'low' | 'medium' | 'high' | 'critical';\n} {\n const detectedPatterns: string[] = [];\n let maxRisk: 'low' | 'medium' | 'high' | 'critical' = 'low';\n \n SQL_INJECTION_PATTERNS.forEach((pattern, index) => {\n if (pattern.test(input)) {\n detectedPatterns.push(`Pattern ${index + 1}`);\n \n // Assign risk levels based on pattern severity\n if (index < 3) { // Most dangerous patterns first\n maxRisk = 'critical';\n } else if (index < 7 && maxRisk !== 'critical') {\n maxRisk = 'high';\n } else if (index < 12 && !['critical', 'high'].includes(maxRisk)) {\n maxRisk = 'medium';\n }\n }\n });\n \n return {\n isSuspicious: detectedPatterns.length > 0,\n patterns: detectedPatterns,\n riskLevel: maxRisk\n };\n}\n","import { z } from 'zod';\nimport { emailSchema, nameSchema } from './common';\n\n/**\n * Schema for user profile data\n */\nexport const userProfileSchema = z.object({\n name: nameSchema,\n email: emailSchema,\n phone: z.string().optional(),\n website: z.string().url().optional(),\n bio: z.string().max(500).optional(),\n});\n\n/**\n * Schema for user settings\n */\nexport const userSettingsSchema = z.object({\n notifications: z.object({\n email: z.boolean(),\n push: z.boolean(),\n }),\n language: z.string(),\n});\n\n/**\n * Schema for user preferences\n */\nexport const userPreferencesSchema = z.object({\n displayName: nameSchema,\n timezone: z.string(),\n dateFormat: z.string(),\n currency: z.string(),\n}); ","\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport { createLogger } from '../core/logger';\n\nconst log = createLogger('Security');\n\nexport interface SecurityEvent {\n type: string;\n timestamp: Date;\n userId?: string;\n details: Record<string, unknown>;\n}\n\nexport function logSecurityEvent(event: SecurityEvent): void {\n // In production, this should log to your security monitoring system\n // Using Logger.warn for now - can be upgraded to audit system later\n log.warn('Security event:', {\n ...event,\n timestamp: event.timestamp.toISOString()\n });\n}\n\nexport function validateUserSession(userId: string, sessionToken?: string): Promise<boolean> {\n // Mock implementation - replace with actual session validation\n if (!userId || typeof userId !== 'string') {\n logSecurityEvent({\n type: 'invalid_session_validation',\n timestamp: new Date(),\n details: { reason: 'Invalid userId provided' }\n });\n return Promise.resolve(false);\n }\n \n if (sessionToken && sessionToken.length < 10) {\n logSecurityEvent({\n type: 'suspicious_session_token',\n timestamp: new Date(),\n userId,\n details: { reason: 'Session token too short' }\n });\n return Promise.resolve(false);\n }\n \n return Promise.resolve(true);\n}\n\nexport function createSecureSession(\n _supabaseClient: SupabaseClient,\n sessionData: { userId: string; deviceFingerprint?: string }\n): Promise<string> {\n // Mock implementation - in production, create actual secure session\n const sessionId = `sess_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n \n logSecurityEvent({\n type: 'session_created',\n timestamp: new Date(),\n userId: sessionData.userId,\n details: { \n sessionId,\n hasDeviceFingerprint: !!sessionData.deviceFingerprint\n }\n });\n \n return Promise.resolve(sessionId);\n}\n\nexport function invalidateSession(\n _supabaseClient: SupabaseClient,\n sessionId: string\n): Promise<void> {\n // Mock implementation - in production, invalidate actual session\n logSecurityEvent({\n type: 'session_invalidated',\n timestamp: new Date(),\n details: { sessionId }\n });\n \n return Promise.resolve();\n}\n\nexport function getSecurityHeaders(): Record<string, string> {\n return {\n 'X-Content-Type-Options': 'nosniff',\n 'X-Frame-Options': 'DENY',\n 'X-XSS-Protection': '1; mode=block',\n 'Referrer-Policy': 'strict-origin-when-cross-origin',\n 'Strict-Transport-Security': 'max-age=31536000; includeSubDomains'\n };\n}\n\nexport function validateSecurityHeaders(headers: Record<string, string>): boolean {\n const requiredHeaders = ['X-Content-Type-Options', 'X-Frame-Options'];\n const missingHeaders = requiredHeaders.filter(header => !headers[header]);\n \n if (missingHeaders.length > 0) {\n logSecurityEvent({\n type: 'missing_security_headers',\n timestamp: new Date(),\n details: { missingHeaders }\n });\n return false;\n }\n \n return true;\n}\n\nexport function generateDeviceFingerprint(): string {\n // Basic device fingerprinting - in production, use more sophisticated methods\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n if (ctx) {\n ctx.textBaseline = 'top';\n ctx.font = '14px Arial';\n ctx.fillText('Device fingerprint', 2, 2);\n }\n \n const fingerprint = [\n navigator.userAgent,\n navigator.language,\n screen.width + 'x' + screen.height,\n new Date().getTimezoneOffset(),\n canvas.toDataURL()\n ].join('|');\n \n // Simple hash function for demonstration\n let hash = 0;\n for (let i = 0; i < fingerprint.length; i++) {\n const char = fingerprint.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash; // Convert to 32-bit integer\n }\n \n return Math.abs(hash).toString(16);\n}\n\nexport function validateDeviceFingerprint(fingerprint: string, expectedFingerprint?: string): boolean {\n if (!fingerprint || typeof fingerprint !== 'string') {\n logSecurityEvent({\n type: 'invalid_device_fingerprint',\n timestamp: new Date(),\n details: { reason: 'Invalid fingerprint format' }\n });\n return false;\n }\n \n if (expectedFingerprint && fingerprint !== expectedFingerprint) {\n logSecurityEvent({\n type: 'device_fingerprint_mismatch',\n timestamp: new Date(),\n details: { \n provided: fingerprint,\n expected: expectedFingerprint\n }\n });\n return false;\n }\n \n return true;\n}\n","\ninterface SecurityEvent {\n id?: string;\n action: string;\n details: Record<string, any>;\n timestamp?: number;\n}\n\ninterface SecurityAlert {\n id: string;\n type: string;\n message: string;\n timestamp: Date;\n}\n\nclass SecurityMonitor {\n private events: SecurityEvent[] = [];\n\n logEvent(event: SecurityEvent) {\n const eventWithId = {\n ...event,\n id: Math.random().toString(36).substr(2, 9),\n timestamp: Date.now()\n };\n this.events.push(eventWithId);\n }\n\n getEvents(): SecurityEvent[] {\n return [...this.events];\n }\n\n clearEvents() {\n this.events = [];\n }\n\n createAlert(alert: Omit<SecurityAlert, 'id' | 'timestamp'>): SecurityAlert {\n return {\n ...alert,\n id: Math.random().toString(36).substr(2, 9),\n timestamp: new Date()\n };\n }\n}\n\nexport const securityMonitor = new SecurityMonitor();\n","/**\n * @file Performance Constants\n * @package @jmruthers/pace-core\n * @module Constants/Performance\n * @since 0.1.0\n * \n * Performance thresholds and constants used across the application.\n */\n\n/**\n * Performance thresholds for various operations.\n * These thresholds are used for smoke tests to detect significant regressions.\n * They are intentionally generous to avoid flakiness in CI/coverage environments.\n */\nexport const PERFORMANCE_THRESHOLDS = {\n /** Render time threshold in milliseconds */\n RENDER_TIME: 200,\n /** Permission check time threshold in milliseconds */\n PERMISSION_CHECK_TIME: 110,\n /** Memory usage increase threshold in bytes */\n MEMORY_USAGE_INCREASE: 1024 * 1024, // 1MB\n /** Maximum acceptable re-render count */\n RE_RENDER_COUNT: 3,\n} as const;\n\n","/**\n * Performance benchmarking utilities\n */\n\nexport interface PerformanceMetrics {\n renderTime: number;\n interactionTime: number;\n memoryUsage: number;\n bundleSize: number;\n}\n\nexport function createPerformanceBenchmark(name: string) {\n const startTime = performance.now();\n const startMemory = (performance as any).memory?.usedJSHeapSize || 0;\n\n return {\n end: () => {\n const endTime = performance.now();\n const endMemory = (performance as any).memory?.usedJSHeapSize || 0;\n \n const metrics: PerformanceMetrics = {\n renderTime: endTime - startTime,\n interactionTime: 0, // Would be measured separately\n memoryUsage: endMemory - startMemory,\n bundleSize: 0, // Would be measured at build time\n };\n\n // TODO: Replace with proper logging service integration\n // For now, we'll use a no-op to prevent console pollution\n const _unused = { \n benchmark: `Performance Benchmark [${name}]`, \n metrics \n };\n \n return metrics;\n }\n };\n}\n\nexport function measureRenderPerformance(componentName: string, renderFn: () => void): PerformanceMetrics {\n const startTime = performance.now();\n const startMemory = (performance as any).memory?.usedJSHeapSize || 0;\n \n renderFn();\n \n const endTime = performance.now();\n const endMemory = (performance as any).memory?.usedJSHeapSize || 0;\n \n const metrics: PerformanceMetrics = {\n renderTime: endTime - startTime,\n interactionTime: 0,\n memoryUsage: endMemory - startMemory,\n bundleSize: 0,\n };\n \n // TODO: Replace with proper logging service integration\n // For now, we'll use a no-op to prevent console pollution\n const _unused = { \n benchmark: `Render Performance [${componentName}]`, \n metrics \n };\n \n return metrics;\n} ","\ninterface BundleStats {\n totalSize: number;\n gzippedSize: number;\n chunks: ChunkInfo[];\n treeshakingEffectiveness: number;\n}\n\ninterface ChunkInfo {\n name: string;\n size: number;\n modules: string[];\n dynamicallyImported: boolean;\n}\n\nclass BundleAnalyzer {\n private get enabled(): boolean {\n try {\n return import.meta.env?.MODE === 'development';\n } catch {\n return false;\n }\n }\n\n analyzeBundle(): BundleStats | null {\n if (!this.enabled) return null;\n\n // In a real implementation, this would integrate with webpack-bundle-analyzer\n // or similar tools. For now, we'll simulate analysis\n \n // TODO: Replace with proper logging service integration\n // For now, we'll log to console for testing purposes\n console.log('Bundle analysis would run here in development');\n console.log('To enable real bundle analysis:');\n console.log('1. Install webpack-bundle-analyzer');\n console.log('2. Add bundle analysis to build scripts');\n console.log('3. Integrate with performance budgets');\n\n return {\n totalSize: 0,\n gzippedSize: 0,\n chunks: [],\n treeshakingEffectiveness: 0\n };\n }\n\n checkTreeshaking(): void {\n if (!this.enabled) return;\n\n const potentialIssues = [\n 'Check for unused exports in index files',\n 'Verify side-effect free modules in package.json',\n 'Ensure proper ES module syntax',\n 'Check for circular dependencies'\n ];\n\n // TODO: Replace with proper logging service integration\n // For now, we'll log to console for testing purposes\n console.group('Tree-shaking Analysis');\n potentialIssues.forEach(issue => console.log('- ' + issue));\n console.groupEnd();\n }\n\n validateExports(): void {\n if (!this.enabled) return;\n\n // TODO: Replace with proper logging service integration\n // For now, we'll log to console for testing purposes\n console.group('Export Validation');\n console.log('Checking for optimal export patterns...');\n console.log('- Prefer named exports over default exports');\n console.log('- Avoid barrel exports for large modules');\n console.log('- Use dynamic imports for large dependencies');\n console.groupEnd();\n }\n\n generateReport(): string {\n const report = `\n# Bundle Analysis Report\n\n## Recommendations for @jmruthers/pace-core\n\n### 1. Code Splitting Opportunities\n- ✅ DataTable virtualization is lazy-loaded\n- ⚠️ Consider splitting auth providers by use case\n- ⚠️ Lazy load heavy UI components (charts, complex forms)\n\n### 2. Tree-shaking Optimization\n- ✅ Using ES modules throughout\n- ✅ Proper sideEffects configuration\n- ⚠️ Check for unused utility functions\n\n### 3. Bundle Size Targets\n- Core components: < 50KB gzipped\n- Auth module: < 30KB gzipped \n- Utilities: < 20KB gzipped\n- Total package: < 150KB gzipped\n\n### 4. Performance Monitoring\n- Monitor component render times\n- Track bundle size changes\n- Validate tree-shaking effectiveness\n `;\n\n return report.trim();\n }\n}\n\nexport const bundleAnalyzer = new BundleAnalyzer();\n\n// Helper to check if imports are optimized\nexport function validateImportPattern(moduleId: string, importedItems: string[]): void {\n try {\n if (import.meta.env?.MODE !== 'development') return;\n } catch {\n return; // Silently skip in test environments\n }\n\n const largeModules = ['lodash', 'moment', 'rxjs'];\n const isLargeModule = largeModules.some(mod => moduleId.includes(mod));\n \n if (isLargeModule && importedItems.length > 5) {\n // TODO: Replace with proper logging service integration\n // For now, we'll log to console for testing purposes\n console.warn(\n 'Large import detected: importing ' + importedItems.length + ' items from ' + moduleId + '. ' +\n 'Consider splitting imports or using more specific imports.'\n );\n }\n}\n\n// Monitor dynamic imports\nexport function trackDynamicImport(moduleName: string): void {\n try {\n if (import.meta.env?.MODE !== 'development') return;\n } catch {\n return; // Silently skip in test environments\n }\n \n // TODO: Replace with proper logging service integration\n // For now, we'll log to console for testing purposes\n console.log('Dynamic import: ' + moduleName + ' - Good for code splitting!');\n}\n","\n/**\n * Dynamic utility loader to reduce initial bundle size\n * Heavy utilities are loaded on-demand\n */\n\n// Type definitions for dynamic imports\ntype DebounceFunction = <T extends (...args: unknown[]) => unknown>(\n func: T,\n wait?: number,\n options?: { leading?: boolean; maxWait?: number; trailing?: boolean }\n) => T & { cancel(): void; flush(): void };\n\ntype ThrottleFunction = <T extends (...args: unknown[]) => unknown>(\n func: T,\n wait?: number,\n options?: { leading?: boolean; trailing?: boolean }\n) => T & { cancel(): void; flush(): void };\n\n// Dynamic lodash utilities\nexport const loadLodash = async (): Promise<{\n debounce: DebounceFunction;\n throttle: ThrottleFunction;\n}> => {\n // Using type assertions for dynamic imports - these modules don't have consistent type exports\n // These are optional dependencies provided by consuming apps\n // @ts-ignore - lodash.debounce is an optional dependency\n const debounceModule = await import('lodash.debounce') as { default?: DebounceFunction } & { [key: string]: unknown };\n // @ts-ignore - lodash.throttle is an optional dependency\n const throttleModule = await import('lodash.throttle') as { default?: ThrottleFunction } & { [key: string]: unknown };\n \n return {\n debounce: (debounceModule.default || debounceModule) as DebounceFunction,\n throttle: (throttleModule.default || throttleModule) as ThrottleFunction\n };\n};\n\n// Dynamic date utilities\nexport const loadDateUtils = async (): Promise<typeof import('date-fns')> => {\n const dateFns = await import('date-fns');\n return dateFns;\n};\n\n// Dynamic chart utilities - using unknown type to avoid Recharts type issues\nexport const loadChartUtils = async (): Promise<unknown> => {\n // @ts-ignore - recharts is an optional dependency provided by consuming apps\n const recharts = await import('recharts');\n return recharts;\n};\n\n// Dynamic form utilities\nexport const loadFormUtils = async (): Promise<{\n useForm: unknown;\n useController: unknown;\n Controller: unknown;\n FormProvider: unknown;\n useFormContext: unknown;\n useWatch: unknown;\n useFormState: unknown;\n useFieldArray: unknown;\n zodResolver: unknown;\n}> => {\n const [reactHookForm, zodResolvers] = await Promise.all([\n import('react-hook-form'),\n import('@hookform/resolvers/zod')\n ]);\n \n return {\n ...reactHookForm,\n zodResolver: zodResolvers.zodResolver\n };\n};\n\n// Dynamic CSV utilities\nexport const loadCSVUtils = async (): Promise<unknown> => {\n // @ts-ignore - papaparse is an optional dependency provided by consuming apps\n const papaparse = await import('papaparse');\n return papaparse.default;\n};\n\n// Utility function to create lazy utility hooks\nexport function createLazyUtility<T>(loader: () => Promise<T>) {\n let cached: T | null = null;\n let loading: Promise<T> | null = null;\n\n return {\n load: async (): Promise<T> => {\n if (cached) return cached;\n if (loading) return loading;\n\n loading = loader().then(result => {\n cached = result;\n loading = null;\n return result;\n });\n\n return loading;\n },\n getCached: (): T | null => cached,\n isLoaded: (): boolean => cached !== null\n };\n}\n\n// Pre-configured lazy utilities with explicit types\nexport const lazyLodash: ReturnType<typeof createLazyUtility<Awaited<ReturnType<typeof loadLodash>>>> = createLazyUtility(loadLodash);\nexport const lazyDateUtils: ReturnType<typeof createLazyUtility<Awaited<ReturnType<typeof loadDateUtils>>>> = createLazyUtility(loadDateUtils);\nexport const lazyChartUtils: ReturnType<typeof createLazyUtility<unknown>> = createLazyUtility(loadChartUtils);\nexport const lazyFormUtils: ReturnType<typeof createLazyUtility<Awaited<ReturnType<typeof loadFormUtils>>>> = createLazyUtility(loadFormUtils);\nexport const lazyCSVUtils: ReturnType<typeof createLazyUtility<unknown>> = createLazyUtility(loadCSVUtils);\n","import React, { Suspense, ComponentType, lazy } from 'react';\nimport { LoadingSpinner } from '../../components/LoadingSpinner/LoadingSpinner';\n\ninterface LazyLoadOptions {\n fallback?: React.ReactNode;\n errorBoundary?: ComponentType<{ children: React.ReactNode }>;\n}\n\n/**\n * Create a lazy-loaded component with error boundary and loading fallback\n */\nexport function createLazyComponent<T extends ComponentType<any>>(\n importFn: () => Promise<{ default: T }>,\n componentName: string,\n options: LazyLoadOptions = {}\n): T {\n const LazyComponent = lazy(importFn);\n \n const WrappedComponent = (props: any) => {\n const content = (\n <Suspense fallback={options.fallback || <LoadingSpinner />}>\n <LazyComponent {...props} />\n </Suspense>\n );\n\n if (options.errorBoundary) {\n const ErrorBoundary = options.errorBoundary;\n return <ErrorBoundary>{content}</ErrorBoundary>;\n }\n\n return content;\n };\n \n WrappedComponent.displayName = `Lazy${componentName}`;\n return WrappedComponent as T;\n}\n\n/**\n * Lazy-loaded DataTable component\n */\nexport const LazyDataTable = createLazyComponent(\n () => import('../../components/DataTable').then(module => ({ default: module.DataTable })),\n 'DataTable'\n);\n","\n/**\n * Permission utilities for transforming and managing permissions\n */\n\nexport function transformPermissionMapToBoolean(permissions: Record<string, unknown>): Record<string, boolean> {\n const result: Record<string, boolean> = {};\n \n Object.entries(permissions).forEach(([key, value]) => {\n if (typeof value === 'string') {\n // Handle string values - 'false' should be false, empty strings are false, other non-empty strings are true\n result[key] = value !== '' && value.toLowerCase() !== 'false';\n } else {\n result[key] = Boolean(value);\n }\n });\n \n return result;\n}\n\nexport function hasPermission(permissions: Record<string, boolean>, permission: string): boolean {\n return Boolean(permissions[permission]);\n}\n\nexport function hasAnyPermission(permissions: Record<string, boolean>, permissionList: string[] | null | undefined): boolean {\n if (!permissionList || permissionList.length === 0) return false;\n return permissionList.some(permission => hasPermission(permissions, permission));\n}\n\nexport function hasAllPermissions(permissions: Record<string, boolean>, permissionList: string[] | null | undefined): boolean {\n if (!permissionList) return false;\n if (permissionList.length === 0) return true;\n return permissionList.every(permission => hasPermission(permissions, permission));\n}\n","\n/**\n * @file Permission type definitions and utilities\n */\n\nexport enum PermissionType {\n READ = 'read',\n WRITE = 'write',\n DELETE = 'delete',\n ADMIN = 'admin'\n}\n\n/**\n * Parse a permission string into components\n */\nexport function parsePermission(permission: string): { resource: string; action: string } | null {\n if (!permission || typeof permission !== 'string') {\n return null;\n }\n \n const parts = permission.split(':');\n if (parts.length !== 2) {\n return null;\n }\n \n const [action, resource] = parts;\n \n // Check that both action and resource exist and are not empty\n if (action === undefined || resource === undefined || action === '' || resource === '') {\n return null;\n }\n \n return {\n resource,\n action\n };\n}\n","\n/**\n * @file Audit Logger - General Utility\n * \n * Moved from shared/auditLogger to lib for better organization\n */\n\nexport interface AuditEvent {\n type: 'auth' | 'permission' | 'security';\n action?: string;\n event?: string;\n user?: string;\n userId?: string;\n details?: Record<string, unknown>;\n data?: Record<string, unknown>;\n timestamp?: number;\n severity?: 'low' | 'medium' | 'high' | 'critical';\n source?: string;\n}\n\nclass AuditLogger {\n private events: AuditEvent[] = [];\n\n log(event: AuditEvent): void {\n const eventWithTimestamp = {\n ...event,\n timestamp: Date.now(),\n };\n \n this.events.push(eventWithTimestamp);\n // TODO: In production, this should send to a proper logging service\n // Console logging removed for production\n }\n\n async logPermissionEvent(event: {\n event: string;\n userId: string;\n data?: Record<string, unknown>;\n }): Promise<void> {\n this.log({\n type: 'permission',\n event: event.event,\n userId: event.userId,\n data: event.data,\n });\n }\n\n async logSecurityEvent(event: {\n event: string;\n data?: Record<string, unknown>;\n }): Promise<void> {\n this.log({\n type: 'security',\n event: event.event,\n data: event.data,\n });\n }\n\n async logAuthEvent(event: {\n event: string;\n userId?: string;\n data?: Record<string, unknown>;\n }): Promise<void> {\n this.log({\n type: 'auth',\n event: event.event,\n userId: event.userId,\n data: event.data,\n });\n }\n\n async getSecurityEvents(): Promise<AuditEvent[]> {\n return this.events.filter(event => event.type === 'security');\n }\n\n getEvents(): AuditEvent[] {\n return [...this.events];\n }\n\n clearEvents(): void {\n this.events = [];\n }\n}\n\nexport const auditLogger = new AuditLogger();\n\nexport function logAuthEvent(action: string, user?: string, details?: Record<string, unknown>): void {\n auditLogger.log({\n type: 'auth',\n action,\n user,\n details,\n });\n // Console logging removed for production\n}\n\nexport function logPermissionEvent(action: string, user?: string, details?: Record<string, unknown>): void {\n auditLogger.log({\n type: 'permission',\n action,\n user,\n details,\n });\n // Console logging removed for production\n}\n\nexport function logSecurityEvent(action: string, user?: string, details?: Record<string, unknown>): void {\n auditLogger.log({\n type: 'security',\n action,\n user,\n details,\n });\n // Console logging removed for production\n}\n\nexport function logAuditEvent(action: string, user?: string, details?: Record<string, unknown>): void {\n auditLogger.log({\n type: 'auth', // Default to auth type for general audit events\n action,\n user,\n details,\n });\n}\n","/**\n * @file Secure Device Fingerprinting\n * @description Enhanced device fingerprinting with encryption and security measures\n */\n\nimport { secureStorage } from '../security/secureStorage';\n\nexport interface DeviceFingerprint {\n hash: string;\n timestamp: number;\n components: {\n userAgent: string;\n language: string;\n platform: string;\n screen: string;\n timezone: string;\n canvas?: string;\n webgl?: string;\n };\n entropy: number;\n}\n\n/**\n * Generate a secure device fingerprint (synchronous)\n */\nexport function generateDeviceFingerprint(): DeviceFingerprint {\n try {\n const components = {\n userAgent: getHashedUserAgent(),\n language: navigator.language || 'unknown',\n platform: navigator.platform || 'unknown',\n screen: `${screen.width}x${screen.height}x${screen.colorDepth}`,\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone || 'unknown',\n canvas: getCanvasFingerprint(),\n webgl: getWebGLFingerprint(),\n };\n\n // Calculate entropy (uniqueness score)\n const entropy = calculateEntropy(components);\n \n // Create a hash from all components\n const fingerprintData = JSON.stringify(components);\n const hash = hashStringSync(fingerprintData);\n\n const fingerprint: DeviceFingerprint = {\n hash,\n timestamp: Date.now(),\n components,\n entropy,\n };\n\n // Store fingerprint asynchronously\n secureStorage.setItem('device_fingerprint', JSON.stringify(fingerprint));\n \n return fingerprint;\n } catch (error) {\n return generateFallbackFingerprint();\n }\n}\n\n/**\n * Validate device fingerprint with security checks\n */\nexport function validateDeviceFingerprint(\n storedFingerprint: DeviceFingerprint,\n currentFingerprint: DeviceFingerprint\n): {\n isValid: boolean;\n confidence: number;\n reasons: string[];\n} {\n const reasons: string[] = [];\n let matchingComponents = 0;\n const totalComponents = Object.keys(storedFingerprint.components).length;\n\n // Check each component\n Object.entries(storedFingerprint.components).forEach(([key, value]) => {\n if (currentFingerprint.components[key as keyof typeof currentFingerprint.components] === value) {\n matchingComponents++;\n } else {\n reasons.push(`Component mismatch: ${key}`);\n }\n });\n\n // Calculate confidence score\n const confidence = (matchingComponents / totalComponents) * 100;\n\n // Security thresholds\n const isValid = confidence >= 80; // Require 80% match\n \n // Additional security checks\n const timeDiff = currentFingerprint.timestamp - storedFingerprint.timestamp;\n const maxAge = 30 * 24 * 60 * 60 * 1000; // 30 days\n \n if (timeDiff > maxAge) {\n reasons.push('Fingerprint too old');\n return { isValid: false, confidence, reasons };\n }\n\n if (confidence < 60) {\n reasons.push('Device signature changed significantly');\n }\n\n return { isValid, confidence, reasons };\n}\n\n/**\n * Generate canvas fingerprint for enhanced uniqueness\n */\nfunction getCanvasFingerprint(): string {\n try {\n const canvas = document.createElement('canvas');\n const ctx = canvas.getContext('2d');\n \n if (!ctx) return 'canvas-unavailable';\n\n // Draw complex pattern for fingerprinting\n ctx.textBaseline = 'top';\n ctx.font = '14px Arial';\n ctx.fillStyle = '#f60';\n ctx.fillRect(125, 1, 62, 20);\n ctx.fillStyle = '#069';\n ctx.fillText('Device fingerprint 🔒', 2, 15);\n ctx.fillStyle = 'rgba(102, 204, 0, 0.2)';\n ctx.fillText('Device fingerprint 🔒', 4, 17);\n\n const dataURL = canvas.toDataURL();\n return hashStringSync(dataURL);\n } catch (error) {\n return 'canvas-error';\n }\n}\n\n/**\n * Get WebGL fingerprint\n */\nfunction getWebGLFingerprint(): string {\n try {\n const canvas = document.createElement('canvas');\n const gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl') as WebGLRenderingContext | null;\n \n if (!gl) return 'webgl-unavailable';\n\n const debugInfo = gl.getExtension('WEBGL_debug_renderer_info');\n if (!debugInfo) return 'webgl-no-debug';\n\n const vendor = gl.getParameter(debugInfo.UNMASKED_VENDOR_WEBGL);\n const renderer = gl.getParameter(debugInfo.UNMASKED_RENDERER_WEBGL);\n \n return `${vendor}|${renderer}`;\n } catch (error) {\n return 'webgl-error';\n }\n}\n\n/**\n * Hash user agent to prevent direct exposure\n */\nfunction getHashedUserAgent(): string {\n const ua = navigator.userAgent;\n return hashStringSync(ua).substring(0, 16); // Shorter hash for storage\n}\n\n/**\n * Calculate entropy of fingerprint components\n */\nfunction calculateEntropy(components: Record<string, string>): number {\n const values = Object.values(components).join('');\n const charCounts = new Map<string, number>();\n \n for (const char of values) {\n charCounts.set(char, (charCounts.get(char) || 0) + 1);\n }\n \n let entropy = 0;\n for (const count of charCounts.values()) {\n const probability = count / values.length;\n entropy -= probability * Math.log2(probability);\n }\n \n return entropy;\n}\n\n/**\n * Synchronous hash function for device fingerprinting\n */\nfunction hashStringSync(str: string): string {\n let hash = 0;\n for (let i = 0; i < str.length; i++) {\n const char = str.charCodeAt(i);\n hash = ((hash << 5) - hash) + char;\n hash = hash & hash;\n }\n return Math.abs(hash).toString(36);\n}\n\n/**\n * Generate fallback fingerprint for error cases\n */\nfunction generateFallbackFingerprint(): DeviceFingerprint {\n const components = {\n userAgent: 'fallback',\n language: 'unknown',\n platform: 'unknown',\n screen: 'unknown',\n timezone: 'unknown',\n };\n\n return {\n hash: `fallback_${Date.now()}_${Math.random().toString(36)}`,\n timestamp: Date.now(),\n components,\n entropy: 1, // Low entropy for fallback\n };\n}\n","/**\n * @file Location Utilities\n * @package @jmruthers/pace-core\n * @module Utils/Location\n * @since 0.1.0\n *\n * Utility functions for working with geographic coordinates.\n * Provides functions for formatting, validating, comparing, and generating URLs for coordinates.\n *\n * Features:\n * - Format coordinates for display\n * - Validate coordinate objects\n * - Compare coordinates with tolerance\n * - Generate Google Maps URLs\n *\n * @example\n * ```ts\n * import { formatCoordinates, hasValidCoordinates, areCoordinatesEqual, getGoogleMapsUrl } from '@jmruthers/pace-core/utils/location';\n *\n * const coords = { lat: -37.8136, lng: 144.9631 };\n *\n * // Format for display\n * formatCoordinates(coords); // \"-37.813600, 144.963100\"\n *\n * // Validate\n * hasValidCoordinates(coords); // true\n *\n * // Compare\n * areCoordinatesEqual(coords, { lat: -37.8137, lng: 144.9632 }); // true (within tolerance)\n *\n * // Generate Google Maps URL\n * getGoogleMapsUrl(coords); // \"https://www.google.com/maps/search/?api=1&query=-37.8136,144.9631\"\n * ```\n */\n\n/**\n * Coordinate interface for latitude and longitude\n */\nexport interface Coordinates {\n lat: number;\n lng: number;\n}\n\n/**\n * Format coordinates as a string with 6 decimal places\n *\n * @param coords - Coordinate object with lat and lng\n * @returns Formatted string \"lat, lng\" or \"N/A\" if invalid\n *\n * @example\n * ```ts\n * formatCoordinates({ lat: -37.8136, lng: 144.9631 });\n * // \"-37.813600, 144.963100\"\n *\n * formatCoordinates(undefined);\n * // \"N/A\"\n * ```\n */\nexport function formatCoordinates(coords?: Coordinates): string {\n if (!coords || typeof coords.lat !== 'number' || typeof coords.lng !== 'number') {\n return 'N/A';\n }\n\n if (!isFinite(coords.lat) || !isFinite(coords.lng)) {\n return 'N/A';\n }\n\n return `${coords.lat.toFixed(6)}, ${coords.lng.toFixed(6)}`;\n}\n\n/**\n * Check if coordinates are valid\n *\n * @param coords - Coordinate object to validate\n * @returns true if coordinates are valid, false otherwise\n *\n * @example\n * ```ts\n * hasValidCoordinates({ lat: -37.8136, lng: 144.9631 }); // true\n * hasValidCoordinates({ lat: 91, lng: 0 }); // false (lat out of range)\n * hasValidCoordinates(undefined); // false\n * ```\n */\nexport function hasValidCoordinates(coords?: { lat?: number; lng?: number }): boolean {\n if (!coords) {\n return false;\n }\n\n const { lat, lng } = coords;\n\n if (typeof lat !== 'number' || typeof lng !== 'number') {\n return false;\n }\n\n if (!isFinite(lat) || !isFinite(lng)) {\n return false;\n }\n\n // Latitude must be between -90 and 90\n if (lat < -90 || lat > 90) {\n return false;\n }\n\n // Longitude must be between -180 and 180\n if (lng < -180 || lng > 180) {\n return false;\n }\n\n return true;\n}\n\n/**\n * Check if two coordinates are equal within a tolerance\n *\n * @param coords1 - First coordinate object\n * @param coords2 - Second coordinate object\n * @param tolerance - Tolerance in degrees (default: 0.0001° ≈ 11 meters)\n * @returns true if coordinates are within tolerance, false otherwise\n *\n * @example\n * ```ts\n * const coords1 = { lat: -37.8136, lng: 144.9631 };\n * const coords2 = { lat: -37.8137, lng: 144.9632 };\n * areCoordinatesEqual(coords1, coords2); // true (within default tolerance)\n * areCoordinatesEqual(coords1, coords2, 0.00001); // false (stricter tolerance)\n * ```\n */\nexport function areCoordinatesEqual(\n coords1: Coordinates | null | undefined,\n coords2: Coordinates | null | undefined,\n tolerance: number = 0.0001\n): boolean {\n // Both null/undefined are considered equal\n if (!coords1 && !coords2) {\n return true;\n }\n\n // One null/undefined and one not are not equal\n if (!coords1 || !coords2) {\n return false;\n }\n\n // Validate both coordinates\n if (!hasValidCoordinates(coords1) || !hasValidCoordinates(coords2)) {\n return false;\n }\n\n // Check if within tolerance (with small epsilon for floating point precision)\n const epsilon = 1e-10;\n const latDiff = Math.abs(coords1.lat - coords2.lat);\n const lngDiff = Math.abs(coords1.lng - coords2.lng);\n\n return latDiff <= tolerance + epsilon && lngDiff <= tolerance + epsilon;\n}\n\n/**\n * Generate a Google Maps search URL for coordinates\n *\n * @param coords - Coordinate object with lat and lng\n * @returns Google Maps search URL or empty string if invalid\n *\n * @example\n * ```ts\n * getGoogleMapsUrl({ lat: -37.8136, lng: 144.9631 });\n * // \"https://www.google.com/maps/search/?api=1&query=-37.8136,144.9631\"\n * ```\n */\nexport function getGoogleMapsUrl(coords?: Coordinates): string {\n if (!coords || !hasValidCoordinates(coords)) {\n return '';\n }\n\n return `https://www.google.com/maps/search/?api=1&query=${coords.lat},${coords.lng}`;\n}\n\n"],"mappings":"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","names":["z","emailSchema","nameSchema","phoneSchema","urlSchema","dateSchema","secureLoginSchema","emailSchema","z","passwordSchema","nameSchema","phoneSchema","urlSchema","z","z","userProfileSchema","z","PermissionType","logSecurityEvent"]}
|