@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
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Sensitive Field Detection
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Utils/Persistence
|
|
5
|
+
* @since 1.0.0
|
|
6
|
+
*
|
|
7
|
+
* Utilities for detecting and filtering sensitive fields that should not be persisted.
|
|
8
|
+
* Provides pattern matching and type-based detection for sensitive data.
|
|
9
|
+
*
|
|
10
|
+
* Features:
|
|
11
|
+
* - Pattern-based field name matching
|
|
12
|
+
* - Input type-based detection
|
|
13
|
+
* - Safe filtering of sensitive fields from data objects
|
|
14
|
+
* - Configurable denylist patterns
|
|
15
|
+
*
|
|
16
|
+
* Security:
|
|
17
|
+
* - Defaults to NOT persisting when uncertain
|
|
18
|
+
* - Comprehensive pattern matching for common sensitive fields
|
|
19
|
+
* - Type-based detection for password and hidden inputs
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Denylist patterns for sensitive field names (case-insensitive)
|
|
24
|
+
* Matches any field name containing these patterns
|
|
25
|
+
*/
|
|
26
|
+
const SENSITIVE_FIELD_PATTERNS = [
|
|
27
|
+
// Authentication and credentials
|
|
28
|
+
/password/i,
|
|
29
|
+
/secret/i,
|
|
30
|
+
/token/i,
|
|
31
|
+
/key/i,
|
|
32
|
+
/credential/i,
|
|
33
|
+
/auth/i,
|
|
34
|
+
/api[_-]?key/i,
|
|
35
|
+
/access[_-]?token/i,
|
|
36
|
+
/refresh[_-]?token/i,
|
|
37
|
+
/session[_-]?id/i,
|
|
38
|
+
|
|
39
|
+
// Payment information
|
|
40
|
+
/credit[_-]?card/i,
|
|
41
|
+
/card[_-]?number/i,
|
|
42
|
+
/cvv/i,
|
|
43
|
+
/cvc/i,
|
|
44
|
+
/pin/i,
|
|
45
|
+
/account[_-]?number/i,
|
|
46
|
+
/routing[_-]?number/i,
|
|
47
|
+
|
|
48
|
+
// Personal identification
|
|
49
|
+
/ssn/i,
|
|
50
|
+
/social[_-]?security/i,
|
|
51
|
+
/tax[_-]?id/i,
|
|
52
|
+
/driver[_-]?license/i,
|
|
53
|
+
/passport/i,
|
|
54
|
+
|
|
55
|
+
// Medical and health information
|
|
56
|
+
/medical/i,
|
|
57
|
+
/health/i,
|
|
58
|
+
/phi/i, // Protected Health Information
|
|
59
|
+
/hipaa/i,
|
|
60
|
+
/diagnosis/i,
|
|
61
|
+
/prescription/i,
|
|
62
|
+
|
|
63
|
+
// Other sensitive data
|
|
64
|
+
/private[_-]?key/i,
|
|
65
|
+
/signing[_-]?key/i,
|
|
66
|
+
/encryption[_-]?key/i,
|
|
67
|
+
];
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Sensitive input types that should never be persisted
|
|
71
|
+
*/
|
|
72
|
+
const SENSITIVE_INPUT_TYPES = new Set([
|
|
73
|
+
'password',
|
|
74
|
+
'hidden',
|
|
75
|
+
]);
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Check if a field name matches sensitive patterns
|
|
79
|
+
*
|
|
80
|
+
* @param name - Field name to check
|
|
81
|
+
* @returns true if field is sensitive
|
|
82
|
+
*/
|
|
83
|
+
function isSensitiveFieldName(name: string): boolean {
|
|
84
|
+
if (!name || typeof name !== 'string') {
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const normalizedName = name.trim();
|
|
89
|
+
if (normalizedName.length === 0) {
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Check against denylist patterns
|
|
94
|
+
return SENSITIVE_FIELD_PATTERNS.some((pattern) => pattern.test(normalizedName));
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Check if an input type is sensitive
|
|
99
|
+
*
|
|
100
|
+
* @param type - Input type to check
|
|
101
|
+
* @returns true if input type is sensitive
|
|
102
|
+
*/
|
|
103
|
+
function isSensitiveInputType(type?: string): boolean {
|
|
104
|
+
if (!type || typeof type !== 'string') {
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return SENSITIVE_INPUT_TYPES.has(type.toLowerCase().trim());
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Check if a field is sensitive based on name and/or type
|
|
113
|
+
*
|
|
114
|
+
* @param name - Field name
|
|
115
|
+
* @param type - Optional input type
|
|
116
|
+
* @returns true if field should not be persisted
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```ts
|
|
120
|
+
* isSensitiveField('password', 'password'); // true
|
|
121
|
+
* isSensitiveField('email', 'text'); // false
|
|
122
|
+
* isSensitiveField('api_key', 'text'); // true
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
export function isSensitiveField(name: string, type?: string): boolean {
|
|
126
|
+
// Check input type first (most reliable)
|
|
127
|
+
if (isSensitiveInputType(type)) {
|
|
128
|
+
return true;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Check field name patterns
|
|
132
|
+
if (isSensitiveFieldName(name)) {
|
|
133
|
+
return true;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
// Default to NOT sensitive when uncertain
|
|
137
|
+
return false;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Filter sensitive fields from a data object
|
|
142
|
+
*
|
|
143
|
+
* Creates a new object with only non-sensitive fields.
|
|
144
|
+
* When uncertain, fields are excluded (safe default).
|
|
145
|
+
*
|
|
146
|
+
* @template T - Type of the data object
|
|
147
|
+
* @param data - Data object to filter
|
|
148
|
+
* @param fieldNames - Array of field names in the data
|
|
149
|
+
* @param fieldTypes - Optional map of field names to input types
|
|
150
|
+
* @returns Filtered data with sensitive fields removed
|
|
151
|
+
*
|
|
152
|
+
* @example
|
|
153
|
+
* ```ts
|
|
154
|
+
* const data = { name: 'John', password: 'secret123', email: 'john@example.com' };
|
|
155
|
+
* const filtered = filterSensitiveFields(data, ['name', 'password', 'email'], {
|
|
156
|
+
* password: 'password'
|
|
157
|
+
* });
|
|
158
|
+
* // Result: { name: 'John', email: 'john@example.com' }
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export function filterSensitiveFields<T extends Record<string, any>>(
|
|
162
|
+
data: T,
|
|
163
|
+
fieldNames: string[],
|
|
164
|
+
fieldTypes?: Record<string, string>
|
|
165
|
+
): Partial<T> {
|
|
166
|
+
if (!data || typeof data !== 'object') {
|
|
167
|
+
return {};
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
const filtered: Partial<T> = {};
|
|
171
|
+
|
|
172
|
+
for (const fieldName of fieldNames) {
|
|
173
|
+
// Skip if field doesn't exist in data
|
|
174
|
+
if (!(fieldName in data)) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// Get field type if provided
|
|
179
|
+
const fieldType = fieldTypes?.[fieldName];
|
|
180
|
+
|
|
181
|
+
// Check if field is sensitive
|
|
182
|
+
if (isSensitiveField(fieldName, fieldType)) {
|
|
183
|
+
// Skip sensitive field
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// Include non-sensitive field
|
|
188
|
+
filtered[fieldName as keyof T] = data[fieldName];
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
return filtered;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Get list of sensitive field names from an array of field names
|
|
196
|
+
*
|
|
197
|
+
* Useful for logging or debugging which fields were filtered.
|
|
198
|
+
*
|
|
199
|
+
* @param fieldNames - Array of field names to check
|
|
200
|
+
* @param fieldTypes - Optional map of field names to input types
|
|
201
|
+
* @returns Array of sensitive field names
|
|
202
|
+
*/
|
|
203
|
+
export function getSensitiveFieldNames(
|
|
204
|
+
fieldNames: string[],
|
|
205
|
+
fieldTypes?: Record<string, string>
|
|
206
|
+
): string[] {
|
|
207
|
+
return fieldNames.filter((name) => {
|
|
208
|
+
const type = fieldTypes?.[name];
|
|
209
|
+
return isSensitiveField(name, type);
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
|
|
@@ -37,7 +37,7 @@ class SecureStorageImpl {
|
|
|
37
37
|
false,
|
|
38
38
|
['encrypt', 'decrypt']
|
|
39
39
|
);
|
|
40
|
-
} catch (
|
|
40
|
+
} catch (_error) {
|
|
41
41
|
await this.generateNewKey();
|
|
42
42
|
}
|
|
43
43
|
} else {
|
|
@@ -45,7 +45,7 @@ class SecureStorageImpl {
|
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
47
|
this.initialized = true;
|
|
48
|
-
} catch (
|
|
48
|
+
} catch (_error) {
|
|
49
49
|
this.initialized = true;
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -101,7 +101,7 @@ class SecureStorageImpl {
|
|
|
101
101
|
}
|
|
102
102
|
|
|
103
103
|
return parsed.value;
|
|
104
|
-
} catch (
|
|
104
|
+
} catch (_error) {
|
|
105
105
|
// Silent fail - try plain storage
|
|
106
106
|
}
|
|
107
107
|
}
|
|
@@ -120,7 +120,7 @@ class SecureStorageImpl {
|
|
|
120
120
|
}
|
|
121
121
|
|
|
122
122
|
return parsed.value || plainData;
|
|
123
|
-
} catch (
|
|
123
|
+
} catch (_error) {
|
|
124
124
|
// If parsing fails, return as-is (backward compatibility)
|
|
125
125
|
return plainData;
|
|
126
126
|
}
|
|
@@ -163,7 +163,7 @@ class SecureStorageImpl {
|
|
|
163
163
|
const exportedKey = await window.crypto.subtle.exportKey('raw', this.encryptionKey);
|
|
164
164
|
const keyData = this.arrayBufferToBase64(exportedKey);
|
|
165
165
|
localStorage.setItem('_sec_key', keyData);
|
|
166
|
-
} catch (
|
|
166
|
+
} catch (_error) {
|
|
167
167
|
// Silent fail - encryption not available
|
|
168
168
|
}
|
|
169
169
|
}
|
|
@@ -67,7 +67,7 @@ Enhanced file upload component with progress tracking, previews, and validation.
|
|
|
67
67
|
onProgress={(progress) => {}} // Progress callback
|
|
68
68
|
>
|
|
69
69
|
{/* Optional custom upload UI */}
|
|
70
|
-
<
|
|
70
|
+
<section>Custom upload area</section>
|
|
71
71
|
</FileUpload>
|
|
72
72
|
```
|
|
73
73
|
|
|
@@ -106,7 +106,7 @@ export async function extractFileMetadata(
|
|
|
106
106
|
const dimensions = await getImageDimensions(file);
|
|
107
107
|
metadata.width = dimensions.width;
|
|
108
108
|
metadata.height = dimensions.height;
|
|
109
|
-
} catch (
|
|
109
|
+
} catch (_error) {
|
|
110
110
|
// Non-critical error - image dimensions are optional metadata
|
|
111
111
|
// Using Logger would be better, but this is in a utility function
|
|
112
112
|
// For now, silently continue - dimensions are optional
|
|
@@ -116,7 +116,7 @@ export async function extractFileMetadata(
|
|
|
116
116
|
// Generate file hash if possible
|
|
117
117
|
try {
|
|
118
118
|
metadata.hash = await generateFileHash(file);
|
|
119
|
-
} catch (
|
|
119
|
+
} catch (_error) {
|
|
120
120
|
// Non-critical error - file hash is optional metadata
|
|
121
121
|
// Using Logger would be better, but this is in a utility function
|
|
122
122
|
// For now, silently continue - hash is optional
|
|
@@ -320,7 +320,7 @@ export function getPublicUrl(
|
|
|
320
320
|
}
|
|
321
321
|
|
|
322
322
|
// Normalise path by trimming whitespace and leading slashes
|
|
323
|
-
|
|
323
|
+
const normalisedPath = path.trim().replace(/^\/+/, '');
|
|
324
324
|
|
|
325
325
|
if (!normalisedPath) {
|
|
326
326
|
throw new Error('Storage path cannot be empty after normalisation');
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @file Base Supabase Client Creation Utility
|
|
3
|
+
* @package @jmruthers/pace-core
|
|
4
|
+
* @module Utils/Supabase
|
|
5
|
+
* @since 0.6.6
|
|
6
|
+
*
|
|
7
|
+
* Restricted wrapper for creating the base Supabase client for UnifiedAuthProvider.
|
|
8
|
+
* This is the ONLY acceptable way to create a Supabase client in consuming apps.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```tsx
|
|
12
|
+
* // ✅ CORRECT: In main.tsx, App.tsx, or lib/supabase.ts
|
|
13
|
+
* import { createBaseClient } from '@jmruthers/pace-core';
|
|
14
|
+
*
|
|
15
|
+
* const supabase = createBaseClient(
|
|
16
|
+
* import.meta.env.VITE_SUPABASE_URL,
|
|
17
|
+
* import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
|
|
18
|
+
* );
|
|
19
|
+
*
|
|
20
|
+
* // Pass to UnifiedAuthProvider
|
|
21
|
+
* <UnifiedAuthProvider supabaseClient={supabase} ... />
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
|
26
|
+
import { Database } from '../../types/database';
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Allowed file patterns for base client creation
|
|
30
|
+
*
|
|
31
|
+
* Note: Patterns allow optional query parameters (e.g., ?t=timestamp) and line numbers
|
|
32
|
+
* that Vite and other bundlers add in stack traces
|
|
33
|
+
*/
|
|
34
|
+
const ALLOWED_FILE_PATTERNS = [
|
|
35
|
+
/[\/\\]main\.(tsx?|jsx?)(\?|:|\s|$)/i,
|
|
36
|
+
/[\/\\]App\.(tsx?|jsx?)(\?|:|\s|$)/i,
|
|
37
|
+
/[\/\\]lib[\/\\]supabase\.(tsx?|jsx?)(\?|:|\s|$)/i,
|
|
38
|
+
/[\/\\]src[\/\\]supabase\.(tsx?|jsx?)(\?|:|\s|$)/i,
|
|
39
|
+
];
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check if the current file is in an allowed location for base client creation
|
|
43
|
+
*
|
|
44
|
+
* This uses Error.stack to detect the caller's file path.
|
|
45
|
+
* Only works in development/build time, not at runtime.
|
|
46
|
+
*/
|
|
47
|
+
function isAllowedContext(): boolean {
|
|
48
|
+
// In production builds, we can't reliably detect the caller
|
|
49
|
+
// So we allow it but document the restriction
|
|
50
|
+
if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {
|
|
51
|
+
return true; // Allow in production (documentation/ESLint enforces)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const stack = new Error().stack;
|
|
56
|
+
if (!stack) return false;
|
|
57
|
+
|
|
58
|
+
// Check if any stack frame matches allowed patterns
|
|
59
|
+
const stackLines = stack.split('\n');
|
|
60
|
+
for (const line of stackLines) {
|
|
61
|
+
for (const pattern of ALLOWED_FILE_PATTERNS) {
|
|
62
|
+
if (pattern.test(line)) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return false;
|
|
68
|
+
} catch {
|
|
69
|
+
// If we can't check, allow it (documentation/ESLint enforces)
|
|
70
|
+
return true;
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Create a base Supabase client for UnifiedAuthProvider
|
|
76
|
+
*
|
|
77
|
+
* **CRITICAL**: This function can ONLY be called from:
|
|
78
|
+
* - `src/main.tsx` (or `main.jsx`)
|
|
79
|
+
* - `src/App.tsx` (or `App.jsx`)
|
|
80
|
+
* - `src/lib/supabase.ts` (or `supabase.js`)
|
|
81
|
+
* - `src/supabase.ts` (or `supabase.js`)
|
|
82
|
+
*
|
|
83
|
+
* **DO NOT** use this client directly for queries. Always use `useSecureSupabase()` hook instead.
|
|
84
|
+
*
|
|
85
|
+
* The client is configured with explicit auth options to ensure consistent session persistence:
|
|
86
|
+
* - `persistSession: true` - Sessions are saved to localStorage and restored on page load/refresh
|
|
87
|
+
* - `autoRefreshToken: true` - Tokens are automatically refreshed before expiry
|
|
88
|
+
* - `detectSessionInUrl: true` - Detects and handles OAuth callback URLs
|
|
89
|
+
* - `flowType: 'pkce'` - Uses PKCE flow for enhanced security
|
|
90
|
+
*
|
|
91
|
+
* This configuration ensures that users remain logged in after hard refresh (Cmd+Shift+R)
|
|
92
|
+
* and other browser navigation scenarios across all consuming apps.
|
|
93
|
+
*
|
|
94
|
+
* @param supabaseUrl - Supabase project URL
|
|
95
|
+
* @param supabaseKey - Supabase publishable key or anon key (accepts both legacy anon keys and modern publishable keys)
|
|
96
|
+
* @returns Supabase client instance with auth configuration
|
|
97
|
+
*
|
|
98
|
+
* @throws {Error} If called from an unauthorized file location (development only)
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```tsx
|
|
102
|
+
* // main.tsx
|
|
103
|
+
* import { createBaseClient } from '@jmruthers/pace-core';
|
|
104
|
+
* import { UnifiedAuthProvider } from '@jmruthers/pace-core';
|
|
105
|
+
*
|
|
106
|
+
* const supabase = createBaseClient(
|
|
107
|
+
* import.meta.env.VITE_SUPABASE_URL,
|
|
108
|
+
* import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
|
|
109
|
+
* );
|
|
110
|
+
*
|
|
111
|
+
* function App() {
|
|
112
|
+
* return (
|
|
113
|
+
* <UnifiedAuthProvider supabaseClient={supabase} appName="MyApp">
|
|
114
|
+
* <YourApp />
|
|
115
|
+
* </UnifiedAuthProvider>
|
|
116
|
+
* );
|
|
117
|
+
* }
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
export function createBaseClient(
|
|
121
|
+
supabaseUrl: string,
|
|
122
|
+
supabaseKey: string
|
|
123
|
+
): SupabaseClient<Database> {
|
|
124
|
+
// Check context in development
|
|
125
|
+
if (!isAllowedContext()) {
|
|
126
|
+
const error = new Error(
|
|
127
|
+
'createBaseClient() can only be called from main.tsx, App.tsx, or lib/supabase.ts.\n' +
|
|
128
|
+
'This is a security requirement to ensure the base client is only created once and passed to UnifiedAuthProvider.\n' +
|
|
129
|
+
'See: https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/standards/00-pace-core-compliance.md'
|
|
130
|
+
);
|
|
131
|
+
console.error('[pace-core Security Error]', error);
|
|
132
|
+
throw error;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Create and return the base client with explicit auth configuration
|
|
136
|
+
// These options ensure consistent session persistence across all consuming apps,
|
|
137
|
+
// especially important for hard refresh (Cmd+Shift+R) scenarios
|
|
138
|
+
return createClient<Database>(supabaseUrl, supabaseKey, {
|
|
139
|
+
auth: {
|
|
140
|
+
autoRefreshToken: true,
|
|
141
|
+
persistSession: true,
|
|
142
|
+
detectSessionInUrl: true,
|
|
143
|
+
flowType: 'pkce'
|
|
144
|
+
}
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
@@ -247,7 +247,7 @@ describe('Timezone Utilities', () => {
|
|
|
247
247
|
|
|
248
248
|
it('returns original date for invalid minutesStep', () => {
|
|
249
249
|
const date = new Date('2024-01-15T10:23:00Z');
|
|
250
|
-
|
|
250
|
+
roundToNearestMinutes(date, 0);
|
|
251
251
|
expect(date).toBe(date);
|
|
252
252
|
});
|
|
253
253
|
|
|
@@ -296,7 +296,6 @@ describe('Timezone Utilities', () => {
|
|
|
296
296
|
|
|
297
297
|
it('handles DST correctly', () => {
|
|
298
298
|
// Test in summer (EDT vs PDT = 3 hours)
|
|
299
|
-
const summerDate = new Date('2024-07-15T10:00:00Z');
|
|
300
299
|
const result = getTimeZoneDifference('America/New_York', 'America/Los_Angeles');
|
|
301
300
|
// Should be negative (LA behind NY)
|
|
302
301
|
expect(result).toBeLessThan(0);
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
* ```
|
|
33
33
|
*/
|
|
34
34
|
|
|
35
|
-
import {
|
|
35
|
+
import { parseISO, addMinutes, differenceInHours, isValid } from 'date-fns';
|
|
36
36
|
import { formatInTimeZone as fnsFormatInTimeZone, toZonedTime as fnsToZonedTime, fromZonedTime as fnsFromZonedTime } from 'date-fns-tz';
|
|
37
37
|
|
|
38
38
|
/**
|
|
@@ -54,7 +54,7 @@ class CSRFManager {
|
|
|
54
54
|
await this.persistTokens();
|
|
55
55
|
|
|
56
56
|
return token;
|
|
57
|
-
} catch (
|
|
57
|
+
} catch (_error) {
|
|
58
58
|
throw new Error('CSRF token generation failed');
|
|
59
59
|
}
|
|
60
60
|
}
|
|
@@ -98,7 +98,7 @@ class CSRFManager {
|
|
|
98
98
|
await this.persistTokens();
|
|
99
99
|
|
|
100
100
|
return true;
|
|
101
|
-
} catch (
|
|
101
|
+
} catch (_error) {
|
|
102
102
|
return false;
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -158,7 +158,7 @@ class CSRFManager {
|
|
|
158
158
|
JSON.stringify(tokensArray),
|
|
159
159
|
{ encrypt: true, expiry: this.TOKEN_EXPIRY }
|
|
160
160
|
);
|
|
161
|
-
} catch (
|
|
161
|
+
} catch (_error) {
|
|
162
162
|
// Silent fail - tokens will be regenerated if needed
|
|
163
163
|
}
|
|
164
164
|
}
|
|
@@ -175,7 +175,7 @@ class CSRFManager {
|
|
|
175
175
|
// Clean up on load
|
|
176
176
|
await this.cleanupExpiredTokens();
|
|
177
177
|
}
|
|
178
|
-
} catch (
|
|
178
|
+
} catch (_error) {
|
|
179
179
|
this.tokenCache.clear();
|
|
180
180
|
}
|
|
181
181
|
}
|