@jmruthers/pace-core 0.5.184 → 0.5.185
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 +38 -0
- package/README.md +60 -1
- package/core-usage-manifest.json +312 -0
- package/dist/{DataTable-QAB34V6K.js → DataTable-IX2NBUTP.js} +6 -6
- package/dist/{DataTable-Bz8ffqyA.d.ts → DataTable-Z9NLVJh0.d.ts} +1 -1
- package/dist/{index-Bl--n7-T.d.ts → PublicPageProvider-BABf6JCh.d.ts} +21 -10
- package/dist/{UnifiedAuthProvider-7F6T4B6K.js → UnifiedAuthProvider-A4BCQRJY.js} +4 -2
- package/dist/{UnifiedAuthProvider-F86d7dSi.d.ts → UnifiedAuthProvider-BG0AL5eE.d.ts} +2 -1
- package/dist/{api-ROMBCNKU.js → api-BMFCXVQX.js} +2 -2
- package/dist/{chunk-RA3JUFMW.js → chunk-445GEP27.js} +154 -4
- package/dist/{chunk-RA3JUFMW.js.map → chunk-445GEP27.js.map} +1 -1
- package/dist/{chunk-CSOFYHAG.js → chunk-AISXLWGZ.js} +374 -60
- package/dist/chunk-AISXLWGZ.js.map +1 -0
- package/dist/{chunk-FUEYYMX5.js → chunk-FXFJRTKI.js} +24 -3
- package/dist/chunk-FXFJRTKI.js.map +1 -0
- package/dist/{chunk-NQPMQGS2.js → chunk-HC67NW5K.js} +379 -359
- package/dist/chunk-HC67NW5K.js.map +1 -0
- package/dist/chunk-HESYZWZW.js +388 -0
- package/dist/chunk-HESYZWZW.js.map +1 -0
- package/dist/{chunk-QUVSNGIP.js → chunk-HGPQUCBC.js} +34 -9
- package/dist/{chunk-QUVSNGIP.js.map → chunk-HGPQUCBC.js.map} +1 -1
- package/dist/{chunk-UHNYIBXL.js → chunk-IXSNYUCT.js} +1 -1
- package/dist/chunk-IXSNYUCT.js.map +1 -0
- package/dist/{chunk-MI7HBHN3.js → chunk-MX3EIJGQ.js} +4 -3
- package/dist/{chunk-MI7HBHN3.js.map → chunk-MX3EIJGQ.js.map} +1 -1
- package/dist/{chunk-PWAHJW4G.js → chunk-OKI34GZD.js} +86 -33
- package/dist/chunk-OKI34GZD.js.map +1 -0
- package/dist/{chunk-W22JP75J.js → chunk-STTZQK2I.js} +3 -3
- package/dist/chunk-THRPYOFK.js +215 -0
- package/dist/chunk-THRPYOFK.js.map +1 -0
- package/dist/{chunk-M7W4CP3M.js → chunk-U6WNSFX5.js} +2 -1
- package/dist/chunk-U6WNSFX5.js.map +1 -0
- package/dist/{chunk-QCDXODCA.js → chunk-XAUHJD3L.js} +2 -2
- package/dist/components.d.ts +182 -6
- package/dist/components.js +157 -11
- package/dist/components.js.map +1 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +406 -0
- package/dist/{file-reference-D06mEEWW.d.ts → file-reference-BjR39ktt.d.ts} +7 -1
- package/dist/hooks.d.ts +7 -14
- package/dist/hooks.js +10 -22
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +11 -11
- package/dist/index.js +79 -16
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +3 -1
- package/dist/rbac/index.d.ts +205 -14
- package/dist/rbac/index.js +28 -6
- package/dist/timezone-_pgH8qrY.d.ts +530 -0
- package/dist/{types-_x1f4QBF.d.ts → types-DUyCRSTj.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-JJczomYq.d.ts → usePublicRouteParams-CvnC3d-e.d.ts} +113 -2
- package/dist/utils.d.ts +109 -151
- package/dist/utils.js +128 -138
- package/dist/utils.js.map +1 -1
- package/docs/api/README.md +60 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/Logger.md +178 -0
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +2 -2
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +2 -2
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +5 -5
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/enums/LogLevel.md +54 -0
- package/docs/api/enums/RBACErrorCode.md +1 -1
- package/docs/api/enums/RPCFunction.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.md +18 -2
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/ComplianceResult.md +30 -0
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/DatabaseComplianceResult.md +85 -0
- package/docs/api/interfaces/DatabaseIssue.md +41 -0
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +6 -6
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +24 -8
- package/docs/api/interfaces/FileUploadProps.md +24 -13
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +1 -1
- package/docs/api/interfaces/FormProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +9 -9
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoggerConfig.md +62 -0
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +36 -23
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProgressProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/QuickFix.md +52 -0
- package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
- package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
- package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +4 -4
- package/docs/api/interfaces/RBACContext.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
- package/docs/api/interfaces/RBACResult.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
- package/docs/api/interfaces/RBACRolesListParams.md +1 -1
- package/docs/api/interfaces/RBACRolesListResult.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +7 -7
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +5 -5
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/RuntimeComplianceResult.md +55 -0
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/SetupIssue.md +41 -0
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseFormDialogOptions.md +62 -0
- package/docs/api/interfaces/UseFormDialogReturn.md +117 -0
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +738 -42
- package/docs/api-reference/hooks.md +111 -0
- package/docs/api-reference/rpc-functions.md +1 -1
- package/docs/api-reference/utilities.md +184 -0
- package/docs/getting-started/installation-guide.md +75 -16
- package/docs/getting-started/quick-start.md +61 -11
- package/docs/implementation-guides/authentication.md +88 -12
- package/docs/implementation-guides/file-reference-system.md +2 -1
- package/docs/implementation-guides/file-upload-storage.md +21 -0
- package/docs/rbac/README.md +1 -0
- package/docs/rbac/compliance/compliance-guide.md +544 -0
- package/docs/rbac/getting-started.md +158 -33
- package/docs/standards/pace-core-compliance.md +432 -0
- package/eslint-config-pace-core.cjs +93 -0
- package/package.json +15 -3
- package/scripts/analyze-bundle.js +232 -0
- package/scripts/build-css.js +56 -0
- package/scripts/build-docs-incremental.js +1015 -0
- package/scripts/check-pace-core-compliance.cjs +2353 -0
- package/scripts/generate-docs.js +157 -0
- package/scripts/setup-build-cache.js +73 -0
- package/scripts/utils/command-runner.js +131 -0
- package/scripts/utils/env.js +33 -0
- package/scripts/utils/index.js +10 -0
- package/scripts/utils/logger.js +88 -0
- package/scripts/utils/path-helpers.js +37 -0
- package/scripts/validate-formats.js +133 -0
- package/scripts/validate-master.js +155 -0
- package/scripts/validate-pre-publish.js +140 -0
- package/scripts/validate-theme.js +142 -0
- package/src/components/Calendar/Calendar.tsx +8 -1
- package/src/components/Card/Card.tsx +47 -8
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +314 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +126 -0
- package/src/components/DatePickerWithTimezone/README.md +135 -0
- package/src/components/DatePickerWithTimezone/index.ts +10 -0
- package/src/components/DateTimeField/DateTimeField.test.tsx +358 -0
- package/src/components/DateTimeField/DateTimeField.tsx +232 -0
- package/src/components/DateTimeField/README.md +148 -0
- package/src/components/DateTimeField/index.ts +10 -0
- package/src/components/FileUpload/FileUpload.tsx +3 -0
- package/src/components/Header/Header.test.tsx +47 -18
- package/src/components/Header/Header.tsx +24 -6
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +29 -20
- package/src/components/PaceAppLayout/README.md +9 -0
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +37 -8
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +12 -4
- package/src/components/index.ts +8 -0
- package/src/eslint-rules/pace-core-compliance.cjs +406 -0
- package/src/eslint-rules/pace-core-compliance.js +640 -0
- package/src/hooks/__tests__/useFormDialog.test.ts +478 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useFileReference.test.ts +1 -0
- package/src/hooks/useFormDialog.ts +147 -0
- package/src/index.ts +27 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +6 -5
- package/src/providers/services/UnifiedAuthProvider.tsx +24 -3
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +3 -0
- package/src/rbac/compliance/database-validator.ts +165 -0
- package/src/rbac/compliance/index.ts +38 -0
- package/src/rbac/compliance/quick-fix-suggestions.ts +209 -0
- package/src/rbac/compliance/runtime-compliance.ts +77 -0
- package/src/rbac/compliance/setup-validator.ts +131 -0
- package/src/rbac/components/PagePermissionGuard.tsx +8 -64
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +35 -21
- package/src/rbac/docs/event-based-apps.md +285 -0
- package/src/rbac/errors.ts +11 -0
- package/src/rbac/hooks/useRoleManagement.ts +292 -12
- package/src/rbac/index.ts +30 -0
- package/src/services/OrganisationService.ts +4 -0
- package/src/types/file-reference.ts +6 -0
- package/src/utils/__tests__/timezone.test.ts +345 -0
- package/src/utils/file-reference/__tests__/file-reference.test.ts +2 -0
- package/src/utils/file-reference/index.ts +1 -0
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +167 -0
- package/src/utils/formatting/formatting.ts +179 -0
- package/src/utils/index.ts +27 -1
- package/src/utils/location/index.ts +16 -0
- package/src/utils/location/location.test.ts +286 -0
- package/src/utils/location/location.ts +175 -0
- package/src/utils/timezone/index.ts +17 -0
- package/src/utils/timezone/timezone.test.ts +349 -0
- package/src/utils/timezone/timezone.ts +281 -0
- package/dist/chunk-CSOFYHAG.js.map +0 -1
- package/dist/chunk-FUEYYMX5.js.map +0 -1
- package/dist/chunk-HKIT6O7W.js +0 -198
- package/dist/chunk-HKIT6O7W.js.map +0 -1
- package/dist/chunk-KUEN3HFB.js +0 -94
- package/dist/chunk-KUEN3HFB.js.map +0 -1
- package/dist/chunk-M7W4CP3M.js.map +0 -1
- package/dist/chunk-NQPMQGS2.js.map +0 -1
- package/dist/chunk-PWAHJW4G.js.map +0 -1
- package/dist/chunk-UHNYIBXL.js.map +0 -1
- package/dist/formatting-5wETwiGF.d.ts +0 -162
- /package/dist/{DataTable-QAB34V6K.js.map → DataTable-IX2NBUTP.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-7F6T4B6K.js.map → UnifiedAuthProvider-A4BCQRJY.js.map} +0 -0
- /package/dist/{api-ROMBCNKU.js.map → api-BMFCXVQX.js.map} +0 -0
- /package/dist/{chunk-W22JP75J.js.map → chunk-STTZQK2I.js.map} +0 -0
- /package/dist/{chunk-QCDXODCA.js.map → chunk-XAUHJD3L.js.map} +0 -0
|
@@ -37,37 +37,112 @@ const supabase = createClient(
|
|
|
37
37
|
setupRBAC(supabase);
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
### 3.
|
|
40
|
+
### 3. Configure Vite (CRITICAL)
|
|
41
|
+
|
|
42
|
+
**⚠️ CRITICAL**: Without this configuration, you'll get React context and Router context errors.
|
|
43
|
+
|
|
44
|
+
Add to your `vite.config.ts`:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { defineConfig } from 'vite';
|
|
48
|
+
import react from '@vitejs/plugin-react';
|
|
49
|
+
import tailwindcss from '@tailwindcss/vite';
|
|
50
|
+
import path from 'path';
|
|
51
|
+
|
|
52
|
+
export default defineConfig({
|
|
53
|
+
plugins: [
|
|
54
|
+
react(),
|
|
55
|
+
tailwindcss({
|
|
56
|
+
content: [
|
|
57
|
+
'./src/**/*.{js,ts,jsx,tsx}',
|
|
58
|
+
'./node_modules/@jmruthers/pace-core/src/**/*.{js,ts,jsx,tsx}'
|
|
59
|
+
]
|
|
60
|
+
})
|
|
61
|
+
],
|
|
62
|
+
resolve: {
|
|
63
|
+
alias: {
|
|
64
|
+
"@": path.resolve(__dirname, "./src"),
|
|
65
|
+
},
|
|
66
|
+
// CRITICAL: Dedupe React and React Router to ensure single instances
|
|
67
|
+
dedupe: ['react', 'react-dom', 'react-router-dom']
|
|
68
|
+
},
|
|
69
|
+
// CRITICAL: Exclude pace-core from pre-bundling to prevent React context mismatches
|
|
70
|
+
optimizeDeps: {
|
|
71
|
+
include: [
|
|
72
|
+
'react',
|
|
73
|
+
'react-dom',
|
|
74
|
+
'react/jsx-runtime'
|
|
75
|
+
],
|
|
76
|
+
exclude: ['@jmruthers/pace-core', 'react-router-dom']
|
|
77
|
+
},
|
|
78
|
+
});
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### 4. Wrap Your App with Required Providers
|
|
82
|
+
|
|
83
|
+
**⚠️ CRITICAL**: Provider nesting order matters! Follow this exact structure.
|
|
41
84
|
|
|
42
85
|
```tsx
|
|
43
|
-
//
|
|
86
|
+
// src/main.tsx - COMPLETE setup (copy this exactly)
|
|
44
87
|
import React from 'react';
|
|
88
|
+
import ReactDOM from 'react-dom/client';
|
|
89
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
90
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
45
91
|
import { setupRBAC } from '@jmruthers/pace-core/rbac';
|
|
46
92
|
import { UnifiedAuthProvider, OrganisationProvider } from '@jmruthers/pace-core';
|
|
47
93
|
import { createClient } from '@supabase/supabase-js';
|
|
94
|
+
import App from './App';
|
|
95
|
+
|
|
96
|
+
// Import CSS
|
|
97
|
+
import '@jmruthers/pace-core/src/styles/core.css';
|
|
48
98
|
|
|
49
99
|
// Initialize Supabase
|
|
50
100
|
const supabase = createClient(
|
|
51
|
-
|
|
52
|
-
|
|
101
|
+
import.meta.env.VITE_SUPABASE_URL!,
|
|
102
|
+
import.meta.env.VITE_SUPABASE_ANON_KEY!
|
|
53
103
|
);
|
|
54
104
|
|
|
55
|
-
// ⚠️ REQUIRED: Setup RBAC
|
|
105
|
+
// ⚠️ REQUIRED: Setup RBAC before rendering
|
|
56
106
|
setupRBAC(supabase);
|
|
57
107
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
|
|
108
|
+
const queryClient = new QueryClient();
|
|
109
|
+
|
|
110
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
111
|
+
<React.StrictMode>
|
|
112
|
+
{/* CRITICAL: Correct nesting order */}
|
|
113
|
+
<QueryClientProvider client={queryClient}>
|
|
114
|
+
<BrowserRouter>
|
|
115
|
+
<UnifiedAuthProvider
|
|
116
|
+
supabaseClient={supabase}
|
|
117
|
+
appName="My App"
|
|
118
|
+
idleTimeoutMs={30 * 60 * 1000}
|
|
119
|
+
warnBeforeMs={5 * 60 * 1000}
|
|
120
|
+
onIdleLogout={() => window.location.href = '/login'}
|
|
121
|
+
>
|
|
122
|
+
<OrganisationProvider>
|
|
123
|
+
<App />
|
|
124
|
+
</OrganisationProvider>
|
|
125
|
+
</UnifiedAuthProvider>
|
|
126
|
+
</BrowserRouter>
|
|
127
|
+
</QueryClientProvider>
|
|
128
|
+
</React.StrictMode>
|
|
129
|
+
);
|
|
69
130
|
```
|
|
70
131
|
|
|
132
|
+
**Provider Nesting Order (CRITICAL):**
|
|
133
|
+
1. `React.StrictMode` (outermost)
|
|
134
|
+
2. `QueryClientProvider`
|
|
135
|
+
3. `BrowserRouter`
|
|
136
|
+
4. `UnifiedAuthProvider`
|
|
137
|
+
5. `OrganisationProvider`
|
|
138
|
+
6. `App` (innermost)
|
|
139
|
+
|
|
140
|
+
**Why this order matters:**
|
|
141
|
+
- `BrowserRouter` must wrap `UnifiedAuthProvider` to provide Router context
|
|
142
|
+
- `UnifiedAuthProvider` must be inside `BrowserRouter` to use Router hooks
|
|
143
|
+
- Wrong nesting causes "useNavigate() may be used only in the context of a <Router>" errors
|
|
144
|
+
- Missing Vite config causes "useUnifiedAuth must be used within a UnifiedAuthProvider" errors
|
|
145
|
+
|
|
71
146
|
## 🎯 **When to Use What Pattern**
|
|
72
147
|
|
|
73
148
|
### Pattern 1: PagePermissionGuard (REQUIRED for Pages)
|
|
@@ -170,33 +245,46 @@ function UserActions() {
|
|
|
170
245
|
Here's a complete, working example that demonstrates all patterns:
|
|
171
246
|
|
|
172
247
|
```tsx
|
|
173
|
-
//
|
|
248
|
+
// src/main.tsx - COMPLETE setup
|
|
174
249
|
import React from 'react';
|
|
250
|
+
import ReactDOM from 'react-dom/client';
|
|
251
|
+
import { BrowserRouter } from 'react-router-dom';
|
|
252
|
+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
175
253
|
import { setupRBAC } from '@jmruthers/pace-core/rbac';
|
|
176
254
|
import { UnifiedAuthProvider, OrganisationProvider } from '@jmruthers/pace-core';
|
|
177
255
|
import { createClient } from '@supabase/supabase-js';
|
|
178
|
-
import
|
|
256
|
+
import App from './App';
|
|
179
257
|
|
|
180
258
|
// Initialize Supabase
|
|
181
259
|
const supabase = createClient(
|
|
182
|
-
|
|
183
|
-
|
|
260
|
+
import.meta.env.VITE_SUPABASE_URL!,
|
|
261
|
+
import.meta.env.VITE_SUPABASE_ANON_KEY!
|
|
184
262
|
);
|
|
185
263
|
|
|
186
|
-
// ⚠️ REQUIRED: Setup RBAC
|
|
264
|
+
// ⚠️ REQUIRED: Setup RBAC before rendering
|
|
187
265
|
setupRBAC(supabase);
|
|
188
266
|
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
267
|
+
const queryClient = new QueryClient();
|
|
268
|
+
|
|
269
|
+
ReactDOM.createRoot(document.getElementById('root')!).render(
|
|
270
|
+
<React.StrictMode>
|
|
271
|
+
<QueryClientProvider client={queryClient}>
|
|
272
|
+
<BrowserRouter>
|
|
273
|
+
<UnifiedAuthProvider
|
|
274
|
+
supabaseClient={supabase}
|
|
275
|
+
appName="My App"
|
|
276
|
+
idleTimeoutMs={30 * 60 * 1000}
|
|
277
|
+
warnBeforeMs={5 * 60 * 1000}
|
|
278
|
+
onIdleLogout={() => window.location.href = '/login'}
|
|
279
|
+
>
|
|
280
|
+
<OrganisationProvider>
|
|
281
|
+
<App />
|
|
282
|
+
</OrganisationProvider>
|
|
283
|
+
</UnifiedAuthProvider>
|
|
284
|
+
</BrowserRouter>
|
|
285
|
+
</QueryClientProvider>
|
|
286
|
+
</React.StrictMode>
|
|
287
|
+
);
|
|
200
288
|
```
|
|
201
289
|
|
|
202
290
|
```tsx
|
|
@@ -471,10 +559,47 @@ setupRBAC(supabase);
|
|
|
471
559
|
**Cause**: OrganisationProvider not wrapping your app or user not in any organisation
|
|
472
560
|
|
|
473
561
|
**Solution**:
|
|
474
|
-
1. Ensure OrganisationProvider wraps your app
|
|
562
|
+
1. Ensure OrganisationProvider wraps your app (inside UnifiedAuthProvider)
|
|
475
563
|
2. Check that user has organisation memberships in the database
|
|
476
564
|
3. Verify user has selected an organisation
|
|
477
565
|
|
|
566
|
+
### Error: "useUnifiedAuth must be used within a UnifiedAuthProvider"
|
|
567
|
+
|
|
568
|
+
**Cause**: Vite is pre-bundling `@jmruthers/pace-core`, creating separate React instances
|
|
569
|
+
|
|
570
|
+
**Solution**:
|
|
571
|
+
1. Add to `vite.config.ts`:
|
|
572
|
+
```typescript
|
|
573
|
+
optimizeDeps: {
|
|
574
|
+
exclude: ['@jmruthers/pace-core', 'react-router-dom']
|
|
575
|
+
}
|
|
576
|
+
```
|
|
577
|
+
2. Clear Vite cache: `rm -rf node_modules/.vite`
|
|
578
|
+
3. Restart dev server
|
|
579
|
+
|
|
580
|
+
### Error: "useNavigate() may be used only in the context of a <Router> component"
|
|
581
|
+
|
|
582
|
+
**Cause**: Incorrect provider nesting - BrowserRouter should wrap UnifiedAuthProvider
|
|
583
|
+
|
|
584
|
+
**Solution**:
|
|
585
|
+
1. Ensure correct nesting order:
|
|
586
|
+
```tsx
|
|
587
|
+
<BrowserRouter>
|
|
588
|
+
<UnifiedAuthProvider>
|
|
589
|
+
<OrganisationProvider>
|
|
590
|
+
<App />
|
|
591
|
+
</OrganisationProvider>
|
|
592
|
+
</UnifiedAuthProvider>
|
|
593
|
+
</BrowserRouter>
|
|
594
|
+
```
|
|
595
|
+
2. Do NOT put BrowserRouter inside UnifiedAuthProvider
|
|
596
|
+
3. Add to `vite.config.ts`:
|
|
597
|
+
```typescript
|
|
598
|
+
resolve: {
|
|
599
|
+
dedupe: ['react', 'react-dom', 'react-router-dom']
|
|
600
|
+
}
|
|
601
|
+
```
|
|
602
|
+
|
|
478
603
|
### Error: Permission checks always return false
|
|
479
604
|
|
|
480
605
|
**Cause**: User doesn't have proper roles or permissions assigned
|
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# pace-core Compliance Enforcement
|
|
2
|
+
|
|
3
|
+
This guide explains how to enforce pace-core usage patterns in consuming apps to ensure consistent design, reduce duplication, and maintain high code quality.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
pace-core provides a comprehensive enforcement system that includes:
|
|
8
|
+
|
|
9
|
+
1. **ESLint Rules** - Real-time linting during development
|
|
10
|
+
2. **Static Analysis Script** - Comprehensive codebase scanning
|
|
11
|
+
3. **ESLint Config Preset** - Easy setup for consuming apps
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
### Option 1: ESLint Config Preset (Recommended)
|
|
16
|
+
|
|
17
|
+
The easiest way to enable compliance checking is to use the shareable ESLint config. The config is CommonJS but works with both ES module and CommonJS ESLint configs:
|
|
18
|
+
|
|
19
|
+
**For ES Module ESLint Config (eslint.config.js):**
|
|
20
|
+
```javascript
|
|
21
|
+
// eslint.config.js (ES modules)
|
|
22
|
+
import paceCoreConfig from '@jmruthers/pace-core/eslint-config';
|
|
23
|
+
|
|
24
|
+
export default [
|
|
25
|
+
...paceCoreConfig,
|
|
26
|
+
// your other config
|
|
27
|
+
];
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
**For CommonJS ESLint Config (.eslintrc.js or eslint.config.cjs):**
|
|
31
|
+
```javascript
|
|
32
|
+
// eslint.config.cjs (CommonJS)
|
|
33
|
+
const paceCoreConfig = require('@jmruthers/pace-core/eslint-config');
|
|
34
|
+
|
|
35
|
+
module.exports = [
|
|
36
|
+
...paceCoreConfig,
|
|
37
|
+
// your other config
|
|
38
|
+
];
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Option 2: Manual ESLint Rules Setup
|
|
42
|
+
|
|
43
|
+
If you prefer more control, you can import the rules directly. Note: The rules are CommonJS, so use `createRequire` in ES modules:
|
|
44
|
+
|
|
45
|
+
**For ES Module ESLint Config:**
|
|
46
|
+
```javascript
|
|
47
|
+
// eslint.config.js
|
|
48
|
+
import { createRequire } from 'module';
|
|
49
|
+
const require = createRequire(import.meta.url);
|
|
50
|
+
const paceCoreRules = require('@jmruthers/pace-core/eslint-rules').rules;
|
|
51
|
+
|
|
52
|
+
export default [
|
|
53
|
+
{
|
|
54
|
+
plugins: {
|
|
55
|
+
'pace-core-compliance': {
|
|
56
|
+
rules: paceCoreRules
|
|
57
|
+
}
|
|
58
|
+
},
|
|
59
|
+
rules: {
|
|
60
|
+
'pace-core-compliance/no-restricted-imports': 'error',
|
|
61
|
+
'pace-core-compliance/prefer-pace-core-components': 'warn',
|
|
62
|
+
'pace-core-compliance/prefer-pace-core-hooks': 'warn',
|
|
63
|
+
'pace-core-compliance/prefer-pace-core-utils': 'warn',
|
|
64
|
+
'pace-core-compliance/no-local-component-duplication': 'error'
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
];
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**For CommonJS ESLint Config:**
|
|
71
|
+
```javascript
|
|
72
|
+
// eslint.config.cjs
|
|
73
|
+
const paceCoreRules = require('@jmruthers/pace-core/eslint-rules').rules;
|
|
74
|
+
|
|
75
|
+
module.exports = [
|
|
76
|
+
{
|
|
77
|
+
plugins: {
|
|
78
|
+
'pace-core-compliance': {
|
|
79
|
+
rules: paceCoreRules
|
|
80
|
+
}
|
|
81
|
+
},
|
|
82
|
+
rules: {
|
|
83
|
+
'pace-core-compliance/no-restricted-imports': 'error',
|
|
84
|
+
'pace-core-compliance/prefer-pace-core-components': 'warn',
|
|
85
|
+
'pace-core-compliance/prefer-pace-core-hooks': 'warn',
|
|
86
|
+
'pace-core-compliance/prefer-pace-core-utils': 'warn',
|
|
87
|
+
'pace-core-compliance/no-local-component-duplication': 'error'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
];
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
## ESLint Rules
|
|
94
|
+
|
|
95
|
+
### no-restricted-imports
|
|
96
|
+
|
|
97
|
+
**Severity**: Error
|
|
98
|
+
|
|
99
|
+
Blocks direct imports of libraries that pace-core wraps and standardizes.
|
|
100
|
+
|
|
101
|
+
**Restricted Libraries**:
|
|
102
|
+
- `@radix-ui/*` - All Radix UI packages (use pace-core components instead)
|
|
103
|
+
- `lucide-react` - Icons (use pace-core components that include icons)
|
|
104
|
+
- `react-day-picker` - Use `Calendar` from pace-core
|
|
105
|
+
- `@tanstack/react-table` - Use `DataTable` from pace-core
|
|
106
|
+
- `react-hook-form` - Use `Form` and `useZodForm` from pace-core
|
|
107
|
+
- `zod` - Use validation utilities from pace-core
|
|
108
|
+
|
|
109
|
+
**Example Violation**:
|
|
110
|
+
```typescript
|
|
111
|
+
// ❌ Bad
|
|
112
|
+
import { Dialog } from '@radix-ui/react-dialog';
|
|
113
|
+
import { Button } from 'lucide-react';
|
|
114
|
+
|
|
115
|
+
// ✅ Good
|
|
116
|
+
import { Dialog } from '@jmruthers/pace-core';
|
|
117
|
+
import { Button } from '@jmruthers/pace-core';
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
### prefer-pace-core-components
|
|
121
|
+
|
|
122
|
+
**Severity**: Warning
|
|
123
|
+
|
|
124
|
+
Suggests using pace-core components instead of native HTML elements.
|
|
125
|
+
|
|
126
|
+
**Detected Patterns**:
|
|
127
|
+
- `<button>` → Use `Button` from pace-core
|
|
128
|
+
- `<input>` → Use `Input` from pace-core
|
|
129
|
+
- `<textarea>` → Use `Textarea` from pace-core
|
|
130
|
+
- `<label>` → Use `Label` from pace-core
|
|
131
|
+
|
|
132
|
+
**Example**:
|
|
133
|
+
```tsx
|
|
134
|
+
// ⚠️ Warning
|
|
135
|
+
<button onClick={handleClick}>Click me</button>
|
|
136
|
+
|
|
137
|
+
// ✅ Recommended
|
|
138
|
+
import { Button } from '@jmruthers/pace-core';
|
|
139
|
+
<Button onClick={handleClick}>Click me</Button>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### prefer-pace-core-hooks
|
|
143
|
+
|
|
144
|
+
**Severity**: Warning
|
|
145
|
+
|
|
146
|
+
Detects custom hooks that duplicate pace-core functionality.
|
|
147
|
+
|
|
148
|
+
**Common Patterns Detected**:
|
|
149
|
+
- `useToast`, `useNotification` → Use `useToast` from pace-core
|
|
150
|
+
- `useDebounce`, `useDebounced` → Use `useDebounce` from pace-core
|
|
151
|
+
- `useAuth`, `useAuthentication` → Use `useUnifiedAuth` from pace-core
|
|
152
|
+
- `useForm`, `useZodForm` → Use `useZodForm` from pace-core
|
|
153
|
+
|
|
154
|
+
**Example**:
|
|
155
|
+
```typescript
|
|
156
|
+
// ⚠️ Warning
|
|
157
|
+
function useToast() {
|
|
158
|
+
// custom implementation
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ✅ Recommended
|
|
162
|
+
import { useToast } from '@jmruthers/pace-core';
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### prefer-pace-core-utils
|
|
166
|
+
|
|
167
|
+
**Severity**: Warning
|
|
168
|
+
|
|
169
|
+
Detects utility functions that duplicate pace-core functionality.
|
|
170
|
+
|
|
171
|
+
**Common Patterns Detected**:
|
|
172
|
+
- `formatDate`, `dateFormat` → Use `formatDate` from pace-core
|
|
173
|
+
- `formatCurrency`, `formatMoney` → Use `formatCurrency` from pace-core
|
|
174
|
+
- `cn`, `classNames`, `clsx` → Use `cn` from pace-core
|
|
175
|
+
- `validate`, `validateInput` → Use `validateUserInput` from pace-core
|
|
176
|
+
|
|
177
|
+
**Example**:
|
|
178
|
+
```typescript
|
|
179
|
+
// ⚠️ Warning
|
|
180
|
+
function formatDate(date: Date): string {
|
|
181
|
+
// custom implementation
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ✅ Recommended
|
|
185
|
+
import { formatDate } from '@jmruthers/pace-core';
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
### no-local-component-duplication
|
|
189
|
+
|
|
190
|
+
**Severity**: Error
|
|
191
|
+
|
|
192
|
+
Prevents creating local components with names matching pace-core components.
|
|
193
|
+
|
|
194
|
+
**Example Violation**:
|
|
195
|
+
```
|
|
196
|
+
// ❌ Error: components/Button.tsx
|
|
197
|
+
export function Button() { ... }
|
|
198
|
+
|
|
199
|
+
// pace-core already provides Button component
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
**Fix**: Remove the local component and import from pace-core:
|
|
203
|
+
```typescript
|
|
204
|
+
import { Button } from '@jmruthers/pace-core';
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Static Analysis Script
|
|
208
|
+
|
|
209
|
+
The static analysis script provides a comprehensive scan of your codebase and generates a detailed compliance report.
|
|
210
|
+
|
|
211
|
+
### Running the Script
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
# From your consuming app root
|
|
215
|
+
node node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
Or add it to your `package.json`:
|
|
219
|
+
|
|
220
|
+
```json
|
|
221
|
+
{
|
|
222
|
+
"scripts": {
|
|
223
|
+
"check:pace-core": "node node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs"
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### What It Checks
|
|
229
|
+
|
|
230
|
+
1. **Restricted Imports** - Scans for direct imports of wrapped libraries
|
|
231
|
+
2. **Duplicate Components** - Finds local components matching pace-core names
|
|
232
|
+
3. **Duplicate Hooks** - Finds local hooks matching pace-core hooks
|
|
233
|
+
4. **Duplicate Utils** - Finds local utils matching pace-core utils
|
|
234
|
+
5. **Suggestions** - Recommends pace-core alternatives for native HTML elements
|
|
235
|
+
|
|
236
|
+
### Report Output
|
|
237
|
+
|
|
238
|
+
The script generates a color-coded terminal report showing:
|
|
239
|
+
|
|
240
|
+
- ❌ **Errors** - Critical violations that must be fixed
|
|
241
|
+
- ⚠️ **Warnings** - Issues that should be addressed
|
|
242
|
+
- 💡 **Suggestions** - Recommendations for improvement
|
|
243
|
+
- ✅ **Summary** - Overall compliance status
|
|
244
|
+
|
|
245
|
+
Example output:
|
|
246
|
+
```
|
|
247
|
+
═══════════════════════════════════════════════════════════
|
|
248
|
+
pace-core Compliance Report
|
|
249
|
+
═══════════════════════════════════════════════════════════
|
|
250
|
+
|
|
251
|
+
❌ Restricted Imports Found: 3
|
|
252
|
+
|
|
253
|
+
• src/components/CustomDialog.tsx:5
|
|
254
|
+
Import: @radix-ui/react-dialog
|
|
255
|
+
Reason: Use Dialog component from pace-core instead
|
|
256
|
+
|
|
257
|
+
Summary:
|
|
258
|
+
Total Issues: 3
|
|
259
|
+
- Restricted Imports: 3
|
|
260
|
+
- Duplicate Components/Hooks/Utils: 0
|
|
261
|
+
- Suggestions: 0
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
## Best Practices
|
|
265
|
+
|
|
266
|
+
### 1. Always Import from pace-core
|
|
267
|
+
|
|
268
|
+
```typescript
|
|
269
|
+
// ✅ Good
|
|
270
|
+
import { Button, Card, Dialog } from '@jmruthers/pace-core';
|
|
271
|
+
import { useToast, useDebounce } from '@jmruthers/pace-core';
|
|
272
|
+
import { formatDate, formatCurrency } from '@jmruthers/pace-core';
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### 2. Use pace-core Components for UI
|
|
276
|
+
|
|
277
|
+
Avoid native HTML elements when pace-core provides a component:
|
|
278
|
+
|
|
279
|
+
```tsx
|
|
280
|
+
// ❌ Avoid
|
|
281
|
+
<button className="btn">Click</button>
|
|
282
|
+
|
|
283
|
+
// ✅ Use pace-core
|
|
284
|
+
<Button>Click</Button>
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### 3. Leverage pace-core Hooks
|
|
288
|
+
|
|
289
|
+
Don't recreate hooks that pace-core already provides:
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
// ❌ Avoid
|
|
293
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
294
|
+
useEffect(() => {
|
|
295
|
+
const timer = setTimeout(() => setDebouncedValue(value), 500);
|
|
296
|
+
return () => clearTimeout(timer);
|
|
297
|
+
}, [value]);
|
|
298
|
+
|
|
299
|
+
// ✅ Use pace-core
|
|
300
|
+
import { useDebounce } from '@jmruthers/pace-core';
|
|
301
|
+
const debouncedValue = useDebounce(value, 500);
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
### 4. Use pace-core Utilities
|
|
305
|
+
|
|
306
|
+
Leverage formatting, validation, and other utilities from pace-core:
|
|
307
|
+
|
|
308
|
+
```typescript
|
|
309
|
+
// ❌ Avoid
|
|
310
|
+
const formatted = new Intl.DateTimeFormat('en-US').format(date);
|
|
311
|
+
|
|
312
|
+
// ✅ Use pace-core
|
|
313
|
+
import { formatDate } from '@jmruthers/pace-core';
|
|
314
|
+
const formatted = formatDate(date);
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
### 5. Check Before Creating New Components
|
|
318
|
+
|
|
319
|
+
Before creating a new component, check if pace-core already provides it:
|
|
320
|
+
|
|
321
|
+
1. Review the [pace-core documentation](https://github.com/your-org/pace-core)
|
|
322
|
+
2. Check `core-usage-manifest.json` for available components
|
|
323
|
+
3. Search pace-core exports
|
|
324
|
+
|
|
325
|
+
## Troubleshooting
|
|
326
|
+
|
|
327
|
+
### ESLint Rules Not Working
|
|
328
|
+
|
|
329
|
+
1. **Verify plugin is loaded**: Check that the config is imported correctly:
|
|
330
|
+
```javascript
|
|
331
|
+
// In your eslint.config.js, add temporarily:
|
|
332
|
+
import paceCoreConfig from '@jmruthers/pace-core/eslint-config';
|
|
333
|
+
console.log('Config:', paceCoreConfig);
|
|
334
|
+
console.log('Has plugins:', paceCoreConfig[0]?.plugins);
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
2. **Check rule names**: Rules must be prefixed with `pace-core-compliance/`
|
|
338
|
+
|
|
339
|
+
3. **Verify manifest exists**: Rules load from `core-usage-manifest.json` in the pace-core package
|
|
340
|
+
|
|
341
|
+
4. **CommonJS/ES Module issues**: If you're using ES modules and rules aren't loading:
|
|
342
|
+
- Ensure you're using the config preset (Option 1) which handles this automatically
|
|
343
|
+
- Or use `createRequire` when importing rules directly (Option 2)
|
|
344
|
+
|
|
345
|
+
5. **Verify rules are available**: Check that the rules file exists:
|
|
346
|
+
```bash
|
|
347
|
+
ls node_modules/@jmruthers/pace-core/dist/eslint-rules/pace-core-compliance.cjs
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
### Static Analysis Script Errors
|
|
351
|
+
|
|
352
|
+
1. **Manifest not found**: Ensure `core-usage-manifest.json` exists in pace-core package
|
|
353
|
+
2. **No files scanned**: Check that you're running from the project root
|
|
354
|
+
3. **Permission errors**: Ensure script has read access to source files
|
|
355
|
+
|
|
356
|
+
### False Positives
|
|
357
|
+
|
|
358
|
+
If you encounter false positives:
|
|
359
|
+
|
|
360
|
+
1. **Component name conflicts**: If you have a legitimate reason to create a local component with a pace-core name, consider:
|
|
361
|
+
- Renaming your component
|
|
362
|
+
- Using a namespace/prefix
|
|
363
|
+
- Documenting why pace-core doesn't meet your needs
|
|
364
|
+
|
|
365
|
+
2. **Hook/Util patterns**: The pattern matching may flag similar names. Review the suggestion and decide if migration makes sense.
|
|
366
|
+
|
|
367
|
+
## Integration with CI/CD
|
|
368
|
+
|
|
369
|
+
While CI/CD integration is not included in the initial release, you can easily add it:
|
|
370
|
+
|
|
371
|
+
```yaml
|
|
372
|
+
# .github/workflows/pace-core-compliance.yml
|
|
373
|
+
name: pace-core Compliance
|
|
374
|
+
|
|
375
|
+
on: [push, pull_request]
|
|
376
|
+
|
|
377
|
+
jobs:
|
|
378
|
+
compliance:
|
|
379
|
+
runs-on: ubuntu-latest
|
|
380
|
+
steps:
|
|
381
|
+
- uses: actions/checkout@v3
|
|
382
|
+
- uses: actions/setup-node@v3
|
|
383
|
+
- run: npm ci
|
|
384
|
+
- run: npm run check:pace-core
|
|
385
|
+
- run: npm run lint
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
## Verification
|
|
389
|
+
|
|
390
|
+
After setting up the ESLint config, verify it's working:
|
|
391
|
+
|
|
392
|
+
1. **Check ESLint can load the config**:
|
|
393
|
+
```bash
|
|
394
|
+
npx eslint --print-config src/App.tsx
|
|
395
|
+
```
|
|
396
|
+
Look for `pace-core-compliance` in the plugins section.
|
|
397
|
+
|
|
398
|
+
2. **Test with a violation**: Create a test file that imports a restricted library:
|
|
399
|
+
```typescript
|
|
400
|
+
// test-violation.ts
|
|
401
|
+
import { Dialog } from '@radix-ui/react-dialog'; // Should trigger error
|
|
402
|
+
```
|
|
403
|
+
Run ESLint and verify it reports the violation.
|
|
404
|
+
|
|
405
|
+
3. **Run static analysis**: Use the compliance script to get a full report:
|
|
406
|
+
```bash
|
|
407
|
+
npm run check:pace-core
|
|
408
|
+
```
|
|
409
|
+
|
|
410
|
+
## Getting Help
|
|
411
|
+
|
|
412
|
+
- **Documentation**: See [pace-core docs](../README.md)
|
|
413
|
+
- **Issues**: Report false positives or rule issues
|
|
414
|
+
- **Manifest**: Check `core-usage-manifest.json` for available exports
|
|
415
|
+
- **ESLint Config**: The config file is at `@jmruthers/pace-core/eslint-config` (CommonJS)
|
|
416
|
+
- **ESLint Rules**: The rules are at `@jmruthers/pace-core/eslint-rules` (CommonJS)
|
|
417
|
+
|
|
418
|
+
## File Locations
|
|
419
|
+
|
|
420
|
+
When installed in a consuming app, the compliance tools are available at:
|
|
421
|
+
|
|
422
|
+
- **ESLint Config**: `node_modules/@jmruthers/pace-core/eslint-config-pace-core.cjs`
|
|
423
|
+
- **ESLint Rules**: `node_modules/@jmruthers/pace-core/dist/eslint-rules/pace-core-compliance.cjs`
|
|
424
|
+
- **Static Analysis Script**: `node_modules/@jmruthers/pace-core/scripts/check-pace-core-compliance.cjs`
|
|
425
|
+
- **Manifest**: `node_modules/@jmruthers/pace-core/core-usage-manifest.json`
|
|
426
|
+
|
|
427
|
+
## Related Documentation
|
|
428
|
+
|
|
429
|
+
- [Component Standards](./03-component-standard.md)
|
|
430
|
+
- [API & RPC Standards](./02-api-and-rpc-standard.md)
|
|
431
|
+
- [Getting Started Guide](../getting-started/README.md)
|
|
432
|
+
|