openxiangda-devkit-core 2.4.2 → 2.5.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.
@@ -1,6 +1,6 @@
1
1
  import { materializeApplicationModules } from './application-model.js';
2
2
  import { nativeFieldRequiresCreateInputV2 } from 'openxiangda-contracts/native-compiler';
3
- import { SCHEMA_VERSIONS, DATA_FIELD_TYPES, PLATFORM_EVENT_TYPES_V2, nativePlatformCapabilityCatalog, validateDataResource, validateWorkflowInstanceCommandPolicies, WORKFLOW_SUMMARY_MAX_FIELDS, WORKFLOW_SUMMARY_TEXT_LONG_MAX_BYTES, isWorkflowSummaryFieldType, } from 'openxiangda-contracts';
3
+ import { SCHEMA_VERSIONS, DATA_AUDIT_METADATA_FIELDS, isDataAuditMetadataField, DATA_FIELD_TYPES, PLATFORM_EVENT_TYPES_V2, nativePlatformCapabilityCatalog, validateDataResource, validateWorkflowInstanceCommandPolicies, WORKFLOW_SUMMARY_MAX_FIELDS, WORKFLOW_SUMMARY_TEXT_LONG_MAX_BYTES, isWorkflowSummaryFieldType, } from 'openxiangda-contracts';
4
4
  import { Ajv2020 } from 'ajv/dist/2020.js';
5
5
  import { CronExpressionParser } from 'cron-parser';
6
6
  import { fieldNullable, supportsGeneratedMutation, } from './field-codec.js';
@@ -3427,12 +3427,13 @@ function validateCapabilityClosure(appCode, config, declarations, diagnostics) {
3427
3427
  catalog.add(string(object(raw).code));
3428
3428
  const data = object(config.data);
3429
3429
  const catalogOwners = new Map();
3430
+ const references = [];
3430
3431
  for (const raw of declarations) {
3431
3432
  const code = string(object(raw).code);
3432
3433
  if (code)
3433
3434
  catalogOwners.set(code, 'authz.capabilities');
3434
3435
  }
3435
- for (const rawResource of Array.isArray(data.resources) ? data.resources : []) {
3436
+ for (const [resourceIndex, rawResource] of (Array.isArray(data.resources) ? data.resources : []).entries()) {
3436
3437
  const resource = object(rawResource);
3437
3438
  const resourceOwner = `data.resources.${string(resource.code)}`;
3438
3439
  Object.values(object(resource.capabilities)).forEach(value => {
@@ -3440,18 +3441,24 @@ function validateCapabilityClosure(appCode, config, declarations, diagnostics) {
3440
3441
  registerCapabilityOwner(code, resourceOwner, catalogOwners, diagnostics);
3441
3442
  catalog.add(code);
3442
3443
  });
3443
- Object.values(object(resource.fieldPolicies)).forEach(rawPolicy => {
3444
+ Object.entries(object(resource.fieldPolicies)).forEach(([fieldCode, rawPolicy]) => {
3444
3445
  const policy = object(rawPolicy);
3445
3446
  for (const key of ['read', 'create', 'update']) {
3446
3447
  for (const value of Array.isArray(policy[key]) ? policy[key] : []) {
3447
3448
  const code = string(value);
3449
+ if (isDataAuditMetadataField(fieldCode)) {
3450
+ references.push({
3451
+ capability: code,
3452
+ path: `data.resources[${resourceIndex}].fieldPolicies.${fieldCode}.${key}`,
3453
+ });
3454
+ continue;
3455
+ }
3448
3456
  registerCapabilityOwner(code, resourceOwner, catalogOwners, diagnostics);
3449
3457
  catalog.add(code);
3450
3458
  }
3451
3459
  }
3452
3460
  });
3453
3461
  }
3454
- const references = [];
3455
3462
  const authz = object(config.authz);
3456
3463
  (Array.isArray(authz.roles) ? authz.roles : []).forEach((rawRole, index) => {
3457
3464
  const role = object(rawRole);
@@ -3765,15 +3772,20 @@ export function materializeDataResource(appCode, declaration) {
3765
3772
  ...(declaration.detailRouteCode
3766
3773
  ? { detailRouteCode: { ...declaration.detailRouteCode } }
3767
3774
  : {}),
3768
- fieldPolicies: Object.fromEntries(declaration.fields.map(field => [
3769
- field.code,
3770
- {
3771
- read: access(field, 'read'),
3772
- create: access(field, 'create'),
3773
- update: access(field, 'update'),
3774
- ...(field.access?.mask ? { mask: field.access.mask } : {}),
3775
- },
3776
- ])),
3775
+ fieldPolicies: {
3776
+ ...Object.fromEntries(declaration.fields.map(field => [
3777
+ field.code,
3778
+ {
3779
+ read: access(field, 'read'),
3780
+ create: access(field, 'create'),
3781
+ update: access(field, 'update'),
3782
+ ...(field.access?.mask ? { mask: field.access.mask } : {}),
3783
+ },
3784
+ ])),
3785
+ ...(declaration.audit === undefined ? {} : Object.fromEntries(DATA_AUDIT_METADATA_FIELDS.map(code => [code, {
3786
+ read: declaration.audit.read === false ? [] : [...declaration.audit.read],
3787
+ }]))),
3788
+ },
3777
3789
  };
3778
3790
  }
3779
3791
  export function validateAppDeclaration(value) {
@@ -3796,6 +3808,7 @@ export function validateAppDeclaration(value) {
3796
3808
  'mobile',
3797
3809
  'dataPolicyCode',
3798
3810
  'detailRouteCode',
3811
+ 'audit',
3799
3812
  ]);
3800
3813
  const fieldKeys = new Set([
3801
3814
  'code',
@@ -3834,6 +3847,18 @@ export function validateAppDeclaration(value) {
3834
3847
  }
3835
3848
  }
3836
3849
  const fields = Array.isArray(resource.fields) ? resource.fields : [];
3850
+ let auditValid = true;
3851
+ if (resource.audit !== undefined) {
3852
+ const audit = object(resource.audit);
3853
+ const read = audit.read;
3854
+ if (!resource.audit || typeof resource.audit !== 'object' || Array.isArray(resource.audit) ||
3855
+ Object.keys(audit).some(key => key !== 'read') ||
3856
+ (read !== false && (!Array.isArray(read) || read.length < 1 || read.length > 20 ||
3857
+ read.some(value => typeof value !== 'string' || !value.trim()) || new Set(read).size !== read.length))) {
3858
+ auditValid = false;
3859
+ diagnostics.push(diagnostic('APP_CONFIG_DATA_AUDIT_READ_INVALID', 'audit.read 必须为 false 或不重复的非空 capability 数组(最多 20 项)', `${resourcePath}.audit`));
3860
+ }
3861
+ }
3837
3862
  const mutationOwner = string(resource.mutationOwner) || 'native';
3838
3863
  const generated = object(resource.generated);
3839
3864
  if (!['native', 'action', 'readonly', 'workflow'].includes(mutationOwner)) {
@@ -3859,7 +3884,7 @@ export function validateAppDeclaration(value) {
3859
3884
  return;
3860
3885
  }
3861
3886
  const declaredCodes = new Set();
3862
- let materializable = true;
3887
+ let materializable = auditValid;
3863
3888
  fields.forEach((rawField, fieldIndex) => {
3864
3889
  const field = object(rawField);
3865
3890
  const fieldPath = `${resourcePath}.fields[${fieldIndex}]`;