@nexia/sdk 0.5.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/app-availability.d.ts +18 -0
- package/dist/app-availability.js +29 -0
- package/dist/approval.d.ts +180 -0
- package/dist/approval.js +9 -0
- package/dist/context.d.ts +49 -0
- package/dist/context.js +1 -0
- package/dist/data-migration.d.ts +123 -0
- package/dist/data-migration.js +70 -0
- package/dist/fixtures/approval-contract-negative.d.ts +1 -0
- package/dist/fixtures/approval-contract-negative.js +8 -0
- package/dist/handoff-result.d.ts +6 -0
- package/dist/handoff-result.js +17 -0
- package/dist/host.d.ts +602 -0
- package/dist/host.js +803 -0
- package/dist/index.d.ts +42 -0
- package/dist/index.js +21 -0
- package/dist/number.d.ts +2 -0
- package/dist/number.js +9 -0
- package/dist/organization-target.d.ts +101 -0
- package/dist/organization-target.js +105 -0
- package/dist/permissions.d.ts +3 -0
- package/dist/permissions.js +12 -0
- package/dist/platform.d.ts +378 -0
- package/dist/platform.js +114 -0
- package/dist/process.d.ts +98 -0
- package/dist/process.js +10 -0
- package/dist/resource-composition.d.ts +104 -0
- package/dist/resource-composition.js +576 -0
- package/dist/resource-create-destination.d.ts +17 -0
- package/dist/resource-create-destination.js +1 -0
- package/dist/resource-reference.d.ts +122 -0
- package/dist/resource-reference.js +203 -0
- package/dist/resources/resource-information.d.ts +128 -0
- package/dist/resources/resource-information.js +12 -0
- package/dist/resources/resource-list.d.ts +23 -0
- package/dist/resources/resource-list.js +1 -0
- package/dist/resources/resource-projections.d.ts +311 -0
- package/dist/resources/resource-projections.js +1 -0
- package/dist/resources/resource-transfer.d.ts +208 -0
- package/dist/resources/resource-transfer.js +1 -0
- package/dist/shell.d.ts +1297 -0
- package/dist/shell.js +1 -0
- package/dist/signature.d.ts +489 -0
- package/dist/signature.js +171 -0
- package/dist/spreadsheet.d.ts +42 -0
- package/dist/spreadsheet.js +15 -0
- package/dist/testing.d.ts +16 -0
- package/dist/testing.js +17 -0
- package/package.json +53 -0
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical cross-app resource reference availability contract.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the backend `Nexia\ResourceReference\ReferenceStatus` enum. Apps
|
|
5
|
+
* must consume these values as-is — re-encoding a status (for example
|
|
6
|
+
* renaming `absent` to `unavailable`) breaks the shared vocabulary that the
|
|
7
|
+
* host and other Apps rely on.
|
|
8
|
+
*
|
|
9
|
+
* This is unrelated to the `WorkTabRef` inspector-stack UI handle exported
|
|
10
|
+
* from `shell.ts`; that type identifies an open work tab, not a cross-app
|
|
11
|
+
* resource reference.
|
|
12
|
+
*/
|
|
13
|
+
export declare const RESOURCE_REFERENCE_STATUSES: readonly ["available", "absent", "disabled", "failed", "stale", "unauthorized"];
|
|
14
|
+
export type ResourceReferenceStatus = (typeof RESOURCE_REFERENCE_STATUSES)[number];
|
|
15
|
+
export declare function isResourceReferenceStatus(value: unknown): value is ResourceReferenceStatus;
|
|
16
|
+
/** Canonical `{app_key, resource_key, resource_id}` reference tuple. */
|
|
17
|
+
export interface ResourceReferenceIdentity {
|
|
18
|
+
app_key: string;
|
|
19
|
+
resource_key: string;
|
|
20
|
+
resource_id: string;
|
|
21
|
+
display?: string;
|
|
22
|
+
href?: string | null;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Present an already-saved reference without treating its snapshot as a live
|
|
26
|
+
* owner-App link. Only an available reference may expose its stored href; all
|
|
27
|
+
* other states retain the saved display while remaining snapshot-only.
|
|
28
|
+
*/
|
|
29
|
+
export declare function savedResourceReferencePresentation(reference: ResourceReferenceIdentity, status: ResourceReferenceStatus): {
|
|
30
|
+
readonly display: string;
|
|
31
|
+
readonly href: string | null;
|
|
32
|
+
readonly liveRefreshAllowed: boolean;
|
|
33
|
+
readonly snapshotOnly: boolean;
|
|
34
|
+
};
|
|
35
|
+
/** PII-free signal emitted after an owning App has committed a resource projection. */
|
|
36
|
+
export interface ResourceProjectionChangeSubscription {
|
|
37
|
+
tenantId: string | undefined;
|
|
38
|
+
resource: Pick<ResourceReferenceIdentity, 'app_key' | 'resource_key' | 'resource_id'>;
|
|
39
|
+
onChanged: () => void;
|
|
40
|
+
enabled?: boolean;
|
|
41
|
+
}
|
|
42
|
+
/** Availability of one referenced resource kind for the current actor. */
|
|
43
|
+
export interface ResourceReferenceAvailability {
|
|
44
|
+
resource_key: string;
|
|
45
|
+
status: ResourceReferenceStatus;
|
|
46
|
+
}
|
|
47
|
+
/** One owner-authorized option returned by the host reference selector. */
|
|
48
|
+
export interface ResourceReferenceOption {
|
|
49
|
+
reference: Required<ResourceReferenceIdentity>;
|
|
50
|
+
fields: Record<string, unknown>;
|
|
51
|
+
revision: number | null;
|
|
52
|
+
status: string | null;
|
|
53
|
+
as_of: string;
|
|
54
|
+
}
|
|
55
|
+
export interface ResourceReferenceOptionsResponse {
|
|
56
|
+
data: ResourceReferenceOption[];
|
|
57
|
+
}
|
|
58
|
+
export interface ResourceReferenceOptionPageMeta {
|
|
59
|
+
resource_key: string;
|
|
60
|
+
dependency_state: ResourceReferenceStatus;
|
|
61
|
+
current_page: number;
|
|
62
|
+
last_page: number;
|
|
63
|
+
per_page: number;
|
|
64
|
+
total: number;
|
|
65
|
+
}
|
|
66
|
+
export interface ResourceReferenceOptionPage extends ResourceReferenceOptionsResponse {
|
|
67
|
+
meta: ResourceReferenceOptionPageMeta;
|
|
68
|
+
}
|
|
69
|
+
/** Validate the host selector response before an App renders owner data. */
|
|
70
|
+
export declare function parseResourceReferenceOptionPage(value: unknown, expectedResourceKey: string): ResourceReferenceOptionPage;
|
|
71
|
+
/** Resource picker data may stay fresh briefly without another network read. */
|
|
72
|
+
export declare const RESOURCE_PICKER_STALE_TIME_MS = 5000;
|
|
73
|
+
export interface ResourcePickerRefetchOptions {
|
|
74
|
+
cancelRefetch?: boolean;
|
|
75
|
+
}
|
|
76
|
+
/** Minimal TanStack-compatible state consumed by the host combobox contract. */
|
|
77
|
+
export interface ResourcePickerQueryState {
|
|
78
|
+
isStale: boolean;
|
|
79
|
+
isFetching: boolean;
|
|
80
|
+
refetch: (options?: ResourcePickerRefetchOptions) => unknown;
|
|
81
|
+
}
|
|
82
|
+
export interface ResourcePickerRevalidationOptions {
|
|
83
|
+
/** Bypass the freshness window for an explicit user refresh. */
|
|
84
|
+
force?: boolean;
|
|
85
|
+
}
|
|
86
|
+
export type ResourcePickerRevalidation = (options?: ResourcePickerRevalidationOptions) => unknown;
|
|
87
|
+
/** Adapt a query result without exposing TanStack Query types through the SDK. */
|
|
88
|
+
export declare function resourcePickerRevalidation(query: ResourcePickerQueryState): ResourcePickerRevalidation;
|
|
89
|
+
export interface ResourceReferencePickerQueryScope {
|
|
90
|
+
resourceKey: string;
|
|
91
|
+
tenantId: string | number | null | undefined;
|
|
92
|
+
legalEntityPublicId?: string | null;
|
|
93
|
+
}
|
|
94
|
+
export interface ResourceReferenceSelectorContext {
|
|
95
|
+
consumerResourceKey: string;
|
|
96
|
+
consumerField: string;
|
|
97
|
+
}
|
|
98
|
+
/** Stable prefix invalidated after any successful mutation of the owner Resource. */
|
|
99
|
+
export declare function resourceReferencePickerQueryRoot({ resourceKey, tenantId, legalEntityPublicId, }: ResourceReferencePickerQueryScope): readonly ["resource-reference-picker", string, string | number | null, string | null];
|
|
100
|
+
/** Exact picker key; purpose and dependencies prevent incompatible cache shapes. */
|
|
101
|
+
export declare function resourceReferencePickerQueryKey(scope: ResourceReferencePickerQueryScope & {
|
|
102
|
+
purpose?: string;
|
|
103
|
+
dependencies?: readonly unknown[];
|
|
104
|
+
}): readonly ["resource-reference-picker", string, string | number | null, string | null, string, ...unknown[]];
|
|
105
|
+
/**
|
|
106
|
+
* Canonical host route for cross-App selectors. `null` is an explicit
|
|
107
|
+
* tenant-scoped context, never a request to infer a Legal Entity or Shell state.
|
|
108
|
+
*/
|
|
109
|
+
export declare function resourceReferenceOptionsRoute(legalEntityPublicId: string | null, resourceKey: string, selector: ResourceReferenceSelectorContext): string;
|
|
110
|
+
/**
|
|
111
|
+
* A referenced target blocks dependent work when it exists but cannot be
|
|
112
|
+
* used right now (disabled, failed, stale, or unauthorized). `absent` is not blocking:
|
|
113
|
+
* the target App is simply not part of this tenant.
|
|
114
|
+
*/
|
|
115
|
+
export declare function isResourceReferenceBlocked(status: ResourceReferenceStatus): boolean;
|
|
116
|
+
/**
|
|
117
|
+
* Manual fallback (free-text entry, exclusion, or local substitute) is only
|
|
118
|
+
* legitimate when the target App is absent from the tenant. Unauthorized or
|
|
119
|
+
* failing references must surface their own recovery path instead of being
|
|
120
|
+
* silently replaced.
|
|
121
|
+
*/
|
|
122
|
+
export declare function allowsManualReferenceFallback(status: ResourceReferenceStatus): boolean;
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Canonical cross-app resource reference availability contract.
|
|
3
|
+
*
|
|
4
|
+
* Mirrors the backend `Nexia\ResourceReference\ReferenceStatus` enum. Apps
|
|
5
|
+
* must consume these values as-is — re-encoding a status (for example
|
|
6
|
+
* renaming `absent` to `unavailable`) breaks the shared vocabulary that the
|
|
7
|
+
* host and other Apps rely on.
|
|
8
|
+
*
|
|
9
|
+
* This is unrelated to the `WorkTabRef` inspector-stack UI handle exported
|
|
10
|
+
* from `shell.ts`; that type identifies an open work tab, not a cross-app
|
|
11
|
+
* resource reference.
|
|
12
|
+
*/
|
|
13
|
+
export const RESOURCE_REFERENCE_STATUSES = [
|
|
14
|
+
'available',
|
|
15
|
+
'absent',
|
|
16
|
+
'disabled',
|
|
17
|
+
'failed',
|
|
18
|
+
'stale',
|
|
19
|
+
'unauthorized',
|
|
20
|
+
];
|
|
21
|
+
export function isResourceReferenceStatus(value) {
|
|
22
|
+
return (typeof value === 'string' &&
|
|
23
|
+
RESOURCE_REFERENCE_STATUSES.includes(value));
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Present an already-saved reference without treating its snapshot as a live
|
|
27
|
+
* owner-App link. Only an available reference may expose its stored href; all
|
|
28
|
+
* other states retain the saved display while remaining snapshot-only.
|
|
29
|
+
*/
|
|
30
|
+
export function savedResourceReferencePresentation(reference, status) {
|
|
31
|
+
const display = typeof reference.display === 'string' && reference.display.trim() !== ''
|
|
32
|
+
? reference.display
|
|
33
|
+
: reference.resource_id;
|
|
34
|
+
const available = status === 'available';
|
|
35
|
+
return {
|
|
36
|
+
display,
|
|
37
|
+
href: available && reference.href ? reference.href : null,
|
|
38
|
+
liveRefreshAllowed: available,
|
|
39
|
+
snapshotOnly: !available,
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
const RESOURCE_KEY_PATTERN = /^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*\.[a-z][a-z0-9_-]*(?:\.[a-z][a-z0-9_-]*)*$/;
|
|
43
|
+
/** Validate the host selector response before an App renders owner data. */
|
|
44
|
+
export function parseResourceReferenceOptionPage(value, expectedResourceKey) {
|
|
45
|
+
if (expectedResourceKey.length > 160 || !RESOURCE_KEY_PATTERN.test(expectedResourceKey)) {
|
|
46
|
+
throw new Error('Expected Resource Reference key is invalid.');
|
|
47
|
+
}
|
|
48
|
+
const root = referenceObject(value, 'response');
|
|
49
|
+
const meta = referenceObject(root.meta, 'meta');
|
|
50
|
+
const resourceKey = referenceString(meta.resource_key, 'meta.resource_key');
|
|
51
|
+
if (resourceKey !== expectedResourceKey) {
|
|
52
|
+
throw new Error(`ResourceReference response key mismatch: expected ${expectedResourceKey}.`);
|
|
53
|
+
}
|
|
54
|
+
const dependencyState = referenceString(meta.dependency_state, 'meta.dependency_state');
|
|
55
|
+
if (!isResourceReferenceStatus(dependencyState)) {
|
|
56
|
+
throw new Error('ResourceReference dependency_state is invalid.');
|
|
57
|
+
}
|
|
58
|
+
const data = referenceArray(root.data, 'data').map((item, index) => {
|
|
59
|
+
const option = referenceObject(item, `data.${index}`);
|
|
60
|
+
const reference = referenceObject(option.reference, `data.${index}.reference`);
|
|
61
|
+
const appKey = referenceString(reference.app_key, `data.${index}.reference.app_key`);
|
|
62
|
+
const optionResourceKey = referenceString(reference.resource_key, `data.${index}.reference.resource_key`);
|
|
63
|
+
if (optionResourceKey !== expectedResourceKey ||
|
|
64
|
+
optionResourceKey.split('.', 1)[0] !== appKey) {
|
|
65
|
+
throw new Error('ResourceReference option ownership is contradictory.');
|
|
66
|
+
}
|
|
67
|
+
const resourceId = referenceString(reference.resource_id, `data.${index}.reference.resource_id`);
|
|
68
|
+
if (resourceId !== resourceId.trim() || [...resourceId].length > 255) {
|
|
69
|
+
throw new Error(`data.${index}.reference.resource_id is invalid.`);
|
|
70
|
+
}
|
|
71
|
+
const href = reference.href;
|
|
72
|
+
if (href !== null && typeof href !== 'string') {
|
|
73
|
+
throw new Error(`data.${index}.reference.href must be a string or null.`);
|
|
74
|
+
}
|
|
75
|
+
const revision = option.revision;
|
|
76
|
+
if (revision !== null &&
|
|
77
|
+
(!Number.isSafeInteger(revision) || Number(revision) < 0)) {
|
|
78
|
+
throw new Error(`data.${index}.revision must be a non-negative integer or null.`);
|
|
79
|
+
}
|
|
80
|
+
const status = option.status;
|
|
81
|
+
if (status !== null && typeof status !== 'string') {
|
|
82
|
+
throw new Error(`data.${index}.status must be a string or null.`);
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
reference: {
|
|
86
|
+
app_key: appKey,
|
|
87
|
+
resource_key: optionResourceKey,
|
|
88
|
+
resource_id: resourceId,
|
|
89
|
+
display: referenceString(reference.display, `data.${index}.reference.display`),
|
|
90
|
+
href,
|
|
91
|
+
},
|
|
92
|
+
fields: referenceObject(option.fields, `data.${index}.fields`),
|
|
93
|
+
revision: revision === null ? null : Number(revision),
|
|
94
|
+
status,
|
|
95
|
+
as_of: referenceString(option.as_of, `data.${index}.as_of`),
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
if (dependencyState !== 'available' && data.length > 0) {
|
|
99
|
+
throw new Error('Non-available ResourceReference responses must not expose records.');
|
|
100
|
+
}
|
|
101
|
+
const currentPage = referenceInteger(meta.current_page, 'meta.current_page', 1);
|
|
102
|
+
const lastPage = referenceInteger(meta.last_page, 'meta.last_page', 1);
|
|
103
|
+
const perPage = referenceInteger(meta.per_page, 'meta.per_page', 1);
|
|
104
|
+
const total = referenceInteger(meta.total, 'meta.total', 0);
|
|
105
|
+
if (lastPage !== Math.max(1, Math.ceil(total / perPage)) ||
|
|
106
|
+
data.length > perPage ||
|
|
107
|
+
data.length > total ||
|
|
108
|
+
(currentPage > lastPage && data.length > 0)) {
|
|
109
|
+
throw new Error('ResourceReference pagination metadata is contradictory.');
|
|
110
|
+
}
|
|
111
|
+
return {
|
|
112
|
+
data,
|
|
113
|
+
meta: {
|
|
114
|
+
resource_key: resourceKey,
|
|
115
|
+
dependency_state: dependencyState,
|
|
116
|
+
current_page: currentPage,
|
|
117
|
+
last_page: lastPage,
|
|
118
|
+
per_page: perPage,
|
|
119
|
+
total,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
/** Resource picker data may stay fresh briefly without another network read. */
|
|
124
|
+
export const RESOURCE_PICKER_STALE_TIME_MS = 5_000;
|
|
125
|
+
/** Adapt a query result without exposing TanStack Query types through the SDK. */
|
|
126
|
+
export function resourcePickerRevalidation(query) {
|
|
127
|
+
return (options = {}) => {
|
|
128
|
+
if ((!options.force && !query.isStale) || query.isFetching)
|
|
129
|
+
return;
|
|
130
|
+
return query.refetch({ cancelRefetch: false });
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
/** Stable prefix invalidated after any successful mutation of the owner Resource. */
|
|
134
|
+
export function resourceReferencePickerQueryRoot({ resourceKey, tenantId, legalEntityPublicId = null, }) {
|
|
135
|
+
return [
|
|
136
|
+
'resource-reference-picker',
|
|
137
|
+
resourceKey,
|
|
138
|
+
tenantId ?? null,
|
|
139
|
+
legalEntityPublicId,
|
|
140
|
+
];
|
|
141
|
+
}
|
|
142
|
+
/** Exact picker key; purpose and dependencies prevent incompatible cache shapes. */
|
|
143
|
+
export function resourceReferencePickerQueryKey(scope) {
|
|
144
|
+
return [
|
|
145
|
+
...resourceReferencePickerQueryRoot(scope),
|
|
146
|
+
scope.purpose ?? 'default',
|
|
147
|
+
...(scope.dependencies ?? []),
|
|
148
|
+
];
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Canonical host route for cross-App selectors. `null` is an explicit
|
|
152
|
+
* tenant-scoped context, never a request to infer a Legal Entity or Shell state.
|
|
153
|
+
*/
|
|
154
|
+
export function resourceReferenceOptionsRoute(legalEntityPublicId, resourceKey, selector) {
|
|
155
|
+
const route = legalEntityPublicId === null
|
|
156
|
+
? `/resource-references/${encodeURIComponent(resourceKey)}/options`
|
|
157
|
+
: `/legal-entities/${encodeURIComponent(legalEntityPublicId)}/resource-references/${encodeURIComponent(resourceKey)}/options`;
|
|
158
|
+
const query = new URLSearchParams({
|
|
159
|
+
consumer_resource_key: selector.consumerResourceKey,
|
|
160
|
+
consumer_field: selector.consumerField,
|
|
161
|
+
});
|
|
162
|
+
return `${route}?${query.toString()}`;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* A referenced target blocks dependent work when it exists but cannot be
|
|
166
|
+
* used right now (disabled, failed, stale, or unauthorized). `absent` is not blocking:
|
|
167
|
+
* the target App is simply not part of this tenant.
|
|
168
|
+
*/
|
|
169
|
+
export function isResourceReferenceBlocked(status) {
|
|
170
|
+
return status !== 'available' && status !== 'absent';
|
|
171
|
+
}
|
|
172
|
+
/**
|
|
173
|
+
* Manual fallback (free-text entry, exclusion, or local substitute) is only
|
|
174
|
+
* legitimate when the target App is absent from the tenant. Unauthorized or
|
|
175
|
+
* failing references must surface their own recovery path instead of being
|
|
176
|
+
* silently replaced.
|
|
177
|
+
*/
|
|
178
|
+
export function allowsManualReferenceFallback(status) {
|
|
179
|
+
return status === 'absent';
|
|
180
|
+
}
|
|
181
|
+
function referenceObject(value, path) {
|
|
182
|
+
if (typeof value !== 'object' || value === null || Array.isArray(value)) {
|
|
183
|
+
throw new Error(`${path} must be an object.`);
|
|
184
|
+
}
|
|
185
|
+
return value;
|
|
186
|
+
}
|
|
187
|
+
function referenceArray(value, path) {
|
|
188
|
+
if (!Array.isArray(value))
|
|
189
|
+
throw new Error(`${path} must be an array.`);
|
|
190
|
+
return value;
|
|
191
|
+
}
|
|
192
|
+
function referenceString(value, path) {
|
|
193
|
+
if (typeof value !== 'string' || value.trim() === '') {
|
|
194
|
+
throw new Error(`${path} must be a non-empty string.`);
|
|
195
|
+
}
|
|
196
|
+
return value;
|
|
197
|
+
}
|
|
198
|
+
function referenceInteger(value, path, minimum) {
|
|
199
|
+
if (!Number.isSafeInteger(value) || Number(value) < minimum) {
|
|
200
|
+
throw new Error(`${path} must be an integer greater than or equal to ${minimum}.`);
|
|
201
|
+
}
|
|
202
|
+
return Number(value);
|
|
203
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
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
|
+
span?: ResourceInformationFieldSpan;
|
|
64
|
+
/** Defaults to all projections. Omissions must be deliberate and explicit. */
|
|
65
|
+
modes?: readonly ResourceInformationMode[];
|
|
66
|
+
/** Context-dependent visibility evaluated after the static mode contract. */
|
|
67
|
+
visibility?: {
|
|
68
|
+
view?: (context: TViewContext) => boolean;
|
|
69
|
+
create?: (context: TEditContext) => boolean;
|
|
70
|
+
edit?: (context: TEditContext) => boolean;
|
|
71
|
+
};
|
|
72
|
+
view: (context: TViewContext) => ResourceInformationValue;
|
|
73
|
+
edit: ResourceInformationEditProjection<TEditContext>;
|
|
74
|
+
}
|
|
75
|
+
export interface ResourceInformationSection<TViewContext, TEditContext> {
|
|
76
|
+
key: string;
|
|
77
|
+
titleKey: string;
|
|
78
|
+
descriptionKey?: string;
|
|
79
|
+
/** Form layout only. View remains an ordered, compact definition list. */
|
|
80
|
+
formColumns?: 1 | 2;
|
|
81
|
+
/** Optional aggregate or projection owner, for example `resource` or `party`. */
|
|
82
|
+
source?: string;
|
|
83
|
+
fields: readonly ResourceInformationField<TViewContext, TEditContext>[];
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* One ordered Resource information contract projected by both View and Edit.
|
|
87
|
+
* Route loading, mutations, and related-resource actions remain Surface-owned.
|
|
88
|
+
*/
|
|
89
|
+
export interface ResourceInformationSchema<TViewContext, TEditContext> {
|
|
90
|
+
sections: readonly ResourceInformationSection<TViewContext, TEditContext>[];
|
|
91
|
+
}
|
|
92
|
+
export interface ResourceInformationTranslator {
|
|
93
|
+
(key: string): string;
|
|
94
|
+
}
|
|
95
|
+
export interface NxResourceInformationViewProps<TViewContext, TEditContext = never> {
|
|
96
|
+
schema: ResourceInformationSchema<TViewContext, TEditContext>;
|
|
97
|
+
context: TViewContext;
|
|
98
|
+
translate: ResourceInformationTranslator;
|
|
99
|
+
emptyValue: ReactNode;
|
|
100
|
+
visibleEmptyRequirements?: readonly ResourceInformationRequirement[];
|
|
101
|
+
testIdPrefix?: string;
|
|
102
|
+
}
|
|
103
|
+
/** Place inside the first input section of a custom form. */
|
|
104
|
+
export interface NxResourceFormLegalEntityFieldProps {
|
|
105
|
+
target: ResourceFormLegalEntity;
|
|
106
|
+
mode: "create" | "edit";
|
|
107
|
+
}
|
|
108
|
+
export interface NxResourceInformationFormProps<TViewContext, TEditContext> {
|
|
109
|
+
schema: ResourceInformationSchema<TViewContext, TEditContext>;
|
|
110
|
+
context: TEditContext;
|
|
111
|
+
mode: "create" | "edit";
|
|
112
|
+
/** First field of the first schema section, full row width. Omit for tenant-owned forms.
|
|
113
|
+
* Use `stored` on edit; the host never renders an editable owner in edit mode.
|
|
114
|
+
* Do not also declare the Legal Entity field in the form schema.
|
|
115
|
+
*/
|
|
116
|
+
legalEntity?: ResourceFormLegalEntity;
|
|
117
|
+
translate: ResourceInformationTranslator;
|
|
118
|
+
emptyValue: ReactNode;
|
|
119
|
+
testIdPrefix?: string;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Checks a schema once, then deliberately widens it to the stable host
|
|
123
|
+
* contract. Keeping every App field as one deep literal union makes a
|
|
124
|
+
* workspace-wide typecheck retain the complete product catalog in memory.
|
|
125
|
+
*/
|
|
126
|
+
export declare function defineResourceInformationSchema<TViewContext, TEditContext>(): (schema: ResourceInformationSchema<TViewContext, TEditContext>) => ResourceInformationSchema<TViewContext, TEditContext>;
|
|
127
|
+
/** Explicit value helper so an empty string is never mistaken for a value. */
|
|
128
|
+
export declare function resourceInformationValue(value: ReactNode, options?: Omit<ResourceInformationValue, "value">): ResourceInformationValue;
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/** A filter definition published by a resource list endpoint. */
|
|
2
|
+
export interface ResourceListFilterableEntry {
|
|
3
|
+
key: string;
|
|
4
|
+
multiple: boolean;
|
|
5
|
+
label: string;
|
|
6
|
+
options: Array<{
|
|
7
|
+
value: string;
|
|
8
|
+
label: string;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Self-describing list schema published as `meta.list_schema`.
|
|
13
|
+
*
|
|
14
|
+
* Apps and the host shell share this wire contract so list chrome can render
|
|
15
|
+
* filtering, sorting, and search without a resource-specific schema mirror.
|
|
16
|
+
*/
|
|
17
|
+
export interface ResourceListSchema {
|
|
18
|
+
/** Canonical record key for host capabilities that refresh this list. */
|
|
19
|
+
resource_key?: string;
|
|
20
|
+
sortable: string[];
|
|
21
|
+
filterable: ResourceListFilterableEntry[];
|
|
22
|
+
searchable: string[];
|
|
23
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|