@rebasepro/app 0.0.1-canary.4829d6e
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/LICENSE +21 -0
- package/README.md +174 -0
- package/dist/auth/api.d.ts +66 -0
- package/dist/auth/index.d.ts +13 -0
- package/dist/auth/types.d.ts +127 -0
- package/dist/auth/useRebaseAuthController.d.ts +13 -0
- package/dist/components/AIIcon.d.ts +17 -0
- package/dist/components/AuthSimulationMenu.d.ts +0 -0
- package/dist/components/ConfirmationDialog.d.ts +9 -0
- package/dist/components/Debug/UIReferenceView.d.ts +13 -0
- package/dist/components/Debug/UIStyleGuide.d.ts +2 -0
- package/dist/components/Debug/collection-views/CardViewDemo.d.ts +2 -0
- package/dist/components/Debug/collection-views/CollectionTableDemo.d.ts +2 -0
- package/dist/components/Debug/collection-views/KanbanBoardDemo.d.ts +2 -0
- package/dist/components/Debug/collection-views/index.d.ts +3 -0
- package/dist/components/Debug/collection-views/sample_data.d.ts +23 -0
- package/dist/components/Debug/crm-dashboard/CalendarWidget.d.ts +22 -0
- package/dist/components/Debug/crm-dashboard/CrmDashboardDemo.d.ts +2 -0
- package/dist/components/Debug/crm-dashboard/DashboardMetrics.d.ts +15 -0
- package/dist/components/Debug/crm-dashboard/PipelineOverview.d.ts +34 -0
- package/dist/components/Debug/crm-dashboard/RecentActivity.d.ts +19 -0
- package/dist/components/Debug/crm-dashboard/TaskFilters.d.ts +30 -0
- package/dist/components/Debug/crm-dashboard/TaskTable.d.ts +50 -0
- package/dist/components/Debug/crm-dashboard/TasksView.d.ts +41 -0
- package/dist/components/ErrorTooltip.d.ts +3 -0
- package/dist/components/ErrorView.d.ts +21 -0
- package/dist/components/LanguageToggle.d.ts +2 -0
- package/dist/components/LoginView/LoginView.d.ts +113 -0
- package/dist/components/LoginView/index.d.ts +2 -0
- package/dist/components/NotFoundPage.d.ts +2 -0
- package/dist/components/RebaseAuth.d.ts +10 -0
- package/dist/components/RebaseLogo.d.ts +7 -0
- package/dist/components/SchemaDriftBanner.d.ts +27 -0
- package/dist/components/UnsavedChangesDialog.d.ts +9 -0
- package/dist/components/UserDisplay.d.ts +7 -0
- package/dist/components/UserSelectPopover.d.ts +63 -0
- package/dist/components/UserSettingsView.d.ts +2 -0
- package/dist/components/common/index.d.ts +6 -0
- package/dist/components/common/table_height.d.ts +5 -0
- package/dist/components/common/types.d.ts +66 -0
- package/dist/components/common/useColumnsIds.d.ts +9 -0
- package/dist/components/common/useDataTableController.d.ts +45 -0
- package/dist/components/common/useDebouncedData.d.ts +9 -0
- package/dist/components/common/useScrollRestoration.d.ts +14 -0
- package/dist/components/index.d.ts +18 -0
- package/dist/contexts/AdminModeController.d.ts +4 -0
- package/dist/contexts/AnalyticsContext.d.ts +3 -0
- package/dist/contexts/AuthControllerContext.d.ts +3 -0
- package/dist/contexts/CollectionScopeContext.d.ts +50 -0
- package/dist/contexts/ComponentOverrideContext.d.ts +42 -0
- package/dist/contexts/CustomizationControllerContext.d.ts +3 -0
- package/dist/contexts/DataDriverContext.d.ts +3 -0
- package/dist/contexts/DataSourcesContext.d.ts +31 -0
- package/dist/contexts/DatabaseAdminContext.d.ts +3 -0
- package/dist/contexts/DialogsProvider.d.ts +4 -0
- package/dist/contexts/EffectiveRoleController.d.ts +4 -0
- package/dist/contexts/ModeController.d.ts +4 -0
- package/dist/contexts/RebaseClientInstanceContext.d.ts +6 -0
- package/dist/contexts/RebaseDataContext.d.ts +3 -0
- package/dist/contexts/SnackbarProvider.d.ts +2 -0
- package/dist/contexts/StorageSourceContext.d.ts +3 -0
- package/dist/contexts/StorageSourcesContext.d.ts +25 -0
- package/dist/contexts/UserConfigurationPersistenceContext.d.ts +3 -0
- package/dist/contexts/index.d.ts +17 -0
- package/dist/core/PluginLifecycleManager.d.ts +17 -0
- package/dist/core/PluginProviderStack.d.ts +21 -0
- package/dist/core/Rebase.d.ts +15 -0
- package/dist/core/RebaseProps.d.ts +291 -0
- package/dist/core/RebaseRouter.d.ts +4 -0
- package/dist/core/RebaseRoutes.d.ts +17 -0
- package/dist/core/index.d.ts +4 -0
- package/dist/hooks/ApiConfigContext.d.ts +24 -0
- package/dist/hooks/data/delete.d.ts +33 -0
- package/dist/hooks/data/save.d.ts +40 -0
- package/dist/hooks/data/useCollection.d.ts +62 -0
- package/dist/hooks/data/useData.d.ts +13 -0
- package/dist/hooks/data/useDataOrder.d.ts +12 -0
- package/dist/hooks/data/useFetch.d.ts +43 -0
- package/dist/hooks/data/useRelationSelector.d.ts +52 -0
- package/dist/hooks/index.d.ts +36 -0
- package/dist/hooks/useAdminModeController.d.ts +19 -0
- package/dist/hooks/useAnalyticsController.d.ts +5 -0
- package/dist/hooks/useAuthController.d.ts +11 -0
- package/dist/hooks/useAuthSubscription.d.ts +2 -0
- package/dist/hooks/useBackendStorageSource.d.ts +30 -0
- package/dist/hooks/useBridgeRegistration.d.ts +18 -0
- package/dist/hooks/useBrowserTitleAndIcon.d.ts +6 -0
- package/dist/hooks/useBuildAdminModeController.d.ts +6 -0
- package/dist/hooks/useBuildEffectiveRoleController.d.ts +8 -0
- package/dist/hooks/useBuildLocalConfigurationPersistence.d.ts +2 -0
- package/dist/hooks/useBuildModeController.d.ts +6 -0
- package/dist/hooks/useClipboard.d.ts +57 -0
- package/dist/hooks/useCollapsedGroups.d.ts +27 -0
- package/dist/hooks/useComponentOverride.d.ts +32 -0
- package/dist/hooks/useCustomizationController.d.ts +11 -0
- package/dist/hooks/useDialogsController.d.ts +11 -0
- package/dist/hooks/useEffectiveRoleController.d.ts +7 -0
- package/dist/hooks/useLargeLayout.d.ts +1 -0
- package/dist/hooks/useModeController.d.ts +19 -0
- package/dist/hooks/usePermissions.d.ts +12 -0
- package/dist/hooks/useRebaseClient.d.ts +5 -0
- package/dist/hooks/useRebaseContext.d.ts +11 -0
- package/dist/hooks/useRebaseRegistry.d.ts +34 -0
- package/dist/hooks/useResolvedComponent.d.ts +47 -0
- package/dist/hooks/useSlot.d.ts +18 -0
- package/dist/hooks/useSnackbarController.d.ts +20 -0
- package/dist/hooks/useStorageSource.d.ts +6 -0
- package/dist/hooks/useStudioBridge.d.ts +79 -0
- package/dist/hooks/useTranslation.d.ts +17 -0
- package/dist/hooks/useUnsavedChangesDialog.d.ts +12 -0
- package/dist/hooks/useUserConfigurationPersistence.d.ts +8 -0
- package/dist/i18n/RebaseI18nProvider.d.ts +33 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.es.js +16843 -0
- package/dist/index.es.js.map +1 -0
- package/dist/index.umd.js +17021 -0
- package/dist/index.umd.js.map +1 -0
- package/dist/internal/common.d.ts +14 -0
- package/dist/internal/useRestoreScroll.d.ts +15 -0
- package/dist/locales/de.d.ts +2 -0
- package/dist/locales/en.d.ts +10 -0
- package/dist/locales/es.d.ts +10 -0
- package/dist/locales/fr.d.ts +2 -0
- package/dist/locales/hi.d.ts +2 -0
- package/dist/locales/it.d.ts +2 -0
- package/dist/locales/pt.d.ts +7 -0
- package/dist/util/constants.d.ts +1 -0
- package/dist/util/createFormexStub.d.ts +2 -0
- package/dist/util/entity_cache.d.ts +22 -0
- package/dist/util/enums.d.ts +5 -0
- package/dist/util/icon_list.d.ts +5 -0
- package/dist/util/icons.d.ts +20 -0
- package/dist/util/index.d.ts +8 -0
- package/dist/util/previews.d.ts +4 -0
- package/dist/util/useStorageUploadController.d.ts +44 -0
- package/dist/vitePlugin.d.ts +60 -0
- package/dist/vitePlugin.js +113 -0
- package/package.json +145 -0
- package/src/auth/api.ts +148 -0
- package/src/auth/index.ts +25 -0
- package/src/auth/types.ts +115 -0
- package/src/auth/useRebaseAuthController.ts +328 -0
- package/src/components/AIIcon.tsx +47 -0
- package/src/components/AuthSimulationMenu.tsx +0 -0
- package/src/components/ConfirmationDialog.tsx +48 -0
- package/src/components/Debug/UIReferenceView.tsx +958 -0
- package/src/components/Debug/UIStyleGuide.tsx +156 -0
- package/src/components/Debug/collection-views/CardViewDemo.tsx +85 -0
- package/src/components/Debug/collection-views/CollectionTableDemo.tsx +107 -0
- package/src/components/Debug/collection-views/KanbanBoardDemo.tsx +90 -0
- package/src/components/Debug/collection-views/index.ts +3 -0
- package/src/components/Debug/collection-views/sample_data.ts +42 -0
- package/src/components/Debug/crm-dashboard/CalendarWidget.tsx +389 -0
- package/src/components/Debug/crm-dashboard/CrmDashboardDemo.tsx +1102 -0
- package/src/components/Debug/crm-dashboard/DashboardMetrics.tsx +133 -0
- package/src/components/Debug/crm-dashboard/PipelineOverview.tsx +290 -0
- package/src/components/Debug/crm-dashboard/RecentActivity.tsx +215 -0
- package/src/components/Debug/crm-dashboard/TaskFilters.tsx +184 -0
- package/src/components/Debug/crm-dashboard/TaskTable.tsx +427 -0
- package/src/components/Debug/crm-dashboard/TasksView.tsx +234 -0
- package/src/components/ErrorTooltip.tsx +12 -0
- package/src/components/ErrorView.tsx +94 -0
- package/src/components/LanguageToggle.tsx +59 -0
- package/src/components/LoginView/LoginView.tsx +932 -0
- package/src/components/LoginView/index.ts +2 -0
- package/src/components/NotFoundPage.tsx +27 -0
- package/src/components/RebaseAuth.tsx +27 -0
- package/src/components/RebaseLogo.tsx +29 -0
- package/src/components/SchemaDriftBanner.tsx +102 -0
- package/src/components/UnsavedChangesDialog.tsx +46 -0
- package/src/components/UserDisplay.tsx +54 -0
- package/src/components/UserSelectPopover.tsx +399 -0
- package/src/components/UserSettingsView.tsx +318 -0
- package/src/components/common/index.ts +6 -0
- package/src/components/common/table_height.tsx +21 -0
- package/src/components/common/types.tsx +66 -0
- package/src/components/common/useColumnsIds.tsx +222 -0
- package/src/components/common/useDataTableController.tsx +514 -0
- package/src/components/common/useDebouncedData.ts +49 -0
- package/src/components/common/useScrollRestoration.tsx +68 -0
- package/src/components/index.tsx +26 -0
- package/src/contexts/AdminModeController.tsx +11 -0
- package/src/contexts/AnalyticsContext.tsx +4 -0
- package/src/contexts/AuthControllerContext.tsx +4 -0
- package/src/contexts/CollectionScopeContext.tsx +67 -0
- package/src/contexts/ComponentOverrideContext.tsx +81 -0
- package/src/contexts/CustomizationControllerContext.tsx +4 -0
- package/src/contexts/DataDriverContext.tsx +4 -0
- package/src/contexts/DataSourcesContext.tsx +36 -0
- package/src/contexts/DatabaseAdminContext.tsx +4 -0
- package/src/contexts/DialogsProvider.tsx +56 -0
- package/src/contexts/EffectiveRoleController.tsx +12 -0
- package/src/contexts/ModeController.tsx +11 -0
- package/src/contexts/RebaseClientInstanceContext.tsx +7 -0
- package/src/contexts/RebaseDataContext.tsx +4 -0
- package/src/contexts/SnackbarProvider.tsx +15 -0
- package/src/contexts/StorageSourceContext.tsx +4 -0
- package/src/contexts/StorageSourcesContext.tsx +30 -0
- package/src/contexts/UserConfigurationPersistenceContext.tsx +4 -0
- package/src/contexts/index.ts +17 -0
- package/src/core/PluginLifecycleManager.tsx +95 -0
- package/src/core/PluginProviderStack.tsx +40 -0
- package/src/core/Rebase.tsx +439 -0
- package/src/core/RebaseProps.tsx +320 -0
- package/src/core/RebaseRouter.tsx +17 -0
- package/src/core/RebaseRoutes.tsx +24 -0
- package/src/core/index.tsx +5 -0
- package/src/hooks/ApiConfigContext.tsx +41 -0
- package/src/hooks/data/delete.ts +55 -0
- package/src/hooks/data/save.ts +77 -0
- package/src/hooks/data/useCollection.tsx +176 -0
- package/src/hooks/data/useData.tsx +18 -0
- package/src/hooks/data/useDataOrder.ts +26 -0
- package/src/hooks/data/useFetch.tsx +140 -0
- package/src/hooks/data/useRelationSelector.tsx +234 -0
- package/src/hooks/index.tsx +45 -0
- package/src/hooks/useAdminModeController.tsx +23 -0
- package/src/hooks/useAnalyticsController.tsx +8 -0
- package/src/hooks/useAuthController.tsx +14 -0
- package/src/hooks/useAuthSubscription.ts +87 -0
- package/src/hooks/useBackendStorageSource.ts +288 -0
- package/src/hooks/useBridgeRegistration.tsx +32 -0
- package/src/hooks/useBrowserTitleAndIcon.tsx +23 -0
- package/src/hooks/useBuildAdminModeController.tsx +24 -0
- package/src/hooks/useBuildEffectiveRoleController.tsx +31 -0
- package/src/hooks/useBuildLocalConfigurationPersistence.tsx +75 -0
- package/src/hooks/useBuildModeController.tsx +71 -0
- package/src/hooks/useClipboard.tsx +158 -0
- package/src/hooks/useCollapsedGroups.ts +116 -0
- package/src/hooks/useComponentOverride.tsx +59 -0
- package/src/hooks/useCustomizationController.tsx +14 -0
- package/src/hooks/useDialogsController.tsx +15 -0
- package/src/hooks/useEffectiveRoleController.tsx +10 -0
- package/src/hooks/useLargeLayout.tsx +65 -0
- package/src/hooks/useModeController.tsx +23 -0
- package/src/hooks/usePermissions.ts +44 -0
- package/src/hooks/useRebaseClient.tsx +10 -0
- package/src/hooks/useRebaseContext.tsx +83 -0
- package/src/hooks/useRebaseRegistry.tsx +91 -0
- package/src/hooks/useResolvedComponent.tsx +159 -0
- package/src/hooks/useSlot.tsx +64 -0
- package/src/hooks/useSnackbarController.tsx +52 -0
- package/src/hooks/useStorageSource.tsx +11 -0
- package/src/hooks/useStudioBridge.tsx +209 -0
- package/src/hooks/useTranslation.ts +33 -0
- package/src/hooks/useUnsavedChangesDialog.tsx +64 -0
- package/src/hooks/useUserConfigurationPersistence.tsx +11 -0
- package/src/i18n/RebaseI18nProvider.tsx +160 -0
- package/src/index.ts +25 -0
- package/src/internal/common.tsx +16 -0
- package/src/internal/useRestoreScroll.tsx +69 -0
- package/src/locales/de.ts +902 -0
- package/src/locales/en.ts +980 -0
- package/src/locales/es.ts +922 -0
- package/src/locales/fr.ts +901 -0
- package/src/locales/hi.ts +901 -0
- package/src/locales/it.ts +901 -0
- package/src/locales/pt.ts +909 -0
- package/src/util/constants.ts +7 -0
- package/src/util/createFormexStub.tsx +66 -0
- package/src/util/entity_cache.ts +239 -0
- package/src/util/enums.ts +32 -0
- package/src/util/icon_list.ts +22 -0
- package/src/util/icons.tsx +149 -0
- package/src/util/index.ts +12 -0
- package/src/util/previews.ts +105 -0
- package/src/util/useStorageUploadController.tsx +350 -0
- package/src/vitePlugin.ts +196 -0
package/src/auth/api.ts
ADDED
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Auth-config fetch helper for the Rebase React frontend.
|
|
3
|
+
*
|
|
4
|
+
* The former per-endpoint auth client (login, register, refresh, OAuth,
|
|
5
|
+
* sessions, …) has been removed: `useRebaseAuthController` now delegates to
|
|
6
|
+
* the headless SDK's `client.auth` (from `@rebasepro/client`), which is the
|
|
7
|
+
* single source of truth for the auth session. The only piece that remains
|
|
8
|
+
* here is the unauthenticated `/api/auth/config` probe used to detect
|
|
9
|
+
* bootstrap mode and enabled providers before a session exists.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { RebaseApiError } from "@rebasepro/types";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* @deprecated Use {@link RebaseApiError} (from `@rebasepro/types`, re-exported by
|
|
16
|
+
* `@rebasepro/client`). Kept as an alias so `instanceof` / imports keep working;
|
|
17
|
+
* errors thrown here now carry `.code` and `.status` on the unified type.
|
|
18
|
+
*/
|
|
19
|
+
export const AuthApiError = RebaseApiError;
|
|
20
|
+
|
|
21
|
+
async function handleResponse<T>(response: Response): Promise<T> {
|
|
22
|
+
let data: Record<string, unknown>;
|
|
23
|
+
try {
|
|
24
|
+
data = await response.json();
|
|
25
|
+
} catch (parseError) {
|
|
26
|
+
// Response wasn't JSON - could be network error or server issue
|
|
27
|
+
throw new RebaseApiError(
|
|
28
|
+
`Server returned non-JSON response (status: ${response.status})`,
|
|
29
|
+
{ status: response.status, code: "PARSE_ERROR" }
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
throw new RebaseApiError(
|
|
35
|
+
(data as Record<string, Record<string, string>>).error?.message || "Request failed",
|
|
36
|
+
{
|
|
37
|
+
status: response.status,
|
|
38
|
+
code: (data as Record<string, Record<string, string>>).error?.code || "UNKNOWN_ERROR"
|
|
39
|
+
}
|
|
40
|
+
);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return data as T;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Wrapper for fetch that catches generic network failures (like server down)
|
|
48
|
+
* and translates them to a {@link RebaseApiError} with code `NETWORK_ERROR`.
|
|
49
|
+
*/
|
|
50
|
+
async function fetchWithHandling(input: RequestInfo | URL, init?: RequestInit): Promise<Response> {
|
|
51
|
+
try {
|
|
52
|
+
return await fetch(input, init);
|
|
53
|
+
} catch (error: unknown) {
|
|
54
|
+
if (error instanceof TypeError && error.message.includes("Failed to fetch")) {
|
|
55
|
+
throw new RebaseApiError(
|
|
56
|
+
"Failed to connect to the backend server. The backend might be down or failed to initialize (e.g., database connection timeout).",
|
|
57
|
+
{ code: "NETWORK_ERROR", cause: error }
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
throw new RebaseApiError(
|
|
61
|
+
"Network error: " + (error instanceof Error ? error.message : String(error)),
|
|
62
|
+
{ code: "NETWORK_ERROR", cause: error }
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Auth config response from the backend
|
|
69
|
+
*/
|
|
70
|
+
export interface AuthConfigResponse {
|
|
71
|
+
/** True when there are no users in the system and first user setup is needed */
|
|
72
|
+
needsSetup: boolean;
|
|
73
|
+
/** Whether new user registration is enabled */
|
|
74
|
+
registrationEnabled: boolean;
|
|
75
|
+
/** Whether email service is configured */
|
|
76
|
+
emailServiceEnabled?: boolean;
|
|
77
|
+
/** Whether the self-service password reset flow (email link) is supported */
|
|
78
|
+
passwordReset?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Whether an admin can reset another user's password, i.e. the adapter
|
|
81
|
+
* mounts `POST /admin/users/:userId/reset-password`. Absent on backends
|
|
82
|
+
* predating this field, which the frontend treats as supported.
|
|
83
|
+
*/
|
|
84
|
+
adminPasswordReset?: boolean;
|
|
85
|
+
/** Whether email verification is supported */
|
|
86
|
+
emailVerification?: boolean;
|
|
87
|
+
/** Complete list of enabled OAuth provider IDs (e.g. ["google", "github", "discord"]) */
|
|
88
|
+
enabledProviders: string[];
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Cache container for `fetchAuthConfig` — holds both the inflight promise
|
|
93
|
+
* (to deduplicate concurrent calls) and the cached result.
|
|
94
|
+
*/
|
|
95
|
+
export interface AuthConfigCache {
|
|
96
|
+
cached: AuthConfigResponse | null;
|
|
97
|
+
inflight: Promise<AuthConfigResponse> | null;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Create a fresh `AuthConfigCache` instance.
|
|
102
|
+
* Callers own the cache object and pass it into `fetchAuthConfig` / `clearAuthConfigCache`.
|
|
103
|
+
*/
|
|
104
|
+
export function createAuthConfigCache(): AuthConfigCache {
|
|
105
|
+
return { cached: null, inflight: null };
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Fetch auth configuration / status from the backend
|
|
110
|
+
* This is an unauthenticated endpoint used to detect bootstrap mode.
|
|
111
|
+
*
|
|
112
|
+
* Results are cached for the session lifetime.
|
|
113
|
+
* Concurrent calls are deduplicated: only one network request is made
|
|
114
|
+
* and all callers share the same promise.
|
|
115
|
+
*/
|
|
116
|
+
export async function fetchAuthConfig(apiUrl: string, cache: AuthConfigCache): Promise<AuthConfigResponse> {
|
|
117
|
+
if (cache.cached) {
|
|
118
|
+
return cache.cached;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (cache.inflight) {
|
|
122
|
+
return cache.inflight;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
cache.inflight = (async () => {
|
|
126
|
+
const response = await fetchWithHandling(`${apiUrl}/api/auth/config`, {
|
|
127
|
+
method: "GET",
|
|
128
|
+
headers: { "Content-Type": "application/json" }
|
|
129
|
+
});
|
|
130
|
+
return handleResponse<AuthConfigResponse>(response);
|
|
131
|
+
})();
|
|
132
|
+
|
|
133
|
+
try {
|
|
134
|
+
const result = await cache.inflight;
|
|
135
|
+
cache.cached = result;
|
|
136
|
+
return result;
|
|
137
|
+
} finally {
|
|
138
|
+
cache.inflight = null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Clear the cached auth config (e.g. on logout or for testing).
|
|
144
|
+
*/
|
|
145
|
+
export function clearAuthConfigCache(cache: AuthConfigCache): void {
|
|
146
|
+
cache.cached = null;
|
|
147
|
+
cache.inflight = null;
|
|
148
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rebasepro/app
|
|
3
|
+
*
|
|
4
|
+
* React authentication controller for Rebase frontends.
|
|
5
|
+
* Provides the `useRebaseAuthController` hook and API utilities
|
|
6
|
+
* for communicating with a Rebase backend's JWT auth endpoints.
|
|
7
|
+
*
|
|
8
|
+
* For the generic LoginView and RebaseAuth components, see @rebasepro/app.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
// Types
|
|
12
|
+
export type {
|
|
13
|
+
RebaseAuthController,
|
|
14
|
+
RebaseAuthControllerProps,
|
|
15
|
+
AuthTokens,
|
|
16
|
+
DeviceSession,
|
|
17
|
+
UserInfo,
|
|
18
|
+
AuthResponse,
|
|
19
|
+
RefreshResponse
|
|
20
|
+
} from "./types";
|
|
21
|
+
|
|
22
|
+
export { useRebaseAuthController } from "./useRebaseAuthController";
|
|
23
|
+
// API utilities
|
|
24
|
+
export { fetchAuthConfig, clearAuthConfigCache, createAuthConfigCache, AuthApiError } from "./api";
|
|
25
|
+
export type { AuthConfigResponse, AuthConfigCache } from "./api";
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import { AuthController, User, AuthTokens, DeviceSession, RebaseSession, AuthChangeEvent } from "@rebasepro/types";
|
|
2
|
+
import type { AuthConfigResponse } from "./api";
|
|
3
|
+
|
|
4
|
+
/** @deprecated Use `User` from `@rebasepro/types` instead. */
|
|
5
|
+
export type UserInfo = User;
|
|
6
|
+
/** @deprecated Use `DeviceSession` from `@rebasepro/types` instead. */
|
|
7
|
+
export type Session = DeviceSession;
|
|
8
|
+
// Re-export canonical types for backward compatibility
|
|
9
|
+
export type { AuthTokens, DeviceSession };
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Auth controller that extends the base AuthController
|
|
13
|
+
* with additional methods for email/password and Google login
|
|
14
|
+
*/
|
|
15
|
+
export type RebaseAuthController = AuthController & {
|
|
16
|
+
/** Login with Google — accepts an ID token, access token, or authorization code payload */
|
|
17
|
+
googleLogin: (payload: { idToken: string } | { accessToken: string } | { code: string; redirectUri: string }) => Promise<void>;
|
|
18
|
+
/** Generic OAuth login — works with any provider. Posts payload to /auth/{providerId}. */
|
|
19
|
+
oauthLogin: (providerId: string, payload: Record<string, unknown>) => Promise<void>;
|
|
20
|
+
/** Login with email and password */
|
|
21
|
+
emailPasswordLogin: (email: string, password: string) => Promise<void>;
|
|
22
|
+
/** Register a new user */
|
|
23
|
+
register: (email: string, password: string, displayName?: string) => Promise<void>;
|
|
24
|
+
/** Skip login (for anonymous access if enabled) */
|
|
25
|
+
skipLogin: () => void;
|
|
26
|
+
/** Whether login was skipped */
|
|
27
|
+
loginSkipped: boolean;
|
|
28
|
+
/** Error from auth provider (login failure details) */
|
|
29
|
+
authProviderError: Error | null;
|
|
30
|
+
/** True when there are no users in the system — first-user bootstrap mode */
|
|
31
|
+
needsSetup: boolean;
|
|
32
|
+
/** Whether new user registration is enabled (always true during setup) */
|
|
33
|
+
registrationEnabled: boolean;
|
|
34
|
+
/** Request password reset email */
|
|
35
|
+
forgotPassword: (email: string) => Promise<void>;
|
|
36
|
+
/** Reset password using token from email */
|
|
37
|
+
resetPassword: (token: string, password: string) => Promise<void>;
|
|
38
|
+
/** Change password for authenticated user */
|
|
39
|
+
changePassword: (oldPassword: string, newPassword: string) => Promise<void>;
|
|
40
|
+
/** Update user profile */
|
|
41
|
+
updateProfile: (displayName?: string, photoURL?: string) => Promise<User>;
|
|
42
|
+
/** Fetch active sessions */
|
|
43
|
+
fetchSessions: () => Promise<DeviceSession[]>;
|
|
44
|
+
/** Revoke a session */
|
|
45
|
+
revokeSession: (sessionId: string) => Promise<void>;
|
|
46
|
+
/** Revoke all active sessions */
|
|
47
|
+
revokeAllSessions: () => Promise<void>;
|
|
48
|
+
/** Get internal API URL */
|
|
49
|
+
getApiUrl?: () => string | undefined;
|
|
50
|
+
/** Clear the current auth provider error */
|
|
51
|
+
clearError: () => void;
|
|
52
|
+
/** Set or clear the auth provider error */
|
|
53
|
+
setAuthProviderError: (error: Error | null) => void;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Structural type for the subset of `client.auth` (from `@rebasepro/client`)
|
|
58
|
+
* that the React hook delegates to. Avoids a hard dependency on
|
|
59
|
+
* `@rebasepro/client` while remaining fully type-safe.
|
|
60
|
+
*/
|
|
61
|
+
export interface ClientAuth {
|
|
62
|
+
getSession(): RebaseSession | null;
|
|
63
|
+
onAuthStateChange(callback: (event: AuthChangeEvent, session: RebaseSession | null) => void): () => void;
|
|
64
|
+
isInitialized(): Promise<void>;
|
|
65
|
+
getAuthConfig(): Promise<AuthConfigResponse>;
|
|
66
|
+
signInWithEmail(email: string, password: string): Promise<unknown>;
|
|
67
|
+
signOut(): Promise<void>;
|
|
68
|
+
refreshSession(): Promise<RebaseSession>;
|
|
69
|
+
signUp(email: string, password: string, displayName?: string): Promise<unknown>;
|
|
70
|
+
signInWithGoogle(payload: { idToken: string } | { accessToken: string } | { code: string; redirectUri: string }): Promise<unknown>;
|
|
71
|
+
signInWithOAuth(providerId: string, payload: Record<string, unknown>): Promise<unknown>;
|
|
72
|
+
resetPasswordForEmail(email: string): Promise<unknown>;
|
|
73
|
+
resetPassword(token: string, password: string): Promise<unknown>;
|
|
74
|
+
changePassword(oldPassword: string, newPassword: string): Promise<unknown>;
|
|
75
|
+
updateUser(updates: { displayName?: string; photoURL?: string }): Promise<User>;
|
|
76
|
+
getSessions(): Promise<DeviceSession[]>;
|
|
77
|
+
revokeSession(sessionId: string): Promise<unknown>;
|
|
78
|
+
revokeAllSessions(): Promise<unknown>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Props for useRebaseAuthController hook
|
|
83
|
+
*/
|
|
84
|
+
export interface RebaseAuthControllerProps {
|
|
85
|
+
/** The Rebase Client instance */
|
|
86
|
+
client?: {
|
|
87
|
+
baseUrl?: string;
|
|
88
|
+
resolveToken?: () => Promise<string | null>;
|
|
89
|
+
setAuthTokenGetter?: (getter: () => Promise<string | null>) => void;
|
|
90
|
+
setOnUnauthorized?: (handler: () => Promise<boolean>) => void;
|
|
91
|
+
ws?: { setAuthTokenGetter: (getter: () => Promise<string | null>) => void };
|
|
92
|
+
auth?: ClientAuth;
|
|
93
|
+
};
|
|
94
|
+
/** Google OAuth client ID (optional, enables Google login) */
|
|
95
|
+
googleClientId?: string;
|
|
96
|
+
/** Callback when user signs out */
|
|
97
|
+
onSignOut?: () => void;
|
|
98
|
+
/** Define roles for a user after login */
|
|
99
|
+
defineRolesFor?: (user: User) => Promise<string[] | undefined> | string[] | undefined;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Auth response from backend login/register endpoints
|
|
104
|
+
*/
|
|
105
|
+
export interface AuthResponse {
|
|
106
|
+
user: User;
|
|
107
|
+
tokens: AuthTokens;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Response from token refresh endpoint
|
|
112
|
+
*/
|
|
113
|
+
export interface RefreshResponse {
|
|
114
|
+
tokens: AuthTokens;
|
|
115
|
+
}
|
|
@@ -0,0 +1,328 @@
|
|
|
1
|
+
import { useCallback, useEffect, useRef, useState } from "react";
|
|
2
|
+
import type { User, AuthChangeEvent, RebaseSession } from "@rebasepro/types";
|
|
3
|
+
import type { AuthConfigResponse } from "./api";
|
|
4
|
+
import { RebaseAuthController, RebaseAuthControllerProps } from "./types";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Auth controller hook for JWT-based authentication.
|
|
8
|
+
*
|
|
9
|
+
* This is a thin React binding over the headless SDK `client.auth`.
|
|
10
|
+
* It synchronizes React state with the SDK's internal state and delegates
|
|
11
|
+
* all operations to the SDK to ensure a single source of truth for
|
|
12
|
+
* authentication sessions across the entire application.
|
|
13
|
+
*
|
|
14
|
+
* @param props Configuration options
|
|
15
|
+
* @returns RebaseAuthController instance
|
|
16
|
+
*/
|
|
17
|
+
export function useRebaseAuthController(
|
|
18
|
+
props: RebaseAuthControllerProps = {}
|
|
19
|
+
): RebaseAuthController {
|
|
20
|
+
const { client, onSignOut, defineRolesFor } = props;
|
|
21
|
+
const auth = client?.auth;
|
|
22
|
+
|
|
23
|
+
const [user, setUser] = useState<User | null>(null);
|
|
24
|
+
const [authLoading, setAuthLoading] = useState(false);
|
|
25
|
+
const [initialLoading, setInitialLoading] = useState(true);
|
|
26
|
+
const [authError, setAuthError] = useState<Error | null>(null);
|
|
27
|
+
const [authProviderError, setAuthProviderError] = useState<Error | null>(null);
|
|
28
|
+
const [loginSkipped, setLoginSkipped] = useState(false);
|
|
29
|
+
const [extra, setExtra] = useState<unknown>(null);
|
|
30
|
+
const [authConfig, setAuthConfig] = useState<AuthConfigResponse | null>(null);
|
|
31
|
+
|
|
32
|
+
const isMountedRef = useRef(true);
|
|
33
|
+
// Keep a stable ref to onSignOut so the listener never goes stale.
|
|
34
|
+
const onSignOutRef = useRef(onSignOut);
|
|
35
|
+
onSignOutRef.current = onSignOut;
|
|
36
|
+
// Keep a stable ref to defineRolesFor too, so an inline (non-memoized)
|
|
37
|
+
// function from the consumer does not re-run the sync effect on every
|
|
38
|
+
// render — which would re-subscribe to auth events and re-fetch the
|
|
39
|
+
// (uncached) auth config each time.
|
|
40
|
+
const defineRolesForRef = useRef(defineRolesFor);
|
|
41
|
+
defineRolesForRef.current = defineRolesFor;
|
|
42
|
+
|
|
43
|
+
const clearError = useCallback(() => {
|
|
44
|
+
setAuthProviderError(null);
|
|
45
|
+
}, []);
|
|
46
|
+
|
|
47
|
+
// Sync state with client.auth
|
|
48
|
+
useEffect(() => {
|
|
49
|
+
if (!auth) {
|
|
50
|
+
setInitialLoading(false);
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
isMountedRef.current = true;
|
|
55
|
+
|
|
56
|
+
const updateState = async (session: RebaseSession | null) => {
|
|
57
|
+
if (!isMountedRef.current) return;
|
|
58
|
+
|
|
59
|
+
let userToSet = session?.user ?? null;
|
|
60
|
+
const defineRolesFor = defineRolesForRef.current;
|
|
61
|
+
if (userToSet && defineRolesFor) {
|
|
62
|
+
try {
|
|
63
|
+
const roles = await defineRolesFor(userToSet);
|
|
64
|
+
if (roles && isMountedRef.current) {
|
|
65
|
+
userToSet = { ...userToSet, roles };
|
|
66
|
+
}
|
|
67
|
+
} catch (e) {
|
|
68
|
+
console.error("Error defining roles:", e);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (isMountedRef.current) {
|
|
73
|
+
setUser(userToSet);
|
|
74
|
+
}
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
const syncState = async (event: AuthChangeEvent, session: RebaseSession | null) => {
|
|
78
|
+
await updateState(session);
|
|
79
|
+
if (event === "SIGNED_OUT") {
|
|
80
|
+
if (isMountedRef.current) {
|
|
81
|
+
setLoginSkipped(false);
|
|
82
|
+
}
|
|
83
|
+
onSignOutRef.current?.();
|
|
84
|
+
}
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
// Initial sync with whatever is currently in the SDK
|
|
88
|
+
updateState(auth.getSession());
|
|
89
|
+
|
|
90
|
+
// Wait for SDK initialization (restoring session from storage or silent refresh)
|
|
91
|
+
auth.isInitialized().then(() => {
|
|
92
|
+
if (isMountedRef.current) {
|
|
93
|
+
updateState(auth.getSession());
|
|
94
|
+
setInitialLoading(false);
|
|
95
|
+
}
|
|
96
|
+
}).catch(() => {
|
|
97
|
+
if (isMountedRef.current) setInitialLoading(false);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// Fetch backend auth configuration
|
|
101
|
+
auth.getAuthConfig().then((config: AuthConfigResponse) => {
|
|
102
|
+
if (isMountedRef.current) setAuthConfig(config);
|
|
103
|
+
}).catch(() => {});
|
|
104
|
+
|
|
105
|
+
const unsubscribe = auth.onAuthStateChange(syncState);
|
|
106
|
+
|
|
107
|
+
return () => {
|
|
108
|
+
isMountedRef.current = false;
|
|
109
|
+
unsubscribe();
|
|
110
|
+
};
|
|
111
|
+
}, [auth]);
|
|
112
|
+
|
|
113
|
+
const getAuthToken = useCallback(async (): Promise<string> => {
|
|
114
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
115
|
+
const session = auth.getSession();
|
|
116
|
+
|
|
117
|
+
// If we have a valid token, return it
|
|
118
|
+
if (session?.accessToken && session.expiresAt > Date.now() + 10000) {
|
|
119
|
+
return session.accessToken;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Otherwise, refresh
|
|
123
|
+
const newSession = await auth.refreshSession();
|
|
124
|
+
return newSession.accessToken;
|
|
125
|
+
}, [auth]);
|
|
126
|
+
|
|
127
|
+
const signOut = useCallback(async () => {
|
|
128
|
+
if (!auth) return;
|
|
129
|
+
setAuthLoading(true);
|
|
130
|
+
try {
|
|
131
|
+
await auth.signOut();
|
|
132
|
+
// signOut emits SIGNED_OUT → syncState calls onSignOutRef.current
|
|
133
|
+
} catch (error: unknown) {
|
|
134
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
135
|
+
setAuthProviderError(err);
|
|
136
|
+
} finally {
|
|
137
|
+
setAuthLoading(false);
|
|
138
|
+
}
|
|
139
|
+
}, [auth]);
|
|
140
|
+
|
|
141
|
+
const emailPasswordLogin = useCallback(async (email: string, password: string) => {
|
|
142
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
143
|
+
setAuthLoading(true);
|
|
144
|
+
setAuthProviderError(null);
|
|
145
|
+
try {
|
|
146
|
+
await auth.signInWithEmail(email, password);
|
|
147
|
+
} catch (error: unknown) {
|
|
148
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
149
|
+
setAuthProviderError(err);
|
|
150
|
+
throw error;
|
|
151
|
+
} finally {
|
|
152
|
+
setAuthLoading(false);
|
|
153
|
+
}
|
|
154
|
+
}, [auth]);
|
|
155
|
+
|
|
156
|
+
const register = useCallback(async (email: string, password: string, displayName?: string) => {
|
|
157
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
158
|
+
setAuthLoading(true);
|
|
159
|
+
setAuthProviderError(null);
|
|
160
|
+
try {
|
|
161
|
+
await auth.signUp(email, password, displayName);
|
|
162
|
+
} catch (error: unknown) {
|
|
163
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
164
|
+
setAuthProviderError(err);
|
|
165
|
+
throw error;
|
|
166
|
+
} finally {
|
|
167
|
+
setAuthLoading(false);
|
|
168
|
+
}
|
|
169
|
+
}, [auth]);
|
|
170
|
+
|
|
171
|
+
const googleLogin = useCallback(async (
|
|
172
|
+
payload: { idToken: string } | { accessToken: string } | { code: string; redirectUri: string }
|
|
173
|
+
) => {
|
|
174
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
175
|
+
setAuthLoading(true);
|
|
176
|
+
setAuthProviderError(null);
|
|
177
|
+
try {
|
|
178
|
+
await auth.signInWithGoogle(payload);
|
|
179
|
+
} catch (error: unknown) {
|
|
180
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
181
|
+
setAuthProviderError(err);
|
|
182
|
+
throw error;
|
|
183
|
+
} finally {
|
|
184
|
+
setAuthLoading(false);
|
|
185
|
+
}
|
|
186
|
+
}, [auth]);
|
|
187
|
+
|
|
188
|
+
const oauthLogin = useCallback(async (providerId: string, payload: Record<string, unknown>) => {
|
|
189
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
190
|
+
setAuthLoading(true);
|
|
191
|
+
setAuthProviderError(null);
|
|
192
|
+
try {
|
|
193
|
+
await auth.signInWithOAuth(providerId, payload);
|
|
194
|
+
} catch (error: unknown) {
|
|
195
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
196
|
+
setAuthProviderError(err);
|
|
197
|
+
throw error;
|
|
198
|
+
} finally {
|
|
199
|
+
setAuthLoading(false);
|
|
200
|
+
}
|
|
201
|
+
}, [auth]);
|
|
202
|
+
|
|
203
|
+
const skipLogin = useCallback(() => {
|
|
204
|
+
setLoginSkipped(true);
|
|
205
|
+
setUser(null);
|
|
206
|
+
}, []);
|
|
207
|
+
|
|
208
|
+
const forgotPassword = useCallback(async (email: string) => {
|
|
209
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
210
|
+
setAuthLoading(true);
|
|
211
|
+
setAuthProviderError(null);
|
|
212
|
+
try {
|
|
213
|
+
await auth.resetPasswordForEmail(email);
|
|
214
|
+
} catch (error: unknown) {
|
|
215
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
216
|
+
setAuthProviderError(err);
|
|
217
|
+
throw error;
|
|
218
|
+
} finally {
|
|
219
|
+
setAuthLoading(false);
|
|
220
|
+
}
|
|
221
|
+
}, [auth]);
|
|
222
|
+
|
|
223
|
+
const resetPassword = useCallback(async (token: string, password: string) => {
|
|
224
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
225
|
+
setAuthLoading(true);
|
|
226
|
+
setAuthProviderError(null);
|
|
227
|
+
try {
|
|
228
|
+
await auth.resetPassword(token, password);
|
|
229
|
+
} catch (error: unknown) {
|
|
230
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
231
|
+
setAuthProviderError(err);
|
|
232
|
+
throw error;
|
|
233
|
+
} finally {
|
|
234
|
+
setAuthLoading(false);
|
|
235
|
+
}
|
|
236
|
+
}, [auth]);
|
|
237
|
+
|
|
238
|
+
const changePassword = useCallback(async (oldPassword: string, newPassword: string) => {
|
|
239
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
240
|
+
setAuthLoading(true);
|
|
241
|
+
setAuthProviderError(null);
|
|
242
|
+
try {
|
|
243
|
+
await auth.changePassword(oldPassword, newPassword);
|
|
244
|
+
// Sign out after password change as sessions are usually invalidated
|
|
245
|
+
await auth.signOut();
|
|
246
|
+
} catch (error: unknown) {
|
|
247
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
248
|
+
setAuthProviderError(err);
|
|
249
|
+
throw error;
|
|
250
|
+
} finally {
|
|
251
|
+
setAuthLoading(false);
|
|
252
|
+
}
|
|
253
|
+
}, [auth]);
|
|
254
|
+
|
|
255
|
+
const updateProfile = useCallback(async (displayName?: string, photoURL?: string) => {
|
|
256
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
257
|
+
setAuthLoading(true);
|
|
258
|
+
setAuthProviderError(null);
|
|
259
|
+
try {
|
|
260
|
+
const updatedUser = await auth.updateUser({ displayName, photoURL });
|
|
261
|
+
return updatedUser;
|
|
262
|
+
} catch (error: unknown) {
|
|
263
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
264
|
+
setAuthProviderError(err);
|
|
265
|
+
throw error;
|
|
266
|
+
} finally {
|
|
267
|
+
setAuthLoading(false);
|
|
268
|
+
}
|
|
269
|
+
}, [auth]);
|
|
270
|
+
|
|
271
|
+
const fetchSessions = useCallback(async () => {
|
|
272
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
273
|
+
return await auth.getSessions();
|
|
274
|
+
}, [auth]);
|
|
275
|
+
|
|
276
|
+
const revokeSession = useCallback(async (sessionId: string) => {
|
|
277
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
278
|
+
await auth.revokeSession(sessionId);
|
|
279
|
+
}, [auth]);
|
|
280
|
+
|
|
281
|
+
const revokeAllSessions = useCallback(async () => {
|
|
282
|
+
if (!auth) throw new Error("Rebase client with auth is required");
|
|
283
|
+
await auth.revokeAllSessions();
|
|
284
|
+
}, [auth]);
|
|
285
|
+
|
|
286
|
+
return {
|
|
287
|
+
user,
|
|
288
|
+
authLoading,
|
|
289
|
+
initialLoading,
|
|
290
|
+
authError,
|
|
291
|
+
authProviderError,
|
|
292
|
+
loginSkipped,
|
|
293
|
+
needsSetup: authConfig?.needsSetup ?? false,
|
|
294
|
+
registrationEnabled: authConfig?.registrationEnabled ?? false,
|
|
295
|
+
getAuthToken,
|
|
296
|
+
getApiUrl: () => client?.baseUrl,
|
|
297
|
+
signOut,
|
|
298
|
+
emailPasswordLogin,
|
|
299
|
+
register,
|
|
300
|
+
googleLogin,
|
|
301
|
+
oauthLogin,
|
|
302
|
+
skipLogin,
|
|
303
|
+
forgotPassword,
|
|
304
|
+
resetPassword,
|
|
305
|
+
changePassword,
|
|
306
|
+
updateProfile,
|
|
307
|
+
fetchSessions,
|
|
308
|
+
revokeSession,
|
|
309
|
+
revokeAllSessions,
|
|
310
|
+
clearError,
|
|
311
|
+
setAuthProviderError,
|
|
312
|
+
extra,
|
|
313
|
+
setExtra,
|
|
314
|
+
capabilities: {
|
|
315
|
+
emailPasswordLogin: true,
|
|
316
|
+
googleLogin: !!(props.googleClientId),
|
|
317
|
+
registration: authConfig?.registrationEnabled ?? false,
|
|
318
|
+
passwordReset: authConfig?.passwordReset ?? false,
|
|
319
|
+
// Defaults to true so backends predating this field keep showing the
|
|
320
|
+
// action. Adapters that don't support it report `false` explicitly.
|
|
321
|
+
adminPasswordReset: authConfig?.adminPasswordReset ?? true,
|
|
322
|
+
sessionManagement: true,
|
|
323
|
+
profileUpdate: true,
|
|
324
|
+
emailVerification: authConfig?.emailVerification ?? false,
|
|
325
|
+
enabledProviders: authConfig?.enabledProviders ?? []
|
|
326
|
+
}
|
|
327
|
+
};
|
|
328
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Wand2Icon } from "@rebasepro/ui";
|
|
2
|
+
import React from "react";
|
|
3
|
+
|
|
4
|
+
export interface AIIconProps {
|
|
5
|
+
size?: "smallest" | "small" | "medium" | "large";
|
|
6
|
+
className?: string;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* AI-styled AutoAwesome icon with gradient coloring.
|
|
11
|
+
* Used consistently across AI features for visual identification.
|
|
12
|
+
*/
|
|
13
|
+
export function AIIcon({ size = "small", className }: AIIconProps) {
|
|
14
|
+
const sizeMap: Record<string, number> = {
|
|
15
|
+
smallest: 16,
|
|
16
|
+
small: 20,
|
|
17
|
+
medium: 24,
|
|
18
|
+
large: 28
|
|
19
|
+
};
|
|
20
|
+
const numericSize = typeof size === "string" ? sizeMap[size] || 20 : size;
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<Wand2Icon
|
|
24
|
+
size={numericSize}
|
|
25
|
+
className={className}
|
|
26
|
+
style={{
|
|
27
|
+
background: "linear-gradient(to right, var(--color-primary), var(--color-secondary))",
|
|
28
|
+
WebkitBackgroundClip: "text",
|
|
29
|
+
WebkitTextFillColor: "transparent",
|
|
30
|
+
backgroundClip: "text"
|
|
31
|
+
}}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Small animated dot indicator for AI-modified elements.
|
|
38
|
+
* Shows a pulsing gradient dot.
|
|
39
|
+
*/
|
|
40
|
+
export function AIModifiedIndicator({ className }: { className?: string }) {
|
|
41
|
+
return (
|
|
42
|
+
<div
|
|
43
|
+
className={`w-2 h-2 rounded-full bg-gradient-to-r from-primary to-secondary animate-pulse ${className ?? ""}`}
|
|
44
|
+
title="AI modified"
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
}
|
|
File without changes
|