openxiangda-devkit-core 2.9.0 → 2.10.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.
@@ -2393,6 +2393,7 @@ function validatePerspectives(rawPerspectives, rawRoles, diagnostics) {
2393
2393
  }
2394
2394
  const CAPABILITY_PATTERN = /^[A-Za-z0-9][A-Za-z0-9:._*-]{0,254}$/;
2395
2395
  const OPERATION_CODE_PATTERN = /^[a-z][a-z0-9]*(?:[-_.][a-z0-9]+)*$/;
2396
+ const FIELD_CODE_PATTERN = /^[A-Za-z][A-Za-z0-9_]{0,62}$/;
2396
2397
  const HTTP_METHODS = new Set(['GET', 'POST', 'PUT', 'PATCH', 'DELETE']);
2397
2398
  const RESERVED_NATIVE_KEYS = new Map([
2398
2399
  ['environmentKey', 'environmentKey'],
@@ -2963,6 +2964,8 @@ const ANONYMOUS_PUBLIC_OPERATIONS = new Set([
2963
2964
  'create',
2964
2965
  'own.list',
2965
2966
  'own.read',
2967
+ 'public.list',
2968
+ 'public.read',
2966
2969
  ]);
2967
2970
  function validateAnonymousPublicAccess(config, diagnostics) {
2968
2971
  const frontend = object(config.frontend);
@@ -2994,6 +2997,13 @@ function validateAnonymousPublicAccess(config, diagnostics) {
2994
2997
  const declaration = object(field);
2995
2998
  return [string(declaration.code), string(declaration.type)];
2996
2999
  }));
3000
+ const subtables = new Map(fields
3001
+ .map(field => object(field))
3002
+ .filter(field => string(field.type) === 'subtable')
3003
+ .map(field => [
3004
+ string(field.code),
3005
+ string(object(field.subtable).resourceCode),
3006
+ ]));
2997
3007
  const surface = object(resource.surface);
2998
3008
  const surfaceFields = object(surface.fields);
2999
3009
  const requiredCreateFields = new Set(fields
@@ -3010,11 +3020,11 @@ function validateAnonymousPublicAccess(config, diagnostics) {
3010
3020
  generated.create !== false;
3011
3021
  return [
3012
3022
  string(resource.code),
3013
- { fields: fieldMap, requiredCreateFields, nativeCreate },
3023
+ { fields: fieldMap, subtables, requiredCreateFields, nativeCreate },
3014
3024
  ];
3015
3025
  }));
3016
3026
  const policyCodes = new Set();
3017
- const routeCodes = new Set();
3027
+ const declaredPolicyCodes = new Set(policies.map(rawPolicy => string(object(rawPolicy).code)));
3018
3028
  policies.forEach((raw, index) => {
3019
3029
  const policy = object(raw);
3020
3030
  const path = `frontend.publicAccess.policies[${index}]`;
@@ -3034,6 +3044,76 @@ function validateAnonymousPublicAccess(config, diagnostics) {
3034
3044
  const ownRecordFields = Array.isArray(policy.ownRecordFields)
3035
3045
  ? policy.ownRecordFields.map(string)
3036
3046
  : fields;
3047
+ const publicSubtableFields = object(policy.publicSubtableFields);
3048
+ const publicFilters = Array.isArray(policy.publicFilters)
3049
+ ? policy.publicFilters
3050
+ : [];
3051
+ const serverGeneratedFields = Array.isArray(policy.serverGeneratedFields)
3052
+ ? policy.serverGeneratedFields
3053
+ : [];
3054
+ const generatedFieldInvalid = serverGeneratedFields.length > 16 ||
3055
+ new Set(serverGeneratedFields.map(item => string(object(item).field))).size !==
3056
+ serverGeneratedFields.length ||
3057
+ serverGeneratedFields.some(rawGenerated => {
3058
+ const generated = object(rawGenerated);
3059
+ const field = string(generated.field);
3060
+ return (Object.keys(generated).some(key => !['field', 'kind'].includes(key)) ||
3061
+ !resourceFields?.has(field) ||
3062
+ fields.includes(field) ||
3063
+ !['text.short', 'text.long'].includes(resourceFields?.get(field) || '') ||
3064
+ generated.kind !== 'random-token');
3065
+ });
3066
+ const schedule = object(policy.schedule);
3067
+ const schedulePolicyKeys = ['campusPolicyCode', 'rulePolicyCode'];
3068
+ const scheduleFieldKeys = [
3069
+ 'campusField', 'ruleCampusField', 'ruleWeekdaysField', 'ruleOpenAtField',
3070
+ 'ruleCloseAtField', 'ruleSlotMinutesField', 'ruleAdvanceHoursField',
3071
+ 'ruleAdvanceDaysField', 'campusEnabledField', 'ruleEnabledField',
3072
+ 'dateField', 'timeField',
3073
+ ];
3074
+ const scheduleKeys = [...schedulePolicyKeys, ...scheduleFieldKeys];
3075
+ const scheduleInvalid = policy.schedule !== undefined && (Object.keys(schedule).some(key => !scheduleKeys.includes(key)) ||
3076
+ schedulePolicyKeys.some(key => !OPERATION_CODE_PATTERN.test(string(schedule[key]))) ||
3077
+ scheduleFieldKeys.some(key => !FIELD_CODE_PATTERN.test(string(schedule[key]))) ||
3078
+ !fields.includes(string(schedule.campusField)) ||
3079
+ !fields.includes(string(schedule.dateField)) ||
3080
+ !fields.includes(string(schedule.timeField)) ||
3081
+ !declaredPolicyCodes.has(string(schedule.campusPolicyCode)) ||
3082
+ !declaredPolicyCodes.has(string(schedule.rulePolicyCode)));
3083
+ const publicFilterInvalid = publicFilters.length > 16 ||
3084
+ new Set(publicFilters.map(item => string(object(item).field))).size !==
3085
+ publicFilters.length ||
3086
+ publicFilters.some(rawFilter => {
3087
+ const filter = object(rawFilter);
3088
+ const field = string(filter.field);
3089
+ const type = resourceFields?.get(field);
3090
+ const value = filter.value;
3091
+ return (Object.keys(filter).some(key => !['field', 'operator', 'value'].includes(key)) ||
3092
+ !resourceFields?.has(field) ||
3093
+ filter.operator !== 'eq' ||
3094
+ !['boolean', 'text.short', 'text.long', 'number.integer', 'number.decimal', 'date', 'time'].includes(type || '') ||
3095
+ !(value === null ||
3096
+ typeof value === 'string' ||
3097
+ typeof value === 'number' ||
3098
+ typeof value === 'boolean'));
3099
+ });
3100
+ const publicSubtableInvalid = Object.entries(publicSubtableFields).some(([parentFieldCode, rawChildFields]) => {
3101
+ const childResourceCode = resource?.subtables.get(parentFieldCode);
3102
+ const childResource = childResourceCode
3103
+ ? resourceMap.get(childResourceCode)
3104
+ : undefined;
3105
+ const childFields = Array.isArray(rawChildFields)
3106
+ ? rawChildFields.map(string)
3107
+ : [];
3108
+ return (!fields.includes(parentFieldCode) ||
3109
+ !childResourceCode ||
3110
+ !childResource ||
3111
+ childFields.length < 1 ||
3112
+ childFields.length > 64 ||
3113
+ new Set(childFields).size !== childFields.length ||
3114
+ childFields.some(field => !childResource.fields.has(field)) ||
3115
+ childFields.some(field => ['signature', 'subtable'].includes(childResource.fields.get(field) || '')));
3116
+ });
3037
3117
  const draft = object(policy.draft);
3038
3118
  const validations = Array.isArray(policy.validations)
3039
3119
  ? policy.validations
@@ -3047,13 +3127,17 @@ function validateAnonymousPublicAccess(config, diagnostics) {
3047
3127
  'fields',
3048
3128
  'requiredFields',
3049
3129
  'ownRecordFields',
3130
+ 'publicRecordFields',
3131
+ 'publicFilters',
3132
+ 'serverGeneratedFields',
3133
+ 'schedule',
3134
+ 'publicSubtableFields',
3050
3135
  'draft',
3051
3136
  'validations',
3052
3137
  ];
3053
3138
  const invalid = Object.keys(policy).some(key => !exactRootKeys.includes(key)) ||
3054
3139
  !OPERATION_CODE_PATTERN.test(code) ||
3055
3140
  policyCodes.has(code) ||
3056
- routeCodes.has(routeCode) ||
3057
3141
  policy.mode !== 'anonymous' ||
3058
3142
  !route ||
3059
3143
  route.surface !== 'user' ||
@@ -3072,8 +3156,23 @@ function validateAnonymousPublicAccess(config, diagnostics) {
3072
3156
  new Set(requiredFields).size !== requiredFields.length ||
3073
3157
  requiredFields.some(field => !fields.includes(field)) ||
3074
3158
  (operations.includes('create') && !resource?.nativeCreate) ||
3159
+ (operations.includes('create') && policy.draft === undefined) ||
3075
3160
  new Set(ownRecordFields).size !== ownRecordFields.length ||
3076
3161
  ownRecordFields.some(field => !fields.includes(field)) ||
3162
+ Object.keys(publicSubtableFields).length > 64 ||
3163
+ publicSubtableInvalid ||
3164
+ publicFilterInvalid ||
3165
+ generatedFieldInvalid ||
3166
+ scheduleInvalid ||
3167
+ (operations.some(operation => operation.startsWith('public.')) &&
3168
+ (!Array.isArray(policy.publicRecordFields) ||
3169
+ policy.publicRecordFields.length < 1 ||
3170
+ new Set(policy.publicRecordFields.map(string)).size !==
3171
+ policy.publicRecordFields.length ||
3172
+ policy.publicRecordFields.some((field) => !fields.includes(string(field)) ||
3173
+ resourceFields?.get(string(field)) === 'signature' ||
3174
+ (resourceFields?.get(string(field)) === 'subtable' &&
3175
+ !Array.isArray(publicSubtableFields[string(field)]))))) ||
3077
3176
  (operations.includes('draft.read') !== operations.includes('draft.update')) ||
3078
3177
  (operations.some(operation => operation.startsWith('draft.')) &&
3079
3178
  (policy.draft === undefined || draft.enabled !== true)) ||
@@ -3121,7 +3220,6 @@ function validateAnonymousPublicAccess(config, diagnostics) {
3121
3220
  validationCodes.add(validationCode);
3122
3221
  });
3123
3222
  policyCodes.add(code);
3124
- routeCodes.add(routeCode);
3125
3223
  });
3126
3224
  }
3127
3225
  function validateApplicationAuthentication(config, diagnostics) {