openxiangda-devkit-core 2.0.0-alpha.92 → 2.0.0-alpha.94

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.
@@ -438,6 +438,11 @@ export const openXiangdaAppConfigSchema = {
438
438
  additionalProperties: false,
439
439
  required: ['capabilities', 'roles'],
440
440
  properties: {
441
+ authenticatedUserRoleCode: {
442
+ type: 'string',
443
+ pattern: '^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$',
444
+ maxLength: 128,
445
+ },
441
446
  capabilities: {
442
447
  type: 'array',
443
448
  maxItems: 2000,
@@ -1037,6 +1042,14 @@ export function validateAppConfig(value) {
1037
1042
  seenCapabilities.add(capability);
1038
1043
  });
1039
1044
  });
1045
+ const authenticatedUserRoleCode = authz.authenticatedUserRoleCode === undefined
1046
+ ? ''
1047
+ : string(authz.authenticatedUserRoleCode);
1048
+ if (authz.authenticatedUserRoleCode !== undefined &&
1049
+ (!/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/.test(authenticatedUserRoleCode) ||
1050
+ !roleCodes.has(authenticatedUserRoleCode))) {
1051
+ diagnostics.push(diagnostic('APP_CONFIG_AUTHENTICATED_USER_ROLE_INVALID', 'authenticatedUserRoleCode 必须引用一个已声明的 package role', 'authz.authenticatedUserRoleCode'));
1052
+ }
1040
1053
  const dimensions = Array.isArray(authz.scopeDimensions)
1041
1054
  ? authz.scopeDimensions
1042
1055
  : [];
@@ -1260,6 +1273,10 @@ export function validateAppConfig(value) {
1260
1273
  !projectionControlFieldsValid(source, fields)) {
1261
1274
  diagnostics.push(diagnostic('APP_CONFIG_AUTHZ_ROLE_MEMBERSHIP_SOURCE_INVALID', 'role membership source 必须声明唯一来源、user.single.value、已声明 package role 与严格控制字段', sourcePath));
1262
1275
  }
1276
+ if (authenticatedUserRoleCode &&
1277
+ string(source.roleCode) === authenticatedUserRoleCode) {
1278
+ diagnostics.push(diagnostic('APP_CONFIG_AUTHENTICATED_USER_ROLE_SOURCE_CONFLICT', '登录用户默认角色不能同时由 roleMembershipSource 管理', `${sourcePath}.roleCode`));
1279
+ }
1263
1280
  projectionSourceCodes.add(code);
1264
1281
  });
1265
1282
  relationshipGrantSources.forEach((raw, index) => {
@@ -1708,11 +1725,57 @@ export function validateAppConfig(value) {
1708
1725
  if (subscription.platformAccess !== undefined) {
1709
1726
  const access = object(subscription.platformAccess);
1710
1727
  const notification = object(access.notification);
1711
- if (Object.keys(access).some(key => key !== 'notification') ||
1712
- access.notification === undefined ||
1713
- notification.mode !== 'business-standard' ||
1714
- Object.keys(notification).some(key => key !== 'mode')) {
1715
- diagnostics.push(diagnostic('APP_CONFIG_EVENT_PLATFORM_ACCESS_INVALID', '事件订阅 platformAccess 只能显式声明标准业务通知依赖', `${path}.platformAccess`));
1728
+ const copies = Array.isArray(access.managedFileCopies)
1729
+ ? access.managedFileCopies
1730
+ : [];
1731
+ let copiesInvalid = access.managedFileCopies !== undefined &&
1732
+ (copies.length === 0 || copies.length > 16);
1733
+ const copyKeys = new Set();
1734
+ for (const rawCopy of copies) {
1735
+ const copy = object(rawCopy);
1736
+ const sourceResourceCode = string(copy.sourceResourceCode);
1737
+ const targetResourceCode = string(copy.targetResourceCode);
1738
+ const sourceFields = Array.isArray(copy.sourceFieldCodes)
1739
+ ? copy.sourceFieldCodes.map(string)
1740
+ : [];
1741
+ const targetFields = Array.isArray(copy.targetFieldCodes)
1742
+ ? copy.targetFieldCodes.map(string)
1743
+ : [];
1744
+ const source = eventResourceFields.get(sourceResourceCode);
1745
+ const target = eventResourceFields.get(targetResourceCode);
1746
+ copiesInvalid ||=
1747
+ copy.mode !== 'copy' ||
1748
+ !source ||
1749
+ !target ||
1750
+ sourceFields.length === 0 ||
1751
+ targetFields.length === 0 ||
1752
+ sourceFields.length > 16 ||
1753
+ targetFields.length > 16 ||
1754
+ new Set(sourceFields).size !== sourceFields.length ||
1755
+ new Set(targetFields).size !== targetFields.length ||
1756
+ sourceFields.some(field => !['file', 'image'].includes(source?.get(field) || '')) ||
1757
+ targetFields.some(field => !['file', 'image'].includes(target?.get(field) || '')) ||
1758
+ sourceFields.length !== targetFields.length ||
1759
+ sourceFields.some((field, i) => source?.get(field) !== target?.get(targetFields[i] || '')) ||
1760
+ Object.keys(copy).some(key => ![
1761
+ 'mode',
1762
+ 'sourceResourceCode',
1763
+ 'sourceFieldCodes',
1764
+ 'targetResourceCode',
1765
+ 'targetFieldCodes',
1766
+ ].includes(key));
1767
+ const key = `${sourceResourceCode}:${sourceFields.join(',')}=>${targetResourceCode}:${targetFields.join(',')}`;
1768
+ if (copyKeys.has(key))
1769
+ copiesInvalid = true;
1770
+ copyKeys.add(key);
1771
+ }
1772
+ if (Object.keys(access).some(key => !['notification', 'managedFileCopies'].includes(key)) ||
1773
+ (access.notification !== undefined &&
1774
+ (notification.mode !== 'business-standard' ||
1775
+ Object.keys(notification).some(key => key !== 'mode'))) ||
1776
+ (access.notification === undefined && access.managedFileCopies === undefined) ||
1777
+ copiesInvalid) {
1778
+ diagnostics.push(diagnostic('APP_CONFIG_EVENT_PLATFORM_ACCESS_INVALID', '事件订阅 platformAccess 只能显式声明标准业务通知或有界托管文件复制依赖', `${path}.platformAccess`));
1716
1779
  }
1717
1780
  }
1718
1781
  const delivery = {
@@ -2226,6 +2289,7 @@ function validateBackendOperations(rawOperations, declaredResources, declaredWor
2226
2289
  const allowedAccessKeys = new Set([
2227
2290
  'directory',
2228
2291
  'managedFiles',
2292
+ 'managedFileCopies',
2229
2293
  'notification',
2230
2294
  'workflow',
2231
2295
  ]);
@@ -2280,6 +2344,51 @@ function validateBackendOperations(rawOperations, declaredResources, declaredWor
2280
2344
  resources.add(resourceCode);
2281
2345
  }
2282
2346
  }
2347
+ if (access.managedFileCopies !== undefined) {
2348
+ const copies = Array.isArray(access.managedFileCopies)
2349
+ ? access.managedFileCopies
2350
+ : [];
2351
+ invalid ||= copies.length === 0 || copies.length > 16;
2352
+ const copyKeys = new Set();
2353
+ for (const rawCopy of copies) {
2354
+ const copy = object(rawCopy);
2355
+ const sourceResourceCode = string(copy.sourceResourceCode);
2356
+ const targetResourceCode = string(copy.targetResourceCode);
2357
+ const sourceFields = Array.isArray(copy.sourceFieldCodes)
2358
+ ? copy.sourceFieldCodes.map(string)
2359
+ : [];
2360
+ const targetFields = Array.isArray(copy.targetFieldCodes)
2361
+ ? copy.targetFieldCodes.map(string)
2362
+ : [];
2363
+ const source = declaredResources.get(sourceResourceCode);
2364
+ const target = declaredResources.get(targetResourceCode);
2365
+ invalid ||=
2366
+ copy.mode !== 'copy' ||
2367
+ !source ||
2368
+ !target ||
2369
+ sourceFields.length === 0 ||
2370
+ targetFields.length === 0 ||
2371
+ sourceFields.length > 16 ||
2372
+ targetFields.length > 16 ||
2373
+ new Set(sourceFields).size !== sourceFields.length ||
2374
+ new Set(targetFields).size !== targetFields.length ||
2375
+ sourceFields.some(field => !['file', 'image'].includes(source?.get(field) || '')) ||
2376
+ targetFields.some(field => !['file', 'image'].includes(target?.get(field) || '')) ||
2377
+ sourceFields.length !== targetFields.length ||
2378
+ sourceFields.some((field, i) => source?.get(field) !== target?.get(targetFields[i] || '')) ||
2379
+ Object.keys(copy).some(key => ![
2380
+ 'mode',
2381
+ 'sourceResourceCode',
2382
+ 'sourceFieldCodes',
2383
+ 'targetResourceCode',
2384
+ 'targetFieldCodes',
2385
+ ].includes(key));
2386
+ const key = `${sourceResourceCode}:${sourceFields.join(',')}=>${targetResourceCode}:${targetFields.join(',')}`;
2387
+ if (copyKeys.has(key))
2388
+ invalid = true;
2389
+ copyKeys.add(key);
2390
+ }
2391
+ }
2283
2392
  if (access.notification !== undefined) {
2284
2393
  const notification = object(access.notification);
2285
2394
  invalid ||=
@@ -2299,7 +2408,7 @@ function validateBackendOperations(rawOperations, declaredResources, declaredWor
2299
2408
  Object.keys(workflow).some(key => key !== 'codes');
2300
2409
  }
2301
2410
  if (invalid) {
2302
- diagnostics.push(diagnostic('APP_CONFIG_BACKEND_OPERATION_PLATFORM_ACCESS_INVALID', 'operation.platformAccess 必须只声明有界的发起人目录、托管文件、标准通知或现有工作流依赖', `${path}.platformAccess`));
2411
+ diagnostics.push(diagnostic('APP_CONFIG_BACKEND_OPERATION_PLATFORM_ACCESS_INVALID', 'operation.platformAccess 必须只声明有界的发起人目录、托管文件、托管文件复制、标准通知或现有工作流依赖', `${path}.platformAccess`));
2303
2412
  }
2304
2413
  }
2305
2414
  if (operation.ai !== undefined) {