@gears-frontx/react 0.1.0 → 0.2.0-alpha.15
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/CLAUDE.md +247 -64
- package/dist/index.cjs +1338 -434
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +653 -146
- package/dist/index.d.ts +653 -146
- package/dist/index.js +1179 -276
- package/dist/index.js.map +1 -1
- package/dist/testing-Dlmfu6tE.d.cts +56 -0
- package/dist/testing-Dlmfu6tE.d.ts +56 -0
- package/dist/testing.cjs +77 -0
- package/dist/testing.cjs.map +1 -0
- package/dist/testing.d.cts +4 -0
- package/dist/testing.d.ts +4 -0
- package/dist/testing.js +56 -0
- package/dist/testing.js.map +1 -0
- package/dist/types-JtpziA_B.d.cts +224 -0
- package/dist/types-JtpziA_B.d.ts +224 -0
- package/dist/types.cjs.map +1 -1
- package/dist/types.d.cts +2 -2
- package/dist/types.d.ts +2 -2
- package/llms.txt +49 -23
- package/package.json +40 -23
- package/commands/hai3-duplicate-screenset.md +0 -58
- package/commands/hai3-new-component.md +0 -48
- package/commands/hai3-new-mfe.md +0 -166
- package/commands/hai3-new-screen.md +0 -39
- package/commands/hai3-new-screenset.md +0 -47
- package/dist/types-Cp8Zm5s0.d.cts +0 -136
- package/dist/types-Cp8Zm5s0.d.ts +0 -136
package/dist/index.d.cts
CHANGED
|
@@ -1,61 +1,203 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
|
-
import React__default, {
|
|
3
|
-
import {
|
|
4
|
-
export {
|
|
5
|
-
import {
|
|
6
|
-
export { ACCOUNTS_DOMAIN, Action, ActionsChain, ApiPlugin, ApiPluginBase, ApiPluginErrorContext, ApiProtocol, ApiRequestContext, ApiResponseContext, ApiServiceConfig, AppDispatch, BaseApiService, BasePluginHooks, ChangeThemePayload, ChildMfeBridge,
|
|
2
|
+
import React__default, { ReactElement } from 'react';
|
|
3
|
+
import { F as FrontXProviderProps, A as ApiQueryResult, a as ApiInfiniteQueryResult, b as ApiMutationResult, C as CanAccessProps, U as UseTranslationReturn, c as UseScreenTranslationsReturn, d as UseFormattersReturn, e as UseThemeReturn, f as ApiSuspenseQueryResult, g as ApiSuspenseInfiniteQueryResult, h as UseCanAccessResult, M as MfeContextValue } from './types-JtpziA_B.cjs';
|
|
4
|
+
export { i as MfeContext, j as UseAppDispatchReturn, k as UseAppSelector, l as UseFrontXReturn, u as useMfeContext } from './types-JtpziA_B.cjs';
|
|
5
|
+
import { FrontXApp, EndpointDescriptor, MutationDescriptor, AccessRecord, AppDispatch, RootState, TranslationMap, TranslationLoader, StreamStatus, StreamDescriptor, AccessQuery, ChildMfeBridge, MfeRegistry, Extension, MfeEntryLifecycle, MfeMountContext, EventPayloadMap as EventPayloadMap$1, EventBus } from '@gears-frontx/framework';
|
|
6
|
+
export { ACCOUNTS_DOMAIN, AccessDecision, AccessQuery, Action, ActionHandler, ActionPayload, ActionsChain, ApiPlugin, ApiPluginBase, ApiPluginErrorContext, ApiProtocol, ApiRequestContext, ApiResponseContext, ApiServiceConfig, AppDispatch, AuthCallbackInput, AuthCapabilities, AuthCheckResult, AuthContext, AuthEvents, AuthLoggedInPayload, AuthLoggedOutPayload, AuthLoginInput, AuthPermissions, AuthPluginConfig, AuthProvider, AuthRuntime, AuthSession, AuthState, AuthStateEvent, AuthStateListener, AuthTransition, AuthUnsubscribe, BaseApiService, BasePluginHooks, ChangeThemePayload, ChildMfeBridge, ConcurrentMountStrategy, ContainerHooks, DomainContext, EndpointDescriptor, EndpointOptions, EventHandler, EventSourceLike, ExclusiveMountStrategy, Extension, ExtensionDomain, ExtensionDomainImplementation, ExtensionDomainImplementationFactory, ExtensionMounter, ExtensionPresentation, ExtensionRegistrationState, FRONTX_ACTION_LOAD_EXT, FRONTX_ACTION_MOUNT_EXT, FRONTX_ACTION_UNMOUNT_EXT, FRONTX_MFE_ENTRY_MF, FRONTX_OVERLAY_DOMAIN, FRONTX_POPUP_DOMAIN, FRONTX_SCREEN_DOMAIN, FRONTX_SCREEN_EXTENSION_TYPE, FRONTX_SHARED_PROPERTY_LANGUAGE, FRONTX_SHARED_PROPERTY_THEME, FRONTX_SIDEBAR_DOMAIN, FooterConfig, FooterState, FrontXApp, FrontXAppBuilder, FrontXConfig, FrontXPlugin, FrontXStore, HeaderConfig, HeaderState, HeaderUser, I18nConfig, I18nRegistry, I18nRegistryImpl, I18nRegistryType, JSONSchema, JsonCompatible, JsonObject, JsonPrimitive, JsonValue, LAYOUT_SLICE_NAME, Language, LanguageDisplayMode, LanguageMetadata, LayoutDomainReducers, LayoutDomainState, LayoutState, LifecycleHook, LifecycleStage, LoadExtPayload, MOCK_PLUGIN, MenuItem, MenuState, MfManifest, MfManifestAssets, MfManifestBuildInfo, MfManifestMetaData, MfManifestRemoteEntry, MfManifestShared, MfeBridgeFactory, MfeEntry, MfeEntryLifecycle, MfeEntryMF, MfeHandler, MfeHandlerMF, MfeMountContext, MfeRegistry, MfeRegistryConfig, MfeRegistryFactory, MfeState, MockEvents, MockMap, MockState, MockTogglePayload, MountExtPayload, MountStrategy, MutationDescriptor, OptionalMountStrategy, OverlayConfig, OverlayState, ParameterizedEndpointDescriptor, ParentMfeBridge, PluginClass, PluginFactory, PluginLifecycle, PluginProvides, PopupConfig, PopupSliceState, PopupState, Preset, Presets, ProtocolClass, ProtocolPluginType, ReducerPayload, RegisterExtensionPayload, RestEndpointProtocol, RestPlugin, RestPluginHooks, RestPluginWithConfig, RestProtocol, RestProtocolConfig, RestRequestContext, RestResponseContext, RestShortCircuitResponse, RootState, RootStateWithLayout, SUPPORTED_LANGUAGES, ScreenExtension, SetLanguagePayload, SharedProperty, ShortCircuitResponse, ShowPopupPayload, SidebarPosition, SidebarState, SliceObject, SseConnectContext, SsePlugin, SsePluginHooks, SsePluginWithConfig, SseProtocol, SseProtocolConfig, SseShortCircuitResponse, SseStreamProtocol, StreamDescriptor, StreamStatus, Subscription, TENANT_SLICE_NAME, Tenant, TenantChangedPayload, TenantClearedPayload, TenantEvents, TenantState, TextDirection, ThemeConfig, ThemeRegistry, TranslationDictionary, TranslationLoader, TranslationMap, TypeSystemPlugin, UnmountExtPayload, UnregisterExtensionPayload, apiRegistry, auth, changeTenant, clearTenant, clearTenantAction, clearUser, closeAllPopups, closePopup, closeTopPopup, createFrontX, createI18nRegistry, createShadowRoot, createSlice, createStore, createThemeRegistry, effects, extractGtsPackage, footerActions, footerSlice, frontxApiTransport, getLanguageMetadata, getStore, gtsPlugin, hasSlice, headerActions, headerSlice, hideOverlay, i18n, i18nRegistry, initMockEffects, initTenantEffects, injectCssVariables, isMockPlugin, isRestShortCircuit, isShortCircuit, isSseShortCircuit, layout, layoutDomainReducers, layoutReducer, loadExtension, menuActions, menuSlice, mfeRegistryFactory, microfrontends, mock, mockActions, mockSlice, mountExtension, openPopup, overlayActions, overlayDomain, overlaySlice, popupActions, popupDomain, popupSlice, presets, queryCache, queryCacheShared, registerExtension, registerSlice, screenDomain, selectExtensionError, selectExtensionState, selectRegisteredExtensions, setFooterConfig, setFooterVisible, setHeaderLoading, setMenuCollapsed, setMenuConfig, setMenuItems, setMenuVisible, setMockEnabled, setOverlayVisible, setSidebarCollapsed, setSidebarConfig, setSidebarContent, setSidebarPosition, setSidebarTitle, setSidebarVisible, setSidebarWidth, setTenant, setTenantLoading, setTenantLoadingState, setUser, showOverlay, sidebarActions, sidebarDomain, sidebarSlice, subscribeQueryCacheRuntimeChanged, tenantActions, tenantReducer, tenantSlice, themes, toggleMenu, toggleMockMode, toggleSidebar, unmountExtension, unregisterExtension } from '@gears-frontx/framework';
|
|
7
|
+
import { M as MutationCallbackContext, Q as QueryCache } from './testing-Dlmfu6tE.cjs';
|
|
8
|
+
export { a as QueryCacheInvalidateFilters, b as QueryCacheState, i as invalidateQueryCacheForApp } from './testing-Dlmfu6tE.cjs';
|
|
7
9
|
import { TypedUseSelectorHook } from 'react-redux';
|
|
10
|
+
import '@tanstack/react-query';
|
|
11
|
+
import '@gears-frontx/framework/testing';
|
|
8
12
|
|
|
9
13
|
/**
|
|
10
|
-
*
|
|
14
|
+
* FrontX Provider - Main provider component for FrontX applications
|
|
11
15
|
*
|
|
12
16
|
* React Layer: L3 (Depends on @gears-frontx/framework)
|
|
17
|
+
*
|
|
18
|
+
* Query cache lifecycle is owned by the queryCache() framework plugin (L2).
|
|
19
|
+
* FrontXProvider reads the plugin-owned QueryClient from the app and mounts the
|
|
20
|
+
* internal React provider around the tree when it is available.
|
|
13
21
|
*/
|
|
14
22
|
|
|
15
23
|
/**
|
|
16
|
-
*
|
|
24
|
+
* FrontX Provider Component
|
|
17
25
|
*
|
|
18
|
-
* Provides the
|
|
19
|
-
*
|
|
26
|
+
* Provides the FrontX application context to all child components. The app
|
|
27
|
+
* is built once per runtime by the caller (`createFrontX(...).build()`); the
|
|
28
|
+
* provider never creates or destroys one.
|
|
20
29
|
*
|
|
21
30
|
* @example
|
|
22
31
|
* ```tsx
|
|
23
|
-
*
|
|
24
|
-
* <
|
|
25
|
-
* <App />
|
|
26
|
-
* </HAI3Provider>
|
|
27
|
-
*
|
|
28
|
-
* // With configuration
|
|
29
|
-
* <HAI3Provider config={{ devMode: true }}>
|
|
30
|
-
* <App />
|
|
31
|
-
* </HAI3Provider>
|
|
32
|
-
*
|
|
33
|
-
* // With pre-built app
|
|
34
|
-
* const app = createHAI3().use(screensets()).use(microfrontends()).build();
|
|
35
|
-
* <HAI3Provider app={app}>
|
|
32
|
+
* const app = createFrontX().use(queryCache()).build();
|
|
33
|
+
* <FrontXProvider app={app}>
|
|
36
34
|
* <App />
|
|
37
|
-
* </
|
|
35
|
+
* </FrontXProvider>
|
|
38
36
|
*
|
|
39
37
|
* // With MFE bridge (for MFE components)
|
|
40
|
-
* <
|
|
38
|
+
* <FrontXProvider app={app} mfeBridge={{ bridge, extensionId, domainId }}>
|
|
41
39
|
* <MyMfeApp />
|
|
42
|
-
* </
|
|
40
|
+
* </FrontXProvider>
|
|
41
|
+
*
|
|
42
|
+
* // QueryCache is resolved from the app's plugin composition
|
|
43
|
+
* <FrontXProvider app={app}>
|
|
44
|
+
* <MyMfeApp />
|
|
45
|
+
* </FrontXProvider>
|
|
43
46
|
* ```
|
|
44
47
|
*/
|
|
45
|
-
declare const
|
|
48
|
+
declare const FrontXProvider: React__default.FC<FrontXProviderProps>;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* FrontX Context
|
|
52
|
+
* Holds the FrontX app instance for the application.
|
|
53
|
+
*/
|
|
54
|
+
declare const FrontXContext: React.Context<FrontXApp | null>;
|
|
55
|
+
/**
|
|
56
|
+
* Use the FrontX context.
|
|
57
|
+
* Throws if used outside of FrontXProvider.
|
|
58
|
+
*
|
|
59
|
+
* @returns The FrontX app instance
|
|
60
|
+
*/
|
|
61
|
+
declare function useFrontX(): FrontXApp;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* useApiQuery - Declarative data fetching hook
|
|
65
|
+
*
|
|
66
|
+
* Accepts an EndpointDescriptor from @gears-frontx/api and returns a Gears FrontX-owned
|
|
67
|
+
* ApiQueryResult. AbortSignal for request cancellation is threaded automatically
|
|
68
|
+
* through the shared QueryClient integration.
|
|
69
|
+
*
|
|
70
|
+
* Cache config cascade: component overrides > descriptor defaults > plugin defaults.
|
|
71
|
+
* Omit overrides to rely on the descriptor's staleTime/gcTime, which in turn
|
|
72
|
+
* fall back to the plugin-level query-cache defaults, so a screen that remounts
|
|
73
|
+
* within staleTime paints from cache without refetching.
|
|
74
|
+
*
|
|
75
|
+
* Pass `enabled: false` to hold a query whose input is not known yet.
|
|
76
|
+
*/
|
|
46
77
|
|
|
47
78
|
/**
|
|
48
|
-
*
|
|
49
|
-
*
|
|
79
|
+
* Per-call cache overrides shared by every read hook.
|
|
80
|
+
* Cascade: these > descriptor > plugin defaults.
|
|
50
81
|
*/
|
|
51
|
-
|
|
82
|
+
interface ApiQueryCacheOverrides {
|
|
83
|
+
/** Override staleTime for this specific call site. */
|
|
84
|
+
staleTime?: number;
|
|
85
|
+
/** Override gcTime for this specific call site. */
|
|
86
|
+
gcTime?: number;
|
|
87
|
+
}
|
|
88
|
+
/** Per-call overrides for useApiSuspenseQuery. */
|
|
89
|
+
interface ApiSuspenseQueryOverrides extends ApiQueryCacheOverrides {
|
|
90
|
+
/** A suspense query always runs; use useApiQuery to hold one back. */
|
|
91
|
+
enabled?: never;
|
|
92
|
+
}
|
|
93
|
+
/** Per-call overrides for useApiQuery. */
|
|
94
|
+
interface ApiQueryOverrides extends ApiQueryCacheOverrides {
|
|
95
|
+
/**
|
|
96
|
+
* `false` keeps the query idle: it is not fetched automatically and
|
|
97
|
+
* `isLoading` stays false until it turns `true`. An explicit `refetch`
|
|
98
|
+
* still fetches. Defaults to `true`.
|
|
99
|
+
*/
|
|
100
|
+
enabled?: boolean;
|
|
101
|
+
}
|
|
102
|
+
declare function useApiQuery<TData = unknown, TError = Error>(descriptor: EndpointDescriptor<TData>, overrides?: ApiQueryOverrides): ApiQueryResult<TData, TError>;
|
|
103
|
+
|
|
52
104
|
/**
|
|
53
|
-
*
|
|
54
|
-
* Throws if used outside of HAI3Provider.
|
|
105
|
+
* useApiInfiniteQuery - Declarative paginated data fetching hook
|
|
55
106
|
*
|
|
56
|
-
*
|
|
107
|
+
* Accepts an initial EndpointDescriptor plus descriptor resolvers for adjacent
|
|
108
|
+
* pages. Each page remains a standard service descriptor so MFE code does not
|
|
109
|
+
* need raw TanStack query keys or query functions.
|
|
57
110
|
*/
|
|
58
|
-
|
|
111
|
+
|
|
112
|
+
interface ApiInfiniteQueryPageContext<TPage> {
|
|
113
|
+
page: TPage;
|
|
114
|
+
pages: readonly TPage[];
|
|
115
|
+
descriptor: EndpointDescriptor<TPage>;
|
|
116
|
+
descriptors: readonly EndpointDescriptor<TPage>[];
|
|
117
|
+
}
|
|
118
|
+
/** Options shared by useApiInfiniteQuery and useApiSuspenseInfiniteQuery. */
|
|
119
|
+
interface ApiInfiniteQueryBaseOptions<TPage> extends ApiQueryCacheOverrides {
|
|
120
|
+
/** Descriptor for the first page in the sequence. */
|
|
121
|
+
initialPage: EndpointDescriptor<TPage>;
|
|
122
|
+
/**
|
|
123
|
+
* Resolve the next page descriptor from the current page payload.
|
|
124
|
+
* Return undefined when there is no next page.
|
|
125
|
+
*/
|
|
126
|
+
getNextPage: (context: ApiInfiniteQueryPageContext<TPage>) => EndpointDescriptor<TPage> | undefined;
|
|
127
|
+
/**
|
|
128
|
+
* Resolve the previous page descriptor from the current first page payload.
|
|
129
|
+
* Return undefined when backward pagination is not available.
|
|
130
|
+
*/
|
|
131
|
+
getPreviousPage?: (context: ApiInfiniteQueryPageContext<TPage>) => EndpointDescriptor<TPage> | undefined;
|
|
132
|
+
/** Optional TanStack maxPages passthrough for bounded page windows. */
|
|
133
|
+
maxPages?: number;
|
|
134
|
+
}
|
|
135
|
+
/** Options for useApiSuspenseInfiniteQuery. */
|
|
136
|
+
interface ApiSuspenseInfiniteQueryOptions<TPage> extends ApiInfiniteQueryBaseOptions<TPage> {
|
|
137
|
+
/** A suspense query always runs; use useApiInfiniteQuery to hold one back. */
|
|
138
|
+
enabled?: never;
|
|
139
|
+
}
|
|
140
|
+
interface ApiInfiniteQueryOptions<TPage> extends ApiInfiniteQueryBaseOptions<TPage> {
|
|
141
|
+
/**
|
|
142
|
+
* `false` keeps the query idle: no page is fetched until it turns `true`.
|
|
143
|
+
* Defaults to `true`.
|
|
144
|
+
*/
|
|
145
|
+
enabled?: boolean;
|
|
146
|
+
}
|
|
147
|
+
declare function useApiInfiniteQuery<TPage = unknown, TError = Error>(options: ApiInfiniteQueryOptions<TPage>): ApiInfiniteQueryResult<TPage, TError>;
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* useApiMutation - Declarative mutation hook with restricted QueryCache injection
|
|
151
|
+
*
|
|
152
|
+
* Accepts { endpoint: MutationDescriptor, callbacks } and returns a Gears FrontX-owned
|
|
153
|
+
* ApiMutationResult. Supports optimistic updates, rollback, and cache invalidation
|
|
154
|
+
* through the QueryCache interface injected into each callback.
|
|
155
|
+
*
|
|
156
|
+
* Optimistic update pattern:
|
|
157
|
+
* onMutate -> cancel outgoing refetches, snapshot via queryCache.get,
|
|
158
|
+
* apply optimistic data via queryCache.set, return snapshot
|
|
159
|
+
* onError -> restore snapshot via queryCache.set(key, context.snapshot)
|
|
160
|
+
* onSettled -> invalidate to refetch authoritative state
|
|
161
|
+
*
|
|
162
|
+
* TanStack Query is used internally only and is NOT re-exported.
|
|
163
|
+
* MFEs interact with the cache through QueryCache, not the raw QueryClient.
|
|
164
|
+
*/
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Options for useApiMutation.
|
|
168
|
+
*
|
|
169
|
+
* Each callback receives { queryCache } as an additional final parameter,
|
|
170
|
+
* providing controlled access to the shared cache without exposing the
|
|
171
|
+
* raw QueryClient. TContext is the return type of onMutate, passed as
|
|
172
|
+
* context to onSuccess, onError, and onSettled.
|
|
173
|
+
*/
|
|
174
|
+
type UseApiMutationOptions<TData = unknown, TError = Error, TVariables = void, TContext = unknown> = {
|
|
175
|
+
endpoint: MutationDescriptor<TData, TVariables>;
|
|
176
|
+
cancelOnSupersede?: boolean;
|
|
177
|
+
abortOnUnmount?: boolean;
|
|
178
|
+
onMutate?: (variables: TVariables, ctx: MutationCallbackContext) => Promise<TContext> | TContext;
|
|
179
|
+
onSuccess?: (data: TData, variables: TVariables, context: TContext | undefined, ctx: MutationCallbackContext) => unknown;
|
|
180
|
+
onError?: (error: TError, variables: TVariables, context: TContext | undefined, ctx: MutationCallbackContext) => unknown;
|
|
181
|
+
onSettled?: (data: TData | undefined, error: TError | null, variables: TVariables, context: TContext | undefined, ctx: MutationCallbackContext) => unknown;
|
|
182
|
+
};
|
|
183
|
+
declare function useApiMutation<TData = unknown, TError = Error, TVariables = void, TContext = unknown>(options: UseApiMutationOptions<TData, TError, TVariables, TContext>): ApiMutationResult<TData, TError, TVariables>;
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Declarative RBAC guard component.
|
|
187
|
+
*
|
|
188
|
+
* Pessimistic: renders `denied` (or `loading` if provided) until an explicit
|
|
189
|
+
* 'allow' decision arrives from app.auth.canAccess. Only renders `allowed`
|
|
190
|
+
* after a confirmed allow.
|
|
191
|
+
*
|
|
192
|
+
* Example:
|
|
193
|
+
* <CanAccess
|
|
194
|
+
* query={{ action: AppAction.InvoicesRead, resource: ResourceKind.Invoice }}
|
|
195
|
+
* allowed={<InvoiceList />}
|
|
196
|
+
* denied={<AccessDenied />}
|
|
197
|
+
* loading={<Spinner />}
|
|
198
|
+
* />
|
|
199
|
+
*/
|
|
200
|
+
declare function CanAccess<TRecord extends AccessRecord = AccessRecord>({ query, allowed, denied, loading, }: CanAccessProps<TRecord>): ReactElement | null;
|
|
59
201
|
|
|
60
202
|
/**
|
|
61
203
|
* useAppDispatch Hook - Type-safe dispatch hook
|
|
@@ -225,12 +367,192 @@ declare function useFormatters(): UseFormattersReturn;
|
|
|
225
367
|
*/
|
|
226
368
|
declare function useTheme(): UseThemeReturn;
|
|
227
369
|
|
|
370
|
+
/**
|
|
371
|
+
* useApiSuspenseQuery - Suspense declarative data fetching hook
|
|
372
|
+
*
|
|
373
|
+
* Mirrors useApiQuery but integrates with React Suspense so the initial load is
|
|
374
|
+
* handled by a Suspense boundary. A suspense query always runs, so there is no
|
|
375
|
+
* `enabled` override.
|
|
376
|
+
*/
|
|
377
|
+
|
|
378
|
+
declare function useApiSuspenseQuery<TData = unknown, TError = Error>(descriptor: EndpointDescriptor<TData>, overrides?: ApiSuspenseQueryOverrides): ApiSuspenseQueryResult<TData, TError>;
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* useApiSuspenseInfiniteQuery - Suspense paginated data fetching hook
|
|
382
|
+
*
|
|
383
|
+
* Mirrors useApiInfiniteQuery but integrates with React Suspense so the initial
|
|
384
|
+
* page load is handled by a Suspense boundary while pagination stays
|
|
385
|
+
* descriptor-driven.
|
|
386
|
+
*/
|
|
387
|
+
|
|
388
|
+
declare function useApiSuspenseInfiniteQuery<TPage = unknown, TError = Error>(options: ApiSuspenseInfiniteQueryOptions<TPage>): ApiSuspenseInfiniteQueryResult<TPage, TError>;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* useApiStream - Declarative SSE streaming hook
|
|
392
|
+
*
|
|
393
|
+
* Accepts a StreamDescriptor from @gears-frontx/api and returns the latest
|
|
394
|
+
* event, accumulated events, connection status, and a manual disconnect
|
|
395
|
+
* function.
|
|
396
|
+
*
|
|
397
|
+
* @example
|
|
398
|
+
* ```tsx
|
|
399
|
+
* const { data, events, status, error } = useApiStream(
|
|
400
|
+
* service.messageStream,
|
|
401
|
+
* { mode: 'latest' } // default — data holds last event
|
|
402
|
+
* );
|
|
403
|
+
*
|
|
404
|
+
* // Accumulate all events
|
|
405
|
+
* const { events, status } = useApiStream(service.messageStream, { mode: 'accumulate' });
|
|
406
|
+
* ```
|
|
407
|
+
*/
|
|
408
|
+
|
|
409
|
+
/** Configuration options for useApiStream. */
|
|
410
|
+
interface ApiStreamOptions {
|
|
411
|
+
/**
|
|
412
|
+
* `'latest'` (default) — `data` holds the most recent event.
|
|
413
|
+
* `'accumulate'` — `events` holds all received events in order.
|
|
414
|
+
*/
|
|
415
|
+
mode?: 'latest' | 'accumulate';
|
|
416
|
+
/** When false the connection is deferred (no connect on mount). Default true. */
|
|
417
|
+
enabled?: boolean;
|
|
418
|
+
}
|
|
419
|
+
/** Return type of useApiStream. */
|
|
420
|
+
interface ApiStreamResult<TEvent> {
|
|
421
|
+
/** Latest event payload, set in both modes — `undefined` until the first event and after each connect attempt resets it. */
|
|
422
|
+
data: TEvent | undefined;
|
|
423
|
+
/** All received events when `mode: 'accumulate'`; empty array in `'latest'` mode. */
|
|
424
|
+
events: TEvent[];
|
|
425
|
+
/** Connection lifecycle status. */
|
|
426
|
+
status: StreamStatus;
|
|
427
|
+
/** Last connect error — set when a connect attempt rejects, cleared when the next attempt starts. */
|
|
428
|
+
error: Error | null;
|
|
429
|
+
/** Manually close the connection. */
|
|
430
|
+
disconnect: () => void;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* Manages the status lifecycle for a single SSE stream connection.
|
|
434
|
+
*
|
|
435
|
+
* **Status values**
|
|
436
|
+
* - `'idle'` — no connection is being attempted. This is the status whenever
|
|
437
|
+
* `enabled` is `false`, including on mount: a hook that mounts disabled
|
|
438
|
+
* never reports anything but `'idle'` until `enabled` flips to `true`. A
|
|
439
|
+
* hook that mounts enabled skips `'idle'` entirely — the status is set
|
|
440
|
+
* during render, so its very first render already reports `'connecting'`.
|
|
441
|
+
* Consumers must not assume `'idle'` means "never
|
|
442
|
+
* connected" — a stream that is disabled after having connected returns to
|
|
443
|
+
* `'idle'` too, and `data`/`events` from the earlier connection are not
|
|
444
|
+
* cleared by that transition alone (they are cleared by mode/key changes,
|
|
445
|
+
* see below).
|
|
446
|
+
* - `'connecting'` — a connection attempt is committed to but has not settled.
|
|
447
|
+
* It is published during the render that turns the stream on, which is
|
|
448
|
+
* before `descriptor.connect()` runs: the call is made from an effect after
|
|
449
|
+
* that render commits. So `'connecting'` means "this stream is being
|
|
450
|
+
* opened", not "the connect promise is pending" — for one render the two
|
|
451
|
+
* differ, and a consumer that reads the status as proof a request is already
|
|
452
|
+
* in flight is reading it too strongly.
|
|
453
|
+
* - `'connected'` — set both when `connect()` resolves (unless a disconnect
|
|
454
|
+
* was requested while it was pending) and, independently, whenever the
|
|
455
|
+
* `onEvent` callback delivers a new event. Because every event re-asserts
|
|
456
|
+
* `'connected'`, this status also serves as "still receiving events."
|
|
457
|
+
* - `'disconnected'` — reached via any of: the descriptor's `onComplete`
|
|
458
|
+
* callback firing (the stream ended normally), `connect()` rejecting while
|
|
459
|
+
* a disconnect was requested concurrently, or the manual `disconnect()`
|
|
460
|
+
* function being called. `disconnect()` has no `enabled` guard, but calling
|
|
461
|
+
* it while the stream is disabled is not observable: the stored status moves
|
|
462
|
+
* to `'disconnected'` while the published one stays `'idle'`, and flipping
|
|
463
|
+
* `enabled` back to `true` sets `'connecting'` during that render, so the
|
|
464
|
+
* stored `'disconnected'` is overwritten before it is ever returned.
|
|
465
|
+
* - `'error'` — `connect()` rejected and no disconnect was requested while it
|
|
466
|
+
* was pending. `error` holds the rejection, coerced to an `Error` if it
|
|
467
|
+
* wasn't one already.
|
|
468
|
+
*
|
|
469
|
+
* **Transitions**
|
|
470
|
+
* - Mounting enabled, `enabled` becoming `true`, or `descriptor.key` / `mode`
|
|
471
|
+
* changing while `enabled` is `true`: `data`, `events`, and `error` are reset
|
|
472
|
+
* and status is set to `'connecting'` synchronously during render (not from
|
|
473
|
+
* an effect); `connect()` is then called from an effect that runs after that
|
|
474
|
+
* render commits.
|
|
475
|
+
* - `descriptor.key` or `mode` changing while `enabled` is `false`: `data`,
|
|
476
|
+
* `events`, and `error` are reset all the same, since that reset is not gated
|
|
477
|
+
* on `enabled`, but the status write is - so no `'connecting'` is written and
|
|
478
|
+
* the published status stays `'idle'`; `connect()` is not called. The skipped
|
|
479
|
+
* `'connecting'` is not owed later either: the change counts as handled when
|
|
480
|
+
* it happens, so what publishes `'connecting'` is the subsequent flip of
|
|
481
|
+
* `enabled` to `true`, once, for whichever key and mode are in force by then.
|
|
482
|
+
* - `enabled` becomes `false` (or starts `false`): the published status is
|
|
483
|
+
* `'idle'` for as long as `enabled` stays `false` — it is derived from
|
|
484
|
+
* `enabled` rather than written, so nothing a prior connection stored can
|
|
485
|
+
* surface through it — and `connect()` is never called; no other field is
|
|
486
|
+
* reset by this transition alone.
|
|
487
|
+
* - Unmount, `descriptor.key` change, `mode` change, or `enabled` flipping to
|
|
488
|
+
* `false` while connected or connecting: the previous connection is torn
|
|
489
|
+
* down via `descriptor.disconnect()` once its `connect()` promise settles
|
|
490
|
+
* (or immediately skipped if it rejected). All four share the same cleanup
|
|
491
|
+
* path: the effect's cleanup runs on every dependency change and on unmount.
|
|
492
|
+
* - Calling `disconnect()`: if a connection id is already resolved, it is
|
|
493
|
+
* disconnected immediately and status becomes `'disconnected'`. If
|
|
494
|
+
* `connect()` is still pending, the request is recorded and honored when
|
|
495
|
+
* the promise settles — the newly resolved connection is torn down instead
|
|
496
|
+
* of being adopted, and status is `'disconnected'`. One caveat:
|
|
497
|
+
* `disconnect()` does not cancel the event callback, so a buffered or
|
|
498
|
+
* in-flight event landing after the call re-asserts `'connected'` — and in
|
|
499
|
+
* the pending-connect case the settle handler tears the connection down
|
|
500
|
+
* without touching status, so that stray `'connected'` persists.
|
|
501
|
+
* - Stream completion while `connect()` is still pending: the current
|
|
502
|
+
* implementation lets `onComplete` set `'disconnected'`, then the settle
|
|
503
|
+
* handler adopts the connection id and re-asserts `'connected'` anyway.
|
|
504
|
+
* This is known current behavior, not a durable guarantee: a pending
|
|
505
|
+
* upstream derived-status rewrite is expected to remove this transition.
|
|
506
|
+
*
|
|
507
|
+
* `enabled` (default `true`) is the only way to defer connecting past mount;
|
|
508
|
+
* flipping it back to `true` re-runs the same connect sequence as a fresh
|
|
509
|
+
* mount would.
|
|
510
|
+
*/
|
|
511
|
+
declare function useApiStream<TEvent>(descriptor: StreamDescriptor<TEvent>, options?: ApiStreamOptions): ApiStreamResult<TEvent>;
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Exposes the sanctioned imperative cache API for app and MFE code without
|
|
515
|
+
* leaking the raw QueryClient.
|
|
516
|
+
*
|
|
517
|
+
* Preferred usage:
|
|
518
|
+
* - useApiQuery() for declarative reads
|
|
519
|
+
* - useApiMutation() for writes
|
|
520
|
+
* - useQueryCache() for controlled imperative cache inspection and invalidation
|
|
521
|
+
*
|
|
522
|
+
* The returned handle is not bound to the cache scope (mock mode, tenant,
|
|
523
|
+
* session): it writes to whatever scope is current. A write after an await or
|
|
524
|
+
* inside a mutation callback must use the `queryCache` that callback receives,
|
|
525
|
+
* which drops writes once the scope changed since the mutation started.
|
|
526
|
+
*/
|
|
527
|
+
declare function useQueryCache(): QueryCache;
|
|
528
|
+
|
|
529
|
+
/**
|
|
530
|
+
* Declarative RBAC guard hook.
|
|
531
|
+
*
|
|
532
|
+
* Pessimistic: `allow` is false until an explicit 'allow' decision arrives.
|
|
533
|
+
* Aborts the in-flight canAccess call on unmount and on query change.
|
|
534
|
+
*
|
|
535
|
+
* State machine:
|
|
536
|
+
* mount -> Pending (allow=false, isResolving=true)
|
|
537
|
+
* Pending -> 'allow' -> Allowed (allow=true, isResolving=false)
|
|
538
|
+
* Pending -> 'deny' -> Denied (allow=false, isResolving=false)
|
|
539
|
+
* Pending -> error -> Denied (allow=false, isResolving=false)
|
|
540
|
+
* Allowed -> query-change -> Pending (re-pessimize)
|
|
541
|
+
* Denied -> query-change -> Pending (re-pessimize)
|
|
542
|
+
*/
|
|
543
|
+
declare function useCanAccess<TRecord extends AccessRecord = AccessRecord>(query: AccessQuery<TRecord>): UseCanAccessResult;
|
|
544
|
+
|
|
228
545
|
/**
|
|
229
546
|
* MFE Provider - Provides MFE context to child components
|
|
230
547
|
*
|
|
231
548
|
* Wraps MFE components with bridge and metadata.
|
|
232
549
|
* Used by the MFE mounting system.
|
|
233
550
|
*
|
|
551
|
+
* MfeProvider does not create or own the shared QueryClient. When the host uses
|
|
552
|
+
* queryCache() and the child app uses queryCacheShared(), overlapping queries
|
|
553
|
+
* (same query key) are deduplicated and cached once across MFE boundaries.
|
|
554
|
+
* Each MFE still uses its own apiRegistry and service instances in queryFn.
|
|
555
|
+
*
|
|
234
556
|
* React Layer: L3 (Depends on @gears-frontx/framework)
|
|
235
557
|
*/
|
|
236
558
|
|
|
@@ -283,7 +605,7 @@ declare const MfeProvider: React__default.FC<MfeProviderProps>;
|
|
|
283
605
|
* // bridge.executeActionsChain(chain);
|
|
284
606
|
* // bridge.subscribeToProperty(propertyTypeId, callback);
|
|
285
607
|
*
|
|
286
|
-
* return <div>Domain: {bridge.
|
|
608
|
+
* return <div>Domain: {bridge.extDomainId}</div>;
|
|
287
609
|
* }
|
|
288
610
|
* ```
|
|
289
611
|
*/
|
|
@@ -292,32 +614,94 @@ declare function useMfeBridge(): ChildMfeBridge;
|
|
|
292
614
|
/**
|
|
293
615
|
* useSharedProperty Hook - Shared property subscription
|
|
294
616
|
*
|
|
295
|
-
* Subscribes to shared property updates from the host
|
|
617
|
+
* Subscribes to shared property updates from the host, either through the
|
|
618
|
+
* ambient MfeProvider context or through an explicitly supplied bridge.
|
|
296
619
|
*
|
|
297
620
|
* React Layer: L3
|
|
298
621
|
*/
|
|
622
|
+
|
|
299
623
|
/**
|
|
300
|
-
*
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
624
|
+
* Options for {@link useSharedProperty}.
|
|
625
|
+
*/
|
|
626
|
+
interface UseSharedPropertyOptions<T> {
|
|
627
|
+
/**
|
|
628
|
+
* Bridge to read the property from, bypassing `MfeContext`.
|
|
629
|
+
*
|
|
630
|
+
* Pass this when the calling component never mounts `MfeProvider` (for
|
|
631
|
+
* example, a component that receives its bridge directly as a prop or from
|
|
632
|
+
* a non-React entry point). When omitted, the hook falls back to the
|
|
633
|
+
* bridge from `MfeContext` and throws if no `MfeProvider` is mounted,
|
|
634
|
+
* matching the zero-argument form.
|
|
635
|
+
*
|
|
636
|
+
* `bridge` and `propertyTypeId` identify the subscription: changing either
|
|
637
|
+
* one unsubscribes from the old source and subscribes to the new one, and
|
|
638
|
+
* the returned value reflects the new source on the same render.
|
|
639
|
+
*/
|
|
640
|
+
bridge?: ChildMfeBridge;
|
|
641
|
+
/**
|
|
642
|
+
* Value returned while the host has not published the property yet
|
|
643
|
+
* (`bridge.getProperty()` returns `undefined`).
|
|
644
|
+
*
|
|
645
|
+
* Only the `undefined` sentinel is substituted: a published `null` is a
|
|
646
|
+
* real value and is returned as-is. The host validates every published
|
|
647
|
+
* value against the property's schema before it reaches any MFE
|
|
648
|
+
* (`TypeSystemPlugin.register()` throws on a schema mismatch and the
|
|
649
|
+
* update is never stored or delivered), so no consumer-side filtering is
|
|
650
|
+
* needed -- `T` is simply the caller's declaration of that schema.
|
|
651
|
+
*
|
|
652
|
+
* `fallback` may be passed inline on every render; it does not affect the
|
|
653
|
+
* host subscription.
|
|
654
|
+
*/
|
|
655
|
+
fallback?: T;
|
|
656
|
+
}
|
|
657
|
+
/**
|
|
658
|
+
* Subscribe to a shared property from the host.
|
|
659
|
+
*
|
|
660
|
+
* Two forms:
|
|
661
|
+
*
|
|
662
|
+
* 1. **Context form** -- `useSharedProperty(propertyTypeId)`. Reads the
|
|
663
|
+
* bridge from `MfeContext` and throws if no `MfeProvider` is mounted.
|
|
664
|
+
* 2. **Options form** -- `useSharedProperty(propertyTypeId, options)`. Pass
|
|
665
|
+
* `options.bridge` for components that never mount `MfeProvider`, and/or
|
|
666
|
+
* `options.fallback` for a value to show until the host publishes one.
|
|
667
|
+
* `options.bridge` may be omitted, in which case the hook still falls
|
|
668
|
+
* back to `MfeContext`.
|
|
669
|
+
*
|
|
670
|
+
* Both forms read through `useSyncExternalStore`: the bridge is the store,
|
|
671
|
+
* `bridge.getProperty()` is the snapshot, so the first render already shows
|
|
672
|
+
* the host's current value, a publish between render and commit is picked
|
|
673
|
+
* up when React re-reads the snapshot after subscribing, and the value is
|
|
674
|
+
* tearing-protected under concurrent rendering.
|
|
675
|
+
*
|
|
676
|
+
* @param propertyTypeId - GTS type ID of the shared property to subscribe to
|
|
677
|
+
* @param options - Optional bridge override and fallback
|
|
678
|
+
* @returns The current property value; `T` when `options.fallback` is set,
|
|
679
|
+
* otherwise `T | undefined`
|
|
680
|
+
*
|
|
681
|
+
* @example Context form (inside MfeProvider)
|
|
312
682
|
* ```tsx
|
|
313
|
-
* function
|
|
314
|
-
* const
|
|
683
|
+
* function ThemedComponent() {
|
|
684
|
+
* const theme = useSharedProperty<{ primaryColor: string }>(THEME_PROPERTY_ID);
|
|
685
|
+
* return <div style={{ color: theme?.primaryColor }} />;
|
|
686
|
+
* }
|
|
687
|
+
* ```
|
|
315
688
|
*
|
|
316
|
-
*
|
|
689
|
+
* @example Explicit bridge with fallback (no MfeProvider)
|
|
690
|
+
* ```tsx
|
|
691
|
+
* function StandaloneComponent({ bridge }: { bridge: ChildMfeBridge }) {
|
|
692
|
+
* const label = useSharedProperty<string>(LABEL_PROPERTY_ID, {
|
|
693
|
+
* bridge,
|
|
694
|
+
* fallback: 'Untitled',
|
|
695
|
+
* });
|
|
696
|
+
* return <span>{label}</span>;
|
|
317
697
|
* }
|
|
318
698
|
* ```
|
|
319
699
|
*/
|
|
320
700
|
declare function useSharedProperty<T = unknown>(propertyTypeId: string): T | undefined;
|
|
701
|
+
declare function useSharedProperty<T>(propertyTypeId: string, options: UseSharedPropertyOptions<T> & {
|
|
702
|
+
fallback: T;
|
|
703
|
+
}): T;
|
|
704
|
+
declare function useSharedProperty<T = unknown>(propertyTypeId: string, options?: UseSharedPropertyOptions<T>): T | undefined;
|
|
321
705
|
|
|
322
706
|
/**
|
|
323
707
|
* useHostAction Hook - Host action requests
|
|
@@ -352,6 +736,31 @@ declare function useSharedProperty<T = unknown>(propertyTypeId: string): T | und
|
|
|
352
736
|
*/
|
|
353
737
|
declare function useHostAction<TPayload extends Record<string, unknown> = Record<string, unknown>>(actionTypeId: string): (payload?: TPayload) => void;
|
|
354
738
|
|
|
739
|
+
/**
|
|
740
|
+
* useMfeRegistry Hook - Shared MfeRegistry access guard
|
|
741
|
+
*
|
|
742
|
+
* Resolves the MFE-enabled registry off the FrontX app instance and throws a
|
|
743
|
+
* descriptive error when the `microfrontends()` plugin was not installed.
|
|
744
|
+
* Extracted so every registry-consuming hook shares one guard implementation
|
|
745
|
+
* instead of hand-rolling the same `if (!app.mfeRegistry)` check.
|
|
746
|
+
*
|
|
747
|
+
* React Layer: L3
|
|
748
|
+
*/
|
|
749
|
+
|
|
750
|
+
/**
|
|
751
|
+
* Hook for accessing the MFE-enabled registry off the current FrontX app.
|
|
752
|
+
*
|
|
753
|
+
* Throws if the app was built without the `microfrontends()` plugin.
|
|
754
|
+
*
|
|
755
|
+
* @returns The MFE-enabled registry
|
|
756
|
+
*
|
|
757
|
+
* @example
|
|
758
|
+
* ```ts
|
|
759
|
+
* const registry = useMfeRegistry();
|
|
760
|
+
* ```
|
|
761
|
+
*/
|
|
762
|
+
declare function useMfeRegistry(): MfeRegistry;
|
|
763
|
+
|
|
355
764
|
/**
|
|
356
765
|
* useDomainExtensions Hook - Domain extension list subscription
|
|
357
766
|
*
|
|
@@ -364,7 +773,7 @@ declare function useHostAction<TPayload extends Record<string, unknown> = Record
|
|
|
364
773
|
/**
|
|
365
774
|
* Hook for observing extensions registered for a domain.
|
|
366
775
|
*
|
|
367
|
-
* Subscribes to the
|
|
776
|
+
* Subscribes to the FrontX store to detect registration state changes,
|
|
368
777
|
* and returns the current list of extensions for the specified domain.
|
|
369
778
|
*
|
|
370
779
|
* @param domainId - Domain ID to query extensions for
|
|
@@ -385,7 +794,7 @@ declare function useHostAction<TPayload extends Record<string, unknown> = Record
|
|
|
385
794
|
* }
|
|
386
795
|
* ```
|
|
387
796
|
*/
|
|
388
|
-
declare function useDomainExtensions(domainId: string): Extension
|
|
797
|
+
declare function useDomainExtensions(domainId: string): Array<Omit<Extension, 'route'>>;
|
|
389
798
|
|
|
390
799
|
/**
|
|
391
800
|
* useRegisteredPackages Hook - Registered GTS packages subscription
|
|
@@ -398,7 +807,7 @@ declare function useDomainExtensions(domainId: string): Extension[];
|
|
|
398
807
|
/**
|
|
399
808
|
* Hook for observing registered GTS packages.
|
|
400
809
|
*
|
|
401
|
-
* Subscribes to the
|
|
810
|
+
* Subscribes to the FrontX store to detect registration state changes,
|
|
402
811
|
* and returns the current list of GTS packages extracted from registered
|
|
403
812
|
* extensions.
|
|
404
813
|
*
|
|
@@ -406,7 +815,7 @@ declare function useDomainExtensions(domainId: string): Extension[];
|
|
|
406
815
|
* This hook uses `useSyncExternalStore` with `app.store.subscribe`, which
|
|
407
816
|
* fires on any Redux dispatch. Since `registerExtension()` dispatches to
|
|
408
817
|
* the mfe store slice, the subscription WILL trigger when packages change.
|
|
409
|
-
* The `getSnapshot` function calls `
|
|
818
|
+
* The `getSnapshot` function calls `mfeRegistry.getRegisteredPackages()`
|
|
410
819
|
* which reads the private `packages` Map. This works because every package
|
|
411
820
|
* map mutation (in registerExtension/unregisterExtension) is always
|
|
412
821
|
* accompanied by a store dispatch in the same serializer callback.
|
|
@@ -434,74 +843,182 @@ declare function useDomainExtensions(domainId: string): Extension[];
|
|
|
434
843
|
declare function useRegisteredPackages(): string[];
|
|
435
844
|
|
|
436
845
|
/**
|
|
437
|
-
*
|
|
438
|
-
*
|
|
439
|
-
*
|
|
440
|
-
*
|
|
441
|
-
*
|
|
442
|
-
*
|
|
846
|
+
* Abstract base class for React-based MFE lifecycle implementations.
|
|
847
|
+
*
|
|
848
|
+
* Styling strategy:
|
|
849
|
+
* 1. adoptHostStylesIntoShadowRoot() clones all host <style> and <link> into the
|
|
850
|
+
* front of the shadow root, bringing the full compiled Tailwind CSS (including
|
|
851
|
+
* MFE utilities, since the host's content paths cover src-app/mfe_packages/**) and
|
|
852
|
+
* the ui-kit component CSS (the host entry side-effect-imports
|
|
853
|
+
* @gears-frontx/ui-kit so that CSS exists in the host document; the kit's
|
|
854
|
+
* CSS-module class names are stable per kit version, so they match the
|
|
855
|
+
* classes MFE bundles reference only while host and MFE install the same
|
|
856
|
+
* kit version - the template-pin-drift policy check is what guarantees
|
|
857
|
+
* that; a drifted MFE renders its kit components unstyled with no error).
|
|
858
|
+
* Front, not back, so the MFE's own stylesheets
|
|
859
|
+
* outrank them - see the method. Design tokens must therefore be full CSS
|
|
860
|
+
* colors - both Tailwind utilities (var(--x)) and ui-kit component CSS
|
|
861
|
+
* consume them directly.
|
|
862
|
+
* 2. injectBaseResets() adds box-model resets and :host defaults that aren't part
|
|
863
|
+
* of Tailwind's compiled output but are needed for consistent rendering, and
|
|
864
|
+
* positions them at the end of the shell-owned head - after the adopted block
|
|
865
|
+
* and the isolation style, ahead of the MFE's own CSS.
|
|
866
|
+
* 3. Subclasses may override initializeStyles() to inject additional CSS that is
|
|
867
|
+
* not covered by the host stylesheet (e.g., MFE-specific @font-face rules).
|
|
868
|
+
*
|
|
869
|
+
* Every mount therefore leaves the same sequence - adopted host block, shadow
|
|
870
|
+
* isolation, base resets, then the MFE's stylesheets - so the shell's CSS is
|
|
871
|
+
* context and the MFE wins every specificity tie against all three shell blocks.
|
|
872
|
+
* Steps 1 and 2 both position what they own rather than appending beside it,
|
|
873
|
+
* because a remounted container arrives with its shadow root intact and the MFE's
|
|
874
|
+
* own stylesheet removed and re-appended around the remount - see each method.
|
|
875
|
+
*
|
|
876
|
+
* Theme CSS variables are delivered via CSS inheritance from :root (Shadow DOM)
|
|
877
|
+
* or via MountManager injection (iframe). MFE lifecycles do NOT need to subscribe
|
|
878
|
+
* to theme changes or call applyThemeToShadowRoot.
|
|
879
|
+
*
|
|
880
|
+
* Concrete subclasses must provide:
|
|
881
|
+
* - `renderContent(bridge)` - screen component rendering
|
|
443
882
|
*/
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
883
|
+
declare abstract class ThemeAwareReactLifecycle implements MfeEntryLifecycle<ChildMfeBridge> {
|
|
884
|
+
private readonly app;
|
|
885
|
+
private root;
|
|
886
|
+
constructor(app: FrontXApp);
|
|
887
|
+
mount(container: Element | ShadowRoot, bridge: ChildMfeBridge, mountContext?: MfeMountContext): void;
|
|
888
|
+
/**
|
|
889
|
+
* `Root.unmount()` itself is synchronous, but a nested `ExtensionDomainSlot`
|
|
890
|
+
* mounted anywhere in this root's own tree cannot make ITS cleanup
|
|
891
|
+
* synchronous too — its mounter's own `detach()` awaits per-extension
|
|
892
|
+
* unmounts. Collecting whatever that cleanup fire-and-forgets (through
|
|
893
|
+
* `domainTeardownCollector`, scoped to this one `Root.unmount()` call) and
|
|
894
|
+
* awaiting it here is what makes this method's own returned promise settle
|
|
895
|
+
* only once every nested domain this root owns has actually finished
|
|
896
|
+
* tearing down — never before. A root with no routed nested domain
|
|
897
|
+
* collects nothing, and this resolves exactly as before (a microtask after
|
|
898
|
+
* the synchronous unmount, same observable timing `void | Promise<void>`
|
|
899
|
+
* already allows).
|
|
900
|
+
*/
|
|
901
|
+
unmount(_container: Element | ShadowRoot): Promise<void>;
|
|
902
|
+
/**
|
|
903
|
+
* Copy all inline <style> and <link rel="stylesheet"> from the host document
|
|
904
|
+
* into the shadow root so that Tailwind and component styles apply inside the MFE.
|
|
905
|
+
*
|
|
906
|
+
* The clones are inserted ahead of everything already in the shadow root, never
|
|
907
|
+
* appended, because adopted host styles are context rather than authority: where
|
|
908
|
+
* they and the MFE's own CSS declare the same property at equal specificity, the
|
|
909
|
+
* MFE has to win. Appending inverted that. `MfeHandlerMF` injects the MFE's
|
|
910
|
+
* compiled stylesheet into the shadow root before it calls mount, so an appended
|
|
911
|
+
* clone of the shell's Tailwind preflight - whose
|
|
912
|
+
* `button, [type='button'], [type='reset'], [type='submit']` rule sets
|
|
913
|
+
* `background-color: transparent` at specificity (0,1,0) - tied with
|
|
914
|
+
* `@gears-frontx/ui-kit`'s single-class button rule and won on document order,
|
|
915
|
+
* leaving every kit Button transparent until it was hovered.
|
|
916
|
+
*
|
|
917
|
+
* Inserting at the front rather than pushing MFE styles to the back is what makes
|
|
918
|
+
* the invariant hold for stylesheets that appear after mount too - a lazily
|
|
919
|
+
* imported component's CSS module, or whatever initializeStyles() adds - since
|
|
920
|
+
* those land behind the adopted block by construction.
|
|
921
|
+
*
|
|
922
|
+
* A cascade layer around the adopted CSS was the alternative and is rejected:
|
|
923
|
+
* layered rules lose to unlayered ones at *any* specificity, so a host utility
|
|
924
|
+
* class would stop overriding an MFE element selector. Document order keeps
|
|
925
|
+
* specificity in charge and only settles the ties.
|
|
926
|
+
*
|
|
927
|
+
* The block replaces its predecessor instead of stacking on it, the same
|
|
928
|
+
* upsert shape `injectStylesheet` and `injectCssVariables` use in
|
|
929
|
+
* `@gears-frontx/mfes`' shadow utilities, widened from one id-keyed node to a
|
|
930
|
+
* marked block. Replacement is required rather than tidy: `createShadowRoot`
|
|
931
|
+
* hands back an existing `element.shadowRoot` instead of attaching a new one,
|
|
932
|
+
* so remounting the same container runs this method again on a shadow root
|
|
933
|
+
* that already holds a full adopted block, and appending would grow it once
|
|
934
|
+
* per mount with no bound. It does not save re-resolving the cloned `<link>`s -
|
|
935
|
+
* every mount clones them afresh and the browser resolves each clone; what
|
|
936
|
+
* replacement buys is that the count stays at one block instead of one per
|
|
937
|
+
* mount.
|
|
938
|
+
*
|
|
939
|
+
* The block is rebuilt from the host head rather than left in place, because
|
|
940
|
+
* the head is not fixed: a lazily imported chunk adds stylesheets to it after
|
|
941
|
+
* the first mount, and the second mount has to pick those up.
|
|
942
|
+
*
|
|
943
|
+
* A `<style>` is copied into a new element that holds the host's CSS - see
|
|
944
|
+
* `cssToCopy` - and takes three things from the host element: `media`,
|
|
945
|
+
* without which a print-only host style applies on screen inside the MFE;
|
|
946
|
+
* `type`, which keeps the copy of a non-CSS element as inert as the original;
|
|
947
|
+
* and the nonce, without which a nonce-based CSP blocks the copy. The nonce is read from the `nonce` property, because
|
|
948
|
+
* browsers blank the attribute in a document served with a CSP header.
|
|
949
|
+
* Nothing else is carried over, because libraries look for their own
|
|
950
|
+
* attributes inside the shadow root: styled-components, rendering into it,
|
|
951
|
+
* puts its tag right after the last `style[data-styled]` there, so a copy of
|
|
952
|
+
* the host's tag would pull the MFE's rules ahead of the base resets and the
|
|
953
|
+
* MFE's own CSS. A `<link>` is a deep clone and is loaded from its `href`
|
|
954
|
+
* again.
|
|
955
|
+
*
|
|
956
|
+
* The fresh block goes in before the previous one comes out. Removing first
|
|
957
|
+
* leaves the shadow root with no host CSS at all, and everything between that
|
|
958
|
+
* removal and the insertion is synchronous work in this same task - so the gap
|
|
959
|
+
* never reaches a paint, but any code that reads computed styles from the tree
|
|
960
|
+
* in between sees an unstyled one. Inserting first costs one moment with two
|
|
961
|
+
* blocks present, which changes nothing: the old block is a clone of the same
|
|
962
|
+
* host head and loses every tie to the new one on document order anyway.
|
|
963
|
+
*/
|
|
964
|
+
protected adoptHostStylesIntoShadowRoot(shadowRoot: ShadowRoot): void;
|
|
965
|
+
/**
|
|
966
|
+
* Box-model resets and :host defaults needed inside every shadow root.
|
|
967
|
+
* These aren't part of Tailwind's compiled output but are required for
|
|
968
|
+
* consistent rendering across browsers.
|
|
969
|
+
*
|
|
970
|
+
* Reuses the node a previous mount left behind, exactly as `injectStylesheet`
|
|
971
|
+
* does in `@gears-frontx/mfes`' shadow utilities: a remount runs against a
|
|
972
|
+
* shadow root that `createShadowRoot` handed back intact, and appending a
|
|
973
|
+
* second copy would add one node per mount forever.
|
|
974
|
+
*
|
|
975
|
+
* Reuse alone is not enough, which is why the node is also positioned on every
|
|
976
|
+
* mount rather than left where the previous one sat. These resets are context
|
|
977
|
+
* like the adopted block is - `border-color: currentColor` on `*` is a 0-0-0
|
|
978
|
+
* declaration that beats an MFE preflight's own 0-0-0 reset purely on document
|
|
979
|
+
* order - so they have to stay ahead of the MFE's CSS, and where they land is
|
|
980
|
+
* not stable on its own. `MfeHandlerMF.wrapLifecycleWithStylesheets` removes the
|
|
981
|
+
* MFE's stylesheet on unmount and appends a fresh one before the next mount, so
|
|
982
|
+
* a node merely left in place ends up ahead of that stylesheet on a remount and
|
|
983
|
+
* behind it on the first mount: two different cascades for one component.
|
|
984
|
+
* Anchoring it to the end of the shell-owned head gives every mount the same
|
|
985
|
+
* order - adopted block, isolation, resets, MFE - which is also the order the
|
|
986
|
+
* adoption method's invariant is written against.
|
|
987
|
+
*
|
|
988
|
+
* With no shell-owned node to anchor to, the resets go to the front. That is the
|
|
989
|
+
* plain-`Element` container: no adopted block, no isolation style, and the MFE
|
|
990
|
+
* stylesheet already appended by the handler, so the front is again the only
|
|
991
|
+
* position that leaves the MFE winning ties.
|
|
992
|
+
*
|
|
993
|
+
* Looked up by attribute-selector form rather than `getElementById`, which
|
|
994
|
+
* `ShadowRoot` has but `Element` does not, and this hook takes either.
|
|
995
|
+
*/
|
|
996
|
+
private injectBaseResets;
|
|
997
|
+
/**
|
|
998
|
+
* Hook for subclasses to inject additional CSS not covered by the adopted host
|
|
999
|
+
* stylesheet (e.g., MFE-specific @font-face rules or custom animations).
|
|
1000
|
+
* No-op by default: host styles adopted in adoptHostStylesIntoShadowRoot()
|
|
1001
|
+
* already include all Tailwind utilities compiled from MFE source files.
|
|
1002
|
+
*/
|
|
1003
|
+
protected initializeStyles(_container: Element | ShadowRoot): void;
|
|
1004
|
+
/**
|
|
1005
|
+
* Return the screen-specific React component tree.
|
|
1006
|
+
*/
|
|
1007
|
+
protected abstract renderContent(bridge: ChildMfeBridge): React__default.ReactNode;
|
|
498
1008
|
}
|
|
499
1009
|
|
|
500
1010
|
/**
|
|
501
1011
|
* Extension Domain Slot Component
|
|
502
1012
|
*
|
|
503
|
-
* React component that
|
|
504
|
-
*
|
|
1013
|
+
* Per-domain React component that provides the DOM root for a registered domain.
|
|
1014
|
+
* Delegates root attachment to the per-domain ExtensionMounter obtained from the
|
|
1015
|
+
* registry. What extensions live inside the root is a domain-policy concern (the
|
|
1016
|
+
* active MountStrategy plus the domain implementation's ContainerHooks), not a
|
|
1017
|
+
* slot-API concern.
|
|
1018
|
+
*
|
|
1019
|
+
* The slot is uniform across all cardinalities (Exclusive / Optional / Concurrent).
|
|
1020
|
+
* Mount and unmount actions are dispatched by the host application via
|
|
1021
|
+
* registry.executeActionsChain — NOT by this component.
|
|
505
1022
|
*
|
|
506
1023
|
* @packageDocumentation
|
|
507
1024
|
*/
|
|
@@ -511,57 +1028,47 @@ declare class RefContainerProvider extends ContainerProvider {
|
|
|
511
1028
|
*/
|
|
512
1029
|
interface ExtensionDomainSlotProps {
|
|
513
1030
|
/**
|
|
514
|
-
* The
|
|
1031
|
+
* The MFE registry instance.
|
|
515
1032
|
*/
|
|
516
|
-
registry:
|
|
1033
|
+
registry: MfeRegistry;
|
|
517
1034
|
/**
|
|
518
|
-
* The domain ID for this slot
|
|
1035
|
+
* The domain ID for this slot.
|
|
519
1036
|
*/
|
|
520
1037
|
domainId: string;
|
|
521
1038
|
/**
|
|
522
|
-
*
|
|
523
|
-
*/
|
|
524
|
-
extensionId: string;
|
|
525
|
-
/**
|
|
526
|
-
* Optional CSS class name for the container
|
|
1039
|
+
* Optional CSS class name for the root container div.
|
|
527
1040
|
*/
|
|
528
1041
|
className?: string;
|
|
529
1042
|
/**
|
|
530
|
-
* Optional callback
|
|
1043
|
+
* Optional callback invoked after mounter.attach(element) returns.
|
|
1044
|
+
* Receives the root element that was attached.
|
|
531
1045
|
*/
|
|
532
|
-
|
|
1046
|
+
onAttached?: (root: Element) => void;
|
|
533
1047
|
/**
|
|
534
|
-
* Optional callback
|
|
1048
|
+
* Optional callback invoked after mounter.detach() returns on cleanup.
|
|
535
1049
|
*/
|
|
536
|
-
|
|
1050
|
+
onDetached?: () => void;
|
|
537
1051
|
/**
|
|
538
|
-
* Optional
|
|
539
|
-
|
|
540
|
-
onError?: (error: Error) => void;
|
|
541
|
-
/**
|
|
542
|
-
* Optional loading component
|
|
1052
|
+
* Optional loading placeholder rendered before the mounter has been attached.
|
|
1053
|
+
* Defaults to null (no visual placeholder).
|
|
543
1054
|
*/
|
|
544
1055
|
loadingComponent?: React__default.ReactNode;
|
|
545
|
-
/**
|
|
546
|
-
* Optional error component renderer
|
|
547
|
-
*/
|
|
548
|
-
errorComponent?: (error: Error) => React__default.ReactNode;
|
|
549
1056
|
}
|
|
550
1057
|
/**
|
|
551
1058
|
* Extension Domain Slot Component
|
|
552
1059
|
*
|
|
553
|
-
* Renders
|
|
554
|
-
* -
|
|
555
|
-
*
|
|
556
|
-
*
|
|
1060
|
+
* Renders a single root `<div>` per domain instance. On ref-attach, resolves the
|
|
1061
|
+
* per-domain mounter via registry.getMounter(domainId) and calls mounter.attach(element).
|
|
1062
|
+
* On cleanup, calls mounter.detach() which mass-unmounts every currently-mounted
|
|
1063
|
+
* extension in the domain so no orphan DOM trees or slice/registry desync remain.
|
|
557
1064
|
*
|
|
558
1065
|
* @example
|
|
559
1066
|
* ```tsx
|
|
560
1067
|
* <ExtensionDomainSlot
|
|
561
1068
|
* registry={registry}
|
|
562
|
-
* domainId=
|
|
563
|
-
*
|
|
564
|
-
*
|
|
1069
|
+
* domainId={FRONTX_SCREEN_DOMAIN}
|
|
1070
|
+
* loadingComponent={<Loading />}
|
|
1071
|
+
* onAttached={(root) => console.log('Root attached:', root)}
|
|
565
1072
|
* />
|
|
566
1073
|
* ```
|
|
567
1074
|
*/
|
|
@@ -571,7 +1078,7 @@ declare function ExtensionDomainSlot(props: ExtensionDomainSlotProps): React__de
|
|
|
571
1078
|
* @gears-frontx/react - React Bindings
|
|
572
1079
|
*
|
|
573
1080
|
* This package provides:
|
|
574
|
-
* -
|
|
1081
|
+
* - FrontXProvider context provider
|
|
575
1082
|
* - Type-safe hooks for state and actions
|
|
576
1083
|
* - MFE context, hooks, and components
|
|
577
1084
|
*
|
|
@@ -587,4 +1094,4 @@ interface EventPayloadMap extends EventPayloadMap$1 {
|
|
|
587
1094
|
*/
|
|
588
1095
|
declare const eventBus: EventBus<EventPayloadMap>;
|
|
589
1096
|
|
|
590
|
-
export { type EventPayloadMap, ExtensionDomainSlot, type ExtensionDomainSlotProps,
|
|
1097
|
+
export { type ApiInfiniteQueryOptions, type ApiInfiniteQueryPageContext, ApiInfiniteQueryResult, ApiMutationResult, type ApiQueryOverrides, ApiQueryResult, type ApiStreamOptions, type ApiStreamResult, type ApiSuspenseInfiniteQueryOptions, ApiSuspenseInfiniteQueryResult, type ApiSuspenseQueryOverrides, ApiSuspenseQueryResult, CanAccess, CanAccessProps, type EventPayloadMap, ExtensionDomainSlot, type ExtensionDomainSlotProps, FrontXContext, FrontXProvider, FrontXProviderProps, MfeContextValue, MfeProvider, type MfeProviderProps, MutationCallbackContext, QueryCache, ThemeAwareReactLifecycle, type UseApiMutationOptions, UseCanAccessResult, UseFormattersReturn, UseScreenTranslationsReturn, type UseSharedPropertyOptions, UseThemeReturn, UseTranslationReturn, eventBus, useApiInfiniteQuery, useApiMutation, useApiQuery, useApiStream, useApiSuspenseInfiniteQuery, useApiSuspenseQuery, useAppDispatch, useAppSelector, useCanAccess, useDomainExtensions, useFormatters, useFrontX, useHostAction, useMfeBridge, useMfeRegistry, useQueryCache, useRegisteredPackages, useScreenTranslations, useSharedProperty, useTheme, useTranslation };
|