@nexia/sdk 0.7.2 → 0.8.0

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/actions.d.ts CHANGED
@@ -9,6 +9,10 @@ export interface NxActionsProps {
9
9
  id: string;
10
10
  label: string;
11
11
  }>;
12
+ /** Declared inputs from the displayed record, such as concurrency tokens.
13
+ * Captured when confirmation opens; server planning/authorization still apply.
14
+ * Do not pass credentials or secrets. */
15
+ inputByAction?: Readonly<Record<string, Readonly<Record<string, unknown>>>>;
12
16
  legalEntityPublicId?: string | null;
13
17
  disabledKeys?: readonly string[];
14
18
  onSuccess?: (actionKey: string, response: unknown) => void;
package/dist/host.d.ts CHANGED
@@ -3,21 +3,20 @@ import { type ComponentType, type ReactNode } from 'react';
3
3
  import type { AxiosInstance } from 'axios';
4
4
  import type { ApprovalBusinessFormRegistrar, ApprovalBusinessFormRegistry } from './approval';
5
5
  import type { ContextQueryResult, PermissionsQueryResult } from './context';
6
- import type { DataMigrationBackgroundOperationClient, DataMigrationRegistrar, DataMigrationRegistry } from './data-migration';
7
- import type { ProcessUserTaskFormRegistrar, ProcessUserTaskFormRegistry } from './process';
6
+ import type { DataMigrationBackgroundOperationClient, DataMigrationProviderRegistration, DataMigrationRegistrar, DataMigrationRegistry, DataMigrationStageRegistration, DataMigrationTargetRegistration } from './data-migration';
7
+ import type { ProcessUserTaskFormRegistration, ProcessUserTaskFormRegistrar, ProcessUserTaskFormRegistry } from './process';
8
8
  import type { AppRouteFrameProps, AutoRegisterPackageSurfacesOptions, FormFieldErrors, InspectorActionProps, InspectorResourceActionsProps, MessageApi, MutationFormError, NxAdaptiveSplitProps, NxActionButtonProps, NxAlertProps, NxButtonProps, NxLinkButtonProps, NxIconButtonProps, NxIconLinkProps, NxCanonicalRoutePaneProps, NxCheckboxProps, NxColumnBrowserProps, NxColumnPickerProps, NxComboboxProps, NxDatePickerProps, NxDateRangePickerProps, NxDetailRowProps, NxEmptyViewProps, NxFieldGroupProps, NxFieldLegendProps, NxFieldsetProps, NxFileDropzoneProps, NxFormFieldProps, NxFormSectionProps, NxDropdownMenuProps, NxInsightFilterBarProps, NxInsightSurfaceProps, NxHelpTooltipProps, NxOverviewBandProps, InsightFilterControls, UseInsightFilterStateOptions, NxLoadingBlockProps, NxModalDialogProps, NxOrgChartProps, NxMissingRequiredReferencesAlertProps, NxPageFrameProps, NxPaginationProps, NxRadioGroupProps, NxRadioProps, NxRefreshControlProps, NxSearchFieldProps, NxSectionCardProps, SectionRowProps, NxSectionStackProps, NxResponsiveRegionProps, NxSelectProps, NxStatCardProps, NxStatusBadgeProps, NxSwitchProps, NxTabNavProps, NxTextAreaProps, NxTextInputProps, NxTooltipProps, OpenResourceWorkTab, ResourceCreateCompletion, ResourceCreateReceiverRegistration, ResourceInspectorAdapterRegistry, ResourceInspectorAdapterRegistrar, ResourceInspectorPanelProps, ResourceInspectorQueryProps, ResourceInspectorStackHostProps, ResourceInspectorStackProviderProps, ResourceInspectorStateProps, ResourceLinkProps, ResourceListParams, ResourceListParamsControls, ResourceListToolbarMoreMenuProps, ResourcePrimaryCellProps, ResourceRowActionsMenuProps, ResourceStatusBadgeProps, ResourceTableProps, ResourceTableSort, ResourceTextCellProps, UseRegisterListLocateActionOptions, UseResourceListParamsOptions, TabContextActionRegistration, RegisterDraftActionOptions, ToastOptions, WorkSectionProps, FavoriteTarget, WorkSurfaceLabelInput, WorkSurfaceLabels, WorkSurfaceProps } from './shell';
9
9
  import type { AgentComponentRenderer, AttachmentDeleteResult, AttachmentQueryResult, AttachmentUploadOptions, AttachmentUploadResult, ApprovalRoutePoliciesQueryResult, ApprovalSharedLinesQueryResult, DashboardWidgetAutoHeightRef, LegalEntityMemberListParams, LegalEntityMemberQueryResult, LegalEntityApplicabilityQueryResult, LegalEntityQueryResult, MediaUploadResult, OperatingUnitQueryResult, OperatingUnitQueryScope, OperatingUnitScopeFieldProps, OperatingUnitScopeResult, OperatingUnitSelectionResult, PartyListParams, PartyQueryResult, TrustedAssetListParams, TrustedAssetsQueryResult, UploadFileClient } from './platform';
10
10
  import type { NxOrganizationTargetSelectorProps, NxOperatingUnitSelectorProps, OrganizationListScopeMode, OrganizationListScopeResult, OrganizationTargetQuery, OrganizationTargetQueryResult } from './organization-target';
11
11
  import type { NxCalendarProps, NxResourceSchedulerProps, ResourceBoardProps, ResourceScheduleProps } from './resources/resource-projections';
12
12
  import type { NxDatasetExportWorkspaceProps, NxDatasetImportWorkspaceProps, NxInlineResourceCreateProps, NxResourceImportDialogProps, NxResourceTransferActionsProps } from './resources/resource-transfer';
13
- import type { NxResourceInformationFormProps, NxResourceFormLegalEntityFieldProps, NxResourceInformationViewProps } from './resources/resource-information';
13
+ import type { NxResourceFormLegalEntityFieldProps } from './resources/resource-form';
14
14
  import type { SignatureAuthenticationMethodSelectorProps, SignatureInvitationChannelSelectorProps, SignatureRequestPreparationEditorProps, SignatureRequestPreparationExactPreviewProps, SignatureRequestPreparationPlacementEditorProps, SignatureSingleRequestDialogProps } from './signature';
15
15
  import type { ResourceProjectionChangeSubscription } from './resource-reference';
16
16
  import type { ResourceCreateDestinationRegistry } from './resource-create-destination';
17
17
  export type { ResourceProjectionChangeSubscription } from './resource-reference';
18
18
  /** Host-only visual component prop contracts. App packages import these from ./host. */
19
19
  export type { AppRoutePrefetchContext, AppRoutePrefetcher, AutoRegisterPackageSurfacesOptions, PackageSurfaceLoader, PackageSurfaceOverride, PackageSurfaceOverrideRegistration, NxAdaptiveSplitAsideWidth, NxAdaptiveSplitBreakpoint, NxAdaptiveSplitDensity, NxAdaptiveSplitProps, NxActionButtonProps, NxAlertProps, NxButtonProps, NxLinkButtonProps, NxIconButtonProps, NxIconLinkProps, NxCanonicalRoutePaneProps, NxCheckboxProps, NxColumnBrowserLabels, NxColumnBrowserProps, NxColumnNode, NxColumnPickerLabels, NxColumnPickerProps, NxComboboxProps, NxDatePickerProps, NxDateRangePickerProps, NxDetailRowProps, NxDropdownMenuProps, NxEmptyViewProps, NxFieldGroupProps, NxFieldLegendProps, NxFieldsetProps, NxFileDropzoneProps, NxFormFieldProps, NxFormSectionProps, NxInsightFilterBarProps, NxInsightSurfaceProps, NxHelpTooltipProps, NxLoadingBlockProps, NxModalDialogProps, NxOrgChartItem, NxOrgChartLabels, NxOrgChartMember, NxOrgChartProps, NxMissingRequiredReferencesAlertProps, NxOverviewBandProps, NxPageFrameProps, NxRadioGroupProps, NxRadioProps, NxRefreshControlProps, NxResponsiveRegionProps, ResourceListToolbarMoreMenuProps, NxSearchFieldProps, NxSectionCardProps, SectionRowProps, NxSectionStackProps, NxSelectProps, NxStatCardProps, NxStatusBadgeProps, NxSwitchProps, NxTabNavItem, NxTabNavProps, NxTextAreaProps, NxTextInputProps, NxTooltipProps, ResourceListRefreshConfig, ResourceTableDensity, ResourceTableStyle, ResourceTableSummaryRow, } from './shell';
20
- export type { NxResourceInformationFormProps, NxResourceFormLegalEntityFieldProps, NxResourceInformationViewProps, ResourceInformationControlProjection, ResourceInformationControlSlot, ResourceInformationCustomProjection, ResourceInformationEditProjection, ResourceInformationEditRenderContext, ResourceInformationField, ResourceInformationFieldSpan, ResourceInformationMode, ResourceInformationReadOnlyProjection, ResourceInformationRequirement, ResourceInformationSchema, ResourceInformationSection, ResourceInformationTranslator, ResourceInformationValue, } from './resources/resource-information';
21
20
  export type { NxCalendarActionBinding, NxCalendarActionCommand, NxCalendarActionResult, NxCalendarInteraction, NxCalendarOccurrence, NxCalendarProps, NxCalendarRange, NxCalendarSelection, NxCalendarTemporalRange, NxCalendarView, NxResourceSchedulerActionBinding, NxResourceSchedulerActionCommand, NxResourceSchedulerActionResult, NxResourceSchedulerInteraction, NxResourceSchedulerOccurrence, NxResourceSchedulerProps, NxResourceSchedulerResource, NxResourceSchedulerSelection, NxResourceSchedulerView, ResourceBoardCard, ResourceBoardLabels, ResourceBoardLane, ResourceBoardLoadState, ResourceBoardMoveCommand, ResourceBoardMutationResult, ResourceBoardProjection, ResourceBoardProps, ResourceBoardSummaryField, ResourceProjectionReference, ResourceScheduleActionBinding, ResourceScheduleActionCommand, ResourceScheduleDatePair, ResourceScheduleDateSemantics, ResourceScheduleDependency, ResourceScheduleDependencyType, ResourceScheduleInteraction, ResourceScheduleItem, ResourceScheduleItemType, ResourceScheduleLoadState, ResourceScheduleMutationResult, ResourceScheduleProjection, ResourceScheduleProps, ResourceScheduleTimeUnit, ResourceScheduleView, } from './resources/resource-projections';
22
21
  export type { DatasetImportConfirmationSummary, NxDatasetExportWorkspaceProps, NxDatasetImportWorkspaceProps, NxInlineResourceCreateProps, NxResourceImportDialogProps, NxResourceTransferActionsProps, } from './resources/resource-transfer';
23
22
  export { projectSignatureCapabilityCatalog, signatureCapabilityIdentity, } from './signature';
@@ -153,6 +152,8 @@ export interface OpenFileOptions {
153
152
  }
154
153
  export interface NexiaAppFrontendHostBindings {
155
154
  api: AxiosInstance;
155
+ /** Build-bound services; the host selects the backend before an App entry runs. */
156
+ appServices?: (appKey: string) => NexiaAppRequestServices;
156
157
  components: {
157
158
  AppRouteFrame: typeof AppRouteFrame;
158
159
  InspectorAction: typeof InspectorAction;
@@ -189,15 +190,13 @@ export interface NexiaAppFrontendHostBindings {
189
190
  FavoriteButton: ComponentType<FavoriteButtonProps>;
190
191
  NxFormField: typeof NxFormField;
191
192
  NxFormSection: typeof NxFormSection;
193
+ NxResourceFormLegalEntityField: ComponentType<NxResourceFormLegalEntityFieldProps>;
192
194
  NxHelpTooltip: ComponentType<NxHelpTooltipProps>;
193
195
  NxInsightFilterBar: typeof NxInsightFilterBar;
194
196
  NxInsightSurface: typeof NxInsightSurface;
195
197
  NxLineChart: typeof NxLineChart;
196
198
  NxResourceScheduler: typeof NxResourceScheduler;
197
199
  NxResourceImportDialog: ComponentType<NxResourceImportDialogProps>;
198
- NxResourceFormLegalEntityField: ComponentType<NxResourceFormLegalEntityFieldProps>;
199
- NxResourceInformationForm: <TViewContext, TEditContext>(props: NxResourceInformationFormProps<TViewContext, TEditContext>) => ReactNode;
200
- NxResourceInformationView: <TViewContext, TEditContext>(props: NxResourceInformationViewProps<TViewContext, TEditContext>) => ReactNode;
201
200
  NxResourceTransferActions: ComponentType<NxResourceTransferActionsProps>;
202
201
  NxDatasetExportWorkspace: ComponentType<NxDatasetExportWorkspaceProps>;
203
202
  NxDatasetImportWorkspace: ComponentType<NxDatasetImportWorkspaceProps>;
@@ -275,6 +274,7 @@ export interface NexiaAppFrontendHostBindings {
275
274
  useIsActiveWorkTabVisible: () => boolean;
276
275
  useMarkTabDirty: (dirty: boolean, snapshot?: string, initialSnapshot?: string) => void;
277
276
  useClearTabDirty: () => () => void;
277
+ useReauthenticate: () => () => Promise<void>;
278
278
  useMessage: () => MessageApi;
279
279
  useOpenResourceWorkTab: (defaultIcon?: string) => OpenResourceWorkTab;
280
280
  useRegisterResourceCreateReceiver: (registration: ResourceCreateReceiverRegistration | null) => void;
@@ -319,6 +319,34 @@ export interface NexiaAppFrontendHostBindings {
319
319
  resourceInspectorAdapterRegistry: ResourceInspectorAdapterRegistry;
320
320
  };
321
321
  }
322
+ export interface NexiaAppRequestServices {
323
+ api: AxiosInstance;
324
+ openFile: (href: string, options?: OpenFileOptions) => Promise<void>;
325
+ wrapComponent?: <P extends object>(component: ComponentType<P>) => ComponentType<P>;
326
+ }
327
+ /** Used by the SDK build facade, not by application source. Captures a fixed owner. */
328
+ export declare function bindNexiaAppRequestServices(appKey: string): {
329
+ resourceInspectorAdapterRegistry: ResourceInspectorAdapterRegistrar;
330
+ autoRegisterPackageResourceInspectors(modules: Record<string, unknown>, contracts?: Record<string, unknown>): void;
331
+ autoRegisterPackageSurfaces(options: AutoRegisterPackageSurfacesOptions): void;
332
+ approvalComposerBusinessFormRegistry: ApprovalBusinessFormRegistrar;
333
+ processUserTaskFormRegistry: {
334
+ register(registration: ProcessUserTaskFormRegistration): void;
335
+ };
336
+ dataMigrationRegistry: {
337
+ registerProvider: (registration: DataMigrationProviderRegistration) => void;
338
+ registerTarget: (registration: DataMigrationTargetRegistration) => void;
339
+ registerStage(registration: DataMigrationStageRegistration): void;
340
+ };
341
+ registerAgentComponent(name: string, component: AgentComponentRenderer): void;
342
+ registerLazyAgentComponent(name: string, load: () => Promise<{
343
+ default: AgentComponentRenderer;
344
+ }>): void;
345
+ api: AxiosInstance;
346
+ openFile: (href: string, options?: OpenFileOptions) => Promise<void>;
347
+ sendUserInvitation(payload: UserInvitationPayload): Promise<UserInvitationResponse>;
348
+ useDataMigrationBackgroundOperation(): DataMigrationBackgroundOperationClient;
349
+ };
322
350
  /**
323
351
  * Installs the host implementation behind the public App frontend contract.
324
352
  * Core calls this once before installed App entries execute.
@@ -356,9 +384,6 @@ export declare function NxDonutChart(props: NxDonutChartProps): ReactNode;
356
384
  export declare function NxGauge(props: NxGaugeProps): ReactNode;
357
385
  export declare function NxHeatmap(props: NxHeatmapProps): ReactNode;
358
386
  export declare function NxResourceScheduler(props: NxResourceSchedulerProps): ReactNode;
359
- export declare function NxResourceFormLegalEntityField(props: NxResourceFormLegalEntityFieldProps): ReactNode;
360
- export declare function NxResourceInformationForm<TViewContext, TEditContext>(props: NxResourceInformationFormProps<TViewContext, TEditContext>): ReactNode;
361
- export declare function NxResourceInformationView<TViewContext, TEditContext>(props: NxResourceInformationViewProps<TViewContext, TEditContext>): ReactNode;
362
387
  export declare function NxSankey(props: NxSankeyProps): ReactNode;
363
388
  export declare function NxDropdownMenu(props: NxDropdownMenuProps): ReactNode;
364
389
  export declare function NxCheckbox(props: NxCheckboxProps): ReactNode;
@@ -381,6 +406,7 @@ export declare function NxFieldset(props: NxFieldsetProps): ReactNode;
381
406
  export declare function NxFileDropzone(props: NxFileDropzoneProps): ReactNode;
382
407
  export declare function NxFormField(props: NxFormFieldProps): ReactNode;
383
408
  export declare function NxFormSection(props: NxFormSectionProps): ReactNode;
409
+ export declare function NxResourceFormLegalEntityField(props: NxResourceFormLegalEntityFieldProps): ReactNode;
384
410
  export declare function NxHelpTooltip(props: NxHelpTooltipProps): ReactNode;
385
411
  export declare function NxLoadingBlock(props: NxLoadingBlockProps): ReactNode;
386
412
  export declare function NxModalDialog(props: NxModalDialogProps): ReactNode;
@@ -586,6 +612,8 @@ export declare function useRegisterResourceCreateReceiver(registration: Resource
586
612
  export declare function useResourceCreateCompletion(): ResourceCreateCompletion;
587
613
  export declare function useMarkTabDirty(dirty: boolean, snapshot?: string, initialSnapshot?: string): void;
588
614
  export declare function useClearTabDirty(): () => void;
615
+ /** Core owns authentication navigation and restores the calling App's host route. */
616
+ export declare function useReauthenticate(): () => Promise<void>;
589
617
  export declare function useRegisterTabActions(actions: TabContextActionRegistration[] | null): void;
590
618
  export declare function useRegisterDraftAction(options: RegisterDraftActionOptions): void;
591
619
  export declare function useWorkTabLabel(label: string | null | undefined): void;
package/dist/host.js CHANGED
@@ -1,6 +1,76 @@
1
1
  import { createElement, useCallback, useEffect, useMemo, useRef, useState, } from 'react';
2
2
  import axios from 'axios';
3
3
  export { projectSignatureCapabilityCatalog, signatureCapabilityIdentity, } from './signature.js';
4
+ /** Used by the SDK build facade, not by application source. Captures a fixed owner. */
5
+ export function bindNexiaAppRequestServices(appKey) {
6
+ if (!/^[a-z][a-z0-9-]*$/.test(appKey))
7
+ throw new Error('Invalid App identity.');
8
+ const resolve = host().appServices;
9
+ if (!resolve)
10
+ throw new Error('This host does not support App-bound frontend services.');
11
+ const services = resolve(appKey);
12
+ const wrap = (component) => services.wrapComponent?.(component) ?? component;
13
+ const loader = (load) => async () => {
14
+ const module = await load();
15
+ return { ...module, default: wrap(module.default) };
16
+ };
17
+ const inspectors = {
18
+ register(type, load) {
19
+ host().registries.resourceInspectorAdapterRegistry.register(type, async () => {
20
+ const module = await load();
21
+ const Component = wrap(module.default);
22
+ return { default: props => createElement(Component, props) };
23
+ });
24
+ },
25
+ };
26
+ const approvals = {
27
+ register(registration, legacyLoader) {
28
+ host().registries.approvalComposerBusinessFormRegistry.register(typeof registration === 'string'
29
+ ? { formWidgetKey: registration, loader: loader(legacyLoader) }
30
+ : { ...registration, loader: loader(registration.loader) });
31
+ },
32
+ };
33
+ return {
34
+ resourceInspectorAdapterRegistry: inspectors,
35
+ autoRegisterPackageResourceInspectors(modules, contracts = {}) {
36
+ registerPackageResourceInspectors(modules, contracts, inspectors);
37
+ },
38
+ autoRegisterPackageSurfaces(options) {
39
+ host().runtime.autoRegisterPackageSurfaces({ ...options, appKey,
40
+ overview: options.overview && loader(options.overview),
41
+ surfaces: Object.fromEntries(Object.entries(options.surfaces).map(([key, load]) => [key, loader(load)])),
42
+ overrides: Object.fromEntries(Object.entries(options.overrides ?? {}).map(([key, value]) => [key,
43
+ typeof value === 'function' ? loader(value) : { ...value, load: loader(value.load) }])), });
44
+ },
45
+ approvalComposerBusinessFormRegistry: approvals,
46
+ processUserTaskFormRegistry: {
47
+ register(registration) {
48
+ host().registries.processUserTaskFormRegistry.register({ ...registration, loader: loader(registration.loader) });
49
+ },
50
+ },
51
+ dataMigrationRegistry: {
52
+ registerProvider: dataMigrationRegistry.registerProvider,
53
+ registerTarget: dataMigrationRegistry.registerTarget,
54
+ registerStage(registration) {
55
+ host().registries.dataMigrationRegistry.registerStage({ ...registration, ownerAppKey: appKey, loader: loader(registration.loader) });
56
+ },
57
+ },
58
+ registerAgentComponent(name, component) {
59
+ host().runtime.registerAgentComponent(name, wrap(component));
60
+ },
61
+ registerLazyAgentComponent(name, load) {
62
+ host().runtime.registerLazyAgentComponent(name, loader(load));
63
+ },
64
+ api: services.api,
65
+ openFile: services.openFile,
66
+ async sendUserInvitation(payload) {
67
+ return (await services.api.post('/users/invitations', payload)).data;
68
+ },
69
+ useDataMigrationBackgroundOperation() {
70
+ return useBackgroundOperationClient(services.api);
71
+ },
72
+ };
73
+ }
4
74
  let activeHost = null;
5
75
  /**
6
76
  * Installs the host implementation behind the public App frontend contract.
@@ -72,6 +142,9 @@ function backgroundOperationClientPath(statusUrl) {
72
142
  * cancels the wait; callers retaining a checkpoint can explicitly keep waiting.
73
143
  */
74
144
  export function useDataMigrationBackgroundOperation() {
145
+ return useBackgroundOperationClient(api);
146
+ }
147
+ function useBackgroundOperationClient(client) {
75
148
  const activeControllers = useRef(new Set());
76
149
  const backgroundControllers = useRef(new Set());
77
150
  useEffect(() => () => {
@@ -101,7 +174,7 @@ export function useDataMigrationBackgroundOperation() {
101
174
  backgroundControllers.current.add(controller);
102
175
  try {
103
176
  for (;;) {
104
- const operation = (await api.get(backgroundOperationClientPath(statusUrl), { signal: controller.signal })).data;
177
+ const operation = (await client.get(backgroundOperationClientPath(statusUrl), { signal: controller.signal })).data;
105
178
  options.onProgress?.(typeof operation.progress === 'number' ? operation.progress : 0, typeof operation.phase === 'string' ? operation.phase : null);
106
179
  if (operation.status === 'completed') {
107
180
  if (operation.result === undefined) {
@@ -123,7 +196,7 @@ export function useDataMigrationBackgroundOperation() {
123
196
  backgroundControllers.current.delete(controller);
124
197
  options.signal?.removeEventListener('abort', abortFromCaller);
125
198
  }
126
- }, []);
199
+ }, [client]);
127
200
  return useMemo(() => ({ wait, cancelAll }), [cancelAll, wait]);
128
201
  }
129
202
  function render(component, props) {
@@ -196,15 +269,6 @@ export function NxHeatmap(props) {
196
269
  export function NxResourceScheduler(props) {
197
270
  return render(host().components.NxResourceScheduler, props);
198
271
  }
199
- export function NxResourceFormLegalEntityField(props) {
200
- return render(host().components.NxResourceFormLegalEntityField, props);
201
- }
202
- export function NxResourceInformationForm(props) {
203
- return createElement(host().components.NxResourceInformationForm, props);
204
- }
205
- export function NxResourceInformationView(props) {
206
- return createElement(host().components.NxResourceInformationView, props);
207
- }
208
272
  export function NxSankey(props) {
209
273
  return render(host().components.NxSankey, props);
210
274
  }
@@ -271,6 +335,9 @@ export function NxFormField(props) {
271
335
  export function NxFormSection(props) {
272
336
  return render(host().components.NxFormSection, props);
273
337
  }
338
+ export function NxResourceFormLegalEntityField(props) {
339
+ return render(host().components.NxResourceFormLegalEntityField, props);
340
+ }
274
341
  export function NxHelpTooltip(props) {
275
342
  return render(host().components.NxHelpTooltip, props);
276
343
  }
@@ -721,6 +788,10 @@ export function useMarkTabDirty(dirty, snapshot, initialSnapshot) {
721
788
  export function useClearTabDirty() {
722
789
  return host().hooks.useClearTabDirty();
723
790
  }
791
+ /** Core owns authentication navigation and restores the calling App's host route. */
792
+ export function useReauthenticate() {
793
+ return host().hooks.useReauthenticate();
794
+ }
724
795
  export function useRegisterTabActions(actions) {
725
796
  host().hooks.useRegisterTabActions(actions);
726
797
  }
@@ -742,14 +813,24 @@ export function autoRegisterPackageSurfaces(options) {
742
813
  * lightweight metadata; implementations are loaded only by the registry.
743
814
  */
744
815
  export function autoRegisterPackageResourceInspectors(modules, resourceContracts = {}) {
816
+ registerPackageResourceInspectors(modules, resourceContracts, host().registries.resourceInspectorAdapterRegistry);
817
+ }
818
+ function registerPackageResourceInspectors(modules, resourceContracts, registry) {
745
819
  const pattern = /^\.\/resources\/[^/]+\/inspector\/register-[^/]+-inspector\.ts$/;
746
- for (const path of Object.keys(modules)) {
747
- if (!pattern.test(path))
820
+ const contractPattern = /^\.\/resources\/[^/]+\/[a-zA-Z0-9-]+-resource-contract\.ts$/;
821
+ const contracts = { ...resourceContracts };
822
+ for (const [path, module] of Object.entries(modules)) {
823
+ if (pattern.test(path))
824
+ continue;
825
+ if (!contractPattern.test(path))
748
826
  throw new Error(`Invalid package inspector registration path [${path}].`);
827
+ if (Object.hasOwn(contracts, path))
828
+ throw new Error(`Duplicate Inspector resource contract [${path}].`);
829
+ contracts[path] = module;
749
830
  }
750
831
  const registrations = new Map();
751
- for (const [path, module] of Object.entries(resourceContracts)) {
752
- if (!/^\.\/resources\/[^/]+\/[a-zA-Z0-9-]+-resource-contract\.ts$/.test(path)
832
+ for (const [path, module] of Object.entries(contracts)) {
833
+ if (!contractPattern.test(path)
753
834
  || module === null || typeof module !== 'object') {
754
835
  throw new Error(`Invalid Inspector resource contract [${path}].`);
755
836
  }
@@ -770,7 +851,7 @@ export function autoRegisterPackageResourceInspectors(modules, resourceContracts
770
851
  }
771
852
  // Validate the complete new declaration set before mutating the registry.
772
853
  for (const [type, load] of registrations) {
773
- host().registries.resourceInspectorAdapterRegistry.register(type, load);
854
+ registry.register(type, load);
774
855
  }
775
856
  }
776
857
  export function firstFieldError(errors, field) {
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  export type { ResourceListFilterableEntry, ResourceListSchema, } from "./resources/resource-list";
2
2
  export { draftStringField } from './resources/draft-field';
3
- export { defineResourceInformationSchema, resourceInformationValue, } from "./resources/resource-information";
4
- export type { NxResourceInformationFormProps, NxResourceInformationViewProps, ResourceFormLegalEntity, ResourceFormBinding, ResourceFormSaved, AppFormSaveBinding, NxResourceFormLegalEntityFieldProps, ResourceInformationControlProjection, ResourceInformationControlSlot, ResourceInformationCustomProjection, ResourceInformationEditProjection, ResourceInformationEditRenderContext, ResourceInformationField, ResourceInformationFieldSpan, ResourceInformationMode, ResourceInformationReadOnlyProjection, ResourceInformationRequirement, ResourceInformationSchema, ResourceInformationSection, ResourceInformationTranslator, ResourceInformationValue, } from "./resources/resource-information";
3
+ export { resourceFieldValue } from './resources/resource-form';
4
+ export type { AppFormSaveBinding, NxResourceFormLegalEntityFieldProps, ResourceFormBinding, ResourceFormSaved, ResourceFieldValue, ResourceFormLegalEntity, } from "./resources/resource-form";
5
5
  export type { DatasetImportConfirmationSummary, DatasetImportPlanChoice, DatasetImportPlanSection, ResourceImportPreview, ResourceImportPreviewRow, ResourceImportResponse, ResourceImportRun, ResourceImportRunStatus, ResourceImportSummary, ResourceTransferFormat, ResourceTransferMessage, ResourceTransferMeta, NxResourceImportDialogProps, NxResourceTransferActionsProps, NxDatasetImportWorkspaceProps, NxInlineResourceCreateProps, NxDatasetExportWorkspaceProps, } from "./resources/resource-transfer";
6
6
  export type { NxCalendarActionBinding, NxCalendarActionCommand, NxCalendarActionResult, NxCalendarInteraction, NxCalendarOccurrence, NxCalendarProps, NxCalendarRange, NxCalendarSelection, NxCalendarTemporalRange, NxCalendarView, NxResourceSchedulerActionBinding, NxResourceSchedulerActionCommand, NxResourceSchedulerActionResult, NxResourceSchedulerInteraction, NxResourceSchedulerOccurrence, NxResourceSchedulerProps, NxResourceSchedulerResource, NxResourceSchedulerSelection, NxResourceSchedulerView, ResourceBoardCard, ResourceBoardLabels, ResourceBoardLane, ResourceBoardLoadState, ResourceBoardMoveCommand, ResourceBoardMutationResult, ResourceBoardProjection, ResourceBoardProps, ResourceBoardSummaryField, ResourceProjectionReference, ResourceScheduleActionBinding, ResourceScheduleActionCommand, ResourceScheduleDatePair, ResourceScheduleDateSemantics, ResourceScheduleDependency, ResourceScheduleDependencyType, ResourceScheduleInteraction, ResourceScheduleItem, ResourceScheduleItemType, ResourceScheduleLoadState, ResourceScheduleMutationResult, ResourceScheduleProjection, ResourceScheduleProps, ResourceScheduleTimeUnit, ResourceScheduleView, } from "./resources/resource-projections";
7
7
  export type { ContextQueryResult, ContextResponse, LegalEntityContext, PermissionsQueryResult, PermissionsResponse, TenantContext, UserContext, WorkspaceContext, } from "./context";
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  export { draftStringField } from './resources/draft-field.js';
2
- export { defineResourceInformationSchema, resourceInformationValue, } from "./resources/resource-information.js";
2
+ export { resourceFieldValue } from './resources/resource-form.js';
3
3
  export { createDataMigrationSessionCheckpointStore, dataMigrationUploadAccept, dataMigrationRunPublicId, isDataMigrationOperationAccepted, } from "./data-migration.js";
4
4
  export { projectSignatureCapabilityCatalog, signatureCapabilityIdentity, } from "./signature.js";
5
5
  export { SIGNATURE_DOCUMENT_DATA_CLASSIFICATIONS, SIGNATURE_DOCUMENT_DATA_FIELD_TYPES, SIGNATURE_DOCUMENT_DATA_FORMATTERS, SIGNATURE_DOCUMENT_DATA_LOOKUP_MODES, SIGNATURE_DOCUMENT_DATA_STATUSES, } from "./signature.js";
@@ -0,0 +1,64 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { OrganizationTargetSelectorOption } from '../organization-target';
3
+ /** Authorized organization owner supplied by the RecordSurface, never inferred from route scope. */
4
+ export type ResourceFormLegalEntity = {
5
+ kind: 'select';
6
+ value: string | null;
7
+ options: readonly OrganizationTargetSelectorOption[];
8
+ onChange: (value: string) => void;
9
+ disabled?: boolean;
10
+ error?: ReactNode;
11
+ } | {
12
+ kind: 'stored';
13
+ /** Human label from the record or a read-authorized lookup of its owner. */
14
+ label: ReactNode;
15
+ };
16
+ /** Props for the host-owned organization owner field within a composed Record form. */
17
+ export interface NxResourceFormLegalEntityFieldProps {
18
+ target: ResourceFormLegalEntity;
19
+ mode: 'create' | 'edit';
20
+ }
21
+ /** A displayed Resource field value whose emptiness is explicit to its owning surface. */
22
+ export interface ResourceFieldValue {
23
+ value: ReactNode;
24
+ empty?: boolean;
25
+ mono?: boolean;
26
+ }
27
+ /** Keeps an empty string distinct from a displayed Resource field value. */
28
+ export declare function resourceFieldValue(value: ReactNode, options?: Omit<ResourceFieldValue, 'value'>): ResourceFieldValue;
29
+ export interface ResourceFormSaved {
30
+ action: "create" | "update";
31
+ /** Unmodified business response; decode it using the owning App contract. */
32
+ response: Readonly<Record<string, unknown>>;
33
+ submittedValues: Readonly<Record<string, unknown>>;
34
+ currentValues: Readonly<Record<string, unknown>>;
35
+ }
36
+ /** Explicit App action associated with a page form; grants no execution authority. */
37
+ export interface AppFormSaveBinding {
38
+ key: string;
39
+ /** Fixed record/scope arguments. Form fields must not overwrite these keys. */
40
+ arguments: Readonly<Record<string, unknown>>;
41
+ /** Decode the App response, preserve newer input, and refresh human-owned queries. */
42
+ onSaved: (result: Omit<ResourceFormSaved, "action">) => void | Promise<void>;
43
+ }
44
+ /**
45
+ * Explicit binding for a composed Resource form. Resource fields and controls
46
+ * remain App-owned; the host only uses this identity for draft/save actions.
47
+ */
48
+ export interface ResourceFormBinding {
49
+ /** Local identity for a form without a Resource. Requires explicit scopeKey; do not combine with resourceKey/resourceId/onSaved. */
50
+ formKey?: string;
51
+ /** Only for a formKey-based page; pairs an explicit server action with this form. */
52
+ saveAction?: AppFormSaveBinding;
53
+ /** Omit identity inside a declared Resource route; the host supplies it. */
54
+ resourceKey?: string;
55
+ resourceId?: string | null;
56
+ /** Additional form-owned scope; otherwise use the pane-local route scope. */
57
+ scopeKey?: string;
58
+ effect: "draft" | "autosave";
59
+ disabled?: boolean;
60
+ /** Host-confirmed external save for this mounted form; never performs a write. */
61
+ onSaved?: (result: ResourceFormSaved) => void | Promise<void>;
62
+ /** Pure cross-field preflight; return rejected keys before any value writer runs. */
63
+ validateBatch?: (values: Readonly<Record<string, unknown>>) => readonly string[];
64
+ }
@@ -0,0 +1,4 @@
1
+ /** Keeps an empty string distinct from a displayed Resource field value. */
2
+ export function resourceFieldValue(value, options = {}) {
3
+ return { value, ...options };
4
+ }
package/dist/shell.d.ts CHANGED
@@ -3,7 +3,7 @@ import type { QueryClient, UseQueryResult } from "@tanstack/react-query";
3
3
  import type { PermissionsResponse } from "./context";
4
4
  import type { ResourcePickerRevalidation, ResourceReferenceIdentity } from "./resource-reference";
5
5
  import type { ResourceListSchema } from "./resources/resource-list";
6
- import type { AppFormSaveBinding, ResourceFormBinding, ResourceFormSaved } from "./resources/resource-information";
6
+ import type { AppFormSaveBinding, ResourceFormBinding, ResourceFormSaved } from "./resources/resource-form";
7
7
  import type { ResourceTransferMeta } from "./resources/resource-transfer";
8
8
  /** A server-authorized, durable favorite identity. */
9
9
  export type FavoriteTarget = {
@@ -793,6 +793,8 @@ export interface NxFormFieldProps {
793
793
  export interface NxFormSectionProps {
794
794
  /** Explicit unsaved semantics for composed forms; uses published route identity. */
795
795
  binding?: ResourceFormBinding;
796
+ /** Restricts route-derived draft identity to the owning RecordSurface mode. */
797
+ mode?: "create" | "edit";
796
798
  id?: string;
797
799
  children: ReactNode;
798
800
  onSubmit?: (event: FormEvent<HTMLFormElement>) => void;
@@ -0,0 +1,9 @@
1
+ export const nexiaHostPeers: readonly string[];
2
+ export function nexiaAppConfig(configUrl: string | URL): Record<string, unknown>;
3
+ export function nexiaAppFrontend(apps: { appKey: string; root: string } | Array<{ appKey: string; root: string }>): {
4
+ name: string;
5
+ enforce: 'pre';
6
+ resolveId(source: string, importer?: string): string | undefined;
7
+ load(id: string): string | undefined;
8
+ generateBundle(this: { emitFile(file: { type: 'asset'; fileName: string; source: string }): unknown }, options: unknown, bundle: Record<string, unknown>): void;
9
+ };
package/dist/vite.mjs ADDED
@@ -0,0 +1,65 @@
1
+ import path from 'node:path';
2
+ import { readFileSync } from 'node:fs';
3
+ import { fileURLToPath } from 'node:url';
4
+
5
+ // Only these modules are supplied by Core's import map. Other App dependencies
6
+ // (for example icons or Axios error helpers) stay in the App bundle.
7
+ export const nexiaHostPeers = ['react', 'react/jsx-runtime', 'react/jsx-dev-runtime',
8
+ '@tanstack/react-query', 'react-router-dom', 'react-i18next', '@nexia/sdk', '@nexia/sdk/host'];
9
+
10
+ /** The same standalone build contract for generated and existing Apps. */
11
+ export function nexiaAppConfig(configUrl) {
12
+ const root = fileURLToPath(new URL('.', configUrl));
13
+ const manifest = JSON.parse(readFileSync(new URL('./nexia.json', configUrl), 'utf8'));
14
+ return {
15
+ root, plugins: [nexiaAppFrontend({ appKey: manifest.app.app_key, root })],
16
+ publicDir: false, envDir: false, esbuild: { jsx: 'automatic' },
17
+ resolve: { alias: { '#app': path.join(root, 'resources/js'), '#lang': path.join(root, 'resources/lang') } },
18
+ build: {
19
+ outDir: 'dist/frontend', emptyOutDir: true, sourcemap: false, manifest: true,
20
+ lib: { entry: path.join(root, 'resources/js/index.ts'), formats: ['es'], fileName: () => 'index.js' },
21
+ rollupOptions: {
22
+ external: (id, importer) => nexiaHostPeers.includes(id)
23
+ && (!['@nexia/sdk', '@nexia/sdk/host'].includes(id) || importer?.startsWith('\0nexia-app-services:')),
24
+ },
25
+ },
26
+ };
27
+ }
28
+
29
+ /** Bind App service imports at build time; App source keeps using the ordinary SDK. */
30
+ export function nexiaAppFrontend(apps) {
31
+ const owners = (Array.isArray(apps) ? apps : [apps]).map(({ appKey, root }) => {
32
+ if (!/^[a-z][a-z0-9-]*$/.test(appKey)) throw new Error('Invalid App frontend owner.');
33
+ return { appKey, root: path.resolve(root).replaceAll('\\', '/') + '/' };
34
+ });
35
+ const prefix = '\0nexia-app-services:';
36
+ return {
37
+ name: 'nexia:app-services',
38
+ enforce: 'pre',
39
+ resolveId(source, importer) {
40
+ if (!['@nexia/sdk', '@nexia/sdk/host'].includes(source) || !importer || importer.startsWith(prefix)) return;
41
+ const owner = owners.find(app => importer.replaceAll('\\', '/').startsWith(app.root));
42
+ if (owner) return prefix + owner.appKey + ':' + source;
43
+ },
44
+ load(id) {
45
+ if (!id.startsWith(prefix)) return;
46
+ const [appKey, source] = id.slice(prefix.length).split(':');
47
+ return `export * from ${JSON.stringify(source)};
48
+ import { bindNexiaAppRequestServices } from '@nexia/sdk/host';
49
+ const services = bindNexiaAppRequestServices(${JSON.stringify(appKey)});
50
+ export const { api, openFile, sendUserInvitation, useDataMigrationBackgroundOperation,
51
+ autoRegisterPackageSurfaces, autoRegisterPackageResourceInspectors,
52
+ resourceInspectorAdapterRegistry, approvalComposerBusinessFormRegistry,
53
+ processUserTaskFormRegistry, dataMigrationRegistry,
54
+ registerAgentComponent, registerLazyAgentComponent } = services;`;
55
+ },
56
+ generateBundle(_options, bundle) {
57
+ // Standalone App builds expose compatibility before executing their entry.
58
+ if (owners.length === 1) this.emitFile({
59
+ type: 'asset', fileName: 'nexia-host.json',
60
+ source: JSON.stringify({ version: 1, app_key: owners[0].appKey,
61
+ styles: Object.keys(bundle).filter(file => file.endsWith('.css')) }),
62
+ });
63
+ },
64
+ };
65
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nexia/sdk",
3
- "version": "0.7.2",
3
+ "version": "0.8.0",
4
4
  "description": "Frontend contracts for Nexia App Packages",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",
@@ -11,6 +11,7 @@
11
11
  "main": "./dist/index.js",
12
12
  "types": "./dist/index.d.ts",
13
13
  "exports": {
14
+ "./vite": "./dist/vite.mjs",
14
15
  ".": {
15
16
  "development": "./dist/index.js",
16
17
  "types": "./dist/index.d.ts",
@@ -31,7 +32,7 @@
31
32
  "scripts": {
32
33
  "build": "node scripts/build.mjs",
33
34
  "prepack": "npm run build",
34
- "test": "npm run build && node tests/WireValuesTest.mjs && node tests/ResourceCompositionFrontendContractsTest.mjs && node scripts/organization-target-contract.mjs && node tests/ResourceInspectorRegistrationTest.mjs && node tests/SettingsPrimitivesTest.mjs",
35
+ "test": "npm run build && node tests/WireValuesTest.mjs && node tests/ResourceCompositionFrontendContractsTest.mjs && node scripts/organization-target-contract.mjs && node tests/ResourceInspectorRegistrationTest.mjs && node tests/SettingsPrimitivesTest.mjs && node tests/AppServicesTest.mjs",
35
36
  "test:wire-values": "node tests/WireValuesTest.mjs",
36
37
  "typecheck": "tsc -p tsconfig.json --noEmit",
37
38
  "test:resource-composition": "pnpm run build && node tests/ResourceCompositionFrontendContractsTest.mjs",
@@ -1,164 +0,0 @@
1
- import type { ReactNode } from "react";
2
- import type { OrganizationTargetSelectorOption } from "../organization-target";
3
- /** Surface-owned, authorized form target. Never a page/list scope. */
4
- export type ResourceFormLegalEntity = {
5
- kind: "select";
6
- value: string | null;
7
- options: readonly OrganizationTargetSelectorOption[];
8
- onChange: (value: string) => void;
9
- disabled?: boolean;
10
- error?: ReactNode;
11
- } | {
12
- kind: "stored";
13
- /** Human label from the record or a read-authorized lookup of its owner. */
14
- label: ReactNode;
15
- };
16
- /** Why a field matters to the Resource lifecycle. */
17
- export type ResourceInformationRequirement = "save" | "readiness" | "optional";
18
- /** The projections in which a field occupies its canonical position. */
19
- export type ResourceInformationMode = "view" | "create" | "edit";
20
- /** Responsive width hint for the Form projection. View always uses detail rows. */
21
- export type ResourceInformationFieldSpan = "half" | "full";
22
- export interface ResourceInformationValue {
23
- value: ReactNode;
24
- empty?: boolean;
25
- mono?: boolean;
26
- }
27
- export interface ResourceInformationControlSlot {
28
- id: string;
29
- describedBy?: string;
30
- invalid: boolean;
31
- }
32
- export interface ResourceInformationEditRenderContext<TContext> {
33
- mode: "create" | "edit";
34
- context: TContext;
35
- }
36
- export interface ResourceInformationControlProjection<TContext> {
37
- kind: "control";
38
- render: (context: ResourceInformationEditRenderContext<TContext>, slot: ResourceInformationControlSlot) => ReactNode;
39
- error?: (context: ResourceInformationEditRenderContext<TContext>) => ReactNode;
40
- }
41
- export interface ResourceInformationReadOnlyProjection<TContext> {
42
- kind: "read-only";
43
- render: (context: ResourceInformationEditRenderContext<TContext>) => ResourceInformationValue;
44
- }
45
- /**
46
- * Escape hatch for a composite field such as an address editor. The field
47
- * still has one canonical schema position and one View value, while the App
48
- * owns the compound Edit control.
49
- */
50
- export interface ResourceInformationCustomProjection<TContext> {
51
- kind: "custom";
52
- render: (context: ResourceInformationEditRenderContext<TContext>) => ReactNode;
53
- }
54
- export type ResourceInformationEditProjection<TContext> = ResourceInformationControlProjection<TContext> | ResourceInformationReadOnlyProjection<TContext> | ResourceInformationCustomProjection<TContext>;
55
- export interface ResourceInformationField<TViewContext, TEditContext> {
56
- key: string;
57
- labelKey: string;
58
- /** Persistent entry guidance rendered below an Edit control. */
59
- helpKey?: string;
60
- /** Short domain definition rendered from the field label. */
61
- definitionKey?: string;
62
- requirement?: ResourceInformationRequirement;
63
- /** Personal/secret values are excluded from automated form discovery and writes. */
64
- sensitive?: boolean;
65
- span?: ResourceInformationFieldSpan;
66
- /** Defaults to all projections. Omissions must be deliberate and explicit. */
67
- modes?: readonly ResourceInformationMode[];
68
- /** Context-dependent visibility evaluated after the static mode contract. */
69
- visibility?: {
70
- view?: (context: TViewContext) => boolean;
71
- create?: (context: TEditContext) => boolean;
72
- edit?: (context: TEditContext) => boolean;
73
- };
74
- view: (context: TViewContext) => ResourceInformationValue;
75
- edit: ResourceInformationEditProjection<TEditContext>;
76
- }
77
- export interface ResourceInformationSection<TViewContext, TEditContext> {
78
- key: string;
79
- titleKey: string;
80
- descriptionKey?: string;
81
- /** Form layout only. View remains an ordered, compact definition list. */
82
- formColumns?: 1 | 2;
83
- /** Optional aggregate or projection owner, for example `resource` or `party`. */
84
- source?: string;
85
- fields: readonly ResourceInformationField<TViewContext, TEditContext>[];
86
- }
87
- /**
88
- * One ordered Resource information contract projected by both View and Edit.
89
- * Route loading, mutations, and related-resource actions remain Surface-owned.
90
- */
91
- export interface ResourceInformationSchema<TViewContext, TEditContext> {
92
- sections: readonly ResourceInformationSection<TViewContext, TEditContext>[];
93
- }
94
- export interface ResourceInformationTranslator {
95
- (key: string): string;
96
- }
97
- export interface NxResourceInformationViewProps<TViewContext, TEditContext = never> {
98
- schema: ResourceInformationSchema<TViewContext, TEditContext>;
99
- context: TViewContext;
100
- translate: ResourceInformationTranslator;
101
- emptyValue: ReactNode;
102
- visibleEmptyRequirements?: readonly ResourceInformationRequirement[];
103
- testIdPrefix?: string;
104
- }
105
- /** Place inside the first input section of a custom form. */
106
- export interface NxResourceFormLegalEntityFieldProps {
107
- target: ResourceFormLegalEntity;
108
- mode: "create" | "edit";
109
- }
110
- export interface NxResourceInformationFormProps<TViewContext, TEditContext> {
111
- schema: ResourceInformationSchema<TViewContext, TEditContext>;
112
- context: TEditContext;
113
- mode: "create" | "edit";
114
- /** Explicit owner and effect of this form; control writers remain public callbacks. */
115
- binding?: ResourceFormBinding;
116
- /** First field of the first schema section, full row width. Omit for tenant-owned forms.
117
- * Use `stored` on edit; the host never renders an editable owner in edit mode.
118
- * Do not also declare the Legal Entity field in the form schema.
119
- */
120
- legalEntity?: ResourceFormLegalEntity;
121
- translate: ResourceInformationTranslator;
122
- emptyValue: ReactNode;
123
- testIdPrefix?: string;
124
- }
125
- export interface ResourceFormSaved {
126
- action: "create" | "update";
127
- /** Unmodified business response; decode it using the owning App contract. */
128
- response: Readonly<Record<string, unknown>>;
129
- submittedValues: Readonly<Record<string, unknown>>;
130
- currentValues: Readonly<Record<string, unknown>>;
131
- }
132
- /** Explicit App action associated with a page form; grants no execution authority. */
133
- export interface AppFormSaveBinding {
134
- key: string;
135
- /** Fixed record/scope arguments. Form fields must not overwrite these keys. */
136
- arguments: Readonly<Record<string, unknown>>;
137
- /** Decode the App response, preserve newer input, and refresh human-owned queries. */
138
- onSaved: (result: Omit<ResourceFormSaved, "action">) => void | Promise<void>;
139
- }
140
- export interface ResourceFormBinding {
141
- /** Local identity for a form without a Resource. Requires explicit scopeKey; do not combine with resourceKey/resourceId/onSaved. */
142
- formKey?: string;
143
- /** Only for a formKey-based page; pairs an explicit server action with this form. */
144
- saveAction?: AppFormSaveBinding;
145
- /** Omit identity inside a declared Resource route; the host supplies it. */
146
- resourceKey?: string;
147
- resourceId?: string | null;
148
- /** Additional form-owned scope; otherwise use the pane-local route scope. */
149
- scopeKey?: string;
150
- effect: "draft" | "autosave";
151
- disabled?: boolean;
152
- /** Host-confirmed external save for this mounted form; never performs a write. */
153
- onSaved?: (result: ResourceFormSaved) => void | Promise<void>;
154
- /** Pure cross-field preflight; return rejected keys before any value writer runs. */
155
- validateBatch?: (values: Readonly<Record<string, unknown>>) => readonly string[];
156
- }
157
- /**
158
- * Checks a schema once, then deliberately widens it to the stable host
159
- * contract. Keeping every App field as one deep literal union makes a
160
- * workspace-wide typecheck retain the complete product catalog in memory.
161
- */
162
- export declare function defineResourceInformationSchema<TViewContext, TEditContext>(): (schema: ResourceInformationSchema<TViewContext, TEditContext>) => ResourceInformationSchema<TViewContext, TEditContext>;
163
- /** Explicit value helper so an empty string is never mistaken for a value. */
164
- export declare function resourceInformationValue(value: ReactNode, options?: Omit<ResourceInformationValue, "value">): ResourceInformationValue;
@@ -1,12 +0,0 @@
1
- /**
2
- * Checks a schema once, then deliberately widens it to the stable host
3
- * contract. Keeping every App field as one deep literal union makes a
4
- * workspace-wide typecheck retain the complete product catalog in memory.
5
- */
6
- export function defineResourceInformationSchema() {
7
- return (schema) => schema;
8
- }
9
- /** Explicit value helper so an empty string is never mistaken for a value. */
10
- export function resourceInformationValue(value, options = {}) {
11
- return { value, ...options };
12
- }