openxiangda-contracts 2.16.2 → 2.17.1
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/data-view-validation.d.ts +1 -0
- package/dist/data-view-validation.d.ts.map +1 -1
- package/dist/data-view-validation.js +38 -1
- package/dist/data-view-validation.js.map +1 -1
- package/dist/native-compiler/compiler.d.ts +1 -0
- package/dist/native-compiler/compiler.d.ts.map +1 -1
- package/dist/native-compiler/compiler.js +336 -2
- package/dist/native-compiler/compiler.js.map +1 -1
- package/dist/native-compiler/data-surface.d.ts +2 -1
- package/dist/native-compiler/data-surface.d.ts.map +1 -1
- package/dist/native-compiler/data-surface.js +4 -1
- package/dist/native-compiler/data-surface.js.map +1 -1
- package/dist/native-compiler/draft-state.d.ts +3 -0
- package/dist/native-compiler/draft-state.d.ts.map +1 -0
- package/dist/native-compiler/draft-state.js +101 -0
- package/dist/native-compiler/draft-state.js.map +1 -0
- package/dist/native-compiler/index.cjs +5 -5
- package/dist/native-compiler/index.d.ts +1 -0
- package/dist/native-compiler/index.d.ts.map +1 -1
- package/dist/native-compiler/index.js +5 -5
- package/dist/native.d.ts +134 -0
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js.map +1 -1
- package/dist/schemas.d.ts +1090 -30
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +227 -0
- package/dist/schemas.js.map +1 -1
- package/dist/surface.d.ts +26 -0
- package/dist/surface.d.ts.map +1 -1
- package/dist/surface.js.map +1 -1
- package/dist/types.d.ts +9 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/validation.d.ts.map +1 -1
- package/dist/validation.js +2 -1
- package/dist/validation.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Diagnostic } from './types.js';
|
|
2
|
+
export declare function validateDataResourceDraftStates(resource: Record<string, unknown>): Diagnostic[];
|
|
2
3
|
export declare function validateDataResourceListActions(value: unknown, path: string): Diagnostic[];
|
|
3
4
|
/** Named views may select existing presentation fields, never redefine data facts. */
|
|
4
5
|
export declare function validateDataResourceViews(resource: Record<string, unknown>): Diagnostic[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-view-validation.d.ts","sourceRoot":"","sources":["../src/data-view-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"data-view-validation.d.ts","sourceRoot":"","sources":["../src/data-view-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAQ7C,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,UAAU,EAAE,CAsCd;AAED,wBAAgB,+BAA+B,CAAC,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,UAAU,EAAE,CAO1F;AAaD,sFAAsF;AACtF,wBAAgB,yBAAyB,CACvC,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAChC,UAAU,EAAE,CA+Nd"}
|
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
import { isDataSystemSortField } from './native-compiler/data-audit-access.js';
|
|
2
2
|
import { diagnostic, isRecord } from './validation-common.js';
|
|
3
|
+
import { validateNativeDataDraftStateV2, } from './native-compiler/draft-state.js';
|
|
4
|
+
export function validateDataResourceDraftStates(resource) {
|
|
5
|
+
const surface = isRecord(resource.surface) ? resource.surface : {};
|
|
6
|
+
const candidates = [];
|
|
7
|
+
if (isRecord(surface.form) && surface.form.draftState !== undefined) {
|
|
8
|
+
candidates.push({
|
|
9
|
+
value: surface.form.draftState,
|
|
10
|
+
path: 'surface.form.draftState',
|
|
11
|
+
});
|
|
12
|
+
}
|
|
13
|
+
if (Array.isArray(surface.views)) {
|
|
14
|
+
surface.views.forEach((view, index) => {
|
|
15
|
+
if (isRecord(view) &&
|
|
16
|
+
isRecord(view.form) &&
|
|
17
|
+
view.form.draftState !== undefined) {
|
|
18
|
+
candidates.push({
|
|
19
|
+
value: view.form.draftState,
|
|
20
|
+
path: `surface.views[${index}].form.draftState`,
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
return candidates.flatMap(candidate => {
|
|
26
|
+
try {
|
|
27
|
+
validateNativeDataDraftStateV2(candidate.value, candidate.path);
|
|
28
|
+
return [];
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
const contractError = error;
|
|
32
|
+
return [
|
|
33
|
+
diagnostic('DATA_RESOURCE_DRAFT_STATE_INVALID', contractError.code || '草稿状态 Schema 无效', contractError.pointer || candidate.path),
|
|
34
|
+
];
|
|
35
|
+
}
|
|
36
|
+
});
|
|
37
|
+
}
|
|
3
38
|
export function validateDataResourceListActions(value, path) {
|
|
4
39
|
if (value === undefined)
|
|
5
40
|
return [];
|
|
@@ -111,7 +146,9 @@ export function validateDataResourceViews(resource) {
|
|
|
111
146
|
'filterFields',
|
|
112
147
|
'defaultSort',
|
|
113
148
|
]
|
|
114
|
-
:
|
|
149
|
+
: kind === 'form'
|
|
150
|
+
? ['layout', 'fieldOrder', 'draftState']
|
|
151
|
+
: ['layout', 'fieldOrder'], `${path}.${kind}`);
|
|
115
152
|
selection(layout.fieldOrder, `${path}.${kind}.fieldOrder`);
|
|
116
153
|
if (kind !== 'list' &&
|
|
117
154
|
layout.layout !== undefined &&
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-view-validation.js","sourceRoot":"","sources":["../src/data-view-validation.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,wCAAwC,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"data-view-validation.js","sourceRoot":"","sources":["../src/data-view-validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ declare const COMPILER_CONTRACT_VERSION: "native-4";
|
|
|
4
4
|
export declare const NATIVE_CONTRACT_CAPACITY_V2: Readonly<{
|
|
5
5
|
readonly perspectives: 100;
|
|
6
6
|
readonly resources: 100;
|
|
7
|
+
readonly subjectReadSurfaces: 50;
|
|
7
8
|
readonly capabilities: 2000;
|
|
8
9
|
readonly operations: 500;
|
|
9
10
|
readonly eventConsumers: 100;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/native-compiler/compiler.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,KAAK,kCAAkC,IAAI,uCAAuC,EACnF,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../../src/native-compiler/compiler.ts"],"names":[],"mappings":"AAUA,OAAO,EAEL,KAAK,kCAAkC,IAAI,uCAAuC,EACnF,MAAM,aAAa,CAAC;AAyBrB,QAAA,MAAM,iBAAiB,mDAAmD,CAAC;AAC3E,QAAA,MAAM,yBAAyB,YAA2C,CAAC;AAgF3E,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;;;EAe7B,CAAC;AACZ,eAAO,MAAM,mBAAmB,6HAItB,CAAC;AACX,eAAO,MAAM,uBAAuB,u/CAkC1B,CAAC;AAGX,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;AAEtC,MAAM,WAAW,gCAAgC;IAC/C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;IAC1C,aAAa,EAAE,MAAM,GAAG,MAAM,GAAG,UAAU,CAAC;IAC5C,oBAAoB,EAAE,MAAM,CAAC;IAC7B,sBAAsB,EAAE,MAAM,CAAC;CAChC;AAED,MAAM,WAAW,6BAA6B,CAAC,CAAC,GAAG,UAAU;IAC3D,KAAK,EAAE,CAAC,CAAC;IACT,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,iCAAiC;IAChD,aAAa,EAAE,OAAO,iBAAiB,CAAC;IACxC,uBAAuB,EAAE,OAAO,yBAAyB,CAAC;IAC1D,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE;QACN,YAAY,EAAE,MAAM,CAAC;QACrB,cAAc,EAAE,MAAM,CAAC;QACvB,gBAAgB,EAAE,MAAM,CAAC;KAC1B,CAAC;IACF,WAAW,EAAE;QACX,KAAK,EAAE,6BAA6B,CAAC;QACrC,IAAI,EAAE,6BAA6B,CAAC;QACpC,MAAM,EAAE,6BAA6B,CAAC;QACtC,SAAS,EAAE,6BAA6B,CAAC;QACzC,OAAO,EAAE,6BAA6B,CAAC;QACvC,SAAS,EAAE,6BAA6B,CAAC;KAC1C,CAAC;IACF,4BAA4B,EAAE,uCAAuC,EAAE,CAAC;IACxE,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,qBAAa,gCAAiC,SAAQ,KAAK;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBAG3C,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,MAAM,EACf,WAAW,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM;CAY5C;AAED,wBAAgB,qCAAqC,CACnD,KAAK,EAAE,gCAAgC,GACtC,iCAAiC,CAkJnC;AAED;;;GAGG;AACH,wBAAgB,qCAAqC,CACnD,MAAM,EAAE,UAAU,GACjB,uCAAuC,EAAE,CA4R3C;AAED,MAAM,WAAW,wBAAwB;IACvC,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,mBAAmB,EAAE,MAAM,EAAE,CAAC;IAC9B,aAAa,EAAE,MAAM,EAAE,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAED;;;;GAIG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,EAAE;IACtD,SAAS,EAAE,UAAU,EAAE,CAAC;IACxB,YAAY,EAAE,UAAU,EAAE,CAAC;IAC3B,aAAa,EAAE,UAAU,EAAE,CAAC;IAC5B,eAAe,CAAC,EAAE,UAAU,EAAE,CAAC;CAChC,GAAG,wBAAwB,EAAE,CA4J7B"}
|
|
@@ -7,6 +7,7 @@ import { OPENXIANGDA_COMPILER_CONTRACT_VERSION as OPENXIANGDA_V2_COMPILER_CONTRA
|
|
|
7
7
|
import { canonicalJson, sha256Digest as sha256Canonical } from '../canonical.js';
|
|
8
8
|
import { NativeDataFieldContractV2Error, nativeFieldRequiresCreateInputV2, parseNativeDataFieldsV2, parseNativeDataResourceInvariantsV2, validateNativeDataResourceReferencesV2, } from './data-field.js';
|
|
9
9
|
import { validateNativeDataResourceSurfaceV2 } from './data-surface.js';
|
|
10
|
+
import { nativeFieldSupportsSortV2 } from './field-query-plan.js';
|
|
10
11
|
import { nativeScopeSourceGrantPathSupportedV2, nativeScopeSourceSubjectPathSupportedV2, resolveNativeScopeSourceFieldPathV2, } from './scope-source-field-path.js';
|
|
11
12
|
import { NativeDataPolicyExpressionV2Error, nativeDataPolicyExpressionLeavesV2, nativeDataPolicyExpressionToCnfV2, } from './data-policy-expression.js';
|
|
12
13
|
const CONFIG_SCHEMA = 'openxiangda.config-bundle/v3';
|
|
@@ -94,6 +95,7 @@ const EVENT_AUTHORIZATION_SYSTEM_FIELDS = new Set([
|
|
|
94
95
|
export const NATIVE_CONTRACT_CAPACITY_V2 = Object.freeze({
|
|
95
96
|
perspectives: 100,
|
|
96
97
|
resources: 100,
|
|
98
|
+
subjectReadSurfaces: 50,
|
|
97
99
|
capabilities: 2000,
|
|
98
100
|
operations: 500,
|
|
99
101
|
eventConsumers: 100,
|
|
@@ -196,6 +198,9 @@ export function compileNativeApplicationConfiguration(input) {
|
|
|
196
198
|
appCode,
|
|
197
199
|
resources: config.data.resources,
|
|
198
200
|
resourceContracts: expectedContract.resources,
|
|
201
|
+
...(expectedContract.subjectReadSurfaces
|
|
202
|
+
? { subjectReadSurfaces: expectedContract.subjectReadSurfaces }
|
|
203
|
+
: {}),
|
|
199
204
|
},
|
|
200
205
|
events: {
|
|
201
206
|
appCode,
|
|
@@ -309,6 +314,7 @@ export function compileRequiredPlatformCapabilitiesV3(config) {
|
|
|
309
314
|
path: operation.path,
|
|
310
315
|
capability: operation.capability,
|
|
311
316
|
platformAccess: operation.platformAccess || null,
|
|
317
|
+
...(operation.browser ? { browser: operation.browser } : {}),
|
|
312
318
|
ai: operation.ai || null,
|
|
313
319
|
})),
|
|
314
320
|
},
|
|
@@ -702,8 +708,14 @@ function validateConfigurationEnvelope(config, appCode) {
|
|
|
702
708
|
boundedArray(backend.operations, '/config/backend/operations', 500);
|
|
703
709
|
validateBackendSecrets(backend.secrets);
|
|
704
710
|
const data = object(config.data, '/config/data');
|
|
705
|
-
exactKeys(data, ['resources'], '/config/data', [
|
|
711
|
+
exactKeys(data, ['resources'], '/config/data', [
|
|
712
|
+
'resourceDetailRoutes',
|
|
713
|
+
'subjectReadSurfaces',
|
|
714
|
+
]);
|
|
706
715
|
boundedArray(data.resources, '/config/data/resources', 100);
|
|
716
|
+
if (data.subjectReadSurfaces !== undefined) {
|
|
717
|
+
boundedArray(data.subjectReadSurfaces, '/config/data/subjectReadSurfaces', NATIVE_CONTRACT_CAPACITY_V2.subjectReadSurfaces);
|
|
718
|
+
}
|
|
707
719
|
if (data.resourceDetailRoutes !== undefined) {
|
|
708
720
|
boundedArray(data.resourceDetailRoutes, '/config/data/resourceDetailRoutes', 100);
|
|
709
721
|
}
|
|
@@ -774,7 +786,12 @@ function validateContractEnvelope(contract, appCode, configDigest) {
|
|
|
774
786
|
'routeManifest',
|
|
775
787
|
'adminPages',
|
|
776
788
|
'adminNavigation',
|
|
777
|
-
], '/contracts', [
|
|
789
|
+
], '/contracts', [
|
|
790
|
+
'authentication',
|
|
791
|
+
'publicAccess',
|
|
792
|
+
'adminAccess',
|
|
793
|
+
'subjectReadSurfaces',
|
|
794
|
+
]);
|
|
778
795
|
equal(contract.schemaVersion, CONTRACT_SCHEMA, '/contracts/schemaVersion');
|
|
779
796
|
equal(contract.compilerContractVersion, COMPILER_CONTRACT_VERSION, '/contracts/compilerContractVersion');
|
|
780
797
|
requiredString(contract.generatorVersion, '/contracts/generatorVersion', 128);
|
|
@@ -782,6 +799,9 @@ function validateContractEnvelope(contract, appCode, configDigest) {
|
|
|
782
799
|
equal(contract.configDigest, configDigest, '/contracts/configDigest');
|
|
783
800
|
boundedArray(contract.perspectives, '/contracts/perspectives', NATIVE_CONTRACT_CAPACITY_V2.perspectives);
|
|
784
801
|
boundedArray(contract.resources, '/contracts/resources', NATIVE_CONTRACT_CAPACITY_V2.resources);
|
|
802
|
+
if (contract.subjectReadSurfaces !== undefined) {
|
|
803
|
+
boundedArray(contract.subjectReadSurfaces, '/contracts/subjectReadSurfaces', NATIVE_CONTRACT_CAPACITY_V2.subjectReadSurfaces);
|
|
804
|
+
}
|
|
785
805
|
boundedArray(contract.capabilities, '/contracts/capabilities', NATIVE_CONTRACT_CAPACITY_V2.capabilities);
|
|
786
806
|
boundedArray(contract.operations, '/contracts/operations', NATIVE_CONTRACT_CAPACITY_V2.operations);
|
|
787
807
|
boundedArray(contract.eventConsumers, '/contracts/eventConsumers', NATIVE_CONTRACT_CAPACITY_V2.eventConsumers);
|
|
@@ -904,6 +924,7 @@ function compileExpectedContract(config, configDigest, generatorVersion) {
|
|
|
904
924
|
]);
|
|
905
925
|
validateAdminNavigationReferences(config);
|
|
906
926
|
const adminPages = compileAdminPages(config);
|
|
927
|
+
const subjectReadSurfaces = compileSubjectReadSurfaces(config, capabilities);
|
|
907
928
|
return {
|
|
908
929
|
schemaVersion: CONTRACT_SCHEMA,
|
|
909
930
|
compilerContractVersion: COMPILER_CONTRACT_VERSION,
|
|
@@ -912,6 +933,7 @@ function compileExpectedContract(config, configDigest, generatorVersion) {
|
|
|
912
933
|
configDigest,
|
|
913
934
|
perspectives: config.perspectives,
|
|
914
935
|
resources: compileResources(config),
|
|
936
|
+
...(subjectReadSurfaces.length ? { subjectReadSurfaces } : {}),
|
|
915
937
|
capabilities: sorted(capabilities, item => item.code),
|
|
916
938
|
operations: compileOperations(config),
|
|
917
939
|
eventConsumers,
|
|
@@ -1118,6 +1140,145 @@ function compileResources(config) {
|
|
|
1118
1140
|
};
|
|
1119
1141
|
}), (item) => item.code);
|
|
1120
1142
|
}
|
|
1143
|
+
function compileSubjectReadSurfaces(config, capabilities) {
|
|
1144
|
+
if (config.data.subjectReadSurfaces === undefined)
|
|
1145
|
+
return [];
|
|
1146
|
+
const declarations = boundedArray(config.data.subjectReadSurfaces, '/config/data/subjectReadSurfaces', NATIVE_CONTRACT_CAPACITY_V2.subjectReadSurfaces);
|
|
1147
|
+
const capabilityCodes = new Set(capabilities.map(capability => String(capability.code)));
|
|
1148
|
+
const resources = new Map(config.data.resources.map((raw, index) => {
|
|
1149
|
+
const pointer = `/config/data/resources/${index}`;
|
|
1150
|
+
const resource = validateResource(raw, pointer, config.appCode);
|
|
1151
|
+
return [
|
|
1152
|
+
String(resource.code),
|
|
1153
|
+
{
|
|
1154
|
+
resource,
|
|
1155
|
+
fields: new Map(boundedArray(object(resource.schema, `${pointer}/schema`).fields, `${pointer}/schema/fields`, 500).map(field => {
|
|
1156
|
+
const declaration = object(field, `${pointer}/schema/fields`);
|
|
1157
|
+
return [String(declaration.code), declaration];
|
|
1158
|
+
})),
|
|
1159
|
+
},
|
|
1160
|
+
];
|
|
1161
|
+
}));
|
|
1162
|
+
const surfaceCodes = new Set();
|
|
1163
|
+
return sorted(declarations.map((raw, surfaceIndex) => {
|
|
1164
|
+
const pointer = `/config/data/subjectReadSurfaces/${surfaceIndex}`;
|
|
1165
|
+
const surface = object(raw, pointer);
|
|
1166
|
+
exactKeys(surface, ['code', 'name', 'capability', 'subject', 'relations'], pointer);
|
|
1167
|
+
const code = stableCode(surface.code, `${pointer}/code`);
|
|
1168
|
+
if (surfaceCodes.has(code)) {
|
|
1169
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_CODE_DUPLICATE', `${pointer}/code`);
|
|
1170
|
+
}
|
|
1171
|
+
surfaceCodes.add(code);
|
|
1172
|
+
const capability = capabilityCode(surface.capability, `${pointer}/capability`, config.appCode);
|
|
1173
|
+
if (!capabilityCodes.has(capability)) {
|
|
1174
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_CAPABILITY_NOT_DECLARED', `${pointer}/capability`);
|
|
1175
|
+
}
|
|
1176
|
+
const subject = object(surface.subject, `${pointer}/subject`);
|
|
1177
|
+
exactKeys(subject, ['resourceCode', 'fields'], `${pointer}/subject`);
|
|
1178
|
+
const subjectResourceCode = resourceCode(subject.resourceCode, `${pointer}/subject/resourceCode`);
|
|
1179
|
+
const subjectResource = resources.get(subjectResourceCode);
|
|
1180
|
+
if (!subjectResource) {
|
|
1181
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_RESOURCE_NOT_DECLARED', `${pointer}/subject/resourceCode`);
|
|
1182
|
+
}
|
|
1183
|
+
const subjectFields = uniqueStrings(subject.fields, `${pointer}/subject/fields`, 100).map((field, index) => fieldCodeValue(field, `${pointer}/subject/fields/${index}`));
|
|
1184
|
+
if (!subjectFields.length) {
|
|
1185
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_FIELDS_REQUIRED', `${pointer}/subject/fields`);
|
|
1186
|
+
}
|
|
1187
|
+
for (const [index, field] of subjectFields.entries()) {
|
|
1188
|
+
const declaration = subjectResource.fields.get(field);
|
|
1189
|
+
if (!declaration || declaration.type === 'subtable') {
|
|
1190
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_FIELD_INVALID', `${pointer}/subject/fields/${index}`);
|
|
1191
|
+
}
|
|
1192
|
+
}
|
|
1193
|
+
const rawRelations = boundedArray(surface.relations, `${pointer}/relations`, 8);
|
|
1194
|
+
if (!rawRelations.length) {
|
|
1195
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_RELATIONS_REQUIRED', `${pointer}/relations`);
|
|
1196
|
+
}
|
|
1197
|
+
const relationCodes = new Set();
|
|
1198
|
+
let rowBudget = 0;
|
|
1199
|
+
const relations = sorted(rawRelations.map((rawRelation, relationIndex) => {
|
|
1200
|
+
const relationPointer = `${pointer}/relations/${relationIndex}`;
|
|
1201
|
+
const relation = object(rawRelation, relationPointer);
|
|
1202
|
+
exactKeys(relation, [
|
|
1203
|
+
'code',
|
|
1204
|
+
'resourceCode',
|
|
1205
|
+
'foreignKeyField',
|
|
1206
|
+
'fields',
|
|
1207
|
+
'limit',
|
|
1208
|
+
], relationPointer, ['order']);
|
|
1209
|
+
const relationCode = stableCode(relation.code, `${relationPointer}/code`);
|
|
1210
|
+
if (relationCodes.has(relationCode)) {
|
|
1211
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_RELATION_CODE_DUPLICATE', `${relationPointer}/code`);
|
|
1212
|
+
}
|
|
1213
|
+
relationCodes.add(relationCode);
|
|
1214
|
+
const relationResourceCode = resourceCode(relation.resourceCode, `${relationPointer}/resourceCode`);
|
|
1215
|
+
const relationResource = resources.get(relationResourceCode);
|
|
1216
|
+
if (!relationResource) {
|
|
1217
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_RESOURCE_NOT_DECLARED', `${relationPointer}/resourceCode`);
|
|
1218
|
+
}
|
|
1219
|
+
const foreignKeyField = fieldCodeValue(relation.foreignKeyField, `${relationPointer}/foreignKeyField`);
|
|
1220
|
+
const foreignKey = relationResource.fields.get(foreignKeyField);
|
|
1221
|
+
const foreignKeySource = object(foreignKey?.source || {}, `${relationPointer}/foreignKeyField/source`);
|
|
1222
|
+
if (!foreignKey ||
|
|
1223
|
+
!['uuid', 'resource-ref.single'].includes(String(foreignKey.type)) ||
|
|
1224
|
+
(foreignKey.type === 'resource-ref.single' &&
|
|
1225
|
+
(foreignKeySource.kind !== 'resource' ||
|
|
1226
|
+
foreignKeySource.resourceCode !== subjectResourceCode))) {
|
|
1227
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_RELATION_INVALID', `${relationPointer}/foreignKeyField`);
|
|
1228
|
+
}
|
|
1229
|
+
const fields = uniqueStrings(relation.fields, `${relationPointer}/fields`, 100).map((field, index) => fieldCodeValue(field, `${relationPointer}/fields/${index}`));
|
|
1230
|
+
if (!fields.length) {
|
|
1231
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_FIELDS_REQUIRED', `${relationPointer}/fields`);
|
|
1232
|
+
}
|
|
1233
|
+
for (const [index, field] of fields.entries()) {
|
|
1234
|
+
const declaration = relationResource.fields.get(field);
|
|
1235
|
+
if (!declaration || declaration.type === 'subtable') {
|
|
1236
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_FIELD_INVALID', `${relationPointer}/fields/${index}`);
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
const order = boundedArray(relation.order || [], `${relationPointer}/order`, 10).map((rawOrder, orderIndex) => {
|
|
1240
|
+
const orderPointer = `${relationPointer}/order/${orderIndex}`;
|
|
1241
|
+
const item = object(rawOrder, orderPointer);
|
|
1242
|
+
exactKeys(item, ['field', 'direction'], orderPointer);
|
|
1243
|
+
const field = fieldCodeValue(item.field, `${orderPointer}/field`);
|
|
1244
|
+
const declaration = relationResource.fields.get(field);
|
|
1245
|
+
if ((!EVENT_AUTHORIZATION_SYSTEM_FIELDS.has(field) && !declaration) ||
|
|
1246
|
+
declaration?.type === 'subtable' ||
|
|
1247
|
+
(declaration &&
|
|
1248
|
+
!nativeFieldSupportsSortV2(declaration.type))) {
|
|
1249
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_ORDER_FIELD_INVALID', `${orderPointer}/field`);
|
|
1250
|
+
}
|
|
1251
|
+
if (!['asc', 'desc'].includes(String(item.direction))) {
|
|
1252
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_ORDER_DIRECTION_INVALID', `${orderPointer}/direction`);
|
|
1253
|
+
}
|
|
1254
|
+
return { field, direction: item.direction };
|
|
1255
|
+
});
|
|
1256
|
+
const limit = boundedInteger(relation.limit, `${relationPointer}/limit`, 1, 100);
|
|
1257
|
+
rowBudget += limit;
|
|
1258
|
+
return {
|
|
1259
|
+
code: relationCode,
|
|
1260
|
+
resourceCode: relationResourceCode,
|
|
1261
|
+
foreignKeyField,
|
|
1262
|
+
fields: uniqueSorted(fields),
|
|
1263
|
+
...(order.length ? { order } : {}),
|
|
1264
|
+
limit,
|
|
1265
|
+
};
|
|
1266
|
+
}), relation => relation.code);
|
|
1267
|
+
if (rowBudget > 400) {
|
|
1268
|
+
fail('NATIVE_SUBJECT_READ_SURFACE_ROW_LIMIT_EXCEEDED', `${pointer}/relations`);
|
|
1269
|
+
}
|
|
1270
|
+
return {
|
|
1271
|
+
code,
|
|
1272
|
+
name: requiredString(surface.name, `${pointer}/name`, 255),
|
|
1273
|
+
capability,
|
|
1274
|
+
subject: {
|
|
1275
|
+
resourceCode: subjectResourceCode,
|
|
1276
|
+
fields: uniqueSorted(subjectFields),
|
|
1277
|
+
},
|
|
1278
|
+
relations,
|
|
1279
|
+
};
|
|
1280
|
+
}), surface => surface.code);
|
|
1281
|
+
}
|
|
1121
1282
|
function compileResourceDetailRoutes(config) {
|
|
1122
1283
|
const declarations = config.data.resourceDetailRoutes === undefined
|
|
1123
1284
|
? []
|
|
@@ -1190,6 +1351,17 @@ function compileResourceDetailRoutes(config) {
|
|
|
1190
1351
|
return result;
|
|
1191
1352
|
}
|
|
1192
1353
|
function compileOperations(config) {
|
|
1354
|
+
const declaredResourceFields = new Map(config.data.resources.map((resource, resourceIndex) => {
|
|
1355
|
+
const pointer = `/config/data/resources/${resourceIndex}`;
|
|
1356
|
+
const declaration = validateResource(resource, pointer, config.appCode);
|
|
1357
|
+
return [
|
|
1358
|
+
declaration.code,
|
|
1359
|
+
new Map(declaration.schema.fields.map((field) => [
|
|
1360
|
+
String(field.code),
|
|
1361
|
+
field,
|
|
1362
|
+
])),
|
|
1363
|
+
];
|
|
1364
|
+
}));
|
|
1193
1365
|
const declaredResources = new Map(config.data.resources.map((resource, resourceIndex) => {
|
|
1194
1366
|
const pointer = `/config/data/resources/${resourceIndex}`;
|
|
1195
1367
|
const declaration = validateResource(resource, pointer, config.appCode);
|
|
@@ -1215,6 +1387,7 @@ function compileOperations(config) {
|
|
|
1215
1387
|
'responseSchema',
|
|
1216
1388
|
'description',
|
|
1217
1389
|
'platformAccess',
|
|
1390
|
+
'browser',
|
|
1218
1391
|
'ai',
|
|
1219
1392
|
], pointer, true);
|
|
1220
1393
|
const method = requiredString(operation.method, `${pointer}/method`, 16);
|
|
@@ -1224,6 +1397,7 @@ function compileOperations(config) {
|
|
|
1224
1397
|
const code = stableCode(operation.code, `${pointer}/code`);
|
|
1225
1398
|
validateBackendOperationAi(operation.ai, pointer, code, method, declaredResourceCodes);
|
|
1226
1399
|
const platformAccess = validateOperationPlatformAccess(operation.platformAccess, `${pointer}/platformAccess`, declaredResources, declaredWorkflowCodes, new Set(config.authz.roles.map((role) => String(role.code))));
|
|
1400
|
+
const browser = validateOperationBrowser(operation.browser, `${pointer}/browser`, method, operation.requestSchema, operation.responseSchema, declaredResources, declaredResourceFields, config.data.subjectReadSurfaces || []);
|
|
1227
1401
|
return {
|
|
1228
1402
|
code,
|
|
1229
1403
|
method,
|
|
@@ -1237,9 +1411,169 @@ function compileOperations(config) {
|
|
|
1237
1411
|
description: optionalString(operation.description, `${pointer}/description`, 2000),
|
|
1238
1412
|
}),
|
|
1239
1413
|
...(platformAccess ? { platformAccess } : {}),
|
|
1414
|
+
...(browser ? { browser } : {}),
|
|
1240
1415
|
};
|
|
1241
1416
|
}), (item) => item.code);
|
|
1242
1417
|
}
|
|
1418
|
+
function validateOperationBrowser(value, pointer, method, requestSchemaInput, responseSchemaInput, declaredResources, declaredResourceFields, subjectReadSurfacesInput) {
|
|
1419
|
+
if (value === undefined)
|
|
1420
|
+
return null;
|
|
1421
|
+
const browser = object(value, pointer);
|
|
1422
|
+
exactKeys(browser, ['exposure', 'behavior', 'idempotency', 'subject'], pointer, ['refreshTargets', 'fileIntent']);
|
|
1423
|
+
equal(browser.exposure, 'authenticated', `${pointer}/exposure`);
|
|
1424
|
+
const behavior = requiredString(browser.behavior, `${pointer}/behavior`, 32);
|
|
1425
|
+
if (!['read', 'controlled'].includes(behavior)) {
|
|
1426
|
+
fail('NATIVE_OPERATION_BROWSER_BEHAVIOR_INVALID', `${pointer}/behavior`);
|
|
1427
|
+
}
|
|
1428
|
+
const idempotency = requiredString(browser.idempotency, `${pointer}/idempotency`, 32);
|
|
1429
|
+
if (!['none', 'required'].includes(idempotency) ||
|
|
1430
|
+
(behavior === 'controlled' && idempotency !== 'required') ||
|
|
1431
|
+
(behavior === 'read' && idempotency !== 'none')) {
|
|
1432
|
+
fail('NATIVE_OPERATION_BROWSER_IDEMPOTENCY_INVALID', `${pointer}/idempotency`);
|
|
1433
|
+
}
|
|
1434
|
+
const subject = object(browser.subject, `${pointer}/subject`);
|
|
1435
|
+
exactKeys(subject, ['resourceCode', 'inputField'], `${pointer}/subject`);
|
|
1436
|
+
const resource = resourceCode(subject.resourceCode, `${pointer}/subject/resourceCode`);
|
|
1437
|
+
if (!declaredResources.has(resource)) {
|
|
1438
|
+
fail('NATIVE_OPERATION_BROWSER_SUBJECT_RESOURCE_NOT_DECLARED', `${pointer}/subject/resourceCode`);
|
|
1439
|
+
}
|
|
1440
|
+
const inputField = fieldCodeValue(subject.inputField, `${pointer}/subject/inputField`);
|
|
1441
|
+
const requestSchema = object(requestSchemaInput, `${pointer}/requestSchema`);
|
|
1442
|
+
const responseSchema = object(responseSchemaInput, `${pointer}/responseSchema`);
|
|
1443
|
+
if (requestSchema.type !== 'object' ||
|
|
1444
|
+
requestSchema.additionalProperties !== false ||
|
|
1445
|
+
responseSchema.type !== 'object' ||
|
|
1446
|
+
responseSchema.additionalProperties !== false) {
|
|
1447
|
+
fail('NATIVE_OPERATION_BROWSER_SCHEMA_ROOT_INVALID', `${pointer}/requestSchema`);
|
|
1448
|
+
}
|
|
1449
|
+
const requestProperties = object(requestSchema.properties, `${pointer}/requestSchema/properties`);
|
|
1450
|
+
const requiredFields = new Set(requestSchema.required === undefined
|
|
1451
|
+
? []
|
|
1452
|
+
: uniqueStrings(requestSchema.required, `${pointer}/requestSchema/required`, 200));
|
|
1453
|
+
if (!(inputField in requestProperties) || !requiredFields.has(inputField)) {
|
|
1454
|
+
fail('NATIVE_OPERATION_BROWSER_SUBJECT_INPUT_INVALID', `${pointer}/subject/inputField`);
|
|
1455
|
+
}
|
|
1456
|
+
const subjectInputSchema = object(requestProperties[inputField], `${pointer}/requestSchema/properties/${inputField}`);
|
|
1457
|
+
if (subjectInputSchema.type !== 'string' ||
|
|
1458
|
+
subjectInputSchema.format !== 'uuid') {
|
|
1459
|
+
fail('NATIVE_OPERATION_BROWSER_SUBJECT_INPUT_INVALID', `${pointer}/subject/inputField`);
|
|
1460
|
+
}
|
|
1461
|
+
const surfaces = new Map((Array.isArray(subjectReadSurfacesInput) ? subjectReadSurfacesInput : []).map((raw, index) => {
|
|
1462
|
+
const declaration = object(raw, `/config/data/subjectReadSurfaces/${index}`);
|
|
1463
|
+
return [
|
|
1464
|
+
String(declaration.code),
|
|
1465
|
+
String(object(declaration.subject, `/config/data/subjectReadSurfaces/${index}/subject`).resourceCode),
|
|
1466
|
+
];
|
|
1467
|
+
}));
|
|
1468
|
+
const refreshTargets = browser.refreshTargets === undefined
|
|
1469
|
+
? []
|
|
1470
|
+
: boundedArray(browser.refreshTargets, `${pointer}/refreshTargets`, 16);
|
|
1471
|
+
const refreshKeys = new Set();
|
|
1472
|
+
const normalizedTargets = sorted(refreshTargets.map((raw, index) => {
|
|
1473
|
+
const targetPointer = `${pointer}/refreshTargets/${index}`;
|
|
1474
|
+
const target = object(raw, targetPointer);
|
|
1475
|
+
exactKeys(target, ['kind', 'code'], targetPointer);
|
|
1476
|
+
equal(target.kind, 'subject-surface', `${targetPointer}/kind`);
|
|
1477
|
+
const code = stableCode(target.code, `${targetPointer}/code`);
|
|
1478
|
+
if (refreshKeys.has(code) ||
|
|
1479
|
+
!surfaces.has(code) ||
|
|
1480
|
+
surfaces.get(code) !== resource) {
|
|
1481
|
+
fail('NATIVE_OPERATION_BROWSER_REFRESH_TARGET_INVALID', `${targetPointer}/code`);
|
|
1482
|
+
}
|
|
1483
|
+
refreshKeys.add(code);
|
|
1484
|
+
return { kind: 'subject-surface', code };
|
|
1485
|
+
}), target => `${target.kind}:${target.code}`);
|
|
1486
|
+
const fileIntent = validateOperationFileIntent(browser.fileIntent, `${pointer}/fileIntent`, method, behavior, idempotency, resource, requestProperties, requiredFields, declaredResourceFields);
|
|
1487
|
+
return {
|
|
1488
|
+
exposure: 'authenticated',
|
|
1489
|
+
behavior,
|
|
1490
|
+
idempotency,
|
|
1491
|
+
subject: { resourceCode: resource, inputField },
|
|
1492
|
+
...(normalizedTargets.length ? { refreshTargets: normalizedTargets } : {}),
|
|
1493
|
+
...(fileIntent ? { fileIntent } : {}),
|
|
1494
|
+
};
|
|
1495
|
+
}
|
|
1496
|
+
function validateOperationFileIntent(value, pointer, method, behavior, idempotency, subjectResourceCode, requestProperties, requiredFields, declaredResources) {
|
|
1497
|
+
if (value === undefined)
|
|
1498
|
+
return null;
|
|
1499
|
+
const intent = object(value, pointer);
|
|
1500
|
+
exactKeys(intent, [
|
|
1501
|
+
'recordResourceCode',
|
|
1502
|
+
'recordIdInputField',
|
|
1503
|
+
'relationField',
|
|
1504
|
+
'fileNameField',
|
|
1505
|
+
'contentTypeField',
|
|
1506
|
+
'sizeField',
|
|
1507
|
+
'purposes',
|
|
1508
|
+
'maxTtlSeconds',
|
|
1509
|
+
'maxBytes',
|
|
1510
|
+
], pointer);
|
|
1511
|
+
if (method !== 'GET' || behavior !== 'read' || idempotency !== 'none') {
|
|
1512
|
+
fail('NATIVE_OPERATION_FILE_INTENT_BEHAVIOR_INVALID', pointer);
|
|
1513
|
+
}
|
|
1514
|
+
const recordResourceCode = resourceCode(intent.recordResourceCode, `${pointer}/recordResourceCode`);
|
|
1515
|
+
const fields = declaredResources.get(recordResourceCode);
|
|
1516
|
+
if (!fields) {
|
|
1517
|
+
fail('NATIVE_OPERATION_FILE_INTENT_RESOURCE_NOT_DECLARED', `${pointer}/recordResourceCode`);
|
|
1518
|
+
}
|
|
1519
|
+
const recordIdInputField = fieldCodeValue(intent.recordIdInputField, `${pointer}/recordIdInputField`);
|
|
1520
|
+
const recordIdSchema = object(requestProperties[recordIdInputField], `${pointer}/recordIdInputField`);
|
|
1521
|
+
if (!requiredFields.has(recordIdInputField) ||
|
|
1522
|
+
recordIdSchema.type !== 'string' ||
|
|
1523
|
+
recordIdSchema.format !== 'uuid') {
|
|
1524
|
+
fail('NATIVE_OPERATION_FILE_INTENT_RECORD_INPUT_INVALID', `${pointer}/recordIdInputField`);
|
|
1525
|
+
}
|
|
1526
|
+
const relationField = fieldCodeValue(intent.relationField, `${pointer}/relationField`);
|
|
1527
|
+
const relation = fields.get(relationField);
|
|
1528
|
+
if (!relation ||
|
|
1529
|
+
!['uuid', 'resource-ref.single'].includes(String(relation.type)) ||
|
|
1530
|
+
(String(relation.type) === 'resource-ref.single' &&
|
|
1531
|
+
(String(object(relation.source, `${pointer}/relationField`).kind || '') !==
|
|
1532
|
+
'resource' ||
|
|
1533
|
+
String(object(relation.source, `${pointer}/relationField`).resourceCode || '') !==
|
|
1534
|
+
subjectResourceCode))) {
|
|
1535
|
+
fail('NATIVE_OPERATION_FILE_INTENT_RELATION_INVALID', `${pointer}/relationField`);
|
|
1536
|
+
}
|
|
1537
|
+
const metadata = [
|
|
1538
|
+
['fileNameField', ['text.short', 'text.long']],
|
|
1539
|
+
['contentTypeField', ['text.short', 'text.long']],
|
|
1540
|
+
['sizeField', ['number.integer']],
|
|
1541
|
+
];
|
|
1542
|
+
const normalizedMetadata = {};
|
|
1543
|
+
for (const [key, allowedTypes] of metadata) {
|
|
1544
|
+
const fieldCode = fieldCodeValue(intent[key], `${pointer}/${key}`);
|
|
1545
|
+
if (!allowedTypes.includes(String(fields.get(fieldCode)?.type))) {
|
|
1546
|
+
fail('NATIVE_OPERATION_FILE_INTENT_METADATA_INVALID', `${pointer}/${key}`);
|
|
1547
|
+
}
|
|
1548
|
+
normalizedMetadata[key] = fieldCode;
|
|
1549
|
+
}
|
|
1550
|
+
const purposes = sorted(uniqueStrings(intent.purposes, `${pointer}/purposes`, 2), item => item);
|
|
1551
|
+
if (!purposes.length ||
|
|
1552
|
+
purposes.some(purpose => !['preview', 'download'].includes(purpose))) {
|
|
1553
|
+
fail('NATIVE_OPERATION_FILE_INTENT_PURPOSE_INVALID', `${pointer}/purposes`);
|
|
1554
|
+
}
|
|
1555
|
+
const maxTtlSeconds = Number(intent.maxTtlSeconds);
|
|
1556
|
+
if (!Number.isSafeInteger(maxTtlSeconds) ||
|
|
1557
|
+
maxTtlSeconds < 1 ||
|
|
1558
|
+
maxTtlSeconds > 300) {
|
|
1559
|
+
fail('NATIVE_OPERATION_FILE_INTENT_TTL_INVALID', `${pointer}/maxTtlSeconds`);
|
|
1560
|
+
}
|
|
1561
|
+
const maxBytes = Number(intent.maxBytes);
|
|
1562
|
+
if (!Number.isSafeInteger(maxBytes) || maxBytes < 1 || maxBytes > 104857600) {
|
|
1563
|
+
fail('NATIVE_OPERATION_FILE_INTENT_SIZE_INVALID', `${pointer}/maxBytes`);
|
|
1564
|
+
}
|
|
1565
|
+
return {
|
|
1566
|
+
recordResourceCode,
|
|
1567
|
+
recordIdInputField,
|
|
1568
|
+
relationField,
|
|
1569
|
+
fileNameField: normalizedMetadata.fileNameField,
|
|
1570
|
+
contentTypeField: normalizedMetadata.contentTypeField,
|
|
1571
|
+
sizeField: normalizedMetadata.sizeField,
|
|
1572
|
+
purposes,
|
|
1573
|
+
maxTtlSeconds,
|
|
1574
|
+
maxBytes,
|
|
1575
|
+
};
|
|
1576
|
+
}
|
|
1243
1577
|
function validateOperationPlatformAccess(value, pointer, declaredResources, declaredWorkflowCodes, declaredRoleCodes) {
|
|
1244
1578
|
if (value === undefined)
|
|
1245
1579
|
return null;
|