@open-mercato/ui 0.6.8-develop.6930.1.1e5976efc3 → 0.6.8-develop.6940.1.177ea30c6e
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/backend/CrudForm.js +177 -93
- package/dist/backend/CrudForm.js.map +2 -2
- package/dist/backend/injection/InjectionSpot.js +13 -4
- package/dist/backend/injection/InjectionSpot.js.map +2 -2
- package/dist/backend/injection/useRegisteredComponent.js +48 -36
- package/dist/backend/injection/useRegisteredComponent.js.map +2 -2
- package/package.json +3 -3
- package/src/backend/CrudForm.tsx +216 -103
- package/src/backend/__tests__/CrudForm.asyncInjectionTransform.test.tsx +555 -0
- package/src/backend/injection/InjectionSpot.tsx +13 -5
- package/src/backend/injection/__tests__/InjectionSpot.features.test.tsx +26 -0
- package/src/backend/injection/__tests__/useRegisteredComponent.remount.test.tsx +96 -0
- package/src/backend/injection/useRegisteredComponent.tsx +85 -38
|
@@ -211,6 +211,15 @@ function useInjectionSpotEvents(spotId, prefetchedWidgets) {
|
|
|
211
211
|
[payload?.grantedFeatures]
|
|
212
212
|
);
|
|
213
213
|
const hasBackendChromePayload = payload !== null;
|
|
214
|
+
const prefetchedEventWidgets = React.useMemo(() => {
|
|
215
|
+
if (prefetchedWidgets === void 0 || !backendChromeReady) return [];
|
|
216
|
+
return filterWidgetsByGrantedFeatures(
|
|
217
|
+
prefetchedWidgets,
|
|
218
|
+
grantedFeatureList,
|
|
219
|
+
hasBackendChromePayload
|
|
220
|
+
);
|
|
221
|
+
}, [backendChromeReady, grantedFeatureList, hasBackendChromePayload, prefetchedWidgets]);
|
|
222
|
+
const eventWidgets = prefetchedWidgets === void 0 ? widgets : prefetchedEventWidgets;
|
|
214
223
|
React.useEffect(() => {
|
|
215
224
|
return subscribeToInjectionRegistryChanges(() => {
|
|
216
225
|
setRegistryVersion(getInjectionRegistryVersion());
|
|
@@ -287,7 +296,7 @@ function useInjectionSpotEvents(spotId, prefetchedWidgets) {
|
|
|
287
296
|
if (TRANSFORMER_EVENTS.has(event)) {
|
|
288
297
|
let pipelineData = data;
|
|
289
298
|
let applyToForm = false;
|
|
290
|
-
for (const widget of
|
|
299
|
+
for (const widget of eventWidgets) {
|
|
291
300
|
const handler = widget.module.eventHandlers?.[event];
|
|
292
301
|
if (!handler) continue;
|
|
293
302
|
try {
|
|
@@ -315,7 +324,7 @@ function useInjectionSpotEvents(spotId, prefetchedWidgets) {
|
|
|
315
324
|
let fieldValue = meta?.fieldValue;
|
|
316
325
|
let fieldSideEffects;
|
|
317
326
|
let fieldMessages;
|
|
318
|
-
for (const widget of
|
|
327
|
+
for (const widget of eventWidgets) {
|
|
319
328
|
const eventHandlers = widget.module.eventHandlers;
|
|
320
329
|
const operationFilter = eventHandlers?.filter?.operations;
|
|
321
330
|
if (operationFilter) {
|
|
@@ -396,9 +405,9 @@ function useInjectionSpotEvents(spotId, prefetchedWidgets) {
|
|
|
396
405
|
}
|
|
397
406
|
return { ok: true };
|
|
398
407
|
},
|
|
399
|
-
[
|
|
408
|
+
[eventWidgets]
|
|
400
409
|
);
|
|
401
|
-
return { triggerEvent, widgets };
|
|
410
|
+
return { triggerEvent, widgets: eventWidgets };
|
|
402
411
|
}
|
|
403
412
|
export {
|
|
404
413
|
InjectionSpot,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/injection/InjectionSpot.tsx"],
|
|
4
|
-
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport type {\n InjectionSpotId,\n InjectionWidgetModule,\n WidgetInjectionEventHandlers,\n WidgetBeforeDeleteResult,\n WidgetBeforeSaveResult,\n FieldChangeResult,\n NavigateGuardResult,\n} from '@open-mercato/shared/modules/widgets/injection'\nimport {\n getInjectionRegistryVersion,\n loadInjectionWidgetsForSpot,\n subscribeToInjectionRegistryChanges,\n type LoadedInjectionWidget,\n} from '@open-mercato/shared/modules/widgets/injection-loader'\nimport { hasAllFeatures } from '@open-mercato/shared/security/features'\nimport { useBackendChrome } from '../BackendChromeProvider'\nimport { getWidgetSharedState } from './WidgetSharedState'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('ui').child({ component: 'InjectionSpot' })\n\nexport type InjectionSpotProps<TContext = unknown, TData = unknown> = {\n spotId: InjectionSpotId\n context: TContext\n data?: TData\n onDataChange?: (data: TData) => void\n disabled?: boolean\n onEvent?: (\n event: keyof WidgetInjectionEventHandlers<TContext, TData>,\n widgetId: string,\n ) => void\n widgetsOverride?: LoadedWidget[]\n}\n\n/**\n * Transformer events use pipeline dispatch: output of widget N becomes input of widget N+1.\n */\nconst TRANSFORMER_EVENTS = new Set<string>([\n 'transformFormData',\n 'transformDisplayData',\n 'transformValidation',\n])\n\ntype LoadedWidget = {\n widgetId: string\n module: InjectionWidgetModule<any, any>\n moduleId: string\n key: string\n placement?: LoadedInjectionWidget['placement']\n}\n\nexport type LoadedInjectionSpotWidget = LoadedWidget\n\nfunction toLoadedWidget(widget: LoadedInjectionWidget): LoadedWidget {\n return {\n widgetId: widget.metadata.id,\n module: widget,\n moduleId: widget.moduleId,\n key: widget.key,\n placement: widget.placement,\n }\n}\n\nfunction hasGrantedWidgetFeatures(\n widget: LoadedWidget,\n grantedFeatures: string[],\n hasBackendChromePayload: boolean,\n): boolean {\n if (!hasBackendChromePayload) return true\n const features = widget.module.metadata.features ?? []\n return features.length === 0 || hasAllFeatures(grantedFeatures, features)\n}\n\nfunction filterWidgetsByGrantedFeatures(\n widgets: LoadedWidget[],\n grantedFeatures: string[],\n hasBackendChromePayload: boolean,\n): LoadedWidget[] {\n return widgets.filter((widget) => hasGrantedWidgetFeatures(widget, grantedFeatures, hasBackendChromePayload))\n}\n\nfunction areSameLoadedWidgets(current: LoadedWidget[], next: LoadedWidget[]): boolean {\n if (current.length !== next.length) return false\n return current.every((widget, index) => {\n const nextWidget = next[index]\n return (\n nextWidget !== undefined &&\n widget.widgetId === nextWidget.widgetId &&\n widget.moduleId === nextWidget.moduleId &&\n widget.key === nextWidget.key &&\n widget.module === nextWidget.module\n )\n })\n}\n\nfunction setWidgetsIfChanged(\n setWidgets: React.Dispatch<React.SetStateAction<LoadedWidget[]>>,\n next: LoadedWidget[],\n) {\n setWidgets((current) => (areSameLoadedWidgets(current, next) ? current : next))\n}\n\nfunction injectSharedStateIntoContext<TContext>(context: TContext, moduleId: string): TContext {\n const sharedState = getWidgetSharedState(moduleId)\n if (typeof context === 'object' && context !== null && !Array.isArray(context)) {\n return {\n ...(context as Record<string, unknown>),\n sharedState,\n } as TContext\n }\n return {\n value: context,\n sharedState,\n } as TContext\n}\n\nexport function useInjectionWidgets<TContext = unknown>(\n spotId: InjectionSpotId | null | undefined,\n options?: {\n context?: TContext\n triggerOnLoad?: boolean\n onEvent?: (event: 'onLoad', widgetId: string) => void\n }\n) {\n const [widgets, setWidgets] = React.useState<LoadedWidget[]>([])\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [registryVersion, setRegistryVersion] = React.useState(() => getInjectionRegistryVersion())\n const loadedWidgetIdsRef = React.useRef(new Set<string>())\n const contextRef = React.useRef(options?.context)\n const triggerOnLoadRef = React.useRef(options?.triggerOnLoad)\n const onEventRef = React.useRef(options?.onEvent)\n const { payload, isReady: backendChromeReady } = useBackendChrome()\n const grantedFeatureList = React.useMemo(\n () => payload?.grantedFeatures ?? [],\n [payload?.grantedFeatures],\n )\n const hasBackendChromePayload = payload !== null\n\n React.useEffect(() => {\n contextRef.current = options?.context\n triggerOnLoadRef.current = options?.triggerOnLoad\n onEventRef.current = options?.onEvent\n })\n\n React.useEffect(() => {\n return subscribeToInjectionRegistryChanges(() => {\n setRegistryVersion(getInjectionRegistryVersion())\n })\n }, [])\n\n React.useEffect(() => {\n if (!spotId) {\n setWidgets([])\n setLoading(false)\n setError(null)\n return\n }\n if (!backendChromeReady) {\n setLoading(true)\n setError(null)\n return\n }\n let mounted = true\n const load = async () => {\n try {\n setLoading(true)\n setError(null)\n const loaded = await loadInjectionWidgetsForSpot(spotId)\n if (!mounted) return\n const widgetList = filterWidgetsByGrantedFeatures(\n loaded.map(toLoadedWidget),\n grantedFeatureList,\n hasBackendChromePayload,\n )\n setWidgets(widgetList)\n\n // Trigger onLoad for all widgets\n if (triggerOnLoadRef.current) {\n for (const widget of widgetList) {\n if (loadedWidgetIdsRef.current.has(widget.widgetId)) continue\n loadedWidgetIdsRef.current.add(widget.widgetId)\n if (widget.module.eventHandlers?.onLoad) {\n try {\n const widgetContext = injectSharedStateIntoContext(contextRef.current as TContext, widget.moduleId)\n await widget.module.eventHandlers.onLoad(widgetContext)\n onEventRef.current?.('onLoad', widget.widgetId)\n } catch (err) {\n logger.error('Error in onLoad for widget', { widgetId: widget.widgetId, err })\n }\n }\n }\n }\n } catch (err) {\n if (!mounted) return\n logger.error('Failed to load widgets for spot', { spotId, err })\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n if (mounted) setLoading(false)\n }\n }\n load()\n return () => {\n mounted = false\n }\n // context/triggerOnLoad/onEvent are read from refs so only a real registry-version bump reloads the spot\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [spotId, registryVersion, backendChromeReady, grantedFeatureList, hasBackendChromePayload])\n\n return { widgets, loading, error }\n}\n\nexport function InjectionSpot<TContext = unknown, TData = unknown>({\n spotId,\n context,\n data,\n onDataChange,\n disabled,\n onEvent,\n widgetsOverride,\n}: InjectionSpotProps<TContext, TData>) {\n const hasWidgetsOverride = widgetsOverride !== undefined\n const useSpotId = hasWidgetsOverride ? null : spotId\n const onEventRef = React.useRef(onEvent)\n React.useEffect(() => {\n onEventRef.current = onEvent\n })\n const hasOnEvent = Boolean(onEvent)\n const stableOnEvent = React.useMemo(\n () => (hasOnEvent ? (event: 'onLoad', id: string) => onEventRef.current?.(event, id) : undefined),\n [hasOnEvent],\n )\n const { widgets, loading, error } = useInjectionWidgets<TContext>(useSpotId, {\n context,\n triggerOnLoad: !hasWidgetsOverride,\n onEvent: stableOnEvent,\n })\n const { payload: overrideFeaturePayload, isReady: overrideBackendChromeReady } = useBackendChrome()\n const overrideGrantedFeatureList = React.useMemo(\n () => overrideFeaturePayload?.grantedFeatures ?? [],\n [overrideFeaturePayload?.grantedFeatures],\n )\n const overrideHasBackendChromePayload = overrideFeaturePayload !== null\n const filteredWidgetsOverride = React.useMemo(\n () =>\n widgetsOverride === undefined\n ? undefined\n : filterWidgetsByGrantedFeatures(\n widgetsOverride,\n overrideGrantedFeatureList,\n overrideHasBackendChromePayload,\n ),\n [widgetsOverride, overrideGrantedFeatureList, overrideHasBackendChromePayload],\n )\n const effectiveWidgets = hasWidgetsOverride\n ? (overrideBackendChromeReady ? filteredWidgetsOverride ?? [] : [])\n : widgets\n const effectiveLoading = hasWidgetsOverride ? !overrideBackendChromeReady : loading\n const effectiveError = hasWidgetsOverride ? null : error\n\n if (effectiveLoading && effectiveWidgets.length === 0) {\n return null\n }\n\n if (effectiveError) {\n logger.error('Error loading widgets for spot', { spotId, err: effectiveError })\n return null\n }\n\n if (effectiveWidgets.length === 0) {\n return null\n }\n\n return (\n <>\n {effectiveWidgets.map((widget) => {\n const { Widget } = widget.module\n return (\n <Widget\n key={widget.widgetId}\n context={injectSharedStateIntoContext(context, widget.moduleId)}\n data={data}\n onDataChange={onDataChange}\n disabled={disabled}\n />\n )\n })}\n </>\n )\n}\n\n/**\n * Hook to trigger injection widget events imperatively\n */\nexport function useInjectionSpotEvents<TContext = unknown, TData = unknown>(spotId: InjectionSpotId, prefetchedWidgets?: LoadedWidget[]) {\n const [widgets, setWidgets] = React.useState<LoadedWidget[]>([])\n const [registryVersion, setRegistryVersion] = React.useState(() => getInjectionRegistryVersion())\n const { payload, isReady: backendChromeReady } = useBackendChrome()\n const grantedFeatureList = React.useMemo(\n () => payload?.grantedFeatures ?? [],\n [payload?.grantedFeatures],\n )\n const hasBackendChromePayload = payload !== null\n\n React.useEffect(() => {\n return subscribeToInjectionRegistryChanges(() => {\n setRegistryVersion(getInjectionRegistryVersion())\n })\n }, [])\n\n React.useEffect(() => {\n if (!backendChromeReady) {\n setWidgetsIfChanged(setWidgets, [])\n return\n }\n if (prefetchedWidgets !== undefined) {\n setWidgetsIfChanged(\n setWidgets,\n filterWidgetsByGrantedFeatures(prefetchedWidgets, grantedFeatureList, hasBackendChromePayload),\n )\n return\n }\n let mounted = true\n const load = async () => {\n try {\n const loaded = await loadInjectionWidgetsForSpot(spotId)\n if (!mounted) return\n setWidgetsIfChanged(\n setWidgets,\n filterWidgetsByGrantedFeatures(\n loaded.map(toLoadedWidget),\n grantedFeatureList,\n hasBackendChromePayload,\n )\n )\n } catch (err) {\n logger.error('Failed to load widgets for spot', { hook: 'useInjectionSpotEvents', spotId, err })\n }\n }\n load()\n return () => {\n mounted = false\n }\n }, [spotId, prefetchedWidgets, registryVersion, backendChromeReady, grantedFeatureList, hasBackendChromePayload])\n\n const triggerEvent = React.useCallback(\n async (\n event: keyof WidgetInjectionEventHandlers<TContext, TData>,\n data: TData,\n context: TContext,\n meta?: {\n error?: unknown\n fieldId?: string\n fieldValue?: unknown\n originalData?: TData\n target?: unknown\n visible?: boolean\n appEvent?: unknown\n }\n ): Promise<{\n ok: boolean\n message?: string\n fieldErrors?: Record<string, string>\n requestHeaders?: Record<string, string>\n details?: unknown\n data?: TData\n applyToForm?: boolean\n fieldChange?: {\n value?: unknown\n sideEffects?: Record<string, unknown>\n messages?: Array<{ text: string; severity: 'info' | 'warning' | 'error' }>\n }\n }> => {\n const normalizeBeforeSave = (\n result: WidgetBeforeSaveResult,\n ): { ok: boolean; message?: string; fieldErrors?: Record<string, string>; requestHeaders?: Record<string, string>; details?: unknown } => {\n if (result === false) return { ok: false }\n if (result === true || typeof result === 'undefined') return { ok: true }\n if (result && typeof result === 'object') {\n const ok = typeof result.ok === 'boolean' ? result.ok : true\n const message = typeof result.message === 'string' ? result.message : undefined\n const fieldErrors =\n result.fieldErrors && typeof result.fieldErrors === 'object'\n ? Object.fromEntries(\n Object.entries(result.fieldErrors).map(([key, value]) => [key, String(value)]),\n )\n : undefined\n const requestHeaders =\n result.requestHeaders && typeof result.requestHeaders === 'object'\n ? Object.fromEntries(\n Object.entries(result.requestHeaders).map(([key, value]) => [key, String(value)]),\n )\n : undefined\n return { ok, message, fieldErrors, requestHeaders, details: result.details }\n }\n return { ok: true }\n }\n\n const normalizeBeforeDelete = (\n result: WidgetBeforeDeleteResult,\n ): { ok: boolean; message?: string; fieldErrors?: Record<string, string>; requestHeaders?: Record<string, string>; details?: unknown } => {\n if (result === false) return { ok: false }\n if (result === true || typeof result === 'undefined') return { ok: true }\n if (result && typeof result === 'object') {\n const ok = typeof result.ok === 'boolean' ? result.ok : true\n const message = typeof result.message === 'string' ? result.message : undefined\n const fieldErrors =\n result.fieldErrors && typeof result.fieldErrors === 'object'\n ? Object.fromEntries(\n Object.entries(result.fieldErrors).map(([key, value]) => [key, String(value)]),\n )\n : undefined\n const requestHeaders =\n result.requestHeaders && typeof result.requestHeaders === 'object'\n ? Object.fromEntries(\n Object.entries(result.requestHeaders).map(([key, value]) => [key, String(value)]),\n )\n : undefined\n return { ok, message, fieldErrors, requestHeaders, details: result.details }\n }\n return { ok: true }\n }\n\n // --- Transformer events: pipeline dispatch ---\n // Output of widget N becomes input of widget N+1\n if (TRANSFORMER_EVENTS.has(event)) {\n let pipelineData = data\n let applyToForm = false\n for (const widget of widgets) {\n const handler = widget.module.eventHandlers?.[event]\n if (!handler) continue\n try {\n const widgetContext = injectSharedStateIntoContext(context, widget.moduleId)\n let handlerResult: unknown\n if (event === 'transformValidation') {\n handlerResult = await (handler as any)(pipelineData, meta?.originalData ?? data, widgetContext)\n } else {\n handlerResult = await (handler as any)(pipelineData, widgetContext)\n }\n if (\n event === 'transformFormData' &&\n handlerResult !== null &&\n typeof handlerResult === 'object' &&\n 'applyToForm' in handlerResult &&\n (handlerResult as { applyToForm: unknown }).applyToForm === true &&\n 'data' in handlerResult\n ) {\n pipelineData = (handlerResult as { data: TData }).data\n applyToForm = true\n } else {\n pipelineData = handlerResult as TData\n }\n } catch (err) {\n logger.error('Error in event handler for widget', { hook: 'useInjectionSpotEvents', event, widgetId: widget.widgetId, err })\n }\n }\n return { ok: true, data: pipelineData, applyToForm }\n }\n\n // --- Action events: sequential dispatch ---\n const mergedRequestHeaders: Record<string, string> = {}\n let hasRequestHeaders = false\n let fieldValue = meta?.fieldValue\n let fieldSideEffects: Record<string, unknown> | undefined\n let fieldMessages: Array<{ text: string; severity: 'info' | 'warning' | 'error' }> | undefined\n\n for (const widget of widgets) {\n const eventHandlers = widget.module.eventHandlers\n // Check operation filter \u2014 skip widget if current operation is filtered out\n const operationFilter = eventHandlers?.filter?.operations\n if (operationFilter) {\n const currentOperation = (context as Record<string, unknown>)?.operation as string | undefined\n if (currentOperation && !operationFilter.includes(currentOperation as 'create' | 'update' | 'delete')) {\n continue\n }\n }\n let handler = eventHandlers?.[event]\n // Delete-to-save fallback chain\n if (!handler && event === 'onBeforeDelete') handler = eventHandlers?.onBeforeSave as typeof handler\n if (!handler && event === 'onDelete') handler = eventHandlers?.onSave as typeof handler\n if (!handler && event === 'onAfterDelete') handler = eventHandlers?.onAfterSave as typeof handler\n if (handler) {\n try {\n const widgetContext = injectSharedStateIntoContext(context, widget.moduleId)\n const result =\n event === 'onDeleteError'\n ? await (handler as any)(data, widgetContext, meta?.error)\n : event === 'onFieldChange'\n ? await (handler as any)(meta?.fieldId, fieldValue, data, widgetContext)\n : event === 'onBeforeNavigate'\n ? await (handler as any)(meta?.target, widgetContext)\n : event === 'onVisibilityChange'\n ? await (handler as any)(meta?.visible, widgetContext)\n : event === 'onAppEvent'\n ? await (handler as any)(meta?.appEvent, widgetContext)\n : await (handler as any)(data, widgetContext)\n if (event === 'onBeforeSave') {\n const normalized = normalizeBeforeSave(result as WidgetBeforeSaveResult)\n if (!normalized.ok) {\n logger.info('Widget prevented event', { hook: 'useInjectionSpotEvents', widgetId: widget.widgetId, event })\n return normalized\n }\n if (normalized.requestHeaders && Object.keys(normalized.requestHeaders).length > 0) {\n Object.assign(mergedRequestHeaders, normalized.requestHeaders)\n hasRequestHeaders = true\n }\n }\n if (event === 'onBeforeDelete') {\n const normalized = normalizeBeforeDelete(result as WidgetBeforeDeleteResult)\n if (!normalized.ok) {\n logger.info('Widget prevented event', { hook: 'useInjectionSpotEvents', widgetId: widget.widgetId, event })\n return normalized\n }\n if (normalized.requestHeaders && Object.keys(normalized.requestHeaders).length > 0) {\n Object.assign(mergedRequestHeaders, normalized.requestHeaders)\n hasRequestHeaders = true\n }\n }\n if (event === 'onBeforeNavigate') {\n const navResult = result as NavigateGuardResult | undefined\n if (navResult && navResult.ok === false) {\n return { ok: false, message: navResult.message }\n }\n }\n if (event === 'onFieldChange') {\n const changeResult = result as FieldChangeResult | void\n if (changeResult?.value !== undefined) {\n fieldValue = changeResult.value\n }\n if (changeResult?.sideEffects && typeof changeResult.sideEffects === 'object') {\n fieldSideEffects = { ...(fieldSideEffects ?? {}), ...changeResult.sideEffects }\n }\n if (changeResult?.message?.text) {\n fieldMessages = [...(fieldMessages ?? []), changeResult.message]\n }\n }\n } catch (err) {\n logger.error('Error in event handler for widget', { hook: 'useInjectionSpotEvents', event, widgetId: widget.widgetId, err })\n if (event === 'onBeforeSave' || event === 'onBeforeDelete' || event === 'onBeforeNavigate') {\n const message =\n err instanceof Error\n ? err.message || 'Validation blocked'\n : typeof err === 'string'\n ? err\n : undefined\n return { ok: false, message }\n }\n }\n }\n }\n if ((event === 'onBeforeSave' || event === 'onBeforeDelete') && hasRequestHeaders) {\n return { ok: true, requestHeaders: mergedRequestHeaders }\n }\n if (event === 'onFieldChange') {\n return {\n ok: true,\n fieldChange: {\n value: fieldValue,\n sideEffects: fieldSideEffects,\n messages: fieldMessages,\n },\n }\n }\n return { ok: true }\n },\n [widgets]\n )\n\n return { triggerEvent, widgets }\n}\n"],
|
|
5
|
-
"mappings": "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",
|
|
4
|
+
"sourcesContent": ["\"use client\"\nimport * as React from 'react'\nimport type {\n InjectionSpotId,\n InjectionWidgetModule,\n WidgetInjectionEventHandlers,\n WidgetBeforeDeleteResult,\n WidgetBeforeSaveResult,\n FieldChangeResult,\n NavigateGuardResult,\n} from '@open-mercato/shared/modules/widgets/injection'\nimport {\n getInjectionRegistryVersion,\n loadInjectionWidgetsForSpot,\n subscribeToInjectionRegistryChanges,\n type LoadedInjectionWidget,\n} from '@open-mercato/shared/modules/widgets/injection-loader'\nimport { hasAllFeatures } from '@open-mercato/shared/security/features'\nimport { useBackendChrome } from '../BackendChromeProvider'\nimport { getWidgetSharedState } from './WidgetSharedState'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('ui').child({ component: 'InjectionSpot' })\n\nexport type InjectionSpotProps<TContext = unknown, TData = unknown> = {\n spotId: InjectionSpotId\n context: TContext\n data?: TData\n onDataChange?: (data: TData) => void\n disabled?: boolean\n onEvent?: (\n event: keyof WidgetInjectionEventHandlers<TContext, TData>,\n widgetId: string,\n ) => void\n widgetsOverride?: LoadedWidget[]\n}\n\n/**\n * Transformer events use pipeline dispatch: output of widget N becomes input of widget N+1.\n */\nconst TRANSFORMER_EVENTS = new Set<string>([\n 'transformFormData',\n 'transformDisplayData',\n 'transformValidation',\n])\n\ntype LoadedWidget = {\n widgetId: string\n module: InjectionWidgetModule<any, any>\n moduleId: string\n key: string\n placement?: LoadedInjectionWidget['placement']\n}\n\nexport type LoadedInjectionSpotWidget = LoadedWidget\n\nfunction toLoadedWidget(widget: LoadedInjectionWidget): LoadedWidget {\n return {\n widgetId: widget.metadata.id,\n module: widget,\n moduleId: widget.moduleId,\n key: widget.key,\n placement: widget.placement,\n }\n}\n\nfunction hasGrantedWidgetFeatures(\n widget: LoadedWidget,\n grantedFeatures: string[],\n hasBackendChromePayload: boolean,\n): boolean {\n if (!hasBackendChromePayload) return true\n const features = widget.module.metadata.features ?? []\n return features.length === 0 || hasAllFeatures(grantedFeatures, features)\n}\n\nfunction filterWidgetsByGrantedFeatures(\n widgets: LoadedWidget[],\n grantedFeatures: string[],\n hasBackendChromePayload: boolean,\n): LoadedWidget[] {\n return widgets.filter((widget) => hasGrantedWidgetFeatures(widget, grantedFeatures, hasBackendChromePayload))\n}\n\nfunction areSameLoadedWidgets(current: LoadedWidget[], next: LoadedWidget[]): boolean {\n if (current.length !== next.length) return false\n return current.every((widget, index) => {\n const nextWidget = next[index]\n return (\n nextWidget !== undefined &&\n widget.widgetId === nextWidget.widgetId &&\n widget.moduleId === nextWidget.moduleId &&\n widget.key === nextWidget.key &&\n widget.module === nextWidget.module\n )\n })\n}\n\nfunction setWidgetsIfChanged(\n setWidgets: React.Dispatch<React.SetStateAction<LoadedWidget[]>>,\n next: LoadedWidget[],\n) {\n setWidgets((current) => (areSameLoadedWidgets(current, next) ? current : next))\n}\n\nfunction injectSharedStateIntoContext<TContext>(context: TContext, moduleId: string): TContext {\n const sharedState = getWidgetSharedState(moduleId)\n if (typeof context === 'object' && context !== null && !Array.isArray(context)) {\n return {\n ...(context as Record<string, unknown>),\n sharedState,\n } as TContext\n }\n return {\n value: context,\n sharedState,\n } as TContext\n}\n\nexport function useInjectionWidgets<TContext = unknown>(\n spotId: InjectionSpotId | null | undefined,\n options?: {\n context?: TContext\n triggerOnLoad?: boolean\n onEvent?: (event: 'onLoad', widgetId: string) => void\n }\n) {\n const [widgets, setWidgets] = React.useState<LoadedWidget[]>([])\n const [loading, setLoading] = React.useState(true)\n const [error, setError] = React.useState<string | null>(null)\n const [registryVersion, setRegistryVersion] = React.useState(() => getInjectionRegistryVersion())\n const loadedWidgetIdsRef = React.useRef(new Set<string>())\n const contextRef = React.useRef(options?.context)\n const triggerOnLoadRef = React.useRef(options?.triggerOnLoad)\n const onEventRef = React.useRef(options?.onEvent)\n const { payload, isReady: backendChromeReady } = useBackendChrome()\n const grantedFeatureList = React.useMemo(\n () => payload?.grantedFeatures ?? [],\n [payload?.grantedFeatures],\n )\n const hasBackendChromePayload = payload !== null\n React.useEffect(() => {\n contextRef.current = options?.context\n triggerOnLoadRef.current = options?.triggerOnLoad\n onEventRef.current = options?.onEvent\n })\n\n React.useEffect(() => {\n return subscribeToInjectionRegistryChanges(() => {\n setRegistryVersion(getInjectionRegistryVersion())\n })\n }, [])\n\n React.useEffect(() => {\n if (!spotId) {\n setWidgets([])\n setLoading(false)\n setError(null)\n return\n }\n if (!backendChromeReady) {\n setLoading(true)\n setError(null)\n return\n }\n let mounted = true\n const load = async () => {\n try {\n setLoading(true)\n setError(null)\n const loaded = await loadInjectionWidgetsForSpot(spotId)\n if (!mounted) return\n const widgetList = filterWidgetsByGrantedFeatures(\n loaded.map(toLoadedWidget),\n grantedFeatureList,\n hasBackendChromePayload,\n )\n setWidgets(widgetList)\n\n // Trigger onLoad for all widgets\n if (triggerOnLoadRef.current) {\n for (const widget of widgetList) {\n if (loadedWidgetIdsRef.current.has(widget.widgetId)) continue\n loadedWidgetIdsRef.current.add(widget.widgetId)\n if (widget.module.eventHandlers?.onLoad) {\n try {\n const widgetContext = injectSharedStateIntoContext(contextRef.current as TContext, widget.moduleId)\n await widget.module.eventHandlers.onLoad(widgetContext)\n onEventRef.current?.('onLoad', widget.widgetId)\n } catch (err) {\n logger.error('Error in onLoad for widget', { widgetId: widget.widgetId, err })\n }\n }\n }\n }\n } catch (err) {\n if (!mounted) return\n logger.error('Failed to load widgets for spot', { spotId, err })\n setError(err instanceof Error ? err.message : String(err))\n } finally {\n if (mounted) setLoading(false)\n }\n }\n load()\n return () => {\n mounted = false\n }\n // context/triggerOnLoad/onEvent are read from refs so only a real registry-version bump reloads the spot\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [spotId, registryVersion, backendChromeReady, grantedFeatureList, hasBackendChromePayload])\n\n return { widgets, loading, error }\n}\n\nexport function InjectionSpot<TContext = unknown, TData = unknown>({\n spotId,\n context,\n data,\n onDataChange,\n disabled,\n onEvent,\n widgetsOverride,\n}: InjectionSpotProps<TContext, TData>) {\n const hasWidgetsOverride = widgetsOverride !== undefined\n const useSpotId = hasWidgetsOverride ? null : spotId\n const onEventRef = React.useRef(onEvent)\n React.useEffect(() => {\n onEventRef.current = onEvent\n })\n const hasOnEvent = Boolean(onEvent)\n const stableOnEvent = React.useMemo(\n () => (hasOnEvent ? (event: 'onLoad', id: string) => onEventRef.current?.(event, id) : undefined),\n [hasOnEvent],\n )\n const { widgets, loading, error } = useInjectionWidgets<TContext>(useSpotId, {\n context,\n triggerOnLoad: !hasWidgetsOverride,\n onEvent: stableOnEvent,\n })\n const { payload: overrideFeaturePayload, isReady: overrideBackendChromeReady } = useBackendChrome()\n const overrideGrantedFeatureList = React.useMemo(\n () => overrideFeaturePayload?.grantedFeatures ?? [],\n [overrideFeaturePayload?.grantedFeatures],\n )\n const overrideHasBackendChromePayload = overrideFeaturePayload !== null\n const filteredWidgetsOverride = React.useMemo(\n () =>\n widgetsOverride === undefined\n ? undefined\n : filterWidgetsByGrantedFeatures(\n widgetsOverride,\n overrideGrantedFeatureList,\n overrideHasBackendChromePayload,\n ),\n [widgetsOverride, overrideGrantedFeatureList, overrideHasBackendChromePayload],\n )\n const effectiveWidgets = hasWidgetsOverride\n ? (overrideBackendChromeReady ? filteredWidgetsOverride ?? [] : [])\n : widgets\n const effectiveLoading = hasWidgetsOverride ? !overrideBackendChromeReady : loading\n const effectiveError = hasWidgetsOverride ? null : error\n\n if (effectiveLoading && effectiveWidgets.length === 0) {\n return null\n }\n\n if (effectiveError) {\n logger.error('Error loading widgets for spot', { spotId, err: effectiveError })\n return null\n }\n\n if (effectiveWidgets.length === 0) {\n return null\n }\n\n return (\n <>\n {effectiveWidgets.map((widget) => {\n const { Widget } = widget.module\n return (\n <Widget\n key={widget.widgetId}\n context={injectSharedStateIntoContext(context, widget.moduleId)}\n data={data}\n onDataChange={onDataChange}\n disabled={disabled}\n />\n )\n })}\n </>\n )\n}\n\n/**\n * Hook to trigger injection widget events imperatively\n */\nexport function useInjectionSpotEvents<TContext = unknown, TData = unknown>(spotId: InjectionSpotId, prefetchedWidgets?: LoadedWidget[]) {\n const [widgets, setWidgets] = React.useState<LoadedWidget[]>([])\n const [registryVersion, setRegistryVersion] = React.useState(() => getInjectionRegistryVersion())\n const { payload, isReady: backendChromeReady } = useBackendChrome()\n const grantedFeatureList = React.useMemo(\n () => payload?.grantedFeatures ?? [],\n [payload?.grantedFeatures],\n )\n const hasBackendChromePayload = payload !== null\n const prefetchedEventWidgets = React.useMemo(() => {\n if (prefetchedWidgets === undefined || !backendChromeReady) return []\n return filterWidgetsByGrantedFeatures(\n prefetchedWidgets,\n grantedFeatureList,\n hasBackendChromePayload,\n )\n }, [backendChromeReady, grantedFeatureList, hasBackendChromePayload, prefetchedWidgets])\n const eventWidgets = prefetchedWidgets === undefined ? widgets : prefetchedEventWidgets\n\n React.useEffect(() => {\n return subscribeToInjectionRegistryChanges(() => {\n setRegistryVersion(getInjectionRegistryVersion())\n })\n }, [])\n\n React.useEffect(() => {\n if (!backendChromeReady) {\n setWidgetsIfChanged(setWidgets, [])\n return\n }\n if (prefetchedWidgets !== undefined) {\n setWidgetsIfChanged(\n setWidgets,\n filterWidgetsByGrantedFeatures(prefetchedWidgets, grantedFeatureList, hasBackendChromePayload),\n )\n return\n }\n let mounted = true\n const load = async () => {\n try {\n const loaded = await loadInjectionWidgetsForSpot(spotId)\n if (!mounted) return\n setWidgetsIfChanged(\n setWidgets,\n filterWidgetsByGrantedFeatures(\n loaded.map(toLoadedWidget),\n grantedFeatureList,\n hasBackendChromePayload,\n )\n )\n } catch (err) {\n logger.error('Failed to load widgets for spot', { hook: 'useInjectionSpotEvents', spotId, err })\n }\n }\n load()\n return () => {\n mounted = false\n }\n }, [spotId, prefetchedWidgets, registryVersion, backendChromeReady, grantedFeatureList, hasBackendChromePayload])\n\n const triggerEvent = React.useCallback(\n async (\n event: keyof WidgetInjectionEventHandlers<TContext, TData>,\n data: TData,\n context: TContext,\n meta?: {\n error?: unknown\n fieldId?: string\n fieldValue?: unknown\n originalData?: TData\n target?: unknown\n visible?: boolean\n appEvent?: unknown\n }\n ): Promise<{\n ok: boolean\n message?: string\n fieldErrors?: Record<string, string>\n requestHeaders?: Record<string, string>\n details?: unknown\n data?: TData\n applyToForm?: boolean\n fieldChange?: {\n value?: unknown\n sideEffects?: Record<string, unknown>\n messages?: Array<{ text: string; severity: 'info' | 'warning' | 'error' }>\n }\n }> => {\n const normalizeBeforeSave = (\n result: WidgetBeforeSaveResult,\n ): { ok: boolean; message?: string; fieldErrors?: Record<string, string>; requestHeaders?: Record<string, string>; details?: unknown } => {\n if (result === false) return { ok: false }\n if (result === true || typeof result === 'undefined') return { ok: true }\n if (result && typeof result === 'object') {\n const ok = typeof result.ok === 'boolean' ? result.ok : true\n const message = typeof result.message === 'string' ? result.message : undefined\n const fieldErrors =\n result.fieldErrors && typeof result.fieldErrors === 'object'\n ? Object.fromEntries(\n Object.entries(result.fieldErrors).map(([key, value]) => [key, String(value)]),\n )\n : undefined\n const requestHeaders =\n result.requestHeaders && typeof result.requestHeaders === 'object'\n ? Object.fromEntries(\n Object.entries(result.requestHeaders).map(([key, value]) => [key, String(value)]),\n )\n : undefined\n return { ok, message, fieldErrors, requestHeaders, details: result.details }\n }\n return { ok: true }\n }\n\n const normalizeBeforeDelete = (\n result: WidgetBeforeDeleteResult,\n ): { ok: boolean; message?: string; fieldErrors?: Record<string, string>; requestHeaders?: Record<string, string>; details?: unknown } => {\n if (result === false) return { ok: false }\n if (result === true || typeof result === 'undefined') return { ok: true }\n if (result && typeof result === 'object') {\n const ok = typeof result.ok === 'boolean' ? result.ok : true\n const message = typeof result.message === 'string' ? result.message : undefined\n const fieldErrors =\n result.fieldErrors && typeof result.fieldErrors === 'object'\n ? Object.fromEntries(\n Object.entries(result.fieldErrors).map(([key, value]) => [key, String(value)]),\n )\n : undefined\n const requestHeaders =\n result.requestHeaders && typeof result.requestHeaders === 'object'\n ? Object.fromEntries(\n Object.entries(result.requestHeaders).map(([key, value]) => [key, String(value)]),\n )\n : undefined\n return { ok, message, fieldErrors, requestHeaders, details: result.details }\n }\n return { ok: true }\n }\n\n // --- Transformer events: pipeline dispatch ---\n // Output of widget N becomes input of widget N+1\n if (TRANSFORMER_EVENTS.has(event)) {\n let pipelineData = data\n let applyToForm = false\n for (const widget of eventWidgets) {\n const handler = widget.module.eventHandlers?.[event]\n if (!handler) continue\n try {\n const widgetContext = injectSharedStateIntoContext(context, widget.moduleId)\n let handlerResult: unknown\n if (event === 'transformValidation') {\n handlerResult = await (handler as any)(pipelineData, meta?.originalData ?? data, widgetContext)\n } else {\n handlerResult = await (handler as any)(pipelineData, widgetContext)\n }\n if (\n event === 'transformFormData' &&\n handlerResult !== null &&\n typeof handlerResult === 'object' &&\n 'applyToForm' in handlerResult &&\n (handlerResult as { applyToForm: unknown }).applyToForm === true &&\n 'data' in handlerResult\n ) {\n pipelineData = (handlerResult as { data: TData }).data\n applyToForm = true\n } else {\n pipelineData = handlerResult as TData\n }\n } catch (err) {\n logger.error('Error in event handler for widget', { hook: 'useInjectionSpotEvents', event, widgetId: widget.widgetId, err })\n }\n }\n return { ok: true, data: pipelineData, applyToForm }\n }\n\n // --- Action events: sequential dispatch ---\n const mergedRequestHeaders: Record<string, string> = {}\n let hasRequestHeaders = false\n let fieldValue = meta?.fieldValue\n let fieldSideEffects: Record<string, unknown> | undefined\n let fieldMessages: Array<{ text: string; severity: 'info' | 'warning' | 'error' }> | undefined\n\n for (const widget of eventWidgets) {\n const eventHandlers = widget.module.eventHandlers\n // Check operation filter \u2014 skip widget if current operation is filtered out\n const operationFilter = eventHandlers?.filter?.operations\n if (operationFilter) {\n const currentOperation = (context as Record<string, unknown>)?.operation as string | undefined\n if (currentOperation && !operationFilter.includes(currentOperation as 'create' | 'update' | 'delete')) {\n continue\n }\n }\n let handler = eventHandlers?.[event]\n // Delete-to-save fallback chain\n if (!handler && event === 'onBeforeDelete') handler = eventHandlers?.onBeforeSave as typeof handler\n if (!handler && event === 'onDelete') handler = eventHandlers?.onSave as typeof handler\n if (!handler && event === 'onAfterDelete') handler = eventHandlers?.onAfterSave as typeof handler\n if (handler) {\n try {\n const widgetContext = injectSharedStateIntoContext(context, widget.moduleId)\n const result =\n event === 'onDeleteError'\n ? await (handler as any)(data, widgetContext, meta?.error)\n : event === 'onFieldChange'\n ? await (handler as any)(meta?.fieldId, fieldValue, data, widgetContext)\n : event === 'onBeforeNavigate'\n ? await (handler as any)(meta?.target, widgetContext)\n : event === 'onVisibilityChange'\n ? await (handler as any)(meta?.visible, widgetContext)\n : event === 'onAppEvent'\n ? await (handler as any)(meta?.appEvent, widgetContext)\n : await (handler as any)(data, widgetContext)\n if (event === 'onBeforeSave') {\n const normalized = normalizeBeforeSave(result as WidgetBeforeSaveResult)\n if (!normalized.ok) {\n logger.info('Widget prevented event', { hook: 'useInjectionSpotEvents', widgetId: widget.widgetId, event })\n return normalized\n }\n if (normalized.requestHeaders && Object.keys(normalized.requestHeaders).length > 0) {\n Object.assign(mergedRequestHeaders, normalized.requestHeaders)\n hasRequestHeaders = true\n }\n }\n if (event === 'onBeforeDelete') {\n const normalized = normalizeBeforeDelete(result as WidgetBeforeDeleteResult)\n if (!normalized.ok) {\n logger.info('Widget prevented event', { hook: 'useInjectionSpotEvents', widgetId: widget.widgetId, event })\n return normalized\n }\n if (normalized.requestHeaders && Object.keys(normalized.requestHeaders).length > 0) {\n Object.assign(mergedRequestHeaders, normalized.requestHeaders)\n hasRequestHeaders = true\n }\n }\n if (event === 'onBeforeNavigate') {\n const navResult = result as NavigateGuardResult | undefined\n if (navResult && navResult.ok === false) {\n return { ok: false, message: navResult.message }\n }\n }\n if (event === 'onFieldChange') {\n const changeResult = result as FieldChangeResult | void\n if (changeResult?.value !== undefined) {\n fieldValue = changeResult.value\n }\n if (changeResult?.sideEffects && typeof changeResult.sideEffects === 'object') {\n fieldSideEffects = { ...(fieldSideEffects ?? {}), ...changeResult.sideEffects }\n }\n if (changeResult?.message?.text) {\n fieldMessages = [...(fieldMessages ?? []), changeResult.message]\n }\n }\n } catch (err) {\n logger.error('Error in event handler for widget', { hook: 'useInjectionSpotEvents', event, widgetId: widget.widgetId, err })\n if (event === 'onBeforeSave' || event === 'onBeforeDelete' || event === 'onBeforeNavigate') {\n const message =\n err instanceof Error\n ? err.message || 'Validation blocked'\n : typeof err === 'string'\n ? err\n : undefined\n return { ok: false, message }\n }\n }\n }\n }\n if ((event === 'onBeforeSave' || event === 'onBeforeDelete') && hasRequestHeaders) {\n return { ok: true, requestHeaders: mergedRequestHeaders }\n }\n if (event === 'onFieldChange') {\n return {\n ok: true,\n fieldChange: {\n value: fieldValue,\n sideEffects: fieldSideEffects,\n messages: fieldMessages,\n },\n }\n }\n return { ok: true }\n },\n [eventWidgets]\n )\n\n return { triggerEvent, widgets: eventWidgets }\n}\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
|
@@ -21,45 +21,58 @@ class ReplacementErrorBoundary extends React.Component {
|
|
|
21
21
|
return this.props.children;
|
|
22
22
|
}
|
|
23
23
|
}
|
|
24
|
-
function
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
if (!original) {
|
|
31
|
-
if (process.env.NODE_ENV !== "production" && !fallback) {
|
|
32
|
-
logger.warn("Component is not registered", { componentId });
|
|
33
|
-
}
|
|
34
|
-
const Missing = () => null;
|
|
35
|
-
return Missing;
|
|
24
|
+
function resolveComponent(componentId, fallback, userFeatures) {
|
|
25
|
+
const entry = getComponentEntry(componentId);
|
|
26
|
+
const original = entry?.component ?? fallback ?? null;
|
|
27
|
+
if (!original) {
|
|
28
|
+
if (process.env.NODE_ENV !== "production" && !fallback) {
|
|
29
|
+
logger.warn("Component is not registered", { componentId });
|
|
36
30
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if ("propsTransform" in override) transforms.push(override.propsTransform);
|
|
31
|
+
return { original: null, wrapped: null, transforms: [], replacementOverride: null, replacementModule: "unknown" };
|
|
32
|
+
}
|
|
33
|
+
const overrides = getComponentOverrides(componentId, userFeatures);
|
|
34
|
+
const replacementOverrides = overrides.filter((override) => "replacement" in override);
|
|
35
|
+
if (process.env.NODE_ENV !== "production" && replacementOverrides.length > 1) {
|
|
36
|
+
logger.warn("Multiple replacements registered; highest-priority replacement is applied", { componentId });
|
|
37
|
+
}
|
|
38
|
+
let replacement = null;
|
|
39
|
+
let replacementOverride = null;
|
|
40
|
+
const wrappers = [];
|
|
41
|
+
const transforms = [];
|
|
42
|
+
for (const override of overrides) {
|
|
43
|
+
if ("replacement" in override) {
|
|
44
|
+
replacement = override.replacement;
|
|
45
|
+
replacementOverride = override;
|
|
53
46
|
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
47
|
+
if ("wrapper" in override) wrappers.push(override.wrapper);
|
|
48
|
+
if ("propsTransform" in override) transforms.push(override.propsTransform);
|
|
49
|
+
}
|
|
50
|
+
const base = replacement ?? original;
|
|
51
|
+
const wrapped = wrappers.reduce((acc, wrapper) => wrapper(acc), base);
|
|
52
|
+
return {
|
|
53
|
+
original,
|
|
54
|
+
wrapped,
|
|
55
|
+
transforms,
|
|
56
|
+
replacementOverride,
|
|
57
|
+
replacementModule: replacementOverride?.metadata?.module ?? "unknown"
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function useRegisteredComponent(componentId, fallback) {
|
|
61
|
+
return React.useMemo(() => {
|
|
62
|
+
const Registered = (props) => {
|
|
63
|
+
const userFeatures = useOverrideUserFeatures();
|
|
64
|
+
const overrideRevision = useOverrideRegistryRevision();
|
|
65
|
+
const { original, wrapped, transforms, replacementOverride, replacementModule } = React.useMemo(
|
|
66
|
+
() => resolveComponent(componentId, fallback, userFeatures),
|
|
67
|
+
[overrideRevision, userFeatures]
|
|
68
|
+
);
|
|
69
|
+
if (!original || !wrapped) return null;
|
|
57
70
|
const transformed = transforms.reduce((current, transform) => transform(current), props);
|
|
58
71
|
const Fallback = React.createElement(original, transformed);
|
|
59
72
|
if (process.env.NODE_ENV !== "production" && replacementOverride && "replacement" in replacementOverride) {
|
|
60
73
|
const validation = replacementOverride.propsSchema.safeParse(transformed);
|
|
61
74
|
if (!validation.success) {
|
|
62
|
-
logger.error("Props schema validation failed for replacement", { componentId, module:
|
|
75
|
+
logger.error("Props schema validation failed for replacement", { componentId, module: replacementModule, issues: validation.error.format() });
|
|
63
76
|
return Fallback;
|
|
64
77
|
}
|
|
65
78
|
}
|
|
@@ -68,16 +81,15 @@ function useRegisteredComponent(componentId, fallback) {
|
|
|
68
81
|
{
|
|
69
82
|
fallback: Fallback,
|
|
70
83
|
onError: (error) => {
|
|
71
|
-
const replacementModule = overrides.find((override) => "replacement" in override)?.metadata?.module ?? "unknown";
|
|
72
84
|
logger.error("Component replacement failed", { componentId, module: replacementModule, err: error });
|
|
73
85
|
},
|
|
74
86
|
children: React.createElement(wrapped, transformed)
|
|
75
87
|
}
|
|
76
88
|
);
|
|
77
89
|
};
|
|
78
|
-
|
|
79
|
-
return
|
|
80
|
-
}, [componentId, fallback
|
|
90
|
+
Registered.displayName = `RegisteredComponent(${componentId})`;
|
|
91
|
+
return Registered;
|
|
92
|
+
}, [componentId, fallback]);
|
|
81
93
|
}
|
|
82
94
|
var useRegisteredComponent_default = useRegisteredComponent;
|
|
83
95
|
export {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../../src/backend/injection/useRegisteredComponent.tsx"],
|
|
4
|
-
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport type { ComponentType } from 'react'\nimport { getComponentEntry, getComponentOverrides } from '@open-mercato/shared/modules/widgets/component-registry'\nimport { useOverrideRegistryRevision, useOverrideUserFeatures } from './ComponentOverrideProvider'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('ui').child({ component: 'useRegisteredComponent' })\n\nclass ReplacementErrorBoundary extends React.Component<\n { fallback: React.ReactNode; onError: (error: unknown) => void; children: React.ReactNode },\n { hasError: boolean }\n> {\n constructor(props: { fallback: React.ReactNode; onError: (error: unknown) => void; children: React.ReactNode }) {\n super(props)\n this.state = { hasError: false }\n }\n\n static getDerivedStateFromError(): { hasError: boolean } {\n return { hasError: true }\n }\n\n componentDidCatch(error: unknown): void {\n this.props.onError(error)\n }\n\n render() {\n if (this.state.hasError) return this.props.fallback\n return this.props.children\n }\n}\n\
|
|
5
|
-
"mappings": ";
|
|
4
|
+
"sourcesContent": ["'use client'\n\nimport * as React from 'react'\nimport type { ComponentType } from 'react'\nimport type { ComponentOverride } from '@open-mercato/shared/modules/widgets/component-registry'\nimport { getComponentEntry, getComponentOverrides } from '@open-mercato/shared/modules/widgets/component-registry'\nimport { useOverrideRegistryRevision, useOverrideUserFeatures } from './ComponentOverrideProvider'\nimport { createLogger } from '@open-mercato/shared/lib/logger'\n\nconst logger = createLogger('ui').child({ component: 'useRegisteredComponent' })\n\nclass ReplacementErrorBoundary extends React.Component<\n { fallback: React.ReactNode; onError: (error: unknown) => void; children: React.ReactNode },\n { hasError: boolean }\n> {\n constructor(props: { fallback: React.ReactNode; onError: (error: unknown) => void; children: React.ReactNode }) {\n super(props)\n this.state = { hasError: false }\n }\n\n static getDerivedStateFromError(): { hasError: boolean } {\n return { hasError: true }\n }\n\n componentDidCatch(error: unknown): void {\n this.props.onError(error)\n }\n\n render() {\n if (this.state.hasError) return this.props.fallback\n return this.props.children\n }\n}\n\ntype Resolution<TProps> = {\n original: ComponentType<TProps> | null\n wrapped: ComponentType<TProps> | null\n transforms: Array<(props: TProps) => TProps>\n replacementOverride: ComponentOverride | null\n replacementModule: string\n}\n\nfunction resolveComponent<TProps>(\n componentId: string,\n fallback: ComponentType<TProps> | undefined,\n userFeatures: readonly string[],\n): Resolution<TProps> {\n const entry = getComponentEntry(componentId)\n const original = (entry?.component as ComponentType<TProps> | undefined) ?? fallback ?? null\n if (!original) {\n if (process.env.NODE_ENV !== 'production' && !fallback) {\n logger.warn('Component is not registered', { componentId })\n }\n return { original: null, wrapped: null, transforms: [], replacementOverride: null, replacementModule: 'unknown' }\n }\n\n const overrides = getComponentOverrides(componentId, userFeatures)\n const replacementOverrides = overrides.filter((override) => 'replacement' in override)\n if (process.env.NODE_ENV !== 'production' && replacementOverrides.length > 1) {\n logger.warn('Multiple replacements registered; highest-priority replacement is applied', { componentId })\n }\n\n let replacement: ComponentType<TProps> | null = null\n let replacementOverride: ComponentOverride | null = null\n const wrappers: Array<(Original: ComponentType<TProps>) => ComponentType<TProps>> = []\n const transforms: Array<(props: TProps) => TProps> = []\n\n for (const override of overrides) {\n if ('replacement' in override) {\n replacement = override.replacement as ComponentType<TProps>\n replacementOverride = override\n }\n if ('wrapper' in override) wrappers.push(override.wrapper as (Original: ComponentType<TProps>) => ComponentType<TProps>)\n if ('propsTransform' in override) transforms.push(override.propsTransform as (props: TProps) => TProps)\n }\n\n const base = replacement ?? original\n const wrapped = wrappers.reduce<ComponentType<TProps>>((acc, wrapper) => wrapper(acc), base)\n\n return {\n original,\n wrapped,\n transforms,\n replacementOverride,\n replacementModule: replacementOverride?.metadata?.module ?? 'unknown',\n }\n}\n\n/**\n * The returned component's identity must depend only on `componentId` and\n * `fallback` \u2014 never on the override registry.\n *\n * Overrides arrive asynchronously: `ComponentOverridesBootstrap` dynamically\n * imports the generated override module and hands the provider a fresh array,\n * which bumps the registry revision some time after first paint. Resolving the\n * component in a `useMemo` keyed on that revision handed callers a brand-new\n * function on every bump, so React saw a different element type at that\n * position and unmounted the whole subtree \u2014 discarding its DOM and state. On\n * the login form that threw away credentials the user had already typed\n * (#5037), and the same hazard applied to every host of a registered section.\n *\n * Resolution therefore happens *inside* a stable component. When the revision\n * carries no override for this id, `wrapped` keeps its previous identity and\n * React reconciles in place; only a genuine replacement or wrapper swaps the\n * rendered type, where a remount is the correct behaviour.\n */\nexport function useRegisteredComponent<TProps>(\n componentId: string,\n fallback?: ComponentType<TProps>,\n): ComponentType<TProps> {\n return React.useMemo(() => {\n const Registered = (props: TProps) => {\n const userFeatures = useOverrideUserFeatures()\n const overrideRevision = useOverrideRegistryRevision()\n const { original, wrapped, transforms, replacementOverride, replacementModule } = React.useMemo(\n () => resolveComponent<TProps>(componentId, fallback, userFeatures),\n [overrideRevision, userFeatures],\n )\n\n if (!original || !wrapped) return null\n\n const transformed = transforms.reduce((current, transform) => transform(current), props)\n const Fallback = React.createElement(original as React.ComponentType<Record<string, unknown>>, transformed as Record<string, unknown>)\n if (\n process.env.NODE_ENV !== 'production'\n && replacementOverride\n && 'replacement' in replacementOverride\n ) {\n const validation = replacementOverride.propsSchema.safeParse(transformed)\n if (!validation.success) {\n logger.error('Props schema validation failed for replacement', { componentId, module: replacementModule, issues: validation.error.format() })\n return Fallback\n }\n }\n return (\n <ReplacementErrorBoundary\n fallback={Fallback}\n onError={(error) => {\n logger.error('Component replacement failed', { componentId, module: replacementModule, err: error })\n }}\n >\n {React.createElement(wrapped as React.ComponentType<Record<string, unknown>>, transformed as Record<string, unknown>)}\n </ReplacementErrorBoundary>\n )\n }\n\n Registered.displayName = `RegisteredComponent(${componentId})`\n return Registered\n }, [componentId, fallback])\n}\n\nexport default useRegisteredComponent\n"],
|
|
5
|
+
"mappings": ";AAuIQ;AArIR,YAAY,WAAW;AAGvB,SAAS,mBAAmB,6BAA6B;AACzD,SAAS,6BAA6B,+BAA+B;AACrE,SAAS,oBAAoB;AAE7B,MAAM,SAAS,aAAa,IAAI,EAAE,MAAM,EAAE,WAAW,yBAAyB,CAAC;AAE/E,MAAM,iCAAiC,MAAM,UAG3C;AAAA,EACA,YAAY,OAAoG;AAC9G,UAAM,KAAK;AACX,SAAK,QAAQ,EAAE,UAAU,MAAM;AAAA,EACjC;AAAA,EAEA,OAAO,2BAAkD;AACvD,WAAO,EAAE,UAAU,KAAK;AAAA,EAC1B;AAAA,EAEA,kBAAkB,OAAsB;AACtC,SAAK,MAAM,QAAQ,KAAK;AAAA,EAC1B;AAAA,EAEA,SAAS;AACP,QAAI,KAAK,MAAM,SAAU,QAAO,KAAK,MAAM;AAC3C,WAAO,KAAK,MAAM;AAAA,EACpB;AACF;AAUA,SAAS,iBACP,aACA,UACA,cACoB;AACpB,QAAM,QAAQ,kBAAkB,WAAW;AAC3C,QAAM,WAAY,OAAO,aAAmD,YAAY;AACxF,MAAI,CAAC,UAAU;AACb,QAAI,QAAQ,IAAI,aAAa,gBAAgB,CAAC,UAAU;AACtD,aAAO,KAAK,+BAA+B,EAAE,YAAY,CAAC;AAAA,IAC5D;AACA,WAAO,EAAE,UAAU,MAAM,SAAS,MAAM,YAAY,CAAC,GAAG,qBAAqB,MAAM,mBAAmB,UAAU;AAAA,EAClH;AAEA,QAAM,YAAY,sBAAsB,aAAa,YAAY;AACjE,QAAM,uBAAuB,UAAU,OAAO,CAAC,aAAa,iBAAiB,QAAQ;AACrF,MAAI,QAAQ,IAAI,aAAa,gBAAgB,qBAAqB,SAAS,GAAG;AAC5E,WAAO,KAAK,6EAA6E,EAAE,YAAY,CAAC;AAAA,EAC1G;AAEA,MAAI,cAA4C;AAChD,MAAI,sBAAgD;AACpD,QAAM,WAA8E,CAAC;AACrF,QAAM,aAA+C,CAAC;AAEtD,aAAW,YAAY,WAAW;AAChC,QAAI,iBAAiB,UAAU;AAC7B,oBAAc,SAAS;AACvB,4BAAsB;AAAA,IACxB;AACA,QAAI,aAAa,SAAU,UAAS,KAAK,SAAS,OAAqE;AACvH,QAAI,oBAAoB,SAAU,YAAW,KAAK,SAAS,cAA2C;AAAA,EACxG;AAEA,QAAM,OAAO,eAAe;AAC5B,QAAM,UAAU,SAAS,OAA8B,CAAC,KAAK,YAAY,QAAQ,GAAG,GAAG,IAAI;AAE3F,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,mBAAmB,qBAAqB,UAAU,UAAU;AAAA,EAC9D;AACF;AAoBO,SAAS,uBACd,aACA,UACuB;AACvB,SAAO,MAAM,QAAQ,MAAM;AACzB,UAAM,aAAa,CAAC,UAAkB;AACpC,YAAM,eAAe,wBAAwB;AAC7C,YAAM,mBAAmB,4BAA4B;AACrD,YAAM,EAAE,UAAU,SAAS,YAAY,qBAAqB,kBAAkB,IAAI,MAAM;AAAA,QACtF,MAAM,iBAAyB,aAAa,UAAU,YAAY;AAAA,QAClE,CAAC,kBAAkB,YAAY;AAAA,MACjC;AAEA,UAAI,CAAC,YAAY,CAAC,QAAS,QAAO;AAElC,YAAM,cAAc,WAAW,OAAO,CAAC,SAAS,cAAc,UAAU,OAAO,GAAG,KAAK;AACvF,YAAM,WAAW,MAAM,cAAc,UAA0D,WAAsC;AACrI,UACE,QAAQ,IAAI,aAAa,gBACtB,uBACA,iBAAiB,qBACpB;AACA,cAAM,aAAa,oBAAoB,YAAY,UAAU,WAAW;AACxE,YAAI,CAAC,WAAW,SAAS;AACvB,iBAAO,MAAM,kDAAkD,EAAE,aAAa,QAAQ,mBAAmB,QAAQ,WAAW,MAAM,OAAO,EAAE,CAAC;AAC5I,iBAAO;AAAA,QACT;AAAA,MACF;AACA,aACE;AAAA,QAAC;AAAA;AAAA,UACC,UAAU;AAAA,UACV,SAAS,CAAC,UAAU;AAClB,mBAAO,MAAM,gCAAgC,EAAE,aAAa,QAAQ,mBAAmB,KAAK,MAAM,CAAC;AAAA,UACrG;AAAA,UAEC,gBAAM,cAAc,SAAyD,WAAsC;AAAA;AAAA,MACtH;AAAA,IAEJ;AAEA,eAAW,cAAc,uBAAuB,WAAW;AAC3D,WAAO;AAAA,EACT,GAAG,CAAC,aAAa,QAAQ,CAAC;AAC5B;AAEA,IAAO,iCAAQ;",
|
|
6
6
|
"names": []
|
|
7
7
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@open-mercato/ui",
|
|
3
|
-
"version": "0.6.8-develop.
|
|
3
|
+
"version": "0.6.8-develop.6940.1.177ea30c6e",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -155,14 +155,14 @@
|
|
|
155
155
|
"remark-gfm": "^4.0.1"
|
|
156
156
|
},
|
|
157
157
|
"peerDependencies": {
|
|
158
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
158
|
+
"@open-mercato/shared": "0.6.8-develop.6940.1.177ea30c6e",
|
|
159
159
|
"react": ">=18.0.0",
|
|
160
160
|
"react-dom": ">=18.0.0",
|
|
161
161
|
"react-is": ">=18.0.0"
|
|
162
162
|
},
|
|
163
163
|
"devDependencies": {
|
|
164
164
|
"@figma/code-connect": "^1.3.4",
|
|
165
|
-
"@open-mercato/shared": "0.6.8-develop.
|
|
165
|
+
"@open-mercato/shared": "0.6.8-develop.6940.1.177ea30c6e",
|
|
166
166
|
"@testing-library/dom": "^10.4.1",
|
|
167
167
|
"@testing-library/jest-dom": "^7.0.0",
|
|
168
168
|
"@testing-library/react": "^16.3.1",
|