@jmruthers/pace-core 0.6.10 → 0.6.11
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 +21 -0
- package/audit-tool/00-dependencies.cjs +46 -13
- package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
- package/audit-tool/audits/02-project-structure.cjs +13 -3
- package/audit-tool/audits/03-architecture.cjs +78 -4
- package/audit-tool/audits/04-code-quality.cjs +9 -2
- package/audit-tool/audits/05-styling.cjs +19 -7
- package/audit-tool/audits/06-security-rbac.cjs +105 -14
- package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
- package/audit-tool/audits/08-testing-documentation.cjs +11 -3
- package/audit-tool/audits/09-operations.cjs +19 -7
- package/audit-tool/index.cjs +22 -11
- package/audit-tool/utils/report-utils.cjs +4 -0
- package/cursor-rules/01-pace-core-compliance.mdc +1 -0
- package/cursor-rules/02-project-structure.mdc +1 -0
- package/cursor-rules/03-architecture.mdc +3 -1
- package/cursor-rules/04-code-quality.mdc +1 -0
- package/cursor-rules/05-styling.mdc +41 -7
- package/cursor-rules/06-security-rbac.mdc +2 -1
- package/cursor-rules/07-api-tech-stack.mdc +1 -0
- package/cursor-rules/08-testing-documentation.mdc +1 -0
- package/cursor-rules/09-operations.mdc +1 -0
- package/dist/{DataTable-SAXFG4XI.js → DataTable-EFYP2QLE.js} +10 -7
- package/dist/{InactivityServiceProvider-DHryoh6K.d.ts → InactivityServiceProvider-BbxwwDz1.d.ts} +10 -1
- package/dist/{UnifiedAuthProvider-CiBAl9-s.d.ts → UnifiedAuthProvider-Bkt_tzdS.d.ts} +56 -24
- package/dist/{api-F47QJ7FX.js → api-BZR2CYXL.js} +3 -2
- package/dist/api-result-USV1Czr-.d.ts +51 -0
- package/dist/{audit-Z6ZZBWLU.js → audit-HI2DHUVU.js} +2 -1
- package/dist/{auth-BZOJqrdd.d.ts → auth-JvdRVaud.d.ts} +1 -1
- package/dist/{chunk-KSNLMI7N.js → chunk-2DL2WSOE.js} +1 -155
- package/dist/{chunk-MPY44PWB.js → chunk-2OEVOGGR.js} +4648 -3560
- package/dist/chunk-44CNXN4P.js +15 -0
- package/dist/{chunk-Y4PF6HIM.js → chunk-4R3T5ENU.js} +867 -786
- package/dist/{chunk-LNHFAF4X.js → chunk-7A6IMHH2.js} +289 -247
- package/dist/chunk-CU2BU2MQ.js +2 -0
- package/dist/{chunk-JJEYZ3DX.js → chunk-D6BMFMQZ.js} +37 -2
- package/dist/{chunk-BCTXBU6U.js → chunk-ENLXB7GP.js} +88 -71
- package/dist/{chunk-FBZ7U3ID.js → chunk-J2KQK6DG.js} +937 -987
- package/dist/{chunk-TFIPNIPE.js → chunk-KJXRL3XE.js} +3300 -2245
- package/dist/{chunk-3GWSPISD.js → chunk-L5LFKKLJ.js} +1 -1
- package/dist/{chunk-X5EAU5G7.js → chunk-PCSHBLPB.js} +132 -114
- package/dist/{chunk-NIU6DPQV.js → chunk-QRYSEPHB.js} +2 -0
- package/dist/{chunk-KYURMOQM.js → chunk-V7FTM2LU.js} +423 -320
- package/dist/chunk-WY6Y7KC3.js +264 -0
- package/dist/{chunk-FN52B75D.js → chunk-XOJME5T7.js} +176 -15
- package/dist/{chunk-7YDC7LMU.js → chunk-XPFVT3GN.js} +71 -66
- package/dist/{chunk-66R6RLUZ.js → chunk-YFTFFJIV.js} +3 -3
- package/dist/{chunk-W46INAVW.js → chunk-YYTWKVHO.js} +688 -570
- package/dist/components.d.ts +8 -7
- package/dist/components.js +17 -15
- package/dist/{database.generated-DT8JTZiP.d.ts → database.generated-qkdoiVrJ.d.ts} +45 -10
- package/dist/eslint-rules/index.cjs +3 -0
- package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +74 -0
- package/dist/{event-WTAQuGcq.d.ts → event-BfCox3N2.d.ts} +36 -10
- package/dist/{file-reference-BavO2eQj.d.ts → file-reference-DU1hcawx.d.ts} +29 -13
- package/dist/hooks.d.ts +22 -9
- package/dist/hooks.js +34 -25
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +66 -177
- package/dist/index.js +316 -340
- package/dist/pagination-BW1mqywp.d.ts +201 -0
- package/dist/providers.d.ts +6 -5
- package/dist/providers.js +5 -3
- package/dist/rbac/index.d.ts +123 -138
- package/dist/rbac/index.js +10 -8
- package/dist/theming/runtime.d.ts +19 -2
- package/dist/theming/runtime.js +1 -1
- package/dist/{timezone-K-ptz3HO.d.ts → timezone-BTWWXKVY.d.ts} +1 -1
- package/dist/types.d.ts +17 -10
- package/dist/types.js +1 -0
- package/dist/{usePublicPageContext-vxBlEHO9.d.ts → usePublicPageContext-B91dGYW1.d.ts} +433 -356
- package/dist/{usePublicRouteParams-G3Ks53mk.d.ts → usePublicRouteParams-BgV6VhMi.d.ts} +73 -4
- package/dist/utils.d.ts +163 -145
- package/dist/utils.js +42 -25
- package/docs/api/modules.md +782 -643
- package/docs/api-reference/rpc-functions.md +12 -3
- package/docs/core-concepts/rbac-system.md +8 -0
- package/docs/getting-started/cursor-rules.md +17 -20
- package/docs/getting-started/dependencies.md +1 -1
- package/docs/getting-started/setup.md +235 -0
- package/docs/implementation-guides/authentication.md +27 -0
- package/docs/implementation-guides/data-tables.md +176 -3
- package/docs/migration/ApiResult-migration.md +25 -0
- package/docs/rbac/api-reference.md +33 -31
- package/docs/standards/0-standards-overview.md +50 -15
- package/docs/standards/1-pace-core-compliance-standards.md +62 -57
- package/docs/standards/2-project-structure-standards.md +33 -16
- package/docs/standards/3-architecture-standards.md +41 -1
- package/docs/standards/4-code-quality-standards.md +26 -6
- package/docs/standards/5-styling-standards.md +35 -1
- package/docs/standards/6-security-rbac-standards.md +66 -0
- package/docs/standards/7-api-tech-stack-standards.md +25 -14
- package/docs/standards/8-testing-documentation-standards.md +31 -0
- package/docs/standards/9-operations-standards.md +19 -0
- package/docs/standards/README.md +20 -201
- package/docs/testing/test-setup-for-consumers.md +2 -0
- package/docs/troubleshooting/common-issues.md +17 -1
- package/docs/troubleshooting/organisation-context-setup.md +8 -0
- package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
- package/eslint-config-pace-core.cjs +20 -0
- package/package.json +14 -20
- package/scripts/{build-docs-incremental.js → build-docs.js} +3 -2
- package/scripts/setup.cjs +536 -0
- package/scripts/validate.cjs +480 -0
- package/src/__tests__/helpers/{__tests__/component-test-utils.test.tsx → component-test-utils.test.tsx} +3 -3
- package/src/__tests__/helpers/{__tests__/optimized-test-setup.test.ts → optimized-test-setup.test.ts} +2 -2
- package/src/__tests__/helpers/{__tests__/supabaseMock.test.ts → supabaseMock.test.ts} +2 -2
- package/src/__tests__/helpers/{__tests__/test-providers.test.tsx → test-providers.test.tsx} +1 -1
- package/src/__tests__/helpers/test-providers.tsx +37 -39
- package/src/__tests__/helpers/{__tests__/test-utils.test.tsx → test-utils.test.tsx} +4 -3
- package/src/__tests__/helpers/{__tests__/timer-utils.test.ts → timer-utils.test.ts} +2 -2
- package/src/assets/app-icons/index.test.ts +304 -0
- package/src/components/AddressField/AddressField.test.tsx +1 -1
- package/src/components/AddressField/AddressField.tsx +238 -212
- package/src/components/Button/Button.tsx +1 -1
- package/src/components/Card/Card.test.tsx +172 -17
- package/src/components/Card/Card.tsx +19 -10
- package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
- package/src/components/ContextSelector/{__tests__/ContextSelector.test.tsx → ContextSelector.test.tsx} +6 -6
- package/src/components/ContextSelector/ContextSelector.tsx +66 -280
- package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
- package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
- package/src/components/DataTable/AUDIT_REPORT.md +59 -44
- package/src/components/DataTable/{__tests__/DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.default-state.test.tsx → DataTable.default-state.test.tsx} +5 -5
- package/src/components/DataTable/{__tests__/DataTable.export.test.tsx → DataTable.export.test.tsx} +10 -10
- package/src/components/DataTable/{__tests__/DataTable.grouping-aggregation.test.tsx → DataTable.grouping-aggregation.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.hooks.test.tsx → DataTable.hooks.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/DataTable.select-label-display.test.tsx → DataTable.select-label-display.test.tsx} +6 -6
- package/src/components/DataTable/DataTable.test.tsx +787 -416
- package/src/components/DataTable/DataTable.tsx +12 -12
- package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
- package/src/components/DataTable/{__tests__/DataTableCore.test-setup.ts → DataTableCore.test-setup.ts} +10 -9
- package/src/components/DataTable/{__tests__/DataTableCore.test.tsx → DataTableCore.test.tsx} +8 -8
- package/src/components/DataTable/{__tests__/README.md → README.md} +17 -7
- package/src/components/DataTable/TESTING.md +101 -0
- package/src/components/DataTable/{__tests__/a11y.basic.test.tsx → a11y.basic.test.tsx} +34 -34
- package/src/components/DataTable/components/DataTableCore.tsx +104 -864
- package/src/components/DataTable/components/{__tests__/GroupingDropdown.test.tsx → GroupingDropdown.test.tsx} +17 -8
- package/src/components/DataTable/components/GroupingDropdown.tsx +2 -2
- package/src/components/DataTable/components/ImportModal.tsx +61 -559
- package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
- package/src/components/DataTable/context/{__tests__/DataTableContext.test.tsx → DataTableContext.test.tsx} +2 -2
- package/src/components/DataTable/context/DataTableContext.tsx +7 -6
- package/src/components/DataTable/core/{__tests__/ColumnFactory.test.ts → ColumnFactory.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useColumnOrderPersistence.test.ts → useColumnOrderPersistence.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useColumnVisibilityPersistence.test.ts → useColumnVisibilityPersistence.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useDataTableConfiguration.test.ts → useDataTableConfiguration.test.ts} +3 -3
- package/src/components/DataTable/hooks/useDataTableConfiguration.ts +14 -2
- package/src/components/DataTable/hooks/{__tests__/useDataTableDataPipeline.test.ts → useDataTableDataPipeline.test.ts} +6 -6
- package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
- package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
- package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
- package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
- package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
- package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
- package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
- package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
- package/src/components/DataTable/hooks/{__tests__/useDataTablePermissions.test.ts → useDataTablePermissions.test.ts} +11 -11
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +79 -247
- package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
- package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
- package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
- package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
- package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
- package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
- package/src/components/DataTable/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +47 -5
- package/src/components/DataTable/hooks/useDataTableState.ts +145 -94
- package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
- package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
- package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
- package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
- package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
- package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
- package/src/components/DataTable/hooks/{__tests__/useEffectiveColumnOrder.test.ts → useEffectiveColumnOrder.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useHierarchicalState.test.ts → useHierarchicalState.test.ts} +2 -2
- package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.test.ts +3 -3
- package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.ts +2 -2
- package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
- package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
- package/src/components/DataTable/hooks/{__tests__/useKeyboardNavigation.test.ts → useKeyboardNavigation.test.ts} +3 -3
- package/src/components/DataTable/hooks/useKeyboardNavigation.ts +309 -269
- package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.test.ts +3 -3
- package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.ts +3 -3
- package/src/components/DataTable/hooks/{__tests__/useServerSideDataEffect.test.ts → useServerSideDataEffect.test.ts} +2 -2
- package/src/components/DataTable/hooks/useServerSideDataEffect.ts +14 -3
- package/src/components/DataTable/hooks/{__tests__/useTableColumns.test.ts → useTableColumns.test.ts} +2 -2
- package/src/components/DataTable/hooks/{__tests__/useTableHandlers.test.ts → useTableHandlers.test.ts} +25 -4
- package/src/components/DataTable/hooks/useTableHandlers.ts +5 -2
- package/src/components/DataTable/index.ts +18 -17
- package/src/components/DataTable/{__tests__/keyboard.test.tsx → keyboard.test.tsx} +41 -63
- package/src/components/DataTable/{__tests__/mocks → mocks}/MockRBACProvider.tsx +1 -1
- package/src/components/DataTable/{__tests__/pagination.modes.test.tsx → pagination.modes.test.tsx} +6 -6
- package/src/components/DataTable/{__tests__/ssr.strict-mode.test.tsx → ssr.strict-mode.test.tsx} +2 -2
- package/src/components/DataTable/{__tests__/styles.test.ts → styles.test.ts} +1 -4
- package/src/components/DataTable/styles.ts +0 -1
- package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
- package/src/components/DataTable/{__tests__/test-utils → test-utils}/dataFactories.ts +2 -2
- package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
- package/src/components/DataTable/{__tests__/test-utils/sharedTestUtils.tsx → test-utils/sharedTestUtils.ts} +97 -66
- package/src/components/DataTable/{__tests__/test-utils.ts → test-utils.ts} +1 -1
- package/src/components/DataTable/types/actions.ts +71 -0
- package/src/components/DataTable/types/base.ts +39 -0
- package/src/components/DataTable/types/columns.ts +125 -0
- package/src/components/DataTable/types/export.ts +32 -0
- package/src/components/DataTable/types/features.ts +81 -0
- package/src/components/DataTable/types/hierarchical.ts +44 -0
- package/src/components/DataTable/types/index.ts +43 -0
- package/src/components/DataTable/types/pagination.ts +85 -0
- package/src/components/DataTable/types/performance.ts +47 -0
- package/src/components/DataTable/types/props.ts +62 -0
- package/src/components/DataTable/types/rbac.ts +45 -0
- package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableCore.test.tsx +430 -28
- package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
- package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableErrorBoundary.test.tsx +4 -4
- package/src/components/DataTable/{components → ui/layout}/DataTableErrorBoundary.tsx +7 -7
- package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
- package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
- package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
- package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
- package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
- package/src/components/DataTable/{components → ui/modals}/DataTableModals.tsx +36 -28
- package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
- package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
- package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
- package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
- package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
- package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
- package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
- package/src/components/DataTable/{components/__tests__ → ui/shared}/AccessDeniedPage.test.tsx +2 -2
- package/src/components/DataTable/{components → ui/shared}/AccessDeniedPage.tsx +2 -2
- package/src/components/DataTable/{components/__tests__ → ui/shared}/ActionButtons.test.tsx +6 -4
- package/src/components/DataTable/{components → ui/shared}/ActionButtons.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/shared}/ColumnFilter.test.tsx +29 -16
- package/src/components/DataTable/{components → ui/shared}/ColumnFilter.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/shared}/PaginationControls.test.tsx +38 -16
- package/src/components/DataTable/{components → ui/shared}/PaginationControls.tsx +21 -15
- package/src/components/DataTable/{components/__tests__ → ui/shared}/SortIndicator.test.tsx +2 -2
- package/src/components/DataTable/{components → ui/shared}/SortIndicator.tsx +1 -1
- package/src/components/DataTable/{components/__tests__ → ui/table}/EditFields.test.tsx +3 -3
- package/src/components/DataTable/{components → ui/table}/EditFields.tsx +138 -69
- package/src/components/DataTable/{components/__tests__ → ui/table}/EditableRow.test.tsx +36 -27
- package/src/components/DataTable/{components → ui/table}/EditableRow.tsx +86 -104
- package/src/components/DataTable/{components/__tests__ → ui/table}/EmptyState.test.tsx +2 -62
- package/src/components/DataTable/{components → ui/table}/EmptyState.tsx +7 -15
- package/src/components/DataTable/{components/__tests__ → ui/table}/FilterRow.test.tsx +5 -4
- package/src/components/DataTable/{components → ui/table}/FilterRow.tsx +3 -3
- package/src/components/DataTable/{components/__tests__ → ui/table}/LoadingState.test.tsx +6 -10
- package/src/components/DataTable/{components → ui/table}/LoadingState.tsx +4 -4
- package/src/components/DataTable/{components/__tests__ → ui/table}/RowComponent.test.tsx +412 -17
- package/src/components/DataTable/{components → ui/table}/RowComponent.tsx +183 -177
- package/src/components/DataTable/{components/__tests__ → ui/table}/UnifiedTableBody.test.tsx +425 -16
- package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
- package/src/components/DataTable/{components/__tests__ → ui/table}/cellValueUtils.test.ts +2 -2
- package/src/components/DataTable/{components → ui/table}/cellValueUtils.ts +1 -1
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/BulkOperationsDropdown.test.tsx +12 -5
- package/src/components/DataTable/{components → ui/toolbar}/BulkOperationsDropdown.tsx +3 -3
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/ColumnVisibilityDropdown.test.tsx +7 -4
- package/src/components/DataTable/{components → ui/toolbar}/ColumnVisibilityDropdown.tsx +7 -7
- package/src/components/DataTable/{components/__tests__ → ui/toolbar}/DataTableToolbar.test.tsx +4 -4
- package/src/components/DataTable/{components → ui/toolbar}/DataTableToolbar.tsx +4 -4
- package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
- package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
- package/src/components/DataTable/utils/{__tests__/a11yUtils.test.ts → a11yUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/{__tests__/aggregationUtils.test.ts → aggregationUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/columnUtils.test.ts → columnUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/csvParse.test.ts +74 -0
- package/src/components/DataTable/utils/csvParse.ts +65 -0
- package/src/components/DataTable/utils/{__tests__/errorHandling.test.ts → errorHandling.test.ts} +2 -2
- package/src/components/DataTable/utils/{__tests__/exportUtils.test.ts → exportUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/flexibleImport.test.ts → flexibleImport.test.ts} +2 -2
- package/src/components/DataTable/utils/flexibleImport.ts +3 -186
- package/src/components/DataTable/utils/{__tests__/hierarchicalSorting.test.ts → hierarchicalSorting.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/hierarchicalUtils.test.ts → hierarchicalUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
- package/src/components/DataTable/utils/importDateParser.ts +114 -0
- package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
- package/src/components/DataTable/utils/importValueParser.ts +91 -0
- package/src/components/DataTable/utils/{__tests__/paginationUtils.test.ts → paginationUtils.test.ts} +2 -2
- package/src/components/DataTable/utils/paginationUtils.ts +6 -3
- package/src/components/DataTable/utils/{__tests__/performanceUtils.test.ts → performanceUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/rowUtils.test.ts → rowUtils.test.ts} +3 -3
- package/src/components/DataTable/utils/{__tests__/selectFieldUtils.test.ts → selectFieldUtils.test.ts} +66 -3
- package/src/components/DataTable/utils/selectFieldUtils.ts +97 -60
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
- package/src/components/DateTimeField/DateTimeField.test.tsx +1 -1
- package/src/components/Dialog/Dialog.test-utils.ts +49 -0
- package/src/components/Dialog/Dialog.test.tsx +896 -89
- package/src/components/Dialog/Dialog.tsx +174 -882
- package/src/components/Dialog/dialogLock.test.ts +238 -0
- package/src/components/Dialog/dialogLock.ts +98 -0
- package/src/components/Dialog/index.ts +2 -0
- package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
- package/src/components/Dialog/useDialogDimensions.ts +140 -0
- package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
- package/src/components/Dialog/useDialogLifecycle.ts +135 -0
- package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
- package/src/components/Dialog/useDialogPersistence.ts +357 -0
- package/src/components/FileDisplay/FileDisplay.test.tsx +40 -40
- package/src/components/FileDisplay/FileDisplay.tsx +24 -656
- package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
- package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
- package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
- package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
- package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
- package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
- package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
- package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
- package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
- package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
- package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
- package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
- package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
- package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
- package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
- package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
- package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
- package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
- package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
- package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
- package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
- package/src/components/FileDisplay/fallbackUtils.ts +44 -0
- package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
- package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
- package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
- package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
- package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.test.ts +40 -42
- package/src/components/FileDisplay/useFileDisplay.ts +515 -0
- package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.unit.test.ts +406 -77
- package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
- package/src/{hooks/public → components/FileDisplay}/usePublicFileDisplay.test.ts +94 -88
- package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
- package/src/components/FileUpload/FileUpload.test.tsx +16 -10
- package/src/components/FileUpload/FileUpload.tsx +107 -525
- package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
- package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
- package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
- package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
- package/src/components/FileUpload/useFileUploadManager.ts +454 -0
- package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
- package/src/components/FileUpload/useResolvedAppId.ts +77 -0
- package/src/components/Footer/Footer.test.tsx +6 -292
- package/src/components/Footer/Footer.tsx +8 -125
- package/src/components/Form/Form.test.tsx +44 -27
- package/src/components/Form/Form.tsx +64 -287
- package/src/components/Form/useFormPersistence.ts +257 -0
- package/src/components/Header/Header.test.tsx +17 -18
- package/src/components/Header/Header.tsx +10 -1
- package/src/components/Input/Input.tsx +1 -1
- package/src/components/Label/Label.test.tsx +1 -1
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +1 -1
- package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +1029 -26
- package/src/components/NavigationMenu/NavigationMenu.tsx +61 -361
- package/src/components/NavigationMenu/index.ts +6 -1
- package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
- package/src/components/NavigationMenu/{__tests__/useNavigationFiltering.test.ts → useNavigationFiltering.test.ts} +68 -53
- package/src/components/NavigationMenu/useNavigationFiltering.ts +197 -296
- package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
- package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +77 -62
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +3 -3
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +16 -19
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +529 -5
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +280 -756
- package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
- package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
- package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
- package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +31 -25
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +31 -122
- package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
- package/src/components/Progress/Progress.tsx +1 -2
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -235
- package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
- package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
- package/src/components/PublicLayout/PublicLayout.test.tsx +217 -36
- package/src/components/PublicLayout/PublicPageLayout.tsx +132 -73
- package/src/components/PublicLayout/PublicPageProvider.tsx +5 -1
- package/src/components/Select/Select.test.tsx +1 -1
- package/src/components/Select/Select.tsx +28 -18
- package/src/components/Select/{__tests__/context.test.tsx → context.test.tsx} +3 -3
- package/src/components/Select/{utils/__tests__/text.test.tsx → text.test.tsx} +2 -2
- package/src/components/Select/{utils/text.ts → text.ts} +1 -1
- package/src/components/Select/{hooks/__tests__/useSelectEvents.test.ts → useSelectEvents.test.ts} +5 -5
- package/src/components/Select/{hooks/useSelectEvents.ts → useSelectEvents.ts} +2 -2
- package/src/components/Select/{hooks/__tests__/useSelectSearch.test.tsx → useSelectSearch.test.tsx} +7 -7
- package/src/components/Select/{hooks/useSelectSearch.ts → useSelectSearch.ts} +2 -2
- package/src/components/Select/{hooks/__tests__/useSelectState.test.ts → useSelectState.test.ts} +16 -2
- package/src/components/Select/{hooks/useSelectState.ts → useSelectState.ts} +3 -3
- package/src/components/Table/Table.test.tsx +348 -0
- package/src/components/Tabs/Tabs.test.tsx +270 -0
- package/src/components/Tabs/Tabs.tsx +1 -1
- package/src/components/Toast/Toast.test.tsx +420 -0
- package/src/components/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/constants/{__tests__/performance.test.ts → performance.test.ts} +2 -2
- package/src/hooks/{__tests__/ServiceHooks.test.tsx → ServiceHooks.test.tsx} +8 -8
- package/src/hooks/{__tests__/hooks.integration.test.tsx → hooks.integration.test.tsx} +11 -11
- package/src/hooks/index.ts +7 -4
- package/src/hooks/{__tests__/index.unit.test.ts → index.unit.test.ts} +2 -2
- package/src/hooks/public/usePublicEvent.test.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.test.ts +1 -1
- package/src/hooks/public/usePublicRouteParams.test.ts +1 -1
- package/src/hooks/services/useAuth.ts +9 -7
- package/src/hooks/useAddressAutocomplete.test.ts +22 -22
- package/src/hooks/useAddressAutocomplete.ts +90 -75
- package/src/hooks/{__tests__/useAppConfig.unit.test.ts → useAppConfig.unit.test.ts} +328 -22
- package/src/hooks/{__tests__/useComponentPerformance.unit.test.tsx → useComponentPerformance.unit.test.tsx} +27 -41
- package/src/hooks/useDataTablePerformance.ts +100 -120
- package/src/hooks/{__tests__/useDataTablePerformance.unit.test.ts → useDataTablePerformance.unit.test.ts} +5 -5
- package/src/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +2 -2
- package/src/hooks/{__tests__/useDebounce.unit.test.ts → useDebounce.unit.test.ts} +2 -2
- package/src/hooks/useEventTheme.test.ts +4 -1
- package/src/hooks/useEventTheme.ts +49 -21
- package/src/hooks/useEvents.ts +41 -1
- package/src/hooks/{__tests__/useEvents.unit.test.ts → useEvents.unit.test.ts} +5 -5
- package/src/hooks/useFileReference.test.ts +44 -41
- package/src/hooks/useFileReference.ts +182 -173
- package/src/hooks/useFileUrl.ts +1 -1
- package/src/hooks/{__tests__/useFileUrl.unit.test.ts → useFileUrl.unit.test.ts} +26 -36
- package/src/hooks/{__tests__/useFileUrlCache.test.ts → useFileUrlCache.test.ts} +8 -8
- package/src/hooks/useFileUrlCache.ts +1 -1
- package/src/hooks/{__tests__/useFocusManagement.unit.test.ts → useFocusManagement.unit.test.ts} +2 -2
- package/src/hooks/{__tests__/useFocusTrap.unit.test.tsx → useFocusTrap.unit.test.tsx} +2 -2
- package/src/hooks/{__tests__/useFormDialog.test.ts → useFormDialog.test.ts} +2 -2
- package/src/hooks/useInactivityTracker.ts +138 -131
- package/src/hooks/{__tests__/useInactivityTracker.unit.test.ts → useInactivityTracker.unit.test.ts} +3 -3
- package/src/hooks/{__tests__/useIsMobile.unit.test.ts → useIsMobile.unit.test.ts} +2 -2
- package/src/hooks/useIsPrint.ts +62 -0
- package/src/hooks/useIsPrint.unit.test.ts +545 -0
- package/src/hooks/{__tests__/useKeyboardShortcuts.unit.test.ts → useKeyboardShortcuts.unit.test.ts} +2 -2
- package/src/hooks/{__tests__/useOrganisationPermissions.unit.test.tsx → useOrganisationPermissions.unit.test.tsx} +4 -4
- package/src/hooks/useOrganisationSecurity.test.ts +3 -3
- package/src/hooks/useOrganisationSecurity.ts +190 -201
- package/src/hooks/{__tests__/useOrganisationSecurity.unit.test.tsx → useOrganisationSecurity.unit.test.tsx} +61 -63
- package/src/hooks/{__tests__/useOrganisations.unit.test.ts → useOrganisations.unit.test.ts} +5 -5
- package/src/hooks/{__tests__/usePerformanceMonitor.unit.test.ts → usePerformanceMonitor.unit.test.ts} +13 -14
- package/src/hooks/{__tests__/usePermissionCache.test.ts → usePermissionCache.test.ts} +26 -27
- package/src/hooks/usePermissionCache.ts +276 -271
- package/src/hooks/{__tests__/usePreventTabReload.test.ts → usePreventTabReload.test.ts} +2 -2
- package/src/hooks/{__tests__/usePublicEvent.simple.test.ts → usePublicEvent.simple.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicEvent.test.ts → usePublicEvent.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicEvent.unit.test.ts → usePublicEvent.unit.test.ts} +4 -4
- package/src/hooks/{__tests__/usePublicFileDisplay.test.ts → usePublicFileDisplay.test.ts} +12 -12
- package/src/hooks/{__tests__/usePublicRouteParams.unit.test.ts → usePublicRouteParams.unit.test.ts} +3 -3
- package/src/hooks/{__tests__/useQueryCache.test.ts → useQueryCache.test.ts} +2 -2
- package/src/hooks/useQueryCache.ts +0 -2
- package/src/hooks/{__tests__/useRBAC.unit.test.ts → useRBAC.unit.test.ts} +55 -38
- package/src/hooks/{__tests__/useSessionDraft.test.ts → useSessionDraft.test.ts} +2 -2
- package/src/hooks/{__tests__/useSessionRestoration.unit.test.tsx → useSessionRestoration.unit.test.tsx} +10 -19
- package/src/hooks/useStorage.ts +21 -16
- package/src/hooks/{__tests__/useStorage.unit.test.ts → useStorage.unit.test.ts} +38 -75
- package/src/hooks/{__tests__/useToast.test.ts → useToast.test.ts} +2 -2
- package/src/hooks/{__tests__/useToast.unit.test.tsx → useToast.unit.test.tsx} +2 -2
- package/src/hooks/{__tests__/useZodForm.unit.test.tsx → useZodForm.unit.test.tsx} +2 -2
- package/src/icons/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/icons/index.ts +2 -0
- package/src/{__tests__/index.test.ts → index.test.ts} +3 -7
- package/src/index.ts +15 -7
- package/src/providers/{__tests__/AuthProvider.test.tsx → AuthProvider.test.tsx} +3 -3
- package/src/providers/{__tests__/EventProvider.test.tsx → EventProvider.test.tsx} +3 -3
- package/src/providers/InactivityProvider.test-helper.tsx +40 -0
- package/src/providers/{__tests__/InactivityProvider.test.tsx → InactivityProvider.test.tsx} +14 -21
- package/src/providers/{__tests__/ProviderLifecycle.test.tsx → ProviderLifecycle.test.tsx} +4 -4
- package/src/providers/{__tests__/UnifiedAuthProvider.test.tsx → UnifiedAuthProvider.test.tsx} +1 -1
- package/src/providers/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/providers/services/{__tests__/AuthServiceProvider.integration.test.tsx → AuthServiceProvider.integration.test.tsx} +4 -4
- package/src/providers/services/{__tests__/AuthServiceProvider.test.tsx → AuthServiceProvider.test.tsx} +7 -7
- package/src/providers/services/{__tests__/EventServiceProvider.test.tsx → EventServiceProvider.test.tsx} +7 -7
- package/src/providers/services/{__tests__/InactivityServiceProvider.test.tsx → InactivityServiceProvider.test.tsx} +5 -5
- package/src/providers/services/{__tests__/OrganisationServiceProvider.test.tsx → OrganisationServiceProvider.test.tsx} +6 -6
- package/src/providers/services/UnifiedAuthContext.ts +30 -27
- package/src/providers/services/{__tests__/UnifiedAuthProvider.advanced.test.tsx → UnifiedAuthProvider.advanced.test.tsx} +8 -9
- package/src/providers/services/{__tests__/UnifiedAuthProvider.appId.test.tsx → UnifiedAuthProvider.appId.test.tsx} +25 -25
- package/src/providers/services/{__tests__/UnifiedAuthProvider.integration.test.tsx → UnifiedAuthProvider.integration.test.tsx} +14 -11
- package/src/providers/services/UnifiedAuthProvider.tsx +115 -360
- package/src/providers/services/{__tests__/contexts.test.tsx → contexts.test.tsx} +6 -6
- package/src/providers/services/{__tests__/useUnifiedAuth.test.tsx → useUnifiedAuth.test.tsx} +6 -6
- package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
- package/src/providers/useInactivity.test-helper.ts +27 -0
- package/src/rbac/{__tests__/adapters.comprehensive.test.tsx → adapters.comprehensive.test.tsx} +24 -24
- package/src/rbac/adapters.test.tsx +22 -22
- package/src/rbac/adapters.tsx +29 -29
- package/src/rbac/api.test.ts +973 -42
- package/src/rbac/api.ts +228 -253
- package/src/rbac/{__tests__/audit-batched.test.ts → audit-batched.test.ts} +6 -6
- package/src/rbac/audit.ts +4 -1
- package/src/rbac/{__tests__/auth-rbac-security.integration.test.tsx → auth-rbac-security.integration.test.tsx} +1 -1
- package/src/rbac/{__tests__/auth-rbac.e2e.test.tsx → auth-rbac.e2e.test.tsx} +27 -34
- package/src/rbac/cache-invalidation.test.ts +715 -0
- package/src/rbac/components/{__tests__/AccessDenied.test.tsx → AccessDenied.test.tsx} +3 -3
- package/src/rbac/components/{__tests__/NavigationGuard.test.tsx → NavigationGuard.test.tsx} +13 -11
- package/src/{__tests__/rbac/PagePermissionGuard.test.tsx → rbac/components/PagePermissionGuard.guard.test.tsx} +33 -19
- package/src/rbac/components/{__tests__/PagePermissionGuard.performance.test.tsx → PagePermissionGuard.performance.test.tsx} +30 -9
- package/src/rbac/components/{__tests__/PagePermissionGuard.race-condition.test.tsx → PagePermissionGuard.race-condition.test.tsx} +7 -7
- package/src/rbac/components/{__tests__/PagePermissionGuard.test.tsx → PagePermissionGuard.test.tsx} +10 -10
- package/src/rbac/components/PagePermissionGuard.tsx +177 -372
- package/src/rbac/components/{__tests__/PagePermissionGuard.verification.test.tsx → PagePermissionGuard.verification.test.tsx} +7 -7
- package/src/rbac/config.ts +58 -18
- package/src/rbac/{__tests__/engine.comprehensive.test.ts → engine.comprehensive.test.ts} +3 -3
- package/src/rbac/engine.test.ts +494 -0
- package/src/rbac/errors.ts +89 -55
- package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
- package/src/rbac/hooks/permissions/{__tests__/useAccessLevel.test.ts → useAccessLevel.test.ts} +40 -40
- package/src/rbac/hooks/permissions/useAccessLevel.ts +16 -6
- package/src/rbac/hooks/permissions/{__tests__/useCan.test.ts → useCan.test.ts} +41 -41
- package/src/rbac/hooks/permissions/useCan.ts +170 -252
- package/src/rbac/hooks/permissions/{__tests__/useMultiplePermissions.test.ts → useMultiplePermissions.test.ts} +49 -49
- package/src/rbac/hooks/permissions/useMultiplePermissions.ts +6 -2
- package/src/rbac/hooks/permissions/{__tests__/usePermissions.test.ts → usePermissions.test.ts} +10 -12
- package/src/rbac/hooks/permissions/usePermissions.ts +36 -65
- package/src/rbac/hooks/useCan.test.ts +42 -42
- package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
- package/src/rbac/hooks/usePageGuardScope.ts +117 -0
- package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
- package/src/rbac/hooks/{__tests__/usePermissions.integration.test.ts → usePermissions.integration.test.ts} +9 -9
- package/src/{__tests__/hooks/usePermissions.test.ts → rbac/hooks/usePermissions.stability.test.ts} +18 -18
- package/src/rbac/hooks/usePermissions.test.ts +54 -54
- package/src/rbac/hooks/useRBAC.test.ts +313 -217
- package/src/rbac/hooks/useRBAC.ts +145 -81
- package/src/rbac/hooks/useResourcePermissions.test.ts +25 -25
- package/src/rbac/hooks/useResourcePermissions.ts +68 -134
- package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
- package/src/rbac/hooks/useRoleManagement.test.ts +27 -112
- package/src/rbac/hooks/useRoleManagement.ts +153 -585
- package/src/rbac/hooks/{__tests__/useSecureSupabase.test.ts → useSecureSupabase.test.ts} +17 -17
- package/src/rbac/hooks/useSecureSupabase.ts +10 -2
- package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
- package/src/rbac/{__tests__/performance.test.ts → performance.test.ts} +1 -1
- package/src/rbac/{__tests__/rbac-core.test.tsx → rbac-core.test.tsx} +3 -3
- package/src/rbac/{__tests__/rbac-engine-core-logic.test.ts → rbac-engine-core-logic.test.ts} +2 -2
- package/src/rbac/{__tests__/rbac-engine-simplified.test.ts → rbac-engine-simplified.test.ts} +3 -3
- package/src/rbac/{__tests__/rbac-functions.test.ts → rbac-functions.test.ts} +57 -0
- package/src/rbac/{__tests__/rbac-role-isolation.test.ts → rbac-role-isolation.test.ts} +2 -2
- package/src/rbac/request-deduplication.test.ts +14 -9
- package/src/rbac/request-deduplication.ts +5 -4
- package/src/rbac/{__tests__/scenarios.user-role.test.tsx → scenarios.user-role.test.tsx} +23 -23
- package/src/rbac/secureClient.test.ts +514 -83
- package/src/rbac/secureClient.ts +8 -2
- package/src/rbac/security.test.ts +323 -0
- package/src/rbac/types/roleManagement.ts +66 -0
- package/src/rbac/utils/{__tests__/clientSecurity.test.ts → clientSecurity.test.ts} +4 -4
- package/src/rbac/utils/{__tests__/contextValidator.test.ts → contextValidator.test.ts} +4 -4
- package/src/rbac/utils/contextValidator.ts +5 -1
- package/src/rbac/utils/{__tests__/deep-equal.test.ts → deep-equal.test.ts} +1 -1
- package/src/rbac/utils/{__tests__/eventContext.test.ts → eventContext.test.ts} +36 -21
- package/src/rbac/utils/eventContext.ts +37 -33
- package/src/rbac/utils/fetchPermissionMap.ts +13 -0
- package/src/rbac/utils/permissionMapHelpers.ts +34 -0
- package/src/rbac/utils/roleManagementRpc.ts +303 -0
- package/src/services/{__tests__/AuthService.edge-cases.test.ts → AuthService.edge-cases.test.ts} +19 -19
- package/src/services/{__tests__/AuthService.restoreSession.test.ts → AuthService.restoreSession.test.ts} +2 -2
- package/src/services/{__tests__/AuthService.test.ts → AuthService.test.ts} +89 -55
- package/src/services/AuthService.ts +184 -205
- package/src/services/{__tests__/BaseService.edge-cases.test.ts → BaseService.edge-cases.test.ts} +3 -3
- package/src/services/{__tests__/BaseService.test.ts → BaseService.test.ts} +2 -2
- package/src/services/{__tests__/EventService.edge-cases.test.ts → EventService.edge-cases.test.ts} +27 -24
- package/src/services/{__tests__/EventService.eventColours.test.ts → EventService.eventColours.test.ts} +1 -1
- package/src/services/{__tests__/EventService.test.ts → EventService.test.ts} +256 -24
- package/src/services/EventService.ts +242 -312
- package/src/services/{__tests__/InactivityService.edge-cases.test.ts → InactivityService.edge-cases.test.ts} +3 -3
- package/src/services/{__tests__/InactivityService.lifecycle.test.ts → InactivityService.lifecycle.test.ts} +2 -2
- package/src/services/{__tests__/InactivityService.test.ts → InactivityService.test.ts} +179 -4
- package/src/services/InactivityService.ts +172 -213
- package/src/services/{__tests__/OrganisationService.edge-cases.test.ts → OrganisationService.edge-cases.test.ts} +5 -5
- package/src/services/{__tests__/OrganisationService.pagination.test.ts → OrganisationService.pagination.test.ts} +4 -4
- package/src/services/{__tests__/OrganisationService.test.ts → OrganisationService.test.ts} +410 -7
- package/src/services/OrganisationService.ts +184 -238
- package/src/services/base/BaseService.test.ts +1 -1
- package/src/services/interfaces/{__tests__/IAuthService.test.ts → IAuthService.test.ts} +21 -27
- package/src/services/interfaces/IAuthService.ts +10 -9
- package/src/services/interfaces/{__tests__/IEventService.test.ts → IEventService.test.ts} +4 -4
- package/src/services/interfaces/{__tests__/IInactivityService.test.ts → IInactivityService.test.ts} +3 -3
- package/src/services/interfaces/{__tests__/IOrganisationService.test.ts → IOrganisationService.test.ts} +3 -3
- package/src/styles/core.css +243 -12
- package/src/theming/{__tests__/parseEventColours.test.ts → parseEventColours.test.ts} +1 -1
- package/src/theming/{__tests__/runtime.test.ts → runtime.test.ts} +8 -17
- package/src/theming/runtime.ts +71 -2
- package/src/types/api-result.ts +53 -0
- package/src/types/{__tests__/core.test.ts → core.test.ts} +2 -2
- package/src/types/{__tests__/database-generated.test.ts → database-generated.test.ts} +3 -3
- package/src/types/database.generated.ts +45 -10
- package/src/types/event.ts +38 -18
- package/src/types/{__tests__/file-reference.test.ts → file-reference.test.ts} +13 -13
- package/src/types/file-reference.ts +37 -12
- package/src/types/{__tests__/guards.test.ts → guards.test.ts} +2 -2
- package/src/types/{__tests__/index.test.ts → index.test.ts} +2 -2
- package/src/types/index.ts +3 -0
- package/src/types/{__tests__/organisation.roles.test.ts → organisation.roles.test.ts} +1 -1
- package/src/types/{__tests__/organisation.test.ts → organisation.test.ts} +3 -31
- package/src/types/organisation.ts +15 -15
- package/src/types/supabase.ts +13 -4
- package/src/types/{__tests__/theme.test.ts → theme.test.ts} +1 -1
- package/src/types/{__tests__/type-validation.test.ts → type-validation.test.ts} +1 -1
- package/src/types/{__tests__/validation.test.ts → validation.test.ts} +2 -2
- package/src/utils/app/appIdResolver.test.ts +98 -71
- package/src/utils/app/appIdResolver.ts +31 -20
- package/src/utils/{__tests__/appConfig.unit.test.ts → appConfig.unit.test.ts} +1 -1
- package/src/utils/{__tests__/audit.unit.test.ts → audit.unit.test.ts} +1 -1
- package/src/utils/{__tests__/auth-utils.unit.test.ts → auth-utils.unit.test.ts} +16 -17
- package/src/utils/{__tests__/bundleAnalysis.unit.test.ts → bundleAnalysis.unit.test.ts} +35 -35
- package/src/utils/{__tests__/cn.unit.test.ts → cn.unit.test.ts} +1 -1
- package/src/utils/context/organisationContext.test.ts +105 -91
- package/src/utils/context/organisationContext.ts +29 -40
- package/src/utils/core/{__tests__/cn.test.ts → cn.test.ts} +3 -3
- package/src/utils/core/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +2 -2
- package/src/utils/core/{__tests__/logger.test.ts → logger.test.ts} +2 -2
- package/src/utils/core/mergeRefs.ts +24 -0
- package/src/utils/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +1 -1
- package/src/utils/{__tests__/deviceFingerprint.unit.test.ts → deviceFingerprint.unit.test.ts} +1 -1
- package/src/utils/dynamic/createLazyComponent.tsx +9 -1
- package/src/utils/dynamic/{__tests__/dynamicUtils.test.ts → dynamicUtils.test.ts} +2 -2
- package/src/utils/dynamic/{__tests__/lazyLoad.test.tsx → lazyLoad.test.tsx} +2 -2
- package/src/utils/{__tests__/dynamicUtils.unit.test.ts → dynamicUtils.unit.test.ts} +1 -1
- package/src/utils/file-reference/{__tests__/file-reference.test.ts → file-reference.test.ts} +214 -289
- package/src/utils/file-reference/index.ts +330 -347
- package/src/utils/{__tests__/formatDate.unit.test.ts → formatDate.unit.test.ts} +2 -2
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +1 -1
- package/src/utils/formatting/formatNumber.test.ts +1 -1
- package/src/utils/{__tests__/formatting.unit.test.ts → formatting.unit.test.ts} +1 -1
- package/src/utils/google-places/googlePlacesUtils.test.ts +70 -48
- package/src/utils/google-places/googlePlacesUtils.ts +67 -99
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +25 -22
- package/src/utils/google-places/loadGoogleMapsScript.ts +138 -117
- package/src/utils/{__tests__/index.unit.test.ts → index.unit.test.ts} +1 -1
- package/src/utils/{__tests__/lazyLoad.unit.test.tsx → lazyLoad.unit.test.tsx} +13 -14
- package/src/utils/location/location.test.ts +1 -1
- package/src/utils/{__tests__/logger.unit.test.ts → logger.unit.test.ts} +1 -1
- package/src/utils/{__tests__/organisationContext.unit.test.ts → organisationContext.unit.test.ts} +37 -48
- package/src/utils/performance/{__tests__/bundleAnalysis.test.ts → bundleAnalysis.test.ts} +2 -2
- package/src/utils/performance/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
- package/src/utils/performance/{__tests__/performanceBudgets.test.ts → performanceBudgets.test.ts} +2 -2
- package/src/utils/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
- package/src/utils/{__tests__/performanceBudgets.unit.test.ts → performanceBudgets.unit.test.ts} +2 -2
- package/src/utils/{__tests__/permissionTypes.unit.test.ts → permissionTypes.unit.test.ts} +1 -1
- package/src/utils/{__tests__/permissionUtils.unit.test.ts → permissionUtils.unit.test.ts} +1 -1
- package/src/utils/permissions/{__tests__/permissionTypes.test.ts → permissionTypes.test.ts} +2 -2
- package/src/utils/persistence/{__tests__/keyDerivation.test.ts → keyDerivation.test.ts} +2 -2
- package/src/utils/persistence/{__tests__/sensitiveFieldDetection.test.ts → sensitiveFieldDetection.test.ts} +2 -2
- package/src/utils/{__tests__/request-deduplication.test.ts → request-deduplication.test.ts} +2 -2
- package/src/utils/{__tests__/sanitization.unit.test.ts → sanitization.unit.test.ts} +1 -1
- package/src/utils/{__tests__/schemaUtils.unit.test.ts → schemaUtils.unit.test.ts} +1 -1
- package/src/utils/{__tests__/secureDataAccess.unit.test.ts → secureDataAccess.unit.test.ts} +2 -2
- package/src/utils/{__tests__/secureErrors.unit.test.ts → secureErrors.unit.test.ts} +4 -4
- package/src/utils/{__tests__/secureStorage.unit.test.ts → secureStorage.unit.test.ts} +1 -1
- package/src/utils/security/auth-utils.ts +34 -23
- package/src/utils/security/secureDataAccess.ts +241 -281
- package/src/utils/security/secureErrors.test.ts +1 -1
- package/src/utils/security/secureStorage.test.ts +1 -1
- package/src/utils/security/security.test.ts +25 -17
- package/src/utils/security/security.ts +15 -18
- package/src/utils/security/securityMonitor.test.ts +1 -1
- package/src/utils/{__tests__/security.unit.test.ts → security.unit.test.ts} +21 -15
- package/src/utils/{__tests__/securityMonitor.unit.test.ts → securityMonitor.unit.test.ts} +1 -1
- package/src/utils/{__tests__/sessionTracking.unit.test.ts → sessionTracking.unit.test.ts} +12 -12
- package/src/utils/storage/{__tests__/config.unit.test.ts → config.unit.test.ts} +2 -2
- package/src/utils/storage/helpers.test.ts +88 -102
- package/src/utils/storage/helpers.ts +173 -251
- package/src/utils/storage/{__tests__/index.unit.test.ts → index.unit.test.ts} +3 -3
- package/src/utils/storage/types.ts +7 -0
- package/src/utils/supabase/createBaseClient.test.ts +1 -1
- package/src/utils/timezone/timezone.test.ts +1 -1
- package/src/utils/{__tests__/timezone.test.ts → timezone.test.ts} +2 -2
- package/src/utils/validation/{__tests__/common.test.ts → common.test.ts} +2 -2
- package/src/utils/validation/{__tests__/csrf.test.ts → csrf.test.ts} +56 -28
- package/src/utils/validation/csrf.ts +42 -41
- package/src/utils/validation/{__tests__/htmlSanitization.unit.test.ts → htmlSanitization.unit.test.ts} +2 -2
- package/src/utils/validation/{__tests__/passwordSchema.test.ts → passwordSchema.test.ts} +2 -2
- package/src/utils/validation/{__tests__/schema.test.ts → schema.test.ts} +2 -2
- package/src/utils/validation/{__tests__/sqlInjectionProtection.test.ts → sqlInjectionProtection.test.ts} +2 -2
- package/src/utils/validation/{__tests__/user.test.ts → user.test.ts} +2 -2
- package/src/utils/validation/{__tests__/validation.test.ts → validation.test.ts} +2 -2
- package/src/utils/validation/{__tests__/validationUtils.test.ts → validationUtils.test.ts} +2 -2
- package/src/utils/{__tests__/validation.unit.test.ts → validation.unit.test.ts} +1 -1
- package/src/utils/{__tests__/validationUtils.unit.test.ts → validationUtils.unit.test.ts} +5 -2
- package/dist/UnifiedAuthProvider-BBD2PS3Q.js +0 -7
- package/dist/chunk-KPYQWGFQ.js +0 -183
- package/dist/types-D05dCGma.d.ts +0 -521
- package/scripts/eslint-audit.cjs +0 -222
- package/scripts/generate-docs.js +0 -157
- package/scripts/install-cursor-rules.cjs +0 -255
- package/scripts/install-eslint-config.cjs +0 -349
- package/scripts/setup-build-cache.js +0 -73
- package/scripts/validate-pre-publish.js +0 -145
- package/src/__tests__/integration/UserProfile.test.tsx +0 -124
- package/src/__tests__/public-recipe-view.test.ts +0 -228
- package/src/__tests__/rls-policies.test.ts +0 -472
- package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
- package/src/components/DataTable/components/DataTableLayout.tsx +0 -584
- package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -395
- package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +0 -467
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -358
- package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -957
- package/src/components/DataTable/core/ActionManager.ts +0 -235
- package/src/components/DataTable/core/ColumnManager.ts +0 -204
- package/src/components/DataTable/core/DataManager.ts +0 -190
- package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
- package/src/components/DataTable/core/PluginRegistry.ts +0 -229
- package/src/components/DataTable/core/StateManager.ts +0 -312
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -235
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -141
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -178
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -133
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -142
- package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -158
- package/src/components/DataTable/core/interfaces.ts +0 -338
- package/src/components/DataTable/types.ts +0 -764
- package/src/hooks/public/usePublicFileDisplay.ts +0 -534
- package/src/hooks/useFileDisplay.ts +0 -748
- package/src/providers/OrganisationProvider.test.tsx +0 -40
- package/src/providers/OrganisationProvider.tsx +0 -92
- package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
- package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -616
- package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +0 -591
- package/src/rbac/__tests__/cache-invalidation.test.ts +0 -393
- /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
- /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
- /package/src/hooks/{__tests__/useApiFetch.unit.test.ts → useApiFetch.unit.test.ts} +0 -0
- /package/src/providers/{__tests__/README.md → README.md} +0 -0
- /package/src/rbac/{__tests__/index.test.ts → index.test.ts} +0 -0
- /package/src/rbac/{__tests__/rbac-integration.test.ts → rbac-integration.test.ts} +0 -0
- /package/src/types/{__tests__/README.md → README.md} +0 -0
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file Public Recipe View Tests
|
|
3
|
-
* @package @jmruthers/pace-core
|
|
4
|
-
* @module RLS/Tests/PublicViews
|
|
5
|
-
* @since 0.5.181
|
|
6
|
-
*
|
|
7
|
-
* Regression tests for the public_recipe_details view to verify:
|
|
8
|
-
* - Anonymous access works only when event.public_readable = true
|
|
9
|
-
* - View exposes only expected columns
|
|
10
|
-
* - Respects diet/meal filters
|
|
11
|
-
* - Performance is acceptable (< 500ms)
|
|
12
|
-
*/
|
|
13
|
-
|
|
14
|
-
import { describe, it, expect, beforeAll } from 'vitest';
|
|
15
|
-
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
|
16
|
-
import type { Database } from '../../types/database';
|
|
17
|
-
|
|
18
|
-
// Following testing standards: use timeout parameter to prevent hanging
|
|
19
|
-
// See: packages/core/docs/standards/04-testing-standards.md
|
|
20
|
-
const TEST_TIMEOUT = 5000; // 5 seconds per test (matches rls-policies.test.ts pattern)
|
|
21
|
-
const PERFORMANCE_THRESHOLD = 500; // 500ms for public view queries
|
|
22
|
-
|
|
23
|
-
// Check if we're using real test-db (via environment variables)
|
|
24
|
-
const USE_REAL_DB = !!(process.env.SUPABASE_URL && process.env.VITE_SUPABASE_PUBLISHABLE_KEY);
|
|
25
|
-
const TEST_SUPABASE_URL = process.env.SUPABASE_URL || process.env.VITE_SUPABASE_URL;
|
|
26
|
-
const TEST_SUPABASE_PUBLISHABLE_KEY = process.env.VITE_SUPABASE_PUBLISHABLE_KEY;
|
|
27
|
-
const TEST_SUPABASE_SERVICE_ROLE_KEY = process.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
28
|
-
|
|
29
|
-
let anonClient: SupabaseClient<Database>;
|
|
30
|
-
let authenticatedClient: SupabaseClient<Database>;
|
|
31
|
-
|
|
32
|
-
const publicEvent = {
|
|
33
|
-
event_id: 'public-event-1',
|
|
34
|
-
event_name: 'Public Event',
|
|
35
|
-
public_readable: true,
|
|
36
|
-
is_visible: true,
|
|
37
|
-
organisation_id: 'org-1' as any
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
const privateEvent = {
|
|
41
|
-
event_id: 'private-event-1',
|
|
42
|
-
event_name: 'Private Event',
|
|
43
|
-
public_readable: false,
|
|
44
|
-
is_visible: true,
|
|
45
|
-
organisation_id: 'org-1' as any
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// TODO: Fix hanging tests - Supabase queries are blocking indefinitely despite timeout configuration
|
|
49
|
-
// Issue: Queries to cake_public_recipe_details view hang and prevent vitest timeout from firing
|
|
50
|
-
// Investigation needed:
|
|
51
|
-
// 1. Check if view exists and is accessible
|
|
52
|
-
// 2. Verify RLS policies aren't causing deadlocks
|
|
53
|
-
// 3. Investigate Supabase client connection pooling in test environment
|
|
54
|
-
// 4. Consider using AbortController for query cancellation
|
|
55
|
-
// Reference: packages/core/docs/standards/04-testing-standards.md
|
|
56
|
-
// Related: These tests follow the rls-policies.test.ts pattern but queries hang instead of timing out
|
|
57
|
-
describe.skip('Public Recipe View - Anonymous Access', () => {
|
|
58
|
-
// Following testing standards: initialize clients once in beforeAll (matches rls-policies.test.ts pattern)
|
|
59
|
-
beforeAll(() => {
|
|
60
|
-
if (USE_REAL_DB && TEST_SUPABASE_URL && TEST_SUPABASE_PUBLISHABLE_KEY) {
|
|
61
|
-
anonClient = createClient<Database>(TEST_SUPABASE_URL, TEST_SUPABASE_PUBLISHABLE_KEY, {
|
|
62
|
-
auth: { persistSession: false, autoRefreshToken: false }
|
|
63
|
-
});
|
|
64
|
-
authenticatedClient = createClient<Database>(TEST_SUPABASE_URL, TEST_SUPABASE_SERVICE_ROLE_KEY || TEST_SUPABASE_PUBLISHABLE_KEY, {
|
|
65
|
-
auth: { persistSession: false, autoRefreshToken: false }
|
|
66
|
-
});
|
|
67
|
-
} else {
|
|
68
|
-
// This should not happen due to skipIf, but provide fallback
|
|
69
|
-
throw new Error('Test database credentials not available. Set SUPABASE_URL and VITE_SUPABASE_PUBLISHABLE_KEY environment variables.');
|
|
70
|
-
}
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
describe('Public Event Access', () => {
|
|
74
|
-
it('should allow anonymous access when event.public_readable = true', async () => {
|
|
75
|
-
const start = Date.now();
|
|
76
|
-
const { data, error } = await anonClient
|
|
77
|
-
.from('cake_public_recipe_details')
|
|
78
|
-
.select('*')
|
|
79
|
-
.eq('event_id', publicEvent.event_id);
|
|
80
|
-
const duration = Date.now() - start;
|
|
81
|
-
|
|
82
|
-
expect(error).toBeNull();
|
|
83
|
-
expect(data).toBeDefined();
|
|
84
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
85
|
-
}, TEST_TIMEOUT);
|
|
86
|
-
|
|
87
|
-
it('should block anonymous access when event.public_readable = false', async () => {
|
|
88
|
-
const { data, error } = await anonClient
|
|
89
|
-
.from('cake_public_recipe_details')
|
|
90
|
-
.select('*')
|
|
91
|
-
.eq('event_id', privateEvent.event_id);
|
|
92
|
-
|
|
93
|
-
// Should return empty (view filters by public_readable = true)
|
|
94
|
-
expect(data).toEqual([]);
|
|
95
|
-
}, TEST_TIMEOUT);
|
|
96
|
-
|
|
97
|
-
it('should block anonymous access when event.is_visible = false', async () => {
|
|
98
|
-
const { data, error } = await anonClient
|
|
99
|
-
.from('cake_public_recipe_details')
|
|
100
|
-
.select('*')
|
|
101
|
-
.eq('event_id', 'hidden-event-1');
|
|
102
|
-
|
|
103
|
-
// Should return empty (view filters by is_visible = true)
|
|
104
|
-
expect(data).toEqual([]);
|
|
105
|
-
}, TEST_TIMEOUT);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
describe('View Column Exposure', () => {
|
|
109
|
-
it('should expose only expected columns', async () => {
|
|
110
|
-
const { data, error } = await anonClient
|
|
111
|
-
.from('cake_public_recipe_details')
|
|
112
|
-
.select('*')
|
|
113
|
-
.eq('event_id', publicEvent.event_id)
|
|
114
|
-
.limit(1)
|
|
115
|
-
.single();
|
|
116
|
-
|
|
117
|
-
expect(error).toBeNull();
|
|
118
|
-
if (data) {
|
|
119
|
-
// Verify expected columns exist
|
|
120
|
-
expect(data).toHaveProperty('dish_id');
|
|
121
|
-
expect(data).toHaveProperty('dish_name');
|
|
122
|
-
expect(data).toHaveProperty('dish_code');
|
|
123
|
-
expect(data).toHaveProperty('event_id');
|
|
124
|
-
expect(data).toHaveProperty('organisation_id');
|
|
125
|
-
|
|
126
|
-
// Verify sensitive columns are NOT exposed
|
|
127
|
-
// (adjust based on actual view definition)
|
|
128
|
-
// expect(data).not.toHaveProperty('created_by');
|
|
129
|
-
// expect(data).not.toHaveProperty('updated_by');
|
|
130
|
-
}
|
|
131
|
-
}, TEST_TIMEOUT);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
describe('Diet/Meal Filters', () => {
|
|
135
|
-
it('should filter by meal type', async () => {
|
|
136
|
-
const start = Date.now();
|
|
137
|
-
const { data, error } = await anonClient
|
|
138
|
-
.from('cake_public_recipe_details')
|
|
139
|
-
.select('*')
|
|
140
|
-
.eq('event_id', publicEvent.event_id)
|
|
141
|
-
.eq('mealtype_name', 'Breakfast');
|
|
142
|
-
const duration = Date.now() - start;
|
|
143
|
-
|
|
144
|
-
expect(error).toBeNull();
|
|
145
|
-
expect(data).toBeDefined();
|
|
146
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
147
|
-
}, TEST_TIMEOUT);
|
|
148
|
-
|
|
149
|
-
it('should filter by diet requirements', async () => {
|
|
150
|
-
// This test would verify that diet filters work correctly
|
|
151
|
-
// Adjust based on actual view structure
|
|
152
|
-
const { data, error } = await anonClient
|
|
153
|
-
.from('cake_public_recipe_details')
|
|
154
|
-
.select('*')
|
|
155
|
-
.eq('event_id', publicEvent.event_id)
|
|
156
|
-
.eq('dish_dietnote', 'Vegetarian');
|
|
157
|
-
|
|
158
|
-
expect(error).toBeNull();
|
|
159
|
-
expect(data).toBeDefined();
|
|
160
|
-
}, TEST_TIMEOUT);
|
|
161
|
-
});
|
|
162
|
-
|
|
163
|
-
describe('Performance', () => {
|
|
164
|
-
it('should complete view queries in < 500ms', async () => {
|
|
165
|
-
const start = Date.now();
|
|
166
|
-
await anonClient
|
|
167
|
-
.from('cake_public_recipe_details')
|
|
168
|
-
.select('*')
|
|
169
|
-
.eq('event_id', publicEvent.event_id)
|
|
170
|
-
.limit(100);
|
|
171
|
-
const duration = Date.now() - start;
|
|
172
|
-
|
|
173
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
174
|
-
}, TEST_TIMEOUT);
|
|
175
|
-
|
|
176
|
-
it('should handle filtered queries efficiently', async () => {
|
|
177
|
-
const start = Date.now();
|
|
178
|
-
await anonClient
|
|
179
|
-
.from('cake_public_recipe_details')
|
|
180
|
-
.select('*')
|
|
181
|
-
.eq('event_id', publicEvent.event_id)
|
|
182
|
-
.eq('mealtype_name', 'Breakfast')
|
|
183
|
-
.limit(50);
|
|
184
|
-
const duration = Date.now() - start;
|
|
185
|
-
|
|
186
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
187
|
-
}, TEST_TIMEOUT);
|
|
188
|
-
});
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
// TODO: Fix hanging tests - Supabase queries are blocking indefinitely despite timeout configuration
|
|
192
|
-
// Issue: Queries to cake_public_recipe_details view hang and prevent vitest timeout from firing
|
|
193
|
-
// Investigation needed:
|
|
194
|
-
// 1. Check if view exists and is accessible
|
|
195
|
-
// 2. Verify RLS policies aren't causing deadlocks
|
|
196
|
-
// 3. Investigate Supabase client connection pooling in test environment
|
|
197
|
-
// 4. Consider using AbortController for query cancellation
|
|
198
|
-
// Reference: packages/core/docs/standards/04-testing-standards.md
|
|
199
|
-
// Related: These tests follow the rls-policies.test.ts pattern but queries hang instead of timing out
|
|
200
|
-
describe.skip('Public Recipe View - Authenticated Access', () => {
|
|
201
|
-
// Following testing standards: initialize clients once in beforeAll (matches rls-policies.test.ts pattern)
|
|
202
|
-
// Note: Clients are already initialized in the previous describe block's beforeAll
|
|
203
|
-
// This describe block reuses the same clients
|
|
204
|
-
|
|
205
|
-
it.skip('should allow authenticated users to view public recipes', async () => {
|
|
206
|
-
const { data, error } = await authenticatedClient
|
|
207
|
-
.from('cake_public_recipe_details')
|
|
208
|
-
.select('*')
|
|
209
|
-
.eq('event_id', publicEvent.event_id);
|
|
210
|
-
|
|
211
|
-
expect(error).toBeNull();
|
|
212
|
-
expect(data).toBeDefined();
|
|
213
|
-
}, TEST_TIMEOUT);
|
|
214
|
-
|
|
215
|
-
it.skip('should allow authenticated users to view private events they have access to', async () => {
|
|
216
|
-
// Authenticated users with organisation access should be able to view
|
|
217
|
-
// recipes from events in their organisation, even if not public_readable
|
|
218
|
-
// (This depends on the view definition and RLS policies)
|
|
219
|
-
const { data, error } = await authenticatedClient
|
|
220
|
-
.from('cake_public_recipe_details')
|
|
221
|
-
.select('*')
|
|
222
|
-
.eq('event_id', privateEvent.event_id);
|
|
223
|
-
|
|
224
|
-
// Result depends on RLS policies and view definition
|
|
225
|
-
expect(error).toBeNull();
|
|
226
|
-
}, TEST_TIMEOUT);
|
|
227
|
-
});
|
|
228
|
-
|
|
@@ -1,472 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @file RLS Policy Tests
|
|
3
|
-
* @package @jmruthers/pace-core
|
|
4
|
-
* @module RLS/Tests
|
|
5
|
-
* @since 0.5.181
|
|
6
|
-
*
|
|
7
|
-
* Application-level tests for RLS policies to verify they work correctly
|
|
8
|
-
* under different user contexts and that performance is acceptable.
|
|
9
|
-
*
|
|
10
|
-
* These tests verify that:
|
|
11
|
-
* - RLS policies correctly enforce access control
|
|
12
|
-
* - Helper functions are used (no inline auth.uid() calls)
|
|
13
|
-
* - Queries complete in acceptable time (< 1 second)
|
|
14
|
-
* - Cross-organisation access is properly blocked
|
|
15
|
-
*/
|
|
16
|
-
|
|
17
|
-
import { describe, it, expect, beforeAll, afterAll, vi } from 'vitest';
|
|
18
|
-
import { createClient, SupabaseClient } from '@supabase/supabase-js';
|
|
19
|
-
import type { Database } from '../../types/database';
|
|
20
|
-
import { config } from 'dotenv';
|
|
21
|
-
import { existsSync, readFileSync } from 'fs';
|
|
22
|
-
import path from 'path';
|
|
23
|
-
import { fileURLToPath } from 'url';
|
|
24
|
-
import { dirname } from 'path';
|
|
25
|
-
|
|
26
|
-
// Get the project root directory (where .env file is located)
|
|
27
|
-
// Use import.meta.url to get the actual file location, then resolve to project root
|
|
28
|
-
const __filename = fileURLToPath(import.meta.url);
|
|
29
|
-
const __dirname = dirname(__filename);
|
|
30
|
-
// This file is at: packages/core/src/__tests__/rls-policies.test.ts
|
|
31
|
-
// So we need to go up 4 levels to get to project root
|
|
32
|
-
const projectRoot = path.resolve(__dirname, '../../../../');
|
|
33
|
-
const envPath = path.resolve(projectRoot, '.env');
|
|
34
|
-
|
|
35
|
-
// Helper function to manually parse .env file as fallback
|
|
36
|
-
function loadEnvFile(envPath: string): void {
|
|
37
|
-
if (!existsSync(envPath)) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
try {
|
|
42
|
-
const envContent = readFileSync(envPath, 'utf-8');
|
|
43
|
-
const lines = envContent.split('\n');
|
|
44
|
-
|
|
45
|
-
for (const line of lines) {
|
|
46
|
-
// Skip comments and empty lines
|
|
47
|
-
const trimmed = line.trim();
|
|
48
|
-
if (!trimmed || trimmed.startsWith('#')) {
|
|
49
|
-
continue;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// Parse KEY=VALUE
|
|
53
|
-
const match = trimmed.match(/^([^=]+)=(.*)$/);
|
|
54
|
-
if (match) {
|
|
55
|
-
const key = match[1].trim();
|
|
56
|
-
let value = match[2].trim();
|
|
57
|
-
|
|
58
|
-
// Remove quotes if present
|
|
59
|
-
if ((value.startsWith('"') && value.endsWith('"')) ||
|
|
60
|
-
(value.startsWith("'") && value.endsWith("'"))) {
|
|
61
|
-
value = value.slice(1, -1);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// Always set (override existing) to ensure we have the values
|
|
65
|
-
process.env[key] = value;
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
} catch (error) {
|
|
69
|
-
console.warn('⚠️ Failed to manually parse .env file:', error);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Test configuration
|
|
74
|
-
const TEST_TIMEOUT = 5000; // 5 seconds
|
|
75
|
-
const PERFORMANCE_THRESHOLD = 1000; // 1 second in milliseconds
|
|
76
|
-
|
|
77
|
-
// Supabase clients for different user contexts
|
|
78
|
-
let superAdminClient: SupabaseClient<Database>;
|
|
79
|
-
let orgAdminClient: SupabaseClient<Database>;
|
|
80
|
-
let regularMemberClient: SupabaseClient<Database>;
|
|
81
|
-
let anonClient: SupabaseClient<Database>;
|
|
82
|
-
|
|
83
|
-
// Initialize clients once for all tests
|
|
84
|
-
beforeAll(async () => {
|
|
85
|
-
// Always try to load .env file manually first (most reliable in test environment)
|
|
86
|
-
if (existsSync(envPath)) {
|
|
87
|
-
// Force manual parsing to ensure variables are set
|
|
88
|
-
loadEnvFile(envPath);
|
|
89
|
-
|
|
90
|
-
// Also try dotenv as a backup
|
|
91
|
-
const result = config({ path: envPath, override: true });
|
|
92
|
-
if (result.error) {
|
|
93
|
-
// Ignore dotenv errors, manual parser should have worked
|
|
94
|
-
}
|
|
95
|
-
} else {
|
|
96
|
-
throw new Error(`.env file not found at: ${envPath}. Current working directory: ${process.cwd()}`);
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
// Get environment variables at runtime (check both process.env and import.meta.env for Vite)
|
|
100
|
-
const TEST_SUPABASE_URL =
|
|
101
|
-
process.env.SUPABASE_URL ||
|
|
102
|
-
process.env.VITE_SUPABASE_URL ||
|
|
103
|
-
(import.meta.env && (import.meta.env as any).VITE_SUPABASE_URL);
|
|
104
|
-
const TEST_SUPABASE_PUBLISHABLE_KEY =
|
|
105
|
-
process.env.VITE_SUPABASE_PUBLISHABLE_KEY ||
|
|
106
|
-
(import.meta.env && (import.meta.env as any).VITE_SUPABASE_PUBLISHABLE_KEY);
|
|
107
|
-
const TEST_SUPABASE_SERVICE_ROLE_KEY =
|
|
108
|
-
process.env.SUPABASE_SERVICE_ROLE_KEY;
|
|
109
|
-
|
|
110
|
-
// Validate required environment variables
|
|
111
|
-
if (!TEST_SUPABASE_URL) {
|
|
112
|
-
throw new Error(
|
|
113
|
-
'Missing SUPABASE_URL or VITE_SUPABASE_URL environment variable. ' +
|
|
114
|
-
'Please set one of these in your .env file. ' +
|
|
115
|
-
`Current values: SUPABASE_URL=${process.env.SUPABASE_URL || 'undefined'}, ` +
|
|
116
|
-
`VITE_SUPABASE_URL=${process.env.VITE_SUPABASE_URL || 'undefined'}`
|
|
117
|
-
);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
if (!TEST_SUPABASE_PUBLISHABLE_KEY) {
|
|
121
|
-
throw new Error(
|
|
122
|
-
'Missing VITE_SUPABASE_PUBLISHABLE_KEY environment variable. ' +
|
|
123
|
-
'Please set this in your .env file.'
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
// Create base client with anon key
|
|
128
|
-
const baseClient = createClient<Database>(TEST_SUPABASE_URL, TEST_SUPABASE_PUBLISHABLE_KEY);
|
|
129
|
-
|
|
130
|
-
// Create anon client (no auth)
|
|
131
|
-
anonClient = baseClient;
|
|
132
|
-
|
|
133
|
-
// Using service role key for super admin (bypasses RLS - use carefully!)
|
|
134
|
-
if (TEST_SUPABASE_SERVICE_ROLE_KEY) {
|
|
135
|
-
superAdminClient = createClient<Database>(TEST_SUPABASE_URL, TEST_SUPABASE_SERVICE_ROLE_KEY);
|
|
136
|
-
} else {
|
|
137
|
-
console.warn('⚠️ SUPABASE_SERVICE_ROLE_KEY not set. Super admin tests will use anon key (subject to RLS).');
|
|
138
|
-
// Fallback: use anon key (will be subject to RLS)
|
|
139
|
-
superAdminClient = baseClient;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// For org admin and regular member, we'd need to sign in as those users
|
|
143
|
-
// For now, using base client - update this when you have test user sessions
|
|
144
|
-
orgAdminClient = baseClient;
|
|
145
|
-
regularMemberClient = baseClient;
|
|
146
|
-
|
|
147
|
-
console.log('✅ Initialized Supabase clients for testing');
|
|
148
|
-
console.log(' URL:', TEST_SUPABASE_URL);
|
|
149
|
-
console.log(' Service role key:', TEST_SUPABASE_SERVICE_ROLE_KEY ? '✅ Set' : '❌ Not set');
|
|
150
|
-
});
|
|
151
|
-
|
|
152
|
-
// Test data
|
|
153
|
-
// NOTE: These tests require actual database records with valid UUIDs
|
|
154
|
-
// The IDs below are placeholders - in a real test environment, these should be
|
|
155
|
-
// replaced with actual UUIDs from test database records
|
|
156
|
-
const testOrganisation1 = {
|
|
157
|
-
id: '00000000-0000-0000-0000-000000000001' as any, // Valid UUID format
|
|
158
|
-
name: 'Test Organisation 1'
|
|
159
|
-
};
|
|
160
|
-
|
|
161
|
-
const testOrganisation2 = {
|
|
162
|
-
id: '00000000-0000-0000-0000-000000000002' as any, // Valid UUID format
|
|
163
|
-
name: 'Test Organisation 2'
|
|
164
|
-
};
|
|
165
|
-
|
|
166
|
-
const testEvent = {
|
|
167
|
-
event_id: '00000000-0000-0000-0000-000000000010' as any, // Valid UUID format
|
|
168
|
-
event_name: 'Test Event',
|
|
169
|
-
organisation_id: testOrganisation1.id,
|
|
170
|
-
is_visible: true,
|
|
171
|
-
public_readable: false
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
const testUserId = '00000000-0000-0000-0000-000000000100' as any; // Valid UUID format
|
|
175
|
-
|
|
176
|
-
describe('RLS Policies - Organisations', () => {
|
|
177
|
-
|
|
178
|
-
describe('Super Admin Access', () => {
|
|
179
|
-
it('should allow super admin to view all organisations', async () => {
|
|
180
|
-
const start = Date.now();
|
|
181
|
-
const { data, error } = await superAdminClient
|
|
182
|
-
.from('core_organisations')
|
|
183
|
-
.select('*')
|
|
184
|
-
.limit(10);
|
|
185
|
-
const duration = Date.now() - start;
|
|
186
|
-
|
|
187
|
-
expect(error).toBeNull();
|
|
188
|
-
expect(data).toBeDefined();
|
|
189
|
-
// Use <= to account for minor timing variations in test environment
|
|
190
|
-
// Increase threshold for CI/test environments which may be slower
|
|
191
|
-
// Allow 2x threshold for test environment variability
|
|
192
|
-
const adjustedThreshold = PERFORMANCE_THRESHOLD * 2; // Allow 100% more time for test environments
|
|
193
|
-
expect(duration).toBeLessThanOrEqual(adjustedThreshold);
|
|
194
|
-
}, TEST_TIMEOUT);
|
|
195
|
-
|
|
196
|
-
it('should allow super admin to update any organisation', async () => {
|
|
197
|
-
const { data, error } = await superAdminClient
|
|
198
|
-
.from('core_organisations')
|
|
199
|
-
.update({ name: 'Updated Name' })
|
|
200
|
-
.eq('id', testOrganisation1.id)
|
|
201
|
-
.select()
|
|
202
|
-
.single();
|
|
203
|
-
|
|
204
|
-
// Note: This test requires testOrganisation1 to exist in the database
|
|
205
|
-
// If the organisation doesn't exist, we'll get a UUID format error or no rows
|
|
206
|
-
// In a real test environment, ensure test data exists before running
|
|
207
|
-
if (error?.code === '22P02' || error?.code === 'PGRST116') {
|
|
208
|
-
// Invalid UUID format or organisation doesn't exist - skip this test
|
|
209
|
-
console.warn('⚠️ Test skipped: testOrganisation1 does not exist in database');
|
|
210
|
-
return;
|
|
211
|
-
}
|
|
212
|
-
expect(error).toBeNull();
|
|
213
|
-
}, TEST_TIMEOUT);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
describe('Organisation Admin Access', () => {
|
|
217
|
-
it('should allow org admin to view their organisation', async () => {
|
|
218
|
-
const start = Date.now();
|
|
219
|
-
const { data, error } = await orgAdminClient
|
|
220
|
-
.from('core_organisations')
|
|
221
|
-
.select('*')
|
|
222
|
-
.eq('id', testOrganisation1.id)
|
|
223
|
-
.single();
|
|
224
|
-
const duration = Date.now() - start;
|
|
225
|
-
|
|
226
|
-
// Note: This test requires testOrganisation1 to exist and orgAdminClient to be authenticated
|
|
227
|
-
if (error?.code === '22P02' || error?.code === 'PGRST116') {
|
|
228
|
-
console.warn('⚠️ Test skipped: testOrganisation1 does not exist in database or invalid UUID');
|
|
229
|
-
return;
|
|
230
|
-
}
|
|
231
|
-
expect(error).toBeNull();
|
|
232
|
-
expect(data).toBeDefined();
|
|
233
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
234
|
-
}, TEST_TIMEOUT);
|
|
235
|
-
|
|
236
|
-
it('should block org admin from viewing other organisations', async () => {
|
|
237
|
-
const { data, error } = await orgAdminClient
|
|
238
|
-
.from('core_organisations')
|
|
239
|
-
.select('*')
|
|
240
|
-
.eq('id', testOrganisation2.id)
|
|
241
|
-
.single();
|
|
242
|
-
|
|
243
|
-
// Should return empty or error (RLS blocks access)
|
|
244
|
-
expect(data).toBeNull();
|
|
245
|
-
}, TEST_TIMEOUT);
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
describe('Regular Member Access', () => {
|
|
249
|
-
it('should allow member to view their organisation', async () => {
|
|
250
|
-
const start = Date.now();
|
|
251
|
-
const { data, error } = await regularMemberClient
|
|
252
|
-
.from('core_organisations')
|
|
253
|
-
.select('*')
|
|
254
|
-
.eq('id', testOrganisation1.id)
|
|
255
|
-
.single();
|
|
256
|
-
const duration = Date.now() - start;
|
|
257
|
-
|
|
258
|
-
// Note: This test requires testOrganisation1 to exist and regularMemberClient to be authenticated
|
|
259
|
-
if (error?.code === '22P02' || error?.code === 'PGRST116') {
|
|
260
|
-
console.warn('⚠️ Test skipped: testOrganisation1 does not exist in database or invalid UUID');
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
expect(error).toBeNull();
|
|
264
|
-
expect(data).toBeDefined();
|
|
265
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
266
|
-
}, TEST_TIMEOUT);
|
|
267
|
-
|
|
268
|
-
it('should block member from updating organisation', async () => {
|
|
269
|
-
const { data, error } = await regularMemberClient
|
|
270
|
-
.from('core_organisations')
|
|
271
|
-
.update({ name: 'Unauthorized Update' })
|
|
272
|
-
.eq('id', testOrganisation1.id);
|
|
273
|
-
|
|
274
|
-
// Note: This test requires testOrganisation1 to exist
|
|
275
|
-
// If it doesn't exist, the update will affect 0 rows (not an error, but also not a permission test)
|
|
276
|
-
if (error?.code === '22P02' || error?.code === 'PGRST116') {
|
|
277
|
-
console.warn('⚠️ Test skipped: testOrganisation1 does not exist in database');
|
|
278
|
-
return;
|
|
279
|
-
}
|
|
280
|
-
// Should fail (member doesn't have update permission) OR affect 0 rows if org doesn't exist
|
|
281
|
-
// If data is empty/null and no error, it means 0 rows were affected (org doesn't exist)
|
|
282
|
-
if (!error && (!data || data.length === 0)) {
|
|
283
|
-
console.warn('⚠️ Test skipped: testOrganisation1 does not exist (0 rows affected)');
|
|
284
|
-
return;
|
|
285
|
-
}
|
|
286
|
-
// Should fail (member doesn't have update permission)
|
|
287
|
-
expect(error).not.toBeNull();
|
|
288
|
-
}, TEST_TIMEOUT);
|
|
289
|
-
});
|
|
290
|
-
|
|
291
|
-
describe('Anonymous Access', () => {
|
|
292
|
-
it('should block anonymous users from viewing organisations', async () => {
|
|
293
|
-
const { data, error } = await anonClient
|
|
294
|
-
.from('core_organisations')
|
|
295
|
-
.select('*');
|
|
296
|
-
|
|
297
|
-
// Should return empty (RLS blocks anonymous access)
|
|
298
|
-
expect(data).toEqual([]);
|
|
299
|
-
}, TEST_TIMEOUT);
|
|
300
|
-
});
|
|
301
|
-
});
|
|
302
|
-
|
|
303
|
-
describe('RLS Policies - Events', () => {
|
|
304
|
-
describe('Public Event Access', () => {
|
|
305
|
-
it('should allow anonymous access to public events', async () => {
|
|
306
|
-
const start = Date.now();
|
|
307
|
-
const { data, error } = await anonClient
|
|
308
|
-
.from('core_events')
|
|
309
|
-
.select('*')
|
|
310
|
-
.eq('event_id', testEvent.event_id)
|
|
311
|
-
.eq('public_readable', true)
|
|
312
|
-
.eq('is_visible', true)
|
|
313
|
-
.single();
|
|
314
|
-
const duration = Date.now() - start;
|
|
315
|
-
|
|
316
|
-
// Note: This test requires a public event with testEvent.event_id to exist
|
|
317
|
-
if (error?.code === 'PGRST116' || error?.code === '22P02') {
|
|
318
|
-
console.warn('⚠️ Test skipped: testEvent does not exist in database or is not public');
|
|
319
|
-
return;
|
|
320
|
-
}
|
|
321
|
-
expect(error).toBeNull();
|
|
322
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
323
|
-
}, TEST_TIMEOUT);
|
|
324
|
-
|
|
325
|
-
it('should block anonymous access to non-public events', async () => {
|
|
326
|
-
const { data, error } = await anonClient
|
|
327
|
-
.from('core_events')
|
|
328
|
-
.select('*')
|
|
329
|
-
.eq('event_id', testEvent.event_id)
|
|
330
|
-
.eq('public_readable', false)
|
|
331
|
-
.single();
|
|
332
|
-
|
|
333
|
-
// Should return empty (RLS blocks access)
|
|
334
|
-
expect(data).toBeNull();
|
|
335
|
-
}, TEST_TIMEOUT);
|
|
336
|
-
});
|
|
337
|
-
|
|
338
|
-
describe('Authenticated Event Access', () => {
|
|
339
|
-
it('should allow org member to view events in their organisation', async () => {
|
|
340
|
-
const start = Date.now();
|
|
341
|
-
const { data, error } = await regularMemberClient
|
|
342
|
-
.from('core_events')
|
|
343
|
-
.select('*')
|
|
344
|
-
.eq('organisation_id', testOrganisation1.id)
|
|
345
|
-
.limit(10);
|
|
346
|
-
const duration = Date.now() - start;
|
|
347
|
-
|
|
348
|
-
// Note: This test requires testOrganisation1 to exist and regularMemberClient to be authenticated
|
|
349
|
-
if (error?.code === '22P02') {
|
|
350
|
-
console.warn('⚠️ Test skipped: testOrganisation1 does not exist in database or invalid UUID');
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
expect(error).toBeNull();
|
|
354
|
-
expect(data).toBeDefined();
|
|
355
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
356
|
-
}, TEST_TIMEOUT);
|
|
357
|
-
});
|
|
358
|
-
});
|
|
359
|
-
|
|
360
|
-
describe('RLS Policies - RBAC Tables', () => {
|
|
361
|
-
describe('rbac_user_profiles', () => {
|
|
362
|
-
it('should allow user to view their own profile', async () => {
|
|
363
|
-
const start = Date.now();
|
|
364
|
-
const { data, error } = await regularMemberClient
|
|
365
|
-
.from('rbac_user_profiles')
|
|
366
|
-
.select('*')
|
|
367
|
-
.eq('id', testUserId)
|
|
368
|
-
.single();
|
|
369
|
-
const duration = Date.now() - start;
|
|
370
|
-
|
|
371
|
-
// Note: This test requires testUserId to exist and regularMemberClient to be authenticated as that user
|
|
372
|
-
if (error?.code === '22P02' || error?.code === 'PGRST116') {
|
|
373
|
-
console.warn('⚠️ Test skipped: testUserId does not exist in database or invalid UUID');
|
|
374
|
-
return;
|
|
375
|
-
}
|
|
376
|
-
expect(error).toBeNull();
|
|
377
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
378
|
-
}, TEST_TIMEOUT);
|
|
379
|
-
|
|
380
|
-
it('should block user from viewing other profiles', async () => {
|
|
381
|
-
const { data, error } = await regularMemberClient
|
|
382
|
-
.from('rbac_user_profiles')
|
|
383
|
-
.select('*')
|
|
384
|
-
.eq('id', 'other-user-123' as any)
|
|
385
|
-
.single();
|
|
386
|
-
|
|
387
|
-
// Should return empty (RLS blocks access)
|
|
388
|
-
expect(data).toBeNull();
|
|
389
|
-
}, TEST_TIMEOUT);
|
|
390
|
-
});
|
|
391
|
-
|
|
392
|
-
describe('rbac_organisation_roles', () => {
|
|
393
|
-
it('should allow user to view their own roles', async () => {
|
|
394
|
-
const start = Date.now();
|
|
395
|
-
const { data, error } = await regularMemberClient
|
|
396
|
-
.from('rbac_organisation_roles')
|
|
397
|
-
.select('*')
|
|
398
|
-
.eq('user_id', testUserId);
|
|
399
|
-
const duration = Date.now() - start;
|
|
400
|
-
|
|
401
|
-
// Note: This test requires testUserId to exist and regularMemberClient to be authenticated as that user
|
|
402
|
-
if (error?.code === '22P02' || error?.code === 'PGRST116') {
|
|
403
|
-
console.warn('⚠️ Test skipped: testUserId does not exist in database or invalid UUID');
|
|
404
|
-
return;
|
|
405
|
-
}
|
|
406
|
-
expect(error).toBeNull();
|
|
407
|
-
expect(data).toBeDefined();
|
|
408
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
409
|
-
}, TEST_TIMEOUT);
|
|
410
|
-
});
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
describe('RLS Policies - Performance', () => {
|
|
414
|
-
it('should complete organisation queries in < 1 second', async () => {
|
|
415
|
-
const start = Date.now();
|
|
416
|
-
await superAdminClient
|
|
417
|
-
.from('core_organisations')
|
|
418
|
-
.select('*')
|
|
419
|
-
.limit(100);
|
|
420
|
-
const duration = Date.now() - start;
|
|
421
|
-
|
|
422
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
423
|
-
}, TEST_TIMEOUT);
|
|
424
|
-
|
|
425
|
-
it('should complete event queries in < 1 second', async () => {
|
|
426
|
-
const start = Date.now();
|
|
427
|
-
await superAdminClient
|
|
428
|
-
.from('core_events')
|
|
429
|
-
.select('*')
|
|
430
|
-
.eq('is_visible', true)
|
|
431
|
-
.limit(100);
|
|
432
|
-
const duration = Date.now() - start;
|
|
433
|
-
|
|
434
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
435
|
-
}, TEST_TIMEOUT);
|
|
436
|
-
|
|
437
|
-
it('should complete user profile queries in < 1 second', async () => {
|
|
438
|
-
const start = Date.now();
|
|
439
|
-
await superAdminClient
|
|
440
|
-
.from('rbac_user_profiles')
|
|
441
|
-
.select('*')
|
|
442
|
-
.limit(100);
|
|
443
|
-
const duration = Date.now() - start;
|
|
444
|
-
|
|
445
|
-
expect(duration).toBeLessThan(PERFORMANCE_THRESHOLD);
|
|
446
|
-
}, TEST_TIMEOUT);
|
|
447
|
-
});
|
|
448
|
-
|
|
449
|
-
describe('RLS Policies - Helper Functions', () => {
|
|
450
|
-
it('should use helper functions instead of inline auth.uid()', async () => {
|
|
451
|
-
// This test verifies that policies use helper functions
|
|
452
|
-
// by checking query plans don't contain InitPlan nodes
|
|
453
|
-
// Note: EXPLAIN cannot be used in non-volatile functions, so this test
|
|
454
|
-
// requires a custom RPC function that handles EXPLAIN properly
|
|
455
|
-
|
|
456
|
-
const { data, error } = await superAdminClient
|
|
457
|
-
.rpc('check_query_performance', {
|
|
458
|
-
p_query: 'SELECT * FROM core_organisations LIMIT 1'
|
|
459
|
-
});
|
|
460
|
-
|
|
461
|
-
// Note: If the RPC function doesn't exist or uses EXPLAIN incorrectly, we'll get an error
|
|
462
|
-
// This test requires the check_query_performance function to be created in the database
|
|
463
|
-
if (error?.code === '0A000' || error?.code === '42883') {
|
|
464
|
-
console.warn('⚠️ Test skipped: check_query_performance RPC function not available or uses EXPLAIN incorrectly');
|
|
465
|
-
return;
|
|
466
|
-
}
|
|
467
|
-
// Verify no InitPlan nodes (would indicate inline auth.uid() calls)
|
|
468
|
-
expect(error).toBeNull();
|
|
469
|
-
// In real test, verify has_initplan = false
|
|
470
|
-
}, TEST_TIMEOUT);
|
|
471
|
-
});
|
|
472
|
-
|