@jmruthers/pace-core 0.5.121 → 0.5.123
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AuthService-D4646R4b.d.ts → AuthService-DYuQPJj6.d.ts} +0 -9
- package/dist/{DataTable-DGZDJUYM.js → DataTable-WTS4IRF2.js} +7 -8
- package/dist/{PublicLoadingSpinner-DgDWTFqn.d.ts → PublicLoadingSpinner-CaoRbHvJ.d.ts} +30 -4
- package/dist/{UnifiedAuthProvider-UACKFATV.js → UnifiedAuthProvider-6C47WIML.js} +3 -4
- package/dist/{chunk-D6BOFXYR.js → chunk-35ZDPMBM.js} +3 -3
- package/dist/{chunk-CGURJ27Z.js → chunk-4MXVZVNS.js} +2 -2
- package/dist/{chunk-ZYJ6O5CA.js → chunk-C43QIDN3.js} +2 -2
- package/dist/{chunk-VKOCWWVY.js → chunk-CX5M4ZAG.js} +1 -6
- package/dist/{chunk-VKOCWWVY.js 3.map → chunk-CX5M4ZAG.js.map} +1 -1
- package/dist/{chunk-HFBOFZ3Z.js → chunk-DHMFMXFV.js} +258 -243
- package/dist/chunk-DHMFMXFV.js.map +1 -0
- package/dist/{chunk-RIEJGKD3.js → chunk-ESJTIADP.js} +15 -6
- package/dist/{chunk-RIEJGKD3.js.map → chunk-ESJTIADP.js.map} +1 -1
- package/dist/{chunk-SMJZMKYN.js → chunk-GEVIB2UB.js} +43 -10
- package/dist/chunk-GEVIB2UB.js.map +1 -0
- package/dist/{chunk-TDNI6ZWL.js → chunk-IJOZZOGT.js} +7 -7
- package/dist/chunk-IJOZZOGT.js.map +1 -0
- package/dist/{chunk-GZRXOUBE.js → chunk-M6DDYFUD.js} +2 -2
- package/dist/chunk-M6DDYFUD.js.map +1 -0
- package/dist/{chunk-B4GZ2BXO.js → chunk-NZGLXZGP.js} +3 -3
- package/dist/{chunk-NZ32EONV.js → chunk-QWNJCQXZ.js} +2 -2
- package/dist/{chunk-FKFHZUGF.js → chunk-XN6GWKMV.js} +43 -56
- package/dist/chunk-XN6GWKMV.js.map +1 -0
- package/dist/{chunk-BHWIUEYH.js → chunk-ZBLK676C.js} +1 -61
- package/dist/chunk-ZBLK676C.js.map +1 -0
- package/dist/{chunk-QPI2CCBA.js → chunk-ZPJMYGEP.js} +149 -96
- package/dist/chunk-ZPJMYGEP.js.map +1 -0
- package/dist/components.d.ts +1 -1
- package/dist/components.js +11 -11
- package/dist/{formatting-B1jSqgl-.d.ts → formatting-DFcCxUEk.d.ts} +1 -1
- package/dist/hooks.d.ts +1 -1
- package/dist/hooks.js +9 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.js +19 -17
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +2 -3
- package/dist/rbac/index.js +7 -8
- package/dist/styles/index.d.ts +1 -1
- package/dist/styles/index.js +5 -3
- package/dist/theming/runtime.d.ts +73 -1
- package/dist/theming/runtime.js +5 -5
- package/dist/{usePublicRouteParams-BdF8bZgs.d.ts → usePublicRouteParams-Dyt1tzI9.d.ts} +60 -8
- package/dist/utils.d.ts +1 -1
- package/dist/utils.js +5 -5
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.md +6 -6
- package/docs/api/classes/RBACAuditManager.md +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +6 -6
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- package/docs/api/interfaces/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/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.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 +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +1 -1
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +7 -7
- package/docs/api/interfaces/PublicErrorBoundaryState.md +5 -5
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +7 -7
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +51 -12
- package/docs/api/interfaces/PublicPageLayoutProps.md +72 -12
- package/docs/api/interfaces/RBACConfig.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.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 +140 -30
- package/docs/best-practices/README.md +1 -1
- package/docs/implementation-guides/datatable-filtering.md +313 -0
- package/docs/implementation-guides/datatable-rbac-usage.md +317 -0
- package/docs/implementation-guides/hierarchical-datatable.md +850 -0
- package/docs/implementation-guides/large-datasets.md +281 -0
- package/docs/implementation-guides/performance.md +403 -0
- package/docs/implementation-guides/public-pages.md +4 -4
- package/docs/migration/quick-migration-guide.md +320 -0
- package/docs/rbac/quick-start.md +16 -16
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +1 -1
- package/docs/troubleshooting/debugging.md +1117 -0
- package/docs/troubleshooting/migration.md +918 -0
- package/examples/public-pages/CorrectPublicPageImplementation.tsx +30 -30
- package/examples/public-pages/PublicEventPage.tsx +41 -41
- package/examples/public-pages/PublicPageApp.tsx +33 -33
- package/examples/public-pages/PublicPageUsageExample.tsx +30 -30
- package/package.json +4 -4
- package/src/__tests__/hooks/usePermissions.test.ts +265 -0
- package/src/components/DataTable/DataTable.test.tsx +9 -38
- package/src/components/DataTable/DataTable.tsx +0 -7
- package/src/components/DataTable/components/DataTableCore.tsx +66 -136
- package/src/components/DataTable/components/DataTableModals.tsx +25 -22
- package/src/components/DataTable/components/EditableRow.tsx +118 -42
- package/src/components/DataTable/components/UnifiedTableBody.tsx +129 -76
- package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +33 -14
- package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +17 -5
- package/src/components/DataTable/utils/exportUtils.ts +3 -2
- package/src/components/Dialog/Dialog.tsx +1 -1
- package/src/components/Dialog/README.md +24 -24
- package/src/components/Dialog/examples/BasicHtmlTest.tsx +2 -2
- package/src/components/Dialog/examples/DebugHtmlExample.tsx +6 -6
- package/src/components/Dialog/examples/HtmlDialogExample.tsx +2 -2
- package/src/components/Dialog/examples/SimpleHtmlTest.tsx +3 -3
- package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +4 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +12 -1
- package/src/components/PublicLayout/EventLogo.tsx +175 -0
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +22 -18
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +22 -14
- package/src/components/PublicLayout/PublicPageHeader.tsx +133 -40
- package/src/components/PublicLayout/PublicPageLayout.tsx +75 -72
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +1 -1
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +8 -8
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +23 -16
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +86 -14
- package/src/examples/CorrectPublicPageImplementation.tsx +30 -30
- package/src/examples/PublicEventPage.tsx +41 -41
- package/src/examples/PublicPageApp.tsx +33 -33
- package/src/examples/PublicPageUsageExample.tsx +30 -30
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +583 -0
- package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +10 -3
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEventLogo.ts +285 -0
- package/src/hooks/public/usePublicRouteParams.ts +21 -4
- package/src/hooks/useEventTheme.test.ts +119 -43
- package/src/hooks/useEventTheme.ts +84 -55
- package/src/index.ts +3 -1
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +630 -0
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +496 -0
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
- package/src/rbac/secureClient.ts +4 -2
- package/src/services/EventService.ts +0 -66
- package/src/services/__tests__/EventService.eventColours.test.ts +44 -40
- package/src/styles/index.ts +1 -1
- package/src/theming/__tests__/parseEventColours.test.ts +209 -0
- package/src/theming/parseEventColours.ts +123 -0
- package/src/theming/runtime.ts +3 -0
- package/src/types/__tests__/file-reference.test.ts +447 -0
- package/src/utils/formatDate.test.ts +11 -11
- package/src/utils/formatting.ts +3 -2
- package/dist/chunk-BDZUMRBD.js 3.map +0 -1
- package/dist/chunk-BHWIUEYH.js.map +0 -1
- package/dist/chunk-CGURJ27Z.js.map +0 -1
- package/dist/chunk-FKFHZUGF.js.map +0 -1
- package/dist/chunk-GKHF54DI 2.js +0 -619
- package/dist/chunk-GKHF54DI.js 2.map +0 -1
- package/dist/chunk-GZRXOUBE.js.map +0 -1
- package/dist/chunk-HFBOFZ3Z.js.map +0 -1
- package/dist/chunk-NZ32EONV.js.map +0 -1
- package/dist/chunk-O3NWNXDY 2.js +0 -76
- package/dist/chunk-QPI2CCBA.js.map +0 -1
- package/dist/chunk-SMJZMKYN.js.map +0 -1
- package/dist/chunk-TDNI6ZWL.js 2.map +0 -1
- package/dist/chunk-TDNI6ZWL.js.map +0 -1
- package/dist/chunk-VKOCWWVY.js.map +0 -1
- package/dist/chunk-WP5I5GLN 2.js +0 -1564
- package/dist/index 3.js +0 -856
- package/dist/providers 3.js +0 -38
- package/dist/providers.js 3.map +0 -1
- package/dist/types 3.js +0 -128
- package/dist/types.js 3.map +0 -1
- package/dist/useInactivityTracker-MRUU55XI.js 3.map +0 -1
- package/dist/utils.js 3.map +0 -1
- package/dist/validation 3.js +0 -479
- package/src/styles/semantic.css +0 -24
- /package/dist/{DataTable-DGZDJUYM.js.map → DataTable-WTS4IRF2.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-UACKFATV.js.map → UnifiedAuthProvider-6C47WIML.js.map} +0 -0
- /package/dist/{chunk-D6BOFXYR.js.map → chunk-35ZDPMBM.js.map} +0 -0
- /package/dist/{chunk-CGURJ27Z.js 2.map → chunk-4MXVZVNS.js.map} +0 -0
- /package/dist/{chunk-ZYJ6O5CA.js.map → chunk-C43QIDN3.js.map} +0 -0
- /package/dist/{chunk-B4GZ2BXO.js.map → chunk-NZGLXZGP.js.map} +0 -0
- /package/dist/{chunk-NZ32EONV.js 2.map → chunk-QWNJCQXZ.js.map} +0 -0
|
@@ -0,0 +1,918 @@
|
|
|
1
|
+
# Migration Guide
|
|
2
|
+
|
|
3
|
+
This guide provides comprehensive migration strategies for upgrading `@jmruthers/pace-core` applications between versions and handling breaking changes.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
Migration in `@jmruthers/pace-core` covers:
|
|
8
|
+
|
|
9
|
+
- **Version Upgrades**: Upgrading between major/minor versions
|
|
10
|
+
- **Breaking Changes**: Handling API changes and deprecations
|
|
11
|
+
- **Database Migrations**: Schema updates and data transformations
|
|
12
|
+
- **Configuration Updates**: Environment and build configuration changes
|
|
13
|
+
- **Dependency Updates**: Third-party library compatibility
|
|
14
|
+
|
|
15
|
+
## Version Migration
|
|
16
|
+
|
|
17
|
+
### 1. Major Version Migration (v1.x to v2.x)
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
// Before v2.0.0
|
|
21
|
+
import { useAuth, usePermissions } from '@jmruthers/pace-core';
|
|
22
|
+
|
|
23
|
+
function MyComponent() {
|
|
24
|
+
const { user, signIn, signOut } = useAuth();
|
|
25
|
+
const { hasPermission } = usePermissions();
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<div>
|
|
29
|
+
{user && <p>Welcome, {user.email}</p>}
|
|
30
|
+
{hasPermission('read:users') && <UserList />}
|
|
31
|
+
</div>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// After v2.0.0
|
|
36
|
+
import { useUnifiedAuth } from '@jmruthers/pace-core';
|
|
37
|
+
import { useCan } from '@jmruthers/pace-core/rbac';
|
|
38
|
+
|
|
39
|
+
function MyComponent() {
|
|
40
|
+
const { user, signIn, signOut } = useUnifiedAuth();
|
|
41
|
+
const { hasPermission } = useCan();
|
|
42
|
+
|
|
43
|
+
return (
|
|
44
|
+
<div>
|
|
45
|
+
{user && <p>Welcome, {user.email}</p>}
|
|
46
|
+
{hasPermission('read:users') && <UserList />}
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
### 2. Hook Migration Patterns
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
// Migration helper for gradual updates
|
|
56
|
+
function useLegacyAuth() {
|
|
57
|
+
const auth = useUnifiedAuth();
|
|
58
|
+
|
|
59
|
+
// Provide legacy API compatibility
|
|
60
|
+
return {
|
|
61
|
+
user: auth.user,
|
|
62
|
+
loading: auth.loading,
|
|
63
|
+
error: auth.error,
|
|
64
|
+
signIn: auth.signIn,
|
|
65
|
+
signOut: auth.signOut,
|
|
66
|
+
// Legacy methods
|
|
67
|
+
login: auth.signIn,
|
|
68
|
+
logout: auth.signOut,
|
|
69
|
+
isAuthenticated: !!auth.user,
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Migration helper for RBAC
|
|
74
|
+
import { useCan, usePermissions } from '@jmruthers/pace-core/rbac';
|
|
75
|
+
|
|
76
|
+
function useLegacyPermissions() {
|
|
77
|
+
const { hasPermission } = useCan();
|
|
78
|
+
const { permissions } = usePermissions();
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
hasPermission,
|
|
82
|
+
permissions,
|
|
83
|
+
// Legacy methods
|
|
84
|
+
can: hasPermission,
|
|
85
|
+
userPermissions: permissions,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 3. Component Migration
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
// Before: Old component API
|
|
94
|
+
<Button
|
|
95
|
+
variant="primary"
|
|
96
|
+
onClick={handleClick}
|
|
97
|
+
disabled={loading}
|
|
98
|
+
>
|
|
99
|
+
Submit
|
|
100
|
+
</Button>
|
|
101
|
+
|
|
102
|
+
// After: New component API
|
|
103
|
+
<Button
|
|
104
|
+
variant="primary"
|
|
105
|
+
onClick={handleClick}
|
|
106
|
+
disabled={loading}
|
|
107
|
+
loading={loading}
|
|
108
|
+
size="md"
|
|
109
|
+
>
|
|
110
|
+
Submit
|
|
111
|
+
</Button>
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Breaking Changes Migration
|
|
115
|
+
|
|
116
|
+
### 1. Authentication API Changes
|
|
117
|
+
|
|
118
|
+
```typescript
|
|
119
|
+
// Migration script for authentication changes
|
|
120
|
+
function migrateAuthAPI() {
|
|
121
|
+
// Old API
|
|
122
|
+
const oldAuth = {
|
|
123
|
+
user: null,
|
|
124
|
+
signIn: async (email: string, password: string) => {
|
|
125
|
+
// Old implementation
|
|
126
|
+
},
|
|
127
|
+
signOut: async () => {
|
|
128
|
+
// Old implementation
|
|
129
|
+
},
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
// New API
|
|
133
|
+
const newAuth = {
|
|
134
|
+
user: null,
|
|
135
|
+
signIn: async (credentials: { email: string; password: string }) => {
|
|
136
|
+
// New implementation
|
|
137
|
+
},
|
|
138
|
+
signOut: async () => {
|
|
139
|
+
// New implementation
|
|
140
|
+
},
|
|
141
|
+
// Additional methods
|
|
142
|
+
signUp: async (credentials: { email: string; password: string }) => {
|
|
143
|
+
// New signup implementation
|
|
144
|
+
},
|
|
145
|
+
resetPassword: async (email: string) => {
|
|
146
|
+
// New password reset implementation
|
|
147
|
+
},
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
return newAuth;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
// Migration helper
|
|
154
|
+
function useAuthMigration() {
|
|
155
|
+
const auth = useUnifiedAuth();
|
|
156
|
+
|
|
157
|
+
// Provide backward compatibility
|
|
158
|
+
const legacySignIn = useCallback((email: string, password: string) => {
|
|
159
|
+
return auth.signIn({ email, password });
|
|
160
|
+
}, [auth.signIn]);
|
|
161
|
+
|
|
162
|
+
return {
|
|
163
|
+
...auth,
|
|
164
|
+
// Legacy API
|
|
165
|
+
login: legacySignIn,
|
|
166
|
+
logout: auth.signOut,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 2. Permission System Changes
|
|
172
|
+
|
|
173
|
+
```typescript
|
|
174
|
+
// Migration script for permission changes
|
|
175
|
+
function migratePermissions() {
|
|
176
|
+
// Old permission format
|
|
177
|
+
const oldPermissions = [
|
|
178
|
+
'read_users',
|
|
179
|
+
'write_events',
|
|
180
|
+
'delete_posts',
|
|
181
|
+
];
|
|
182
|
+
|
|
183
|
+
// New permission format
|
|
184
|
+
const newPermissions = [
|
|
185
|
+
'read:users',
|
|
186
|
+
'write:events',
|
|
187
|
+
'delete:posts',
|
|
188
|
+
];
|
|
189
|
+
|
|
190
|
+
// Migration function
|
|
191
|
+
function migratePermissionFormat(oldPermission: string): string {
|
|
192
|
+
return oldPermission.replace('_', ':');
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
return {
|
|
196
|
+
oldPermissions,
|
|
197
|
+
newPermissions: oldPermissions.map(migratePermissionFormat),
|
|
198
|
+
migratePermissionFormat,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Migration helper for permission checks
|
|
203
|
+
function usePermissionMigration() {
|
|
204
|
+
const rbac = useRBAC();
|
|
205
|
+
|
|
206
|
+
// Legacy permission check
|
|
207
|
+
const legacyHasPermission = useCallback((permission: string) => {
|
|
208
|
+
// Convert old format to new format
|
|
209
|
+
const newPermission = permission.replace('_', ':');
|
|
210
|
+
return rbac.hasPermission(newPermission);
|
|
211
|
+
}, [rbac]);
|
|
212
|
+
|
|
213
|
+
return {
|
|
214
|
+
...rbac,
|
|
215
|
+
// Legacy API
|
|
216
|
+
can: legacyHasPermission,
|
|
217
|
+
hasAccess: legacyHasPermission,
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### 3. Component Prop Changes
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
// Migration script for component prop changes
|
|
226
|
+
function migrateComponentProps() {
|
|
227
|
+
// Old Button props
|
|
228
|
+
const oldButtonProps = {
|
|
229
|
+
type: 'primary',
|
|
230
|
+
onClick: () => {},
|
|
231
|
+
disabled: false,
|
|
232
|
+
children: 'Click me',
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// New Button props
|
|
236
|
+
const newButtonProps = {
|
|
237
|
+
variant: 'primary', // type -> variant
|
|
238
|
+
onClick: () => {},
|
|
239
|
+
disabled: false,
|
|
240
|
+
loading: false, // New prop
|
|
241
|
+
size: 'md', // New prop
|
|
242
|
+
children: 'Click me',
|
|
243
|
+
};
|
|
244
|
+
|
|
245
|
+
// Migration function
|
|
246
|
+
function migrateButtonProps(oldProps: any) {
|
|
247
|
+
return {
|
|
248
|
+
variant: oldProps.type,
|
|
249
|
+
onClick: oldProps.onClick,
|
|
250
|
+
disabled: oldProps.disabled,
|
|
251
|
+
loading: false, // Default value
|
|
252
|
+
size: 'md', // Default value
|
|
253
|
+
children: oldProps.children,
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
oldButtonProps,
|
|
259
|
+
newButtonProps,
|
|
260
|
+
migrateButtonProps,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## Database Migration
|
|
266
|
+
|
|
267
|
+
### 1. Schema Migration
|
|
268
|
+
|
|
269
|
+
```sql
|
|
270
|
+
-- Migration script for database schema changes
|
|
271
|
+
-- 001_migrate_users_table.sql
|
|
272
|
+
|
|
273
|
+
-- Add new columns to users table
|
|
274
|
+
ALTER TABLE users
|
|
275
|
+
ADD COLUMN IF NOT EXISTS organisation_id UUID REFERENCES organisations(id),
|
|
276
|
+
ADD COLUMN IF NOT EXISTS role VARCHAR(50) DEFAULT 'user',
|
|
277
|
+
ADD COLUMN IF NOT EXISTS permissions JSONB DEFAULT '[]';
|
|
278
|
+
|
|
279
|
+
-- Create index for performance
|
|
280
|
+
CREATE INDEX IF NOT EXISTS idx_users_organisation_id ON users(organisation_id);
|
|
281
|
+
CREATE INDEX IF NOT EXISTS idx_users_role ON users(role);
|
|
282
|
+
|
|
283
|
+
-- Update existing users with default values
|
|
284
|
+
UPDATE users
|
|
285
|
+
SET
|
|
286
|
+
organisation_id = (SELECT id FROM organisations LIMIT 1),
|
|
287
|
+
role = 'user',
|
|
288
|
+
permissions = '[]'
|
|
289
|
+
WHERE organisation_id IS NULL;
|
|
290
|
+
|
|
291
|
+
-- Add constraints
|
|
292
|
+
ALTER TABLE users
|
|
293
|
+
ALTER COLUMN organisation_id SET NOT NULL,
|
|
294
|
+
ALTER COLUMN role SET NOT NULL;
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### 2. Data Migration
|
|
298
|
+
|
|
299
|
+
```typescript
|
|
300
|
+
// Migration script for data transformation
|
|
301
|
+
async function migrateUserData() {
|
|
302
|
+
const { supabase } = useSupabase();
|
|
303
|
+
|
|
304
|
+
// Get all users
|
|
305
|
+
const { data: users, error } = await supabase
|
|
306
|
+
.from('users')
|
|
307
|
+
.select('*');
|
|
308
|
+
|
|
309
|
+
if (error) {
|
|
310
|
+
console.error('Failed to fetch users:', error);
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
// Transform user data
|
|
315
|
+
const migratedUsers = users.map(user => ({
|
|
316
|
+
...user,
|
|
317
|
+
// Convert old permission format to new format
|
|
318
|
+
permissions: user.permissions?.map((permission: string) =>
|
|
319
|
+
permission.replace('_', ':')
|
|
320
|
+
) || [],
|
|
321
|
+
// Add default role if missing
|
|
322
|
+
role: user.role || 'user',
|
|
323
|
+
// Add organisation if missing
|
|
324
|
+
organisation_id: user.organisation_id || 'default-org-id',
|
|
325
|
+
}));
|
|
326
|
+
|
|
327
|
+
// Update users in batches
|
|
328
|
+
const batchSize = 100;
|
|
329
|
+
for (let i = 0; i < migratedUsers.length; i += batchSize) {
|
|
330
|
+
const batch = migratedUsers.slice(i, i + batchSize);
|
|
331
|
+
|
|
332
|
+
const { error: updateError } = await supabase
|
|
333
|
+
.from('users')
|
|
334
|
+
.upsert(batch);
|
|
335
|
+
|
|
336
|
+
if (updateError) {
|
|
337
|
+
console.error(`Failed to update batch ${i / batchSize + 1}:`, updateError);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
console.log('User data migration completed');
|
|
342
|
+
}
|
|
343
|
+
```
|
|
344
|
+
|
|
345
|
+
### 3. RLS Policy Migration
|
|
346
|
+
|
|
347
|
+
```sql
|
|
348
|
+
-- Migration script for RLS policies
|
|
349
|
+
-- 002_migrate_rls_policies.sql
|
|
350
|
+
|
|
351
|
+
-- Drop old policies
|
|
352
|
+
DROP POLICY IF EXISTS "Users can view their own data" ON users;
|
|
353
|
+
DROP POLICY IF EXISTS "Users can update their own data" ON users;
|
|
354
|
+
|
|
355
|
+
-- Create new policies with organisation isolation
|
|
356
|
+
CREATE POLICY "Users can view their own organisation's data" ON users
|
|
357
|
+
FOR SELECT USING (
|
|
358
|
+
organisation_id = auth.jwt() ->> 'organisation_id'
|
|
359
|
+
);
|
|
360
|
+
|
|
361
|
+
CREATE POLICY "Users can update their own data" ON users
|
|
362
|
+
FOR UPDATE USING (
|
|
363
|
+
id = auth.uid() AND
|
|
364
|
+
organisation_id = auth.jwt() ->> 'organisation_id'
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
CREATE POLICY "Users can insert their own data" ON users
|
|
368
|
+
FOR INSERT WITH CHECK (
|
|
369
|
+
organisation_id = auth.jwt() ->> 'organisation_id'
|
|
370
|
+
);
|
|
371
|
+
|
|
372
|
+
-- Apply similar policies to other tables
|
|
373
|
+
-- events table
|
|
374
|
+
CREATE POLICY "Users can view their organisation's events" ON events
|
|
375
|
+
FOR SELECT USING (
|
|
376
|
+
organisation_id = auth.jwt() ->> 'organisation_id'
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
CREATE POLICY "Users can manage their organisation's events" ON events
|
|
380
|
+
FOR ALL USING (
|
|
381
|
+
organisation_id = auth.jwt() ->> 'organisation_id'
|
|
382
|
+
);
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
## Configuration Migration
|
|
386
|
+
|
|
387
|
+
### 1. Environment Variables Migration
|
|
388
|
+
|
|
389
|
+
```bash
|
|
390
|
+
# Migration script for environment variables
|
|
391
|
+
# old.env -> new.env
|
|
392
|
+
|
|
393
|
+
# Old environment variables
|
|
394
|
+
VITE_AUTH_URL=https://old-auth.example.com
|
|
395
|
+
VITE_API_KEY=old-api-key
|
|
396
|
+
VITE_DEBUG_MODE=true
|
|
397
|
+
|
|
398
|
+
# New environment variables
|
|
399
|
+
VITE_SUPABASE_URL=https://your-project.supabase.co
|
|
400
|
+
VITE_SUPABASE_ANON_KEY=your-anon-key
|
|
401
|
+
VITE_APP_ENV=development
|
|
402
|
+
VITE_DEBUG=false
|
|
403
|
+
|
|
404
|
+
# Migration script
|
|
405
|
+
#!/bin/bash
|
|
406
|
+
# migrate-env.sh
|
|
407
|
+
|
|
408
|
+
echo "Migrating environment variables..."
|
|
409
|
+
|
|
410
|
+
# Backup old environment file
|
|
411
|
+
cp .env .env.backup
|
|
412
|
+
|
|
413
|
+
# Create new environment file
|
|
414
|
+
cat > .env << EOF
|
|
415
|
+
# Supabase Configuration
|
|
416
|
+
VITE_SUPABASE_URL=${VITE_SUPABASE_URL:-https://your-project.supabase.co}
|
|
417
|
+
VITE_SUPABASE_ANON_KEY=${VITE_SUPABASE_ANON_KEY:-your-anon-key}
|
|
418
|
+
|
|
419
|
+
# Application Configuration
|
|
420
|
+
VITE_APP_ENV=${VITE_APP_ENV:-development}
|
|
421
|
+
VITE_DEBUG=${VITE_DEBUG:-false}
|
|
422
|
+
|
|
423
|
+
# Feature Flags
|
|
424
|
+
VITE_FEATURE_ANALYTICS=${VITE_FEATURE_ANALYTICS:-false}
|
|
425
|
+
VITE_FEATURE_BETA=${VITE_FEATURE_BETA:-false}
|
|
426
|
+
|
|
427
|
+
# Monitoring
|
|
428
|
+
VITE_SENTRY_DSN=${VITE_SENTRY_DSN:-}
|
|
429
|
+
VITE_ANALYTICS_ID=${VITE_ANALYTICS_ID:-}
|
|
430
|
+
EOF
|
|
431
|
+
|
|
432
|
+
echo "Environment migration completed"
|
|
433
|
+
```
|
|
434
|
+
|
|
435
|
+
### 2. Build Configuration Migration
|
|
436
|
+
|
|
437
|
+
```typescript
|
|
438
|
+
// Migration script for build configuration
|
|
439
|
+
// vite.config.old.ts -> vite.config.ts
|
|
440
|
+
|
|
441
|
+
// Old configuration
|
|
442
|
+
export default defineConfig({
|
|
443
|
+
plugins: [react()],
|
|
444
|
+
build: {
|
|
445
|
+
outDir: 'build',
|
|
446
|
+
sourcemap: true,
|
|
447
|
+
},
|
|
448
|
+
define: {
|
|
449
|
+
global: 'globalThis',
|
|
450
|
+
},
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
// New configuration
|
|
454
|
+
export default defineConfig({
|
|
455
|
+
plugins: [react()],
|
|
456
|
+
build: {
|
|
457
|
+
target: 'es2015',
|
|
458
|
+
outDir: 'dist',
|
|
459
|
+
sourcemap: false, // Disable in production
|
|
460
|
+
minify: 'terser',
|
|
461
|
+
rollupOptions: {
|
|
462
|
+
output: {
|
|
463
|
+
manualChunks: {
|
|
464
|
+
vendor: ['react', 'react-dom'],
|
|
465
|
+
paceCore: ['@jmruthers/pace-core'],
|
|
466
|
+
supabase: ['@supabase/supabase-js'],
|
|
467
|
+
},
|
|
468
|
+
},
|
|
469
|
+
},
|
|
470
|
+
terserOptions: {
|
|
471
|
+
compress: {
|
|
472
|
+
drop_console: true,
|
|
473
|
+
drop_debugger: true,
|
|
474
|
+
},
|
|
475
|
+
},
|
|
476
|
+
},
|
|
477
|
+
define: {
|
|
478
|
+
__DEV__: JSON.stringify(process.env.NODE_ENV === 'development'),
|
|
479
|
+
},
|
|
480
|
+
optimizeDeps: {
|
|
481
|
+
include: ['@jmruthers/pace-core'],
|
|
482
|
+
},
|
|
483
|
+
});
|
|
484
|
+
```
|
|
485
|
+
|
|
486
|
+
### 3. Package.json Migration
|
|
487
|
+
|
|
488
|
+
```json
|
|
489
|
+
// Migration script for package.json dependencies
|
|
490
|
+
// package.json.old -> package.json
|
|
491
|
+
|
|
492
|
+
{
|
|
493
|
+
"name": "my-app",
|
|
494
|
+
"version": "2.0.0",
|
|
495
|
+
"dependencies": {
|
|
496
|
+
// Old dependencies
|
|
497
|
+
"@jmruthers/pace-core": "^1.5.0",
|
|
498
|
+
"react": "^17.0.2",
|
|
499
|
+
"react-dom": "^17.0.2",
|
|
500
|
+
|
|
501
|
+
// New dependencies
|
|
502
|
+
"@jmruthers/pace-core": "^2.0.0",
|
|
503
|
+
"react": "^18.2.0",
|
|
504
|
+
"react-dom": "^18.2.0",
|
|
505
|
+
"@supabase/supabase-js": "^2.38.0",
|
|
506
|
+
"zod": "^3.22.0"
|
|
507
|
+
},
|
|
508
|
+
"devDependencies": {
|
|
509
|
+
// Old dev dependencies
|
|
510
|
+
"@types/react": "^17.0.0",
|
|
511
|
+
"@types/react-dom": "^17.0.0",
|
|
512
|
+
|
|
513
|
+
// New dev dependencies
|
|
514
|
+
"@types/react": "^18.2.0",
|
|
515
|
+
"@types/react-dom": "^18.2.0",
|
|
516
|
+
"@vitejs/plugin-react": "^4.0.0",
|
|
517
|
+
"vite": "^4.4.0",
|
|
518
|
+
"typescript": "^5.0.0"
|
|
519
|
+
},
|
|
520
|
+
"scripts": {
|
|
521
|
+
// Old scripts
|
|
522
|
+
"start": "react-scripts start",
|
|
523
|
+
"build": "react-scripts build",
|
|
524
|
+
"test": "react-scripts test",
|
|
525
|
+
|
|
526
|
+
// New scripts
|
|
527
|
+
"dev": "vite",
|
|
528
|
+
"build": "vite build",
|
|
529
|
+
"preview": "vite preview",
|
|
530
|
+
"test": "vitest",
|
|
531
|
+
"type-check": "tsc --noEmit"
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
## Migration Tools and Utilities
|
|
537
|
+
|
|
538
|
+
### 1. Migration Helper Functions
|
|
539
|
+
|
|
540
|
+
```typescript
|
|
541
|
+
// utils/migrationHelpers.ts
|
|
542
|
+
export class MigrationHelpers {
|
|
543
|
+
// Check if migration is needed
|
|
544
|
+
static needsMigration(currentVersion: string, targetVersion: string): boolean {
|
|
545
|
+
const current = this.parseVersion(currentVersion);
|
|
546
|
+
const target = this.parseVersion(targetVersion);
|
|
547
|
+
|
|
548
|
+
return current.major < target.major ||
|
|
549
|
+
(current.major === target.major && current.minor < target.minor);
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Parse version string
|
|
553
|
+
static parseVersion(version: string) {
|
|
554
|
+
const [major, minor, patch] = version.split('.').map(Number);
|
|
555
|
+
return { major, minor, patch };
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// Migrate component props
|
|
559
|
+
static migrateComponentProps(oldProps: any, componentName: string) {
|
|
560
|
+
const migrations = {
|
|
561
|
+
Button: {
|
|
562
|
+
type: 'variant',
|
|
563
|
+
size: 'md',
|
|
564
|
+
loading: false,
|
|
565
|
+
},
|
|
566
|
+
DataTable: {
|
|
567
|
+
data: 'rows',
|
|
568
|
+
columns: 'columns',
|
|
569
|
+
pagination: 'enablePagination',
|
|
570
|
+
},
|
|
571
|
+
Form: {
|
|
572
|
+
onSubmit: 'onSubmit',
|
|
573
|
+
validation: 'schema',
|
|
574
|
+
},
|
|
575
|
+
};
|
|
576
|
+
|
|
577
|
+
const migration = migrations[componentName];
|
|
578
|
+
if (!migration) return oldProps;
|
|
579
|
+
|
|
580
|
+
const newProps = { ...oldProps };
|
|
581
|
+
|
|
582
|
+
Object.entries(migration).forEach(([oldKey, newKey]) => {
|
|
583
|
+
if (oldProps[oldKey] !== undefined) {
|
|
584
|
+
newProps[newKey] = oldProps[oldKey];
|
|
585
|
+
delete newProps[oldKey];
|
|
586
|
+
}
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
return newProps;
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
// Migrate permission format
|
|
593
|
+
static migratePermissionFormat(permission: string): string {
|
|
594
|
+
return permission.replace('_', ':');
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// Migrate user data
|
|
598
|
+
static migrateUserData(user: any) {
|
|
599
|
+
return {
|
|
600
|
+
...user,
|
|
601
|
+
permissions: user.permissions?.map(this.migratePermissionFormat) || [],
|
|
602
|
+
role: user.role || 'user',
|
|
603
|
+
organisation_id: user.organisation_id || 'default',
|
|
604
|
+
};
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// Generate migration report
|
|
608
|
+
static generateMigrationReport(changes: any[]) {
|
|
609
|
+
return {
|
|
610
|
+
timestamp: new Date().toISOString(),
|
|
611
|
+
changes,
|
|
612
|
+
summary: {
|
|
613
|
+
total: changes.length,
|
|
614
|
+
breaking: changes.filter(c => c.breaking).length,
|
|
615
|
+
nonBreaking: changes.filter(c => !c.breaking).length,
|
|
616
|
+
},
|
|
617
|
+
};
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### 2. Migration Validation
|
|
623
|
+
|
|
624
|
+
```typescript
|
|
625
|
+
// utils/migrationValidation.ts
|
|
626
|
+
export class MigrationValidation {
|
|
627
|
+
// Validate component usage
|
|
628
|
+
static validateComponentUsage(componentName: string, props: any) {
|
|
629
|
+
const validations = {
|
|
630
|
+
Button: {
|
|
631
|
+
required: ['children'],
|
|
632
|
+
optional: ['variant', 'size', 'loading', 'disabled', 'onClick'],
|
|
633
|
+
deprecated: ['type'],
|
|
634
|
+
},
|
|
635
|
+
DataTable: {
|
|
636
|
+
required: ['data', 'columns'],
|
|
637
|
+
optional: ['pagination', 'sorting', 'filtering'],
|
|
638
|
+
deprecated: ['rows'],
|
|
639
|
+
},
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
const validation = validations[componentName];
|
|
643
|
+
if (!validation) return { valid: true, warnings: [] };
|
|
644
|
+
|
|
645
|
+
const warnings = [];
|
|
646
|
+
|
|
647
|
+
// Check for deprecated props
|
|
648
|
+
validation.deprecated.forEach(prop => {
|
|
649
|
+
if (props[prop] !== undefined) {
|
|
650
|
+
warnings.push(`Prop '${prop}' is deprecated in ${componentName}`);
|
|
651
|
+
}
|
|
652
|
+
});
|
|
653
|
+
|
|
654
|
+
// Check for missing required props
|
|
655
|
+
validation.required.forEach(prop => {
|
|
656
|
+
if (props[prop] === undefined) {
|
|
657
|
+
warnings.push(`Required prop '${prop}' is missing in ${componentName}`);
|
|
658
|
+
}
|
|
659
|
+
});
|
|
660
|
+
|
|
661
|
+
return {
|
|
662
|
+
valid: warnings.length === 0,
|
|
663
|
+
warnings,
|
|
664
|
+
};
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// Validate hook usage
|
|
668
|
+
static validateHookUsage(hookName: string, args: any[]) {
|
|
669
|
+
const validations = {
|
|
670
|
+
useUnifiedAuth: {
|
|
671
|
+
args: 0,
|
|
672
|
+
description: 'No arguments required',
|
|
673
|
+
},
|
|
674
|
+
useRBAC: {
|
|
675
|
+
args: 0,
|
|
676
|
+
description: 'No arguments required',
|
|
677
|
+
},
|
|
678
|
+
useEvents: {
|
|
679
|
+
args: 0,
|
|
680
|
+
description: 'No arguments required',
|
|
681
|
+
},
|
|
682
|
+
};
|
|
683
|
+
|
|
684
|
+
const validation = validations[hookName];
|
|
685
|
+
if (!validation) return { valid: true, warnings: [] };
|
|
686
|
+
|
|
687
|
+
const warnings = [];
|
|
688
|
+
|
|
689
|
+
if (args.length !== validation.args) {
|
|
690
|
+
warnings.push(`${hookName} expects ${validation.args} arguments, got ${args.length}`);
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
return {
|
|
694
|
+
valid: warnings.length === 0,
|
|
695
|
+
warnings,
|
|
696
|
+
};
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
// Validate configuration
|
|
700
|
+
static validateConfiguration(config: any) {
|
|
701
|
+
const required = [
|
|
702
|
+
'VITE_SUPABASE_URL',
|
|
703
|
+
'VITE_SUPABASE_ANON_KEY',
|
|
704
|
+
];
|
|
705
|
+
|
|
706
|
+
const warnings = [];
|
|
707
|
+
|
|
708
|
+
required.forEach(key => {
|
|
709
|
+
if (!config[key]) {
|
|
710
|
+
warnings.push(`Required environment variable '${key}' is missing`);
|
|
711
|
+
}
|
|
712
|
+
});
|
|
713
|
+
|
|
714
|
+
return {
|
|
715
|
+
valid: warnings.length === 0,
|
|
716
|
+
warnings,
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
}
|
|
720
|
+
```
|
|
721
|
+
|
|
722
|
+
### 3. Migration Testing
|
|
723
|
+
|
|
724
|
+
```typescript
|
|
725
|
+
// utils/migrationTesting.ts
|
|
726
|
+
export class MigrationTesting {
|
|
727
|
+
// Test component migration
|
|
728
|
+
static testComponentMigration(componentName: string, oldProps: any, newProps: any) {
|
|
729
|
+
const migratedProps = MigrationHelpers.migrateComponentProps(oldProps, componentName);
|
|
730
|
+
|
|
731
|
+
const validation = MigrationValidation.validateComponentUsage(componentName, migratedProps);
|
|
732
|
+
|
|
733
|
+
return {
|
|
734
|
+
success: validation.valid,
|
|
735
|
+
warnings: validation.warnings,
|
|
736
|
+
oldProps,
|
|
737
|
+
newProps: migratedProps,
|
|
738
|
+
};
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
// Test hook migration
|
|
742
|
+
static testHookMigration(hookName: string, oldUsage: any, newUsage: any) {
|
|
743
|
+
const validation = MigrationValidation.validateHookUsage(hookName, newUsage.args);
|
|
744
|
+
|
|
745
|
+
return {
|
|
746
|
+
success: validation.valid,
|
|
747
|
+
warnings: validation.warnings,
|
|
748
|
+
oldUsage,
|
|
749
|
+
newUsage,
|
|
750
|
+
};
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
// Test data migration
|
|
754
|
+
static testDataMigration(oldData: any, newData: any) {
|
|
755
|
+
const migratedData = MigrationHelpers.migrateUserData(oldData);
|
|
756
|
+
|
|
757
|
+
return {
|
|
758
|
+
success: JSON.stringify(migratedData) === JSON.stringify(newData),
|
|
759
|
+
oldData,
|
|
760
|
+
newData: migratedData,
|
|
761
|
+
differences: this.findDifferences(oldData, migratedData),
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
// Find differences between objects
|
|
766
|
+
static findDifferences(obj1: any, obj2: any): Record<string, any> {
|
|
767
|
+
const differences: Record<string, any> = {};
|
|
768
|
+
|
|
769
|
+
const allKeys = new Set([...Object.keys(obj1), ...Object.keys(obj2)]);
|
|
770
|
+
|
|
771
|
+
allKeys.forEach(key => {
|
|
772
|
+
if (obj1[key] !== obj2[key]) {
|
|
773
|
+
differences[key] = {
|
|
774
|
+
old: obj1[key],
|
|
775
|
+
new: obj2[key],
|
|
776
|
+
};
|
|
777
|
+
}
|
|
778
|
+
});
|
|
779
|
+
|
|
780
|
+
return differences;
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
## Migration Best Practices
|
|
786
|
+
|
|
787
|
+
### 1. Migration Checklist
|
|
788
|
+
|
|
789
|
+
- [ ] Review breaking changes documentation
|
|
790
|
+
- [ ] Create migration plan
|
|
791
|
+
- [ ] Set up staging environment
|
|
792
|
+
- [ ] Backup current data
|
|
793
|
+
- [ ] Test migration in staging
|
|
794
|
+
- [ ] Update dependencies
|
|
795
|
+
- [ ] Migrate configuration
|
|
796
|
+
- [ ] Update code for new APIs
|
|
797
|
+
- [ ] Test all functionality
|
|
798
|
+
- [ ] Deploy to production
|
|
799
|
+
- [ ] Monitor for issues
|
|
800
|
+
- [ ] Clean up old code
|
|
801
|
+
|
|
802
|
+
### 2. Migration Strategy
|
|
803
|
+
|
|
804
|
+
```typescript
|
|
805
|
+
// Migration strategy implementation
|
|
806
|
+
export class MigrationStrategy {
|
|
807
|
+
static async executeMigration(fromVersion: string, toVersion: string) {
|
|
808
|
+
console.log(`Starting migration from ${fromVersion} to ${toVersion}`);
|
|
809
|
+
|
|
810
|
+
// 1. Pre-migration checks
|
|
811
|
+
const preChecks = await this.performPreChecks();
|
|
812
|
+
if (!preChecks.success) {
|
|
813
|
+
throw new Error(`Pre-migration checks failed: ${preChecks.errors.join(', ')}`);
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// 2. Backup current state
|
|
817
|
+
const backup = await this.createBackup();
|
|
818
|
+
console.log('Backup created:', backup.location);
|
|
819
|
+
|
|
820
|
+
// 3. Update dependencies
|
|
821
|
+
await this.updateDependencies(toVersion);
|
|
822
|
+
|
|
823
|
+
// 4. Migrate configuration
|
|
824
|
+
await this.migrateConfiguration();
|
|
825
|
+
|
|
826
|
+
// 5. Migrate code
|
|
827
|
+
await this.migrateCode();
|
|
828
|
+
|
|
829
|
+
// 6. Migrate data
|
|
830
|
+
await this.migrateData();
|
|
831
|
+
|
|
832
|
+
// 7. Post-migration validation
|
|
833
|
+
const validation = await this.validateMigration();
|
|
834
|
+
if (!validation.success) {
|
|
835
|
+
console.error('Migration validation failed:', validation.errors);
|
|
836
|
+
await this.rollback(backup);
|
|
837
|
+
throw new Error('Migration failed validation');
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
console.log('Migration completed successfully');
|
|
841
|
+
return { success: true, backup };
|
|
842
|
+
}
|
|
843
|
+
|
|
844
|
+
static async performPreChecks() {
|
|
845
|
+
const checks = [
|
|
846
|
+
this.checkDependencies(),
|
|
847
|
+
this.checkConfiguration(),
|
|
848
|
+
this.checkDataIntegrity(),
|
|
849
|
+
];
|
|
850
|
+
|
|
851
|
+
const results = await Promise.all(checks);
|
|
852
|
+
const errors = results.flatMap(r => r.errors || []);
|
|
853
|
+
|
|
854
|
+
return {
|
|
855
|
+
success: errors.length === 0,
|
|
856
|
+
errors,
|
|
857
|
+
};
|
|
858
|
+
}
|
|
859
|
+
|
|
860
|
+
static async createBackup() {
|
|
861
|
+
// Implementation for creating backup
|
|
862
|
+
return {
|
|
863
|
+
location: '/backups/migration-backup-' + Date.now(),
|
|
864
|
+
timestamp: new Date().toISOString(),
|
|
865
|
+
};
|
|
866
|
+
}
|
|
867
|
+
|
|
868
|
+
static async rollback(backup: any) {
|
|
869
|
+
console.log('Rolling back to backup:', backup.location);
|
|
870
|
+
// Implementation for rollback
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
```
|
|
874
|
+
|
|
875
|
+
### 3. Rollback Strategy
|
|
876
|
+
|
|
877
|
+
```typescript
|
|
878
|
+
// Rollback strategy implementation
|
|
879
|
+
export class RollbackStrategy {
|
|
880
|
+
static async rollbackMigration(backup: any) {
|
|
881
|
+
console.log('Starting rollback process...');
|
|
882
|
+
|
|
883
|
+
try {
|
|
884
|
+
// 1. Restore database
|
|
885
|
+
await this.restoreDatabase(backup.database);
|
|
886
|
+
|
|
887
|
+
// 2. Restore configuration
|
|
888
|
+
await this.restoreConfiguration(backup.config);
|
|
889
|
+
|
|
890
|
+
// 3. Restore code
|
|
891
|
+
await this.restoreCode(backup.code);
|
|
892
|
+
|
|
893
|
+
// 4. Restore dependencies
|
|
894
|
+
await this.restoreDependencies(backup.dependencies);
|
|
895
|
+
|
|
896
|
+
// 5. Validate rollback
|
|
897
|
+
const validation = await this.validateRollback();
|
|
898
|
+
|
|
899
|
+
if (validation.success) {
|
|
900
|
+
console.log('Rollback completed successfully');
|
|
901
|
+
return { success: true };
|
|
902
|
+
} else {
|
|
903
|
+
throw new Error('Rollback validation failed');
|
|
904
|
+
}
|
|
905
|
+
} catch (error) {
|
|
906
|
+
console.error('Rollback failed:', error);
|
|
907
|
+
throw error;
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
static async validateRollback() {
|
|
912
|
+
// Implementation for rollback validation
|
|
913
|
+
return { success: true };
|
|
914
|
+
}
|
|
915
|
+
}
|
|
916
|
+
```
|
|
917
|
+
|
|
918
|
+
For more information about migrating your application, see the [Common Issues Guide](./common-issues.md) and [Debugging Guide](./debugging.md).
|