openxiangda-devkit-core 2.0.0-alpha.80 → 2.0.0-alpha.81
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/application-services.d.ts +5 -0
- package/dist/application-services.d.ts.map +1 -1
- package/dist/application-services.js +29 -36
- package/dist/application-services.js.map +1 -1
- package/dist/compiler/ai-catalog.js +1 -1
- package/dist/compiler/ai-catalog.js.map +1 -1
- package/dist/compiler/bundle.d.ts +1 -1
- package/dist/compiler/bundle.d.ts.map +1 -1
- package/dist/compiler/bundle.js +112 -2
- package/dist/compiler/bundle.js.map +1 -1
- package/dist/compiler/config.d.ts +3 -13
- package/dist/compiler/config.d.ts.map +1 -1
- package/dist/compiler/config.js +154 -26
- package/dist/compiler/config.js.map +1 -1
- package/dist/compiler/field-physical-plan.d.ts +1 -0
- package/dist/compiler/field-physical-plan.d.ts.map +1 -1
- package/dist/compiler/field-physical-plan.js +8 -1
- package/dist/compiler/field-physical-plan.js.map +1 -1
- package/dist/compiler/package-compiler.d.ts +3 -3
- package/dist/compiler/package-compiler.d.ts.map +1 -1
- package/dist/compiler/package-compiler.js +174 -31
- package/dist/compiler/package-compiler.js.map +1 -1
- package/dist/compiler/schema-composition.js +2 -2
- package/dist/compiler/schema-composition.js.map +1 -1
- package/dist/control-plane-client.d.ts +6 -28
- package/dist/control-plane-client.d.ts.map +1 -1
- package/dist/control-plane-client.js +10 -19
- package/dist/control-plane-client.js.map +1 -1
- package/dist/deployment.d.ts +4 -4
- package/dist/deployment.d.ts.map +1 -1
- package/dist/deployment.js +28 -11
- package/dist/deployment.js.map +1 -1
- package/dist/internal/workflow.d.ts.map +1 -1
- package/dist/internal/workflow.js +29 -0
- package/dist/internal/workflow.js.map +1 -1
- package/package.json +2 -2
package/dist/compiler/config.js
CHANGED
|
@@ -346,17 +346,6 @@ export const openXiangdaAppConfigSchema = {
|
|
|
346
346
|
required: ['root'],
|
|
347
347
|
properties: {
|
|
348
348
|
root: { type: 'string', minLength: 1 },
|
|
349
|
-
requiredCapabilities: {
|
|
350
|
-
type: 'array',
|
|
351
|
-
maxItems: 64,
|
|
352
|
-
uniqueItems: true,
|
|
353
|
-
items: {
|
|
354
|
-
type: 'string',
|
|
355
|
-
minLength: 1,
|
|
356
|
-
maxLength: 128,
|
|
357
|
-
pattern: '^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$',
|
|
358
|
-
},
|
|
359
|
-
},
|
|
360
349
|
},
|
|
361
350
|
},
|
|
362
351
|
perspectives: {
|
|
@@ -737,19 +726,14 @@ export function validateAppConfig(value) {
|
|
|
737
726
|
if (!string(app.name)) {
|
|
738
727
|
diagnostics.push(diagnostic('APP_CONFIG_NAME_REQUIRED', 'app.name 必须是非空字符串', 'app.name'));
|
|
739
728
|
}
|
|
740
|
-
const
|
|
741
|
-
|
|
742
|
-
(
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
requiredCapabilities.some(capability => typeof capability !== 'string' ||
|
|
746
|
-
capability.length > 128 ||
|
|
747
|
-
!/^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$/.test(capability)))) {
|
|
748
|
-
diagnostics.push(diagnostic('APP_CONFIG_PLATFORM_CAPABILITIES_INVALID', 'platform.requiredCapabilities 必须是不重复的规范平台能力代码数组(最多 64 项)', 'platform.requiredCapabilities'));
|
|
729
|
+
const platform = object(config.platform);
|
|
730
|
+
for (const key of Object.keys(platform)) {
|
|
731
|
+
if (key !== 'root') {
|
|
732
|
+
diagnostics.push(diagnostic('APP_CONFIG_PLATFORM_PROPERTY_UNSUPPORTED', `platform.${key} 不属于应用声明合同;平台能力要求只能由 compiler 派生`, `platform.${key}`));
|
|
733
|
+
}
|
|
749
734
|
}
|
|
750
735
|
const frontend = object(config.frontend);
|
|
751
736
|
const backend = object(config.backend);
|
|
752
|
-
const platform = object(config.platform);
|
|
753
737
|
const backendKeys = new Set([
|
|
754
738
|
'root',
|
|
755
739
|
'runtime',
|
|
@@ -795,10 +779,25 @@ export function validateAppConfig(value) {
|
|
|
795
779
|
validateFrontendRoutes(config, diagnostics);
|
|
796
780
|
validateAdminNavigation(config, diagnostics);
|
|
797
781
|
validatePerspectives(config.perspectives, object(config.authz).roles, diagnostics);
|
|
798
|
-
const
|
|
782
|
+
const declaredResources = new Map((Array.isArray(object(config.data).resources)
|
|
799
783
|
? object(config.data).resources
|
|
800
|
-
: []).map(resource =>
|
|
801
|
-
|
|
784
|
+
: []).map(resource => {
|
|
785
|
+
const item = object(resource);
|
|
786
|
+
const schema = object(item.schema);
|
|
787
|
+
const fields = Array.isArray(schema.fields) ? schema.fields : [];
|
|
788
|
+
return [
|
|
789
|
+
string(item.code),
|
|
790
|
+
new Map(fields.map(field => {
|
|
791
|
+
const declaration = object(field);
|
|
792
|
+
return [string(declaration.code), string(declaration.type)];
|
|
793
|
+
})),
|
|
794
|
+
];
|
|
795
|
+
}));
|
|
796
|
+
const declaredResourceCodes = new Set(declaredResources.keys());
|
|
797
|
+
const declaredWorkflowCodes = new Set((Array.isArray(object(config.workflows).activations)
|
|
798
|
+
? object(config.workflows).activations
|
|
799
|
+
: []).map(item => string(object(item).workflowCode)));
|
|
800
|
+
validateBackendOperations(backend.operations, declaredResources, declaredWorkflowCodes, diagnostics);
|
|
802
801
|
const eventConfig = object(config.events);
|
|
803
802
|
const workflowConfig = object(config.workflows);
|
|
804
803
|
if (backend.enabled === false &&
|
|
@@ -1646,7 +1645,7 @@ export function validateAppConfig(value) {
|
|
|
1646
1645
|
!Number.isInteger(delivery.maxBackoffMs) ||
|
|
1647
1646
|
Number(delivery.maxBackoffMs) < Number(delivery.initialBackoffMs) ||
|
|
1648
1647
|
Number(delivery.maxBackoffMs) > 1_800_000 ||
|
|
1649
|
-
!['none', 'record'].includes(string(delivery.ordering)) ||
|
|
1648
|
+
!['none', 'record', 'workflow-instance'].includes(string(delivery.ordering)) ||
|
|
1650
1649
|
!Number.isInteger(delivery.concurrency) ||
|
|
1651
1650
|
Number(delivery.concurrency) < 1 ||
|
|
1652
1651
|
Number(delivery.concurrency) > 50) {
|
|
@@ -1881,6 +1880,20 @@ export function validateAppConfig(value) {
|
|
|
1881
1880
|
string(object(declaration.definition).code)) {
|
|
1882
1881
|
diagnostics.push(diagnostic('APP_CONFIG_WORKFLOW_USER_TITLE_REQUIRED', 'Workflow title 必须是用户可读本地化名称,不能等于内部 code', `${path}.definition.title`));
|
|
1883
1882
|
}
|
|
1883
|
+
const subject = object(definition.subject);
|
|
1884
|
+
const factProjection = object(subject.factProjection);
|
|
1885
|
+
const factEntries = Object.entries(factProjection);
|
|
1886
|
+
const subjectFields = eventResourceFields.get(string(subject.resourceCode));
|
|
1887
|
+
if (Object.keys(subject).some(key => !['resourceCode', 'factProjection'].includes(key)) ||
|
|
1888
|
+
!subjectFields ||
|
|
1889
|
+
!isRecord(subject.factProjection) ||
|
|
1890
|
+
factEntries.length < 1 ||
|
|
1891
|
+
factEntries.length > 64 ||
|
|
1892
|
+
factEntries.some(([factKey, fieldCode]) => !/^[A-Za-z][A-Za-z0-9_.]{0,127}$/.test(factKey) ||
|
|
1893
|
+
!/^[A-Za-z][A-Za-z0-9_]{0,62}$/.test(string(fieldCode)) ||
|
|
1894
|
+
!subjectFields.has(string(fieldCode)))) {
|
|
1895
|
+
diagnostics.push(diagnostic('APP_CONFIG_WORKFLOW_SUBJECT_INVALID', 'Workflow subject 必须绑定已声明资源,并将 1 到 64 个 fact key 映射到该资源的已声明字段', `${path}.definition.subject`));
|
|
1896
|
+
}
|
|
1884
1897
|
for (const error of validateWorkflowDefinition(definition)) {
|
|
1885
1898
|
diagnostics.push(diagnostic('APP_CONFIG_WORKFLOW_DEFINITION_INVALID', error, path));
|
|
1886
1899
|
}
|
|
@@ -1904,10 +1917,23 @@ export function validateAppConfig(value) {
|
|
|
1904
1917
|
}
|
|
1905
1918
|
bindingByKey.set(key, binding);
|
|
1906
1919
|
});
|
|
1920
|
+
const activationWorkflowCodes = new Set();
|
|
1907
1921
|
activations.forEach((item, index) => {
|
|
1908
1922
|
const activation = object(item);
|
|
1909
1923
|
const path = `workflows.activations[${index}]`;
|
|
1924
|
+
if (Object.keys(activation).some(key => ![
|
|
1925
|
+
'workflowCode',
|
|
1926
|
+
'definitionVersion',
|
|
1927
|
+
'bindingVersion',
|
|
1928
|
+
'acceptedCommandDeactivationPolicy',
|
|
1929
|
+
].includes(key))) {
|
|
1930
|
+
diagnostics.push(diagnostic('APP_CONFIG_WORKFLOW_ACTIVATION_INVALID', 'Workflow activation 只能声明固定版本与停用策略', path));
|
|
1931
|
+
}
|
|
1910
1932
|
const workflowCode = string(activation.workflowCode);
|
|
1933
|
+
if (activationWorkflowCodes.has(workflowCode)) {
|
|
1934
|
+
diagnostics.push(diagnostic('APP_CONFIG_WORKFLOW_ACTIVATION_DUPLICATE', `Workflow activation 重复: ${workflowCode}`, path));
|
|
1935
|
+
}
|
|
1936
|
+
activationWorkflowCodes.add(workflowCode);
|
|
1911
1937
|
if ('environmentKey' in activation) {
|
|
1912
1938
|
diagnostics.push(diagnostic('APP_CONFIG_ENVIRONMENT_OVERRIDE_FORBIDDEN', 'Workflow activation 属于环境中立 AppVersion,不能声明 environmentKey', `${path}.environmentKey`));
|
|
1913
1939
|
}
|
|
@@ -1919,6 +1945,10 @@ export function validateAppConfig(value) {
|
|
|
1919
1945
|
diagnostics.push(diagnostic('APP_CONFIG_WORKFLOW_ACTIVATION_VERSION_NOT_FOUND', 'Workflow activation 引用的 definition 或 binding 版本不存在', path));
|
|
1920
1946
|
return;
|
|
1921
1947
|
}
|
|
1948
|
+
if (activation.acceptedCommandDeactivationPolicy !==
|
|
1949
|
+
definition.acceptedCommandDeactivationPolicy) {
|
|
1950
|
+
diagnostics.push(diagnostic('APP_CONFIG_WORKFLOW_ACTIVATION_DEACTIVATION_POLICY_MISMATCH', 'Workflow activation 停用策略必须等于所选 definition', `${path}.acceptedCommandDeactivationPolicy`));
|
|
1951
|
+
}
|
|
1922
1952
|
for (const error of validateWorkflowBinding(definition, binding)) {
|
|
1923
1953
|
diagnostics.push(diagnostic('APP_CONFIG_WORKFLOW_BINDING_INVALID', error, path));
|
|
1924
1954
|
}
|
|
@@ -2047,7 +2077,8 @@ function validateCapabilityDeclarations(appCode, declarations, diagnostics) {
|
|
|
2047
2077
|
seen.add(code);
|
|
2048
2078
|
});
|
|
2049
2079
|
}
|
|
2050
|
-
function validateBackendOperations(rawOperations,
|
|
2080
|
+
function validateBackendOperations(rawOperations, declaredResources, declaredWorkflowCodes, diagnostics) {
|
|
2081
|
+
const declaredResourceCodes = new Set(declaredResources.keys());
|
|
2051
2082
|
if (rawOperations !== undefined && !Array.isArray(rawOperations)) {
|
|
2052
2083
|
diagnostics.push(diagnostic('APP_CONFIG_BACKEND_OPERATIONS_INVALID', 'backend.operations 必须是数组', 'backend.operations'));
|
|
2053
2084
|
return;
|
|
@@ -2075,6 +2106,87 @@ function validateBackendOperations(rawOperations, declaredResourceCodes, diagnos
|
|
|
2075
2106
|
if ('resources' in operation) {
|
|
2076
2107
|
diagnostics.push(diagnostic('APP_CONFIG_BACKEND_OPERATION_RESOURCES_REMOVED', '资源范围只能在显式 backend.operations[].ai 中声明', `${path}.resources`));
|
|
2077
2108
|
}
|
|
2109
|
+
if (operation.platformAccess !== undefined) {
|
|
2110
|
+
const access = object(operation.platformAccess);
|
|
2111
|
+
const allowedAccessKeys = new Set([
|
|
2112
|
+
'directory',
|
|
2113
|
+
'managedFiles',
|
|
2114
|
+
'notification',
|
|
2115
|
+
'workflow',
|
|
2116
|
+
]);
|
|
2117
|
+
let invalid = !isRecord(operation.platformAccess) ||
|
|
2118
|
+
Object.keys(access).length === 0 ||
|
|
2119
|
+
Object.keys(access).some(key => !allowedAccessKeys.has(key));
|
|
2120
|
+
if (access.directory !== undefined) {
|
|
2121
|
+
const directory = object(access.directory);
|
|
2122
|
+
const fields = Array.isArray(directory.fields) ? directory.fields : [];
|
|
2123
|
+
const allowedFields = new Set([
|
|
2124
|
+
'displayName',
|
|
2125
|
+
'employeeNumber',
|
|
2126
|
+
'primaryDepartment',
|
|
2127
|
+
'departments',
|
|
2128
|
+
]);
|
|
2129
|
+
invalid ||=
|
|
2130
|
+
directory.mode !== 'current-initiator' ||
|
|
2131
|
+
fields.length === 0 ||
|
|
2132
|
+
fields.length > allowedFields.size ||
|
|
2133
|
+
new Set(fields).size !== fields.length ||
|
|
2134
|
+
fields.some(field => !allowedFields.has(string(field))) ||
|
|
2135
|
+
Object.keys(directory).some(key => !['mode', 'fields'].includes(key));
|
|
2136
|
+
}
|
|
2137
|
+
if (access.managedFiles !== undefined) {
|
|
2138
|
+
const managedFiles = Array.isArray(access.managedFiles)
|
|
2139
|
+
? access.managedFiles
|
|
2140
|
+
: [];
|
|
2141
|
+
invalid ||= managedFiles.length === 0 || managedFiles.length > 16;
|
|
2142
|
+
const resources = new Set();
|
|
2143
|
+
for (const rawManagedFile of managedFiles) {
|
|
2144
|
+
const managedFile = object(rawManagedFile);
|
|
2145
|
+
const resourceCode = string(managedFile.resourceCode);
|
|
2146
|
+
const fieldCodes = Array.isArray(managedFile.fieldCodes)
|
|
2147
|
+
? managedFile.fieldCodes.map(string)
|
|
2148
|
+
: [];
|
|
2149
|
+
const intents = Array.isArray(managedFile.intents)
|
|
2150
|
+
? managedFile.intents.map(string)
|
|
2151
|
+
: [];
|
|
2152
|
+
const resourceFields = declaredResources.get(resourceCode);
|
|
2153
|
+
invalid ||=
|
|
2154
|
+
!resourceFields ||
|
|
2155
|
+
resources.has(resourceCode) ||
|
|
2156
|
+
fieldCodes.length === 0 ||
|
|
2157
|
+
fieldCodes.length > 16 ||
|
|
2158
|
+
new Set(fieldCodes).size !== fieldCodes.length ||
|
|
2159
|
+
fieldCodes.some(fieldCode => !['file', 'image', 'signature'].includes(string(resourceFields?.get(fieldCode)))) ||
|
|
2160
|
+
intents.length === 0 ||
|
|
2161
|
+
intents.length > 2 ||
|
|
2162
|
+
new Set(intents).size !== intents.length ||
|
|
2163
|
+
intents.some(intent => !['create', 'update'].includes(intent)) ||
|
|
2164
|
+
Object.keys(managedFile).some(key => !['resourceCode', 'fieldCodes', 'intents'].includes(key));
|
|
2165
|
+
resources.add(resourceCode);
|
|
2166
|
+
}
|
|
2167
|
+
}
|
|
2168
|
+
if (access.notification !== undefined) {
|
|
2169
|
+
const notification = object(access.notification);
|
|
2170
|
+
invalid ||=
|
|
2171
|
+
notification.mode !== 'business-standard' ||
|
|
2172
|
+
Object.keys(notification).some(key => key !== 'mode');
|
|
2173
|
+
}
|
|
2174
|
+
if (access.workflow !== undefined) {
|
|
2175
|
+
const workflow = object(access.workflow);
|
|
2176
|
+
const workflowCodes = Array.isArray(workflow.codes)
|
|
2177
|
+
? workflow.codes.map(string)
|
|
2178
|
+
: [];
|
|
2179
|
+
invalid ||=
|
|
2180
|
+
workflowCodes.length === 0 ||
|
|
2181
|
+
workflowCodes.length > 16 ||
|
|
2182
|
+
new Set(workflowCodes).size !== workflowCodes.length ||
|
|
2183
|
+
workflowCodes.some(code => !declaredWorkflowCodes.has(code)) ||
|
|
2184
|
+
Object.keys(workflow).some(key => key !== 'codes');
|
|
2185
|
+
}
|
|
2186
|
+
if (invalid) {
|
|
2187
|
+
diagnostics.push(diagnostic('APP_CONFIG_BACKEND_OPERATION_PLATFORM_ACCESS_INVALID', 'operation.platformAccess 必须只声明有界的发起人目录、托管文件、标准通知或现有工作流依赖', `${path}.platformAccess`));
|
|
2188
|
+
}
|
|
2189
|
+
}
|
|
2078
2190
|
if (operation.ai !== undefined) {
|
|
2079
2191
|
const ai = object(operation.ai);
|
|
2080
2192
|
const aiResources = Array.isArray(ai.resources) ? ai.resources : [];
|
|
@@ -2824,6 +2936,9 @@ export function materializeDataResource(appCode, declaration) {
|
|
|
2824
2936
|
...(field.scale !== undefined ? { scale: field.scale } : {}),
|
|
2825
2937
|
...(field.min !== undefined ? { min: field.min } : {}),
|
|
2826
2938
|
...(field.max !== undefined ? { max: field.max } : {}),
|
|
2939
|
+
...(field.rangeBoundary
|
|
2940
|
+
? { rangeBoundary: field.rangeBoundary }
|
|
2941
|
+
: {}),
|
|
2827
2942
|
...(field.timePrecision ? { timePrecision: field.timePrecision } : {}),
|
|
2828
2943
|
...(field.file ? { file: field.file } : {}),
|
|
2829
2944
|
...(field.serial ? { serial: field.serial } : {}),
|
|
@@ -2876,6 +2991,9 @@ export function materializeDataResource(appCode, declaration) {
|
|
|
2876
2991
|
...(field.scale !== undefined ? { scale: field.scale } : {}),
|
|
2877
2992
|
...(field.min !== undefined ? { min: field.min } : {}),
|
|
2878
2993
|
...(field.max !== undefined ? { max: field.max } : {}),
|
|
2994
|
+
...(field.rangeBoundary
|
|
2995
|
+
? { rangeBoundary: field.rangeBoundary }
|
|
2996
|
+
: {}),
|
|
2879
2997
|
...(field.file?.maxCount !== undefined
|
|
2880
2998
|
? { maxCount: field.file.maxCount }
|
|
2881
2999
|
: {}),
|
|
@@ -2972,6 +3090,7 @@ export function validateAppDeclaration(value) {
|
|
|
2972
3090
|
'scale',
|
|
2973
3091
|
'min',
|
|
2974
3092
|
'max',
|
|
3093
|
+
'rangeBoundary',
|
|
2975
3094
|
'timePrecision',
|
|
2976
3095
|
'file',
|
|
2977
3096
|
'serial',
|
|
@@ -3049,6 +3168,15 @@ export function validateAppDeclaration(value) {
|
|
|
3049
3168
|
if (field.sortable === true && !supportsSort(semanticType)) {
|
|
3050
3169
|
diagnostics.push(diagnostic('APP_CONFIG_DATA_FIELD_SORT_UNSUPPORTED', `${semanticType} 不支持稳定排序`, `${fieldPath}.sortable`));
|
|
3051
3170
|
}
|
|
3171
|
+
const rangeType = semanticType === 'date-range' || semanticType === 'datetime-range';
|
|
3172
|
+
if (rangeType &&
|
|
3173
|
+
!['closed', 'half-open'].includes(string(field.rangeBoundary))) {
|
|
3174
|
+
materializable = false;
|
|
3175
|
+
diagnostics.push(diagnostic('APP_CONFIG_DATA_FIELD_RANGE_BOUNDARY_REQUIRED', `${semanticType} 必须显式声明 rangeBoundary: closed 或 half-open`, `${fieldPath}.rangeBoundary`));
|
|
3176
|
+
}
|
|
3177
|
+
else if (!rangeType && field.rangeBoundary !== undefined) {
|
|
3178
|
+
diagnostics.push(diagnostic('APP_CONFIG_DATA_FIELD_RANGE_BOUNDARY_TYPE_INVALID', 'rangeBoundary 只能用于 date-range 或 datetime-range', `${fieldPath}.rangeBoundary`));
|
|
3179
|
+
}
|
|
3052
3180
|
if (field.indexed === false &&
|
|
3053
3181
|
(field.filter === true ||
|
|
3054
3182
|
field.searchable === true ||
|