@buildbase/sdk 0.0.12 → 0.0.13
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/README.md +34 -13
- package/dist/index.d.ts +28 -194
- package/dist/index.esm.js +5 -11
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +5 -11
- package/dist/index.js.map +1 -1
- package/dist/types/components/dropdowns/country/selectCountry.d.ts +2 -2
- package/dist/types/components/dropdowns/currency/selectCurrency.d.ts +2 -2
- package/dist/types/components/dropdowns/language/selectLanguage.d.ts +2 -2
- package/dist/types/components/dropdowns/timezone/selectTimeZone.d.ts +2 -2
- package/dist/types/components/ui/command-select.d.ts +13 -0
- package/dist/types/components/ui/command.d.ts +2 -2
- package/dist/types/contexts/WorkspaceContext/actions.d.ts +1 -1
- package/dist/types/contexts/WorkspaceContext/types.d.ts +3 -3
- package/dist/types/contexts/shared/useSelectWithEquality.d.ts +10 -0
- package/dist/types/index.d.ts +1 -3
- package/dist/types/lib/api-utils.d.ts +18 -0
- package/dist/types/lib/error-handler.d.ts +18 -0
- package/dist/types/lib/logger.d.ts +27 -0
- package/dist/types/lib/useAsyncEffect.d.ts +29 -0
- package/dist/types/lib/utils.d.ts +5 -0
- package/dist/types/providers/auth/types.d.ts +12 -0
- package/dist/types/providers/auth/utils.d.ts +7 -2
- package/dist/types/providers/constants.d.ts +1 -0
- package/dist/types/providers/workspace/hooks.d.ts +10 -7
- package/dist/types/providers/workspace/provider.d.ts +0 -1
- package/dist/types/providers/workspace/types.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
interface
|
|
1
|
+
interface SelectCountryProps {
|
|
2
2
|
value?: string;
|
|
3
3
|
onChange?: (value: string) => void;
|
|
4
4
|
}
|
|
5
|
-
export declare function SelectCountry(
|
|
5
|
+
export declare function SelectCountry({ value, onChange }: SelectCountryProps): import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
interface
|
|
1
|
+
interface SelectCurrencyProps {
|
|
2
2
|
value?: string;
|
|
3
3
|
onChange?: (value: string) => void;
|
|
4
4
|
}
|
|
5
|
-
export declare function SelectCurrency(
|
|
5
|
+
export declare function SelectCurrency({ value, onChange }: SelectCurrencyProps): import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
interface
|
|
1
|
+
interface SelectLanguageProps {
|
|
2
2
|
value?: string;
|
|
3
3
|
onChange?: (value: string) => void;
|
|
4
4
|
}
|
|
5
|
-
export declare function SelectLanguage(
|
|
5
|
+
export declare function SelectLanguage({ value, onChange }: SelectLanguageProps): import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
interface
|
|
1
|
+
interface SelectTimeZoneProps {
|
|
2
2
|
value?: string;
|
|
3
3
|
onChange?: (value: string) => void;
|
|
4
4
|
}
|
|
5
|
-
export declare function SelectTimeZone(
|
|
5
|
+
export declare function SelectTimeZone({ value, onChange }: SelectTimeZoneProps): import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export interface CommandSelectOption {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
icon?: string;
|
|
5
|
+
}
|
|
6
|
+
export interface CommandSelectProps {
|
|
7
|
+
options: CommandSelectOption[];
|
|
8
|
+
value?: string;
|
|
9
|
+
onChange?: (value: string) => void;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
emptyLabel?: string;
|
|
12
|
+
}
|
|
13
|
+
export declare function CommandSelect({ options, value: valueProp, onChange, placeholder, emptyLabel, }: CommandSelectProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -24,7 +24,7 @@ declare const CommandInput: React.ForwardRefExoticComponent<Omit<Omit<Pick<Pick<
|
|
|
24
24
|
ref?: React.Ref<HTMLInputElement>;
|
|
25
25
|
} & {
|
|
26
26
|
asChild?: boolean;
|
|
27
|
-
}, "key" | "asChild" | keyof React.InputHTMLAttributes<HTMLInputElement>>, "value" | "
|
|
27
|
+
}, "key" | "asChild" | keyof React.InputHTMLAttributes<HTMLInputElement>>, "value" | "type" | "onChange"> & {
|
|
28
28
|
value?: string;
|
|
29
29
|
onValueChange?: (search: string) => void;
|
|
30
30
|
} & React.RefAttributes<HTMLInputElement>, "ref"> & React.RefAttributes<HTMLInputElement>>;
|
|
@@ -68,7 +68,7 @@ declare const CommandItem: React.ForwardRefExoticComponent<Omit<{
|
|
|
68
68
|
ref?: React.Ref<HTMLDivElement>;
|
|
69
69
|
} & {
|
|
70
70
|
asChild?: boolean;
|
|
71
|
-
}, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>>, "value" | "
|
|
71
|
+
}, "key" | "asChild" | keyof React.HTMLAttributes<HTMLDivElement>>, "value" | "disabled" | "onSelect"> & {
|
|
72
72
|
disabled?: boolean;
|
|
73
73
|
onSelect?: (value: string) => void;
|
|
74
74
|
value?: string;
|
|
@@ -12,5 +12,5 @@ export declare const workspaceActions: {
|
|
|
12
12
|
setLoading: (loading: boolean) => WorkspaceAction;
|
|
13
13
|
setError: (error: string | null) => WorkspaceAction;
|
|
14
14
|
setRefreshing: (refreshing: boolean) => WorkspaceAction;
|
|
15
|
-
|
|
15
|
+
setSwitchingToId: (workspaceId: string | null) => WorkspaceAction;
|
|
16
16
|
};
|
|
@@ -24,8 +24,8 @@ export type WorkspaceAction = {
|
|
|
24
24
|
type: 'SET_REFRESHING';
|
|
25
25
|
payload: boolean;
|
|
26
26
|
} | {
|
|
27
|
-
type: '
|
|
28
|
-
payload:
|
|
27
|
+
type: 'SET_SWITCHING_TO_ID';
|
|
28
|
+
payload: string | null;
|
|
29
29
|
};
|
|
30
30
|
export interface WorkspaceState {
|
|
31
31
|
workspaces: IWorkspace[];
|
|
@@ -33,7 +33,7 @@ export interface WorkspaceState {
|
|
|
33
33
|
error: string | null;
|
|
34
34
|
currentWorkspace: IWorkspace | null;
|
|
35
35
|
refreshing: boolean;
|
|
36
|
-
|
|
36
|
+
switchingToId: string | null;
|
|
37
37
|
isInitialized: boolean;
|
|
38
38
|
allFeatures: IWorkspaceFeature[];
|
|
39
39
|
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared selector hook with equality-based memoization.
|
|
3
|
+
* Only re-renders when the selected value changes (according to equalityFn).
|
|
4
|
+
*
|
|
5
|
+
* @param state - The state to select from
|
|
6
|
+
* @param selector - Function that selects a value from state
|
|
7
|
+
* @param equalityFn - Optional equality function (default: Object.is)
|
|
8
|
+
* @returns The selected value
|
|
9
|
+
*/
|
|
10
|
+
export declare function useSelectWithEquality<TState, TSelected>(state: TState, selector: (state: TState) => TSelected, equalityFn?: (a: TSelected, b: TSelected) => boolean): TSelected;
|
package/dist/types/index.d.ts
CHANGED
|
@@ -6,6 +6,7 @@ export { WhenAuthenticated, WhenUnauthenticated } from './components/user/auth';
|
|
|
6
6
|
export { WhenRoles, WhenWorkspaceRoles } from './components/user/role';
|
|
7
7
|
export { WhenUserFeatureDisabled, WhenUserFeatureEnabled, WhenWorkspaceFeatureDisabled, WhenWorkspaceFeatureEnabled, } from './components/features';
|
|
8
8
|
export { AuthStatus } from './providers/auth/types';
|
|
9
|
+
export type { OnWorkspaceChangeParams } from './providers/auth/types';
|
|
9
10
|
export { useSaaSAuth } from './providers/auth/hooks';
|
|
10
11
|
export { useSaaSSettings } from './providers/os/hooks';
|
|
11
12
|
export { useUserAttributes, useUserFeatures } from './providers/user/hooks';
|
|
@@ -14,7 +15,4 @@ export { WorkspaceSwitcher } from './providers/workspace/provider';
|
|
|
14
15
|
export { useCreateCheckoutSession, useInvoice, useInvoices, usePlanGroup, usePlanGroupVersions, useSubscription, useSubscriptionManagement, useUpdateSubscription, } from './providers/workspace/subscription-hooks';
|
|
15
16
|
export { eventEmitter } from './providers/events';
|
|
16
17
|
export type { EventData, EventType, IEventCallbacks, UserCreatedEventData, UserUpdatedEventData, WorkspaceChangedEventData, WorkspaceCreatedEventData, WorkspaceDeletedEventData, WorkspaceUpdatedEventData, WorkspaceUserAddedEventData, WorkspaceUserRemovedEventData, WorkspaceUserRoleChangedEventData, } from './providers/events/types';
|
|
17
|
-
export { default as ErrorBoundary, SDKErrorBoundary } from './components/ErrorBoundary';
|
|
18
|
-
export { SDKError, createSDKError, errorHandler, handleError } from './lib/error-handler';
|
|
19
|
-
export type { ErrorHandlerConfig, SDKErrorContext } from './lib/error-handler';
|
|
20
18
|
export type { BillingInterval, IBasePricing, ICheckoutSessionRequest, ICheckoutSessionResponse, IInvoice, IInvoiceListResponse, IInvoiceResponse, InvoiceStatus, IPlan, IPlanGroup, IPlanGroupLatestVersion, IPlanGroupResponse, IPlanGroupVersion, IPlanGroupVersionsResponse, IPlanGroupVersionWithPlans, IPlanVersion, IPlanVersionWithPlan, IQuotaValue, ISubscription, ISubscriptionItem, ISubscriptionResponse, ISubscriptionUpdateRequest, ISubscriptionUpdateResponse, } from './api/types';
|
|
@@ -71,6 +71,24 @@ export declare function isAbortError(error: unknown): boolean;
|
|
|
71
71
|
* ```
|
|
72
72
|
*/
|
|
73
73
|
export declare function safeFetch(url: string, options?: RequestInit): Promise<Response>;
|
|
74
|
+
/**
|
|
75
|
+
* Extract error message from a failed response.
|
|
76
|
+
* Parses JSON body and returns message/error field, or defaultMsg if not available.
|
|
77
|
+
*
|
|
78
|
+
* @param response - The Response object (typically from a failed request)
|
|
79
|
+
* @param defaultMsg - Default message if parsing fails or no message in body
|
|
80
|
+
* @returns Promise resolving to the error message string
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```tsx
|
|
84
|
+
* const response = await safeFetch('/api/users');
|
|
85
|
+
* if (!response.ok) {
|
|
86
|
+
* const msg = await getErrorMessage(response, 'Failed to fetch users');
|
|
87
|
+
* throw new Error(msg);
|
|
88
|
+
* }
|
|
89
|
+
* ```
|
|
90
|
+
*/
|
|
91
|
+
export declare function getErrorMessage(response: Response, defaultMsg: string): Promise<string>;
|
|
74
92
|
/**
|
|
75
93
|
* Parse JSON response with error handling.
|
|
76
94
|
* Provides better error messages if response is not valid JSON.
|
|
@@ -76,6 +76,24 @@ export declare const errorHandler: ErrorHandler;
|
|
|
76
76
|
* ```
|
|
77
77
|
*/
|
|
78
78
|
export declare function handleError(error: Error | unknown, context?: SDKErrorContext): void;
|
|
79
|
+
/**
|
|
80
|
+
* Handle an error only if it is not an AbortError.
|
|
81
|
+
* Convenience for async code that uses AbortSignal - call this in catch and abort errors are ignored.
|
|
82
|
+
*
|
|
83
|
+
* @param error - The error that occurred
|
|
84
|
+
* @param context - Optional context about where the error occurred
|
|
85
|
+
* @returns true if error was handled, false if it was an abort error (ignored)
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```tsx
|
|
89
|
+
* try {
|
|
90
|
+
* await safeFetch(url, { signal });
|
|
91
|
+
* } catch (error) {
|
|
92
|
+
* handleErrorUnlessAborted(error, { component: 'MyComponent', action: 'fetch' });
|
|
93
|
+
* }
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
export declare function handleErrorUnlessAborted(error: Error | unknown, context?: SDKErrorContext): boolean;
|
|
79
97
|
/**
|
|
80
98
|
* Creates a new SDKError instance with optional code and context.
|
|
81
99
|
* Useful for creating standardized errors throughout the SDK.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized logger for SDK
|
|
3
|
+
* All console output should go through this for consistency and configurable behavior
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Configure the SDK logger
|
|
7
|
+
*/
|
|
8
|
+
export declare function configureLogger(config: {
|
|
9
|
+
enableLogging?: boolean;
|
|
10
|
+
}): void;
|
|
11
|
+
/**
|
|
12
|
+
* Log info (dev only, respects enableLogging)
|
|
13
|
+
*/
|
|
14
|
+
export declare function sdkLog(message: string, ...args: unknown[]): void;
|
|
15
|
+
/**
|
|
16
|
+
* Log warning (dev only, respects enableLogging)
|
|
17
|
+
*/
|
|
18
|
+
export declare function sdkWarn(message: string, ...args: unknown[]): void;
|
|
19
|
+
/**
|
|
20
|
+
* Log error (dev only, respects enableLogging)
|
|
21
|
+
*/
|
|
22
|
+
export declare function sdkLogError(message: string, ...args: unknown[]): void;
|
|
23
|
+
/**
|
|
24
|
+
* Log internal/critical error - always logs.
|
|
25
|
+
* Use when the error handling system itself fails (e.g. user's onError callback throws).
|
|
26
|
+
*/
|
|
27
|
+
export declare function sdkError(message: string, ...args: unknown[]): void;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DependencyList } from 'react';
|
|
2
|
+
export interface UseAsyncEffectOptions {
|
|
3
|
+
/**
|
|
4
|
+
* Called when the effect promise rejects (except for AbortError which is ignored).
|
|
5
|
+
*/
|
|
6
|
+
onError?: (err: unknown) => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Encapsulates the AbortController + async effect pattern.
|
|
10
|
+
* Provides cancellation on cleanup and optional error handling.
|
|
11
|
+
*
|
|
12
|
+
* @param effect - Async function that receives AbortSignal for cancellation
|
|
13
|
+
* @param deps - Dependency array (same as useEffect)
|
|
14
|
+
* @param options - Optional onError callback for unhandled rejections
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```tsx
|
|
18
|
+
* useAsyncEffect(
|
|
19
|
+
* async (signal) => {
|
|
20
|
+
* const response = await safeFetch(url, { signal });
|
|
21
|
+
* const data = await response.json();
|
|
22
|
+
* setData(data);
|
|
23
|
+
* },
|
|
24
|
+
* [url],
|
|
25
|
+
* { onError: (err) => handleError(err, { component: 'MyComponent', action: 'fetch' }) }
|
|
26
|
+
* );
|
|
27
|
+
* ```
|
|
28
|
+
*/
|
|
29
|
+
export declare function useAsyncEffect(effect: (signal: AbortSignal) => Promise<void>, deps: DependencyList, options?: UseAsyncEffectOptions): void;
|
|
@@ -1,2 +1,7 @@
|
|
|
1
1
|
import { type ClassValue } from 'clsx';
|
|
2
|
+
/**
|
|
3
|
+
* Check if running in development mode.
|
|
4
|
+
* Safe for browser bundles where process may be undefined.
|
|
5
|
+
*/
|
|
6
|
+
export declare function isDevelopment(): boolean;
|
|
2
7
|
export declare function cn(...inputs: ClassValue[]): string;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EventData, EventType } from '../events/types';
|
|
2
|
+
import type { IWorkspace } from '../workspace/types';
|
|
2
3
|
export declare enum AuthStatus {
|
|
3
4
|
loading = "loading",
|
|
4
5
|
redirecting = "redirecting",
|
|
@@ -47,4 +48,15 @@ export interface IAuthCallbacks {
|
|
|
47
48
|
* @param data - The event data (type varies based on eventType)
|
|
48
49
|
*/
|
|
49
50
|
handleEvent?: (eventType: EventType, data: EventData) => void | Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Called before switching workspace (e.g. generate token, save state).
|
|
53
|
+
* Used when user clicks "Switch to" and when restoring from storage on page refresh.
|
|
54
|
+
* Switch proceeds only when this resolves; reject to abort.
|
|
55
|
+
*/
|
|
56
|
+
onWorkspaceChange?: (params: OnWorkspaceChangeParams) => Promise<void>;
|
|
57
|
+
}
|
|
58
|
+
export interface OnWorkspaceChangeParams {
|
|
59
|
+
workspace: IWorkspace;
|
|
60
|
+
user: AuthUser | null;
|
|
61
|
+
role: string | null;
|
|
50
62
|
}
|
|
@@ -1,5 +1,10 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { AuthUser } from './types';
|
|
1
|
+
import { IUser } from '../../api/types';
|
|
2
|
+
import type { AuthSession, AuthUser } from './types';
|
|
3
|
+
/**
|
|
4
|
+
* Map IUser from API to AuthUser for session
|
|
5
|
+
* @throws Error if user data is missing required ID or email fields
|
|
6
|
+
*/
|
|
7
|
+
export declare function mapIUserToAuthUser(userData: IUser, orgId: string, clientId: string): AuthUser;
|
|
3
8
|
/**
|
|
4
9
|
* Centralized Session Management
|
|
5
10
|
* Only stores sessionId in localStorage - user data is kept in context only
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { IUser } from '../../api/types';
|
|
2
|
-
import { WorkspaceSwitcher } from './provider';
|
|
3
2
|
import { IWorkspace, IWorkspaceUser } from './types';
|
|
4
3
|
/**
|
|
5
4
|
* Main workspace management hook for the SDK.
|
|
@@ -11,11 +10,11 @@ import { IWorkspace, IWorkspaceUser } from './types';
|
|
|
11
10
|
* - `loading`: Boolean indicating if workspaces are being fetched
|
|
12
11
|
* - `error`: Error message string (null if no error)
|
|
13
12
|
* - `refreshing`: Boolean indicating if workspaces are being refreshed in background
|
|
14
|
-
* - `switching`: Boolean
|
|
15
|
-
* - `WorkspaceSwitcher`: Component for switching between workspaces
|
|
13
|
+
* - `switching`: Boolean - true when a workspace switch is in progress
|
|
16
14
|
* - `fetchWorkspaces()`: Function to fetch all workspaces
|
|
17
15
|
* - `refreshWorkspaces()`: Function to refresh workspaces in background (non-blocking)
|
|
18
|
-
* - `setCurrentWorkspace(workspace)`: Function to set the current workspace
|
|
16
|
+
* - `setCurrentWorkspace(workspace)`: Function to set the current workspace (direct, no callback)
|
|
17
|
+
* - `switchToWorkspace(workspace)`: Centralized switch - calls onWorkspaceChange first, then sets workspace
|
|
19
18
|
* - `resetCurrentWorkspace()`: Function to clear the current workspace
|
|
20
19
|
* - `createWorkspace(name, image?)`: Function to create a new workspace
|
|
21
20
|
* - `updateWorkspace(workspace, data)`: Function to update a workspace
|
|
@@ -113,16 +112,19 @@ export declare const useSaaSWorkspaces: () => {
|
|
|
113
112
|
fetchWorkspaces: () => Promise<void>;
|
|
114
113
|
refreshWorkspaces: () => Promise<void>;
|
|
115
114
|
refreshing: boolean;
|
|
116
|
-
WorkspaceSwitcher: typeof WorkspaceSwitcher;
|
|
117
115
|
currentWorkspace: IWorkspace | null;
|
|
118
|
-
setCurrentWorkspace: (ws: IWorkspace
|
|
116
|
+
setCurrentWorkspace: (ws: IWorkspace, options?: {
|
|
117
|
+
forceEmit?: boolean;
|
|
118
|
+
}) => void;
|
|
119
|
+
switchToWorkspace: (ws: IWorkspace, options?: {
|
|
120
|
+
forceEmit?: boolean;
|
|
121
|
+
}) => Promise<void>;
|
|
119
122
|
resetCurrentWorkspace: () => void;
|
|
120
123
|
createWorkspace: (name: string, image: string) => Promise<void>;
|
|
121
124
|
allFeatures: import("./types").IWorkspaceFeature[];
|
|
122
125
|
getFeatures: () => Promise<import("./types").IWorkspaceFeature[] | null>;
|
|
123
126
|
updateFeature: (workspaceId: string, key: string, value: boolean) => Promise<IWorkspace>;
|
|
124
127
|
getWorkspace: (workspaceId: string) => Promise<IWorkspace>;
|
|
125
|
-
switching: boolean;
|
|
126
128
|
updateWorkspace: (ws: IWorkspace, _data: Partial<IWorkspace>) => Promise<void>;
|
|
127
129
|
getUsers: (workspaceId: string) => Promise<IWorkspaceUser[]>;
|
|
128
130
|
addUser: (workspaceId: string, email: string, role: string) => Promise<{
|
|
@@ -145,4 +147,5 @@ export declare const useSaaSWorkspaces: () => {
|
|
|
145
147
|
deleteWorkspace: (workspaceId: string) => Promise<{
|
|
146
148
|
success: boolean;
|
|
147
149
|
}>;
|
|
150
|
+
switching: boolean;
|
|
148
151
|
};
|
|
@@ -5,5 +5,4 @@ export declare const WorkspaceProvider: ({ children }: {
|
|
|
5
5
|
}) => import("react/jsx-runtime").JSX.Element;
|
|
6
6
|
export declare function WorkspaceSwitcher(props: {
|
|
7
7
|
trigger: (isLoading: boolean, currentWorkspace: IWorkspace | null) => ReactNode;
|
|
8
|
-
onWorkspaceChange: (workspace: IWorkspace) => Promise<void>;
|
|
9
8
|
}): import("react/jsx-runtime").JSX.Element;
|
|
@@ -29,7 +29,7 @@ export interface WorkspaceContextValue {
|
|
|
29
29
|
workspaces: IWorkspace[];
|
|
30
30
|
currentWorkspace: IWorkspace | null;
|
|
31
31
|
loading: boolean;
|
|
32
|
-
|
|
32
|
+
switchingToId: string | null;
|
|
33
33
|
refreshing: boolean;
|
|
34
34
|
error: string | null;
|
|
35
35
|
fetchWorkspaces: () => Promise<void>;
|