openxiangda-contracts 2.92.0 → 2.94.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.
- package/dist/native-compiler/compiler.js +203 -3
- package/dist/native-compiler/compiler.js.map +1 -1
- package/dist/native-compiler/index.cjs +4 -4
- package/dist/native-compiler/index.js +4 -4
- package/dist/native.d.ts +48 -1
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js.map +1 -1
- package/dist/schemas.d.ts +660 -4
- package/dist/schemas.d.ts.map +1 -1
- package/dist/schemas.js +105 -0
- package/dist/schemas.js.map +1 -1
- package/package.json +1 -1
|
@@ -2510,6 +2510,7 @@ const ANONYMOUS_PUBLIC_OPERATIONS = new Set([
|
|
|
2510
2510
|
'own.read',
|
|
2511
2511
|
'public.list',
|
|
2512
2512
|
'public.read',
|
|
2513
|
+
'public.query',
|
|
2513
2514
|
]);
|
|
2514
2515
|
function validateAnonymousPublicAccess(value, config, pointer) {
|
|
2515
2516
|
const access = object(value, pointer);
|
|
@@ -2535,6 +2536,7 @@ function validateAnonymousPublicAccess(value, config, pointer) {
|
|
|
2535
2536
|
'serverGeneratedFields',
|
|
2536
2537
|
'schedule',
|
|
2537
2538
|
'publicSubtableFields',
|
|
2539
|
+
'publicQueries',
|
|
2538
2540
|
'draft',
|
|
2539
2541
|
'validations',
|
|
2540
2542
|
]);
|
|
@@ -2707,19 +2709,148 @@ function validateAnonymousPublicAccess(value, config, pointer) {
|
|
|
2707
2709
|
}
|
|
2708
2710
|
}
|
|
2709
2711
|
}
|
|
2712
|
+
const publicRecordFields = Object.prototype.hasOwnProperty.call(policy, 'publicRecordFields')
|
|
2713
|
+
? uniqueStrings(policy.publicRecordFields, policyPointer + '/publicRecordFields', 64)
|
|
2714
|
+
: [];
|
|
2710
2715
|
if (operations.some(operation => operation.startsWith('public.'))) {
|
|
2711
2716
|
if (!Object.prototype.hasOwnProperty.call(policy, 'publicRecordFields')) {
|
|
2712
|
-
fail('NATIVE_PUBLIC_RECORD_FIELDS_REQUIRED',
|
|
2717
|
+
fail('NATIVE_PUBLIC_RECORD_FIELDS_REQUIRED', policyPointer + '/publicRecordFields');
|
|
2713
2718
|
}
|
|
2714
|
-
const publicRecordFields = uniqueStrings(policy.publicRecordFields, `${policyPointer}/publicRecordFields`, 64);
|
|
2715
2719
|
if (publicRecordFields.length < 1 ||
|
|
2716
2720
|
publicRecordFields.some(field => !fields.includes(field)) ||
|
|
2717
2721
|
publicRecordFields.some(field => declaredFields.get(field) === 'signature' ||
|
|
2718
2722
|
(declaredFields.get(field) === 'subtable' &&
|
|
2719
2723
|
!publicSubtableFields?.[field]))) {
|
|
2720
|
-
fail('NATIVE_PUBLIC_RECORD_FIELDS_INVALID',
|
|
2724
|
+
fail('NATIVE_PUBLIC_RECORD_FIELDS_INVALID', policyPointer + '/publicRecordFields');
|
|
2721
2725
|
}
|
|
2722
2726
|
}
|
|
2727
|
+
const publicQueries = Object.prototype.hasOwnProperty.call(policy, 'publicQueries')
|
|
2728
|
+
? boundedArray(policy.publicQueries, policyPointer + '/publicQueries', 16)
|
|
2729
|
+
: [];
|
|
2730
|
+
const queryCodes = new Set();
|
|
2731
|
+
publicQueries.forEach((rawQuery, queryIndex) => {
|
|
2732
|
+
const queryPointer = policyPointer + '/publicQueries/' + queryIndex;
|
|
2733
|
+
const query = object(rawQuery, queryPointer);
|
|
2734
|
+
exactKeys(query, ['code', 'kind', 'resourceCode', 'fields', 'defaultLimit', 'maxLimit'], queryPointer, ['sort', 'parameters', 'aggregate']);
|
|
2735
|
+
const queryCode = stableCode(query.code, queryPointer + '/code');
|
|
2736
|
+
if (queryCodes.has(queryCode)) {
|
|
2737
|
+
fail('NATIVE_PUBLIC_QUERY_DUPLICATE', queryPointer + '/code');
|
|
2738
|
+
}
|
|
2739
|
+
queryCodes.add(queryCode);
|
|
2740
|
+
if (!['records', 'aggregate'].includes(String(query.kind))) {
|
|
2741
|
+
fail('NATIVE_PUBLIC_QUERY_KIND_INVALID', queryPointer + '/kind');
|
|
2742
|
+
}
|
|
2743
|
+
if (String(query.resourceCode) !== declaredResourceCode) {
|
|
2744
|
+
fail('NATIVE_PUBLIC_QUERY_RESOURCE_INVALID', queryPointer + '/resourceCode');
|
|
2745
|
+
}
|
|
2746
|
+
const queryFields = uniqueStrings(query.fields, queryPointer + '/fields', 64);
|
|
2747
|
+
if (queryFields.length < 1 ||
|
|
2748
|
+
queryFields.some(field => !fields.includes(field)) ||
|
|
2749
|
+
queryFields.some(field => !publicRecordFields?.includes(field))) {
|
|
2750
|
+
fail('NATIVE_PUBLIC_QUERY_FIELDS_INVALID', queryPointer + '/fields');
|
|
2751
|
+
}
|
|
2752
|
+
const defaultLimit = Number(query.defaultLimit);
|
|
2753
|
+
const maxLimit = Number(query.maxLimit);
|
|
2754
|
+
if (!Number.isSafeInteger(defaultLimit) ||
|
|
2755
|
+
!Number.isSafeInteger(maxLimit) ||
|
|
2756
|
+
defaultLimit < 1 ||
|
|
2757
|
+
maxLimit < defaultLimit ||
|
|
2758
|
+
maxLimit > 100) {
|
|
2759
|
+
fail('NATIVE_PUBLIC_QUERY_LIMIT_INVALID', queryPointer + '/maxLimit');
|
|
2760
|
+
}
|
|
2761
|
+
if (Object.prototype.hasOwnProperty.call(query, 'sort')) {
|
|
2762
|
+
const sort = boundedArray(query.sort, queryPointer + '/sort', 4);
|
|
2763
|
+
const sortFields = new Set();
|
|
2764
|
+
sort.forEach((rawSort, sortIndex) => {
|
|
2765
|
+
const sortPointer = queryPointer + '/sort/' + sortIndex;
|
|
2766
|
+
const item = object(rawSort, sortPointer);
|
|
2767
|
+
exactKeys(item, ['field', 'direction'], sortPointer);
|
|
2768
|
+
const field = fieldCodeValue(item.field, sortPointer + '/field');
|
|
2769
|
+
if (!queryFields.includes(field) || sortFields.has(field) || !['asc', 'desc'].includes(String(item.direction))) {
|
|
2770
|
+
fail('NATIVE_PUBLIC_QUERY_SORT_INVALID', sortPointer);
|
|
2771
|
+
}
|
|
2772
|
+
sortFields.add(field);
|
|
2773
|
+
});
|
|
2774
|
+
}
|
|
2775
|
+
if (Object.prototype.hasOwnProperty.call(query, 'parameters')) {
|
|
2776
|
+
const parameters = boundedArray(query.parameters, queryPointer + '/parameters', 8);
|
|
2777
|
+
const names = new Set();
|
|
2778
|
+
parameters.forEach((rawParameter, parameterIndex) => {
|
|
2779
|
+
const parameterPointer = queryPointer + '/parameters/' + parameterIndex;
|
|
2780
|
+
const parameter = object(rawParameter, parameterPointer);
|
|
2781
|
+
exactKeys(parameter, ['name', 'field', 'operator', 'type'], parameterPointer);
|
|
2782
|
+
const name = stableCode(parameter.name, parameterPointer + '/name');
|
|
2783
|
+
const field = fieldCodeValue(parameter.field, parameterPointer + '/field');
|
|
2784
|
+
if (names.has(name) ||
|
|
2785
|
+
!queryFields.includes(field) ||
|
|
2786
|
+
!['eq', 'contains', 'in'].includes(String(parameter.operator)) ||
|
|
2787
|
+
!['string', 'number', 'boolean', 'string[]'].includes(String(parameter.type))) {
|
|
2788
|
+
fail('NATIVE_PUBLIC_QUERY_PARAMETER_INVALID', parameterPointer);
|
|
2789
|
+
}
|
|
2790
|
+
names.add(name);
|
|
2791
|
+
});
|
|
2792
|
+
}
|
|
2793
|
+
if (Object.prototype.hasOwnProperty.call(query, 'aggregate')) {
|
|
2794
|
+
if (String(query.kind) !== 'aggregate') {
|
|
2795
|
+
fail('NATIVE_PUBLIC_QUERY_AGGREGATE_KIND_INVALID', queryPointer + '/aggregate');
|
|
2796
|
+
}
|
|
2797
|
+
const aggregatePointer = queryPointer + '/aggregate';
|
|
2798
|
+
const aggregate = object(query.aggregate, aggregatePointer);
|
|
2799
|
+
exactKeys(aggregate, ['measures'], aggregatePointer, ['dimensions', 'order']);
|
|
2800
|
+
const aliases = new Set();
|
|
2801
|
+
const aggregateAlias = (value, pointer) => {
|
|
2802
|
+
const normalized = String(value || '').trim();
|
|
2803
|
+
if (!/^[A-Za-z][A-Za-z0-9_]{0,62}$/.test(normalized) || aliases.has(normalized)) {
|
|
2804
|
+
fail('NATIVE_PUBLIC_QUERY_AGGREGATE_ALIAS_INVALID', pointer);
|
|
2805
|
+
}
|
|
2806
|
+
aliases.add(normalized);
|
|
2807
|
+
return normalized;
|
|
2808
|
+
};
|
|
2809
|
+
const dimensions = Object.prototype.hasOwnProperty.call(aggregate, 'dimensions')
|
|
2810
|
+
? boundedArray(aggregate.dimensions, aggregatePointer + '/dimensions', 3)
|
|
2811
|
+
: [];
|
|
2812
|
+
dimensions.forEach((rawDimension, dimensionIndex) => {
|
|
2813
|
+
const pointer = `${aggregatePointer}/dimensions/${dimensionIndex}`;
|
|
2814
|
+
const dimension = object(rawDimension, pointer);
|
|
2815
|
+
exactKeys(dimension, ['field', 'as'], pointer, ['bucket']);
|
|
2816
|
+
const field = fieldCodeValue(dimension.field, pointer + '/field');
|
|
2817
|
+
if (!queryFields.includes(field))
|
|
2818
|
+
fail('NATIVE_PUBLIC_QUERY_AGGREGATE_FIELD_INVALID', pointer + '/field');
|
|
2819
|
+
aggregateAlias(dimension.as, pointer + '/as');
|
|
2820
|
+
if (dimension.bucket !== undefined && !['day', 'week', 'month', 'quarter', 'year'].includes(String(dimension.bucket))) {
|
|
2821
|
+
fail('NATIVE_PUBLIC_QUERY_AGGREGATE_BUCKET_INVALID', pointer + '/bucket');
|
|
2822
|
+
}
|
|
2823
|
+
});
|
|
2824
|
+
const measures = boundedArray(aggregate.measures, aggregatePointer + '/measures', 8);
|
|
2825
|
+
if (measures.length < 1)
|
|
2826
|
+
fail('NATIVE_PUBLIC_QUERY_AGGREGATE_MEASURES_INVALID', aggregatePointer + '/measures');
|
|
2827
|
+
measures.forEach((rawMeasure, measureIndex) => {
|
|
2828
|
+
const pointer = `${aggregatePointer}/measures/${measureIndex}`;
|
|
2829
|
+
const measure = object(rawMeasure, pointer);
|
|
2830
|
+
exactKeys(measure, ['type', 'as'], pointer, ['field']);
|
|
2831
|
+
const type = String(measure.type);
|
|
2832
|
+
const field = measure.field === undefined ? undefined : fieldCodeValue(measure.field, pointer + '/field');
|
|
2833
|
+
if (!['count', 'countDistinct', 'sum', 'avg', 'min', 'max'].includes(type) ||
|
|
2834
|
+
(type === 'count' ? field !== undefined : !field || !queryFields.includes(field))) {
|
|
2835
|
+
fail('NATIVE_PUBLIC_QUERY_AGGREGATE_MEASURE_INVALID', pointer);
|
|
2836
|
+
}
|
|
2837
|
+
aggregateAlias(measure.as, pointer + '/as');
|
|
2838
|
+
});
|
|
2839
|
+
if (Object.prototype.hasOwnProperty.call(aggregate, 'order')) {
|
|
2840
|
+
const order = boundedArray(aggregate.order, aggregatePointer + '/order', 10);
|
|
2841
|
+
order.forEach((rawOrder, orderIndex) => {
|
|
2842
|
+
const pointer = `${aggregatePointer}/order/${orderIndex}`;
|
|
2843
|
+
const item = object(rawOrder, pointer);
|
|
2844
|
+
exactKeys(item, ['field'], pointer, ['direction', 'nulls']);
|
|
2845
|
+
if (!aliases.has(String(item.field)) ||
|
|
2846
|
+
(item.direction !== undefined && !['asc', 'desc'].includes(String(item.direction))) ||
|
|
2847
|
+
(item.nulls !== undefined && !['first', 'last'].includes(String(item.nulls)))) {
|
|
2848
|
+
fail('NATIVE_PUBLIC_QUERY_AGGREGATE_ORDER_INVALID', pointer);
|
|
2849
|
+
}
|
|
2850
|
+
});
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
});
|
|
2723
2854
|
const requiredFields = Object.prototype.hasOwnProperty.call(policy, 'requiredFields')
|
|
2724
2855
|
? uniqueStrings(policy.requiredFields, `${policyPointer}/requiredFields`, 64)
|
|
2725
2856
|
: [];
|
|
@@ -2818,6 +2949,75 @@ function compileAnonymousPublicAccess(config) {
|
|
|
2818
2949
|
.sort((left, right) => compareText(left.field, right.field)),
|
|
2819
2950
|
}
|
|
2820
2951
|
: {}),
|
|
2952
|
+
...(policy.publicQueries
|
|
2953
|
+
? {
|
|
2954
|
+
publicQueries: sorted(policy.publicQueries.map((query) => ({
|
|
2955
|
+
code: query.code,
|
|
2956
|
+
kind: query.kind,
|
|
2957
|
+
resourceCode: query.resourceCode,
|
|
2958
|
+
fields: uniqueSorted(query.fields),
|
|
2959
|
+
defaultLimit: Number(query.defaultLimit),
|
|
2960
|
+
maxLimit: Number(query.maxLimit),
|
|
2961
|
+
...(query.sort
|
|
2962
|
+
? {
|
|
2963
|
+
sort: query.sort
|
|
2964
|
+
.map((item) => ({
|
|
2965
|
+
field: item.field,
|
|
2966
|
+
direction: item.direction,
|
|
2967
|
+
}))
|
|
2968
|
+
.sort((left, right) => compareText(left.field, right.field)),
|
|
2969
|
+
}
|
|
2970
|
+
: {}),
|
|
2971
|
+
...(query.parameters
|
|
2972
|
+
? {
|
|
2973
|
+
parameters: query.parameters
|
|
2974
|
+
.map((parameter) => ({
|
|
2975
|
+
name: parameter.name,
|
|
2976
|
+
field: parameter.field,
|
|
2977
|
+
operator: parameter.operator,
|
|
2978
|
+
type: parameter.type,
|
|
2979
|
+
}))
|
|
2980
|
+
.sort((left, right) => compareText(left.name, right.name)),
|
|
2981
|
+
}
|
|
2982
|
+
: {}),
|
|
2983
|
+
...(query.aggregate
|
|
2984
|
+
? {
|
|
2985
|
+
aggregate: {
|
|
2986
|
+
...(query.aggregate.dimensions
|
|
2987
|
+
? {
|
|
2988
|
+
dimensions: query.aggregate.dimensions
|
|
2989
|
+
.map((dimension) => ({
|
|
2990
|
+
field: dimension.field,
|
|
2991
|
+
as: dimension.as,
|
|
2992
|
+
...(dimension.bucket ? { bucket: dimension.bucket } : {}),
|
|
2993
|
+
}))
|
|
2994
|
+
.sort((left, right) => left.as.localeCompare(right.as)),
|
|
2995
|
+
}
|
|
2996
|
+
: {}),
|
|
2997
|
+
measures: query.aggregate.measures
|
|
2998
|
+
.map((measure) => ({
|
|
2999
|
+
type: measure.type,
|
|
3000
|
+
...(measure.field ? { field: measure.field } : {}),
|
|
3001
|
+
as: measure.as,
|
|
3002
|
+
}))
|
|
3003
|
+
.sort((left, right) => left.as.localeCompare(right.as)),
|
|
3004
|
+
...(query.aggregate.order
|
|
3005
|
+
? {
|
|
3006
|
+
order: query.aggregate.order
|
|
3007
|
+
.map((item) => ({
|
|
3008
|
+
field: item.field,
|
|
3009
|
+
...(item.direction ? { direction: item.direction } : {}),
|
|
3010
|
+
...(item.nulls ? { nulls: item.nulls } : {}),
|
|
3011
|
+
}))
|
|
3012
|
+
.sort((left, right) => left.field.localeCompare(right.field)),
|
|
3013
|
+
}
|
|
3014
|
+
: {}),
|
|
3015
|
+
},
|
|
3016
|
+
}
|
|
3017
|
+
: {}),
|
|
3018
|
+
})), (query) => String(query.code)),
|
|
3019
|
+
}
|
|
3020
|
+
: {}),
|
|
2821
3021
|
...(policy.publicSubtableFields
|
|
2822
3022
|
? {
|
|
2823
3023
|
publicSubtableFields: Object.fromEntries(Object.entries(policy.publicSubtableFields)
|