@researchdatabox/sails-ng-common 5.0.3 → 5.0.4-beta.12498

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.
Files changed (60) hide show
  1. package/dist/src/config/component/checkbox-input.model.d.ts +1 -0
  2. package/dist/src/config/component/checkbox-input.model.js +2 -1
  3. package/dist/src/config/component/checkbox-input.outline.d.ts +2 -1
  4. package/dist/src/config/component/checkbox-input.outline.js +1 -1
  5. package/dist/src/config/component/data-location.outline.d.ts +1 -0
  6. package/dist/src/config/component/file-upload.outline.d.ts +2 -0
  7. package/dist/src/config/component/file-upload.outline.js +1 -1
  8. package/dist/src/config/component/related-object-data.model.d.ts +45 -0
  9. package/dist/src/config/component/related-object-data.model.js +39 -0
  10. package/dist/src/config/component/related-object-data.outline.d.ts +59 -0
  11. package/dist/src/config/component/related-object-data.outline.js +5 -0
  12. package/dist/src/config/component/save-button.model.d.ts +1 -0
  13. package/dist/src/config/component/save-button.model.js +2 -1
  14. package/dist/src/config/component/save-button.outline.d.ts +5 -0
  15. package/dist/src/config/component/save-status.model.d.ts +4 -0
  16. package/dist/src/config/component/save-status.model.js +5 -1
  17. package/dist/src/config/component/save-status.outline.d.ts +20 -0
  18. package/dist/src/config/component/workspace.model.d.ts +44 -0
  19. package/dist/src/config/component/workspace.model.js +44 -0
  20. package/dist/src/config/component/workspace.outline.d.ts +62 -0
  21. package/dist/src/config/component/workspace.outline.js +5 -0
  22. package/dist/src/config/dictionary.model.d.ts +28 -4
  23. package/dist/src/config/dictionary.model.js +7 -1
  24. package/dist/src/config/dictionary.outline.d.ts +5 -3
  25. package/dist/src/config/form-behaviour.outline.d.ts +120 -7
  26. package/dist/src/config/form-behaviour.outline.js +13 -5
  27. package/dist/src/config/form-component.model.d.ts +1 -0
  28. package/dist/src/config/form-component.model.js +2 -1
  29. package/dist/src/config/form-component.outline.d.ts +14 -0
  30. package/dist/src/config/form-config.model.d.ts +3 -0
  31. package/dist/src/config/form-config.model.js +2 -1
  32. package/dist/src/config/form-config.outline.d.ts +10 -0
  33. package/dist/src/config/form-override.model.js +4 -3
  34. package/dist/src/config/visitor/base.model.d.ts +6 -0
  35. package/dist/src/config/visitor/base.model.js +13 -1
  36. package/dist/src/config/visitor/base.outline.d.ts +6 -0
  37. package/dist/src/config/visitor/common.model.js +2 -1
  38. package/dist/src/index.d.ts +9 -0
  39. package/dist/src/index.js +10 -1
  40. package/dist/src/internal/plain-record.d.ts +11 -0
  41. package/dist/src/internal/plain-record.js +21 -0
  42. package/dist/src/jsonata-helpers.d.ts +15 -0
  43. package/dist/src/jsonata-helpers.js +49 -13
  44. package/dist/src/jsonata-parity.fixtures.d.ts +9 -0
  45. package/dist/src/jsonata-parity.fixtures.js +25 -0
  46. package/dist/src/record-concurrency.model.d.ts +118 -0
  47. package/dist/src/record-concurrency.model.js +199 -0
  48. package/dist/src/record-diff.d.ts +69 -0
  49. package/dist/src/record-diff.js +298 -0
  50. package/dist/src/record-save.model.d.ts +154 -0
  51. package/dist/src/record-save.model.js +289 -0
  52. package/dist/src/testing.d.ts +3 -0
  53. package/dist/src/testing.js +20 -0
  54. package/dist/src/validation/record-validation.model.d.ts +84 -0
  55. package/dist/src/validation/record-validation.model.js +53 -0
  56. package/dist/src/validation/validation-groups.d.ts +29 -0
  57. package/dist/src/validation/validation-groups.fixtures.d.ts +20 -0
  58. package/dist/src/validation/validation-groups.fixtures.js +83 -0
  59. package/dist/src/validation/validation-groups.js +82 -0
  60. package/package.json +16 -11
@@ -0,0 +1,154 @@
1
+ /**
2
+ * Contracts shared by the browser and server for record-save operations.
3
+ *
4
+ * These are deliberately data-only contracts. The server and Angular
5
+ * packages provide their own runtime response classes while this package
6
+ * remains safe to consume from either side of the application.
7
+ */
8
+ import { LineagePathsOptional, LineagePathsPartial } from './config/names/naming-helpers';
9
+ import type { RecordConcurrencyMetadata } from './record-concurrency.model';
10
+ export interface ActionResult {
11
+ /** True when the requested primary action was completed. */
12
+ success: boolean;
13
+ /** The record identifier, when one is known. */
14
+ oid: string;
15
+ /** Compatibility summary for legacy callers. */
16
+ message: string;
17
+ /** Action-specific response data. */
18
+ data?: unknown;
19
+ /** Authoritative server-projected metadata, or null when unavailable. */
20
+ metadata: Record<string, unknown> | null;
21
+ }
22
+ export type RecordSaveOutcome = 'saved' | 'saved-with-warnings' | 'not-saved' | 'unknown';
23
+ export declare const RECORD_SAVE_PROBLEM_KINDS: readonly ["validation", "processing", "authorization", "conflict", "system", "network"];
24
+ export type RecordSaveProblemKind = (typeof RECORD_SAVE_PROBLEM_KINDS)[number];
25
+ export type RecordSaveProblemSource = 'schema';
26
+ export type RecordSaveLifecyclePhase = 'pre-save' | 'persistence' | 'attachments' | 'post-save' | 'response' | 'transport';
27
+ export type RecordSavePhase = 'schema' | RecordSaveLifecyclePhase;
28
+ export type RecordSaveValidatorParameterPrimitive = string | number | boolean | null;
29
+ export type RecordSaveValidatorParameterValue = RecordSaveValidatorParameterPrimitive | RecordSaveValidatorParameterPrimitive[];
30
+ export type RecordSaveValidatorParameters = Record<string, RecordSaveValidatorParameterValue>;
31
+ export declare const RECORD_SAVE_VALIDATOR_PARAMETER_LIMITS: {
32
+ readonly maxEntries: 16;
33
+ readonly maxKeyLength: 64;
34
+ readonly maxStringLength: 256;
35
+ readonly maxArrayLength: 16;
36
+ readonly maxSerializedLength: 4096;
37
+ };
38
+ export declare const RECORD_SAVE_VALIDATOR_CLASS_MAX_LENGTH = 128;
39
+ export declare const RECORD_SAVE_MESSAGE_MAX_LENGTH = 1024;
40
+ export declare const RECORD_SAVE_VALIDATOR_PARAMETER_KEY_PATTERN: RegExp;
41
+ export declare const RECORD_SAVE_PUBLIC_FIELD_LIMITS: {
42
+ readonly maxCodeLength: 128;
43
+ readonly maxFieldLength: 128;
44
+ readonly maxPointerLength: 2048;
45
+ readonly maxAttachmentIdLength: 128;
46
+ };
47
+ export declare const RECORD_SAVE_PUBLIC_IDENTIFIER_PATTERN: RegExp;
48
+ export declare const RECORD_SAVE_EXPECTED_JSON_TYPES: readonly ["array", "boolean", "integer", "null", "number", "object", "string"];
49
+ export type RecordSaveExpectedJsonType = (typeof RECORD_SAVE_EXPECTED_JSON_TYPES)[number];
50
+ export interface RecordSaveIssueExpectedShape {
51
+ type: RecordSaveExpectedJsonType;
52
+ }
53
+ export declare const RECORD_SAVE_LINEAGE_LIMITS: {
54
+ readonly maxSegments: 64;
55
+ readonly maxSegmentLength: 128;
56
+ readonly maxPointerLength: 2048;
57
+ };
58
+ export interface RecordSaveIssue {
59
+ /** A safe, stable identifier suitable for translation or support lookup. */
60
+ code?: string;
61
+ /** Safe user-facing text. Raw provider/exception text must not be placed here. */
62
+ message: string;
63
+ /** Configured form field name, when the issue maps unambiguously. */
64
+ field?: string;
65
+ /** JSON pointer into Angular or record metadata, when available. */
66
+ pointer?: string;
67
+ /** Narrow structural expectation safe to expose for schema type failures. */
68
+ expected?: RecordSaveIssueExpectedShape;
69
+ /** Logical attachment identity, never a storage key or path. */
70
+ attachmentId?: string;
71
+ /** Validator implementation class, when this is a validator failure. */
72
+ class?: string;
73
+ /** Bounded scalar parameters used to render a configured validator message. */
74
+ params?: RecordSaveValidatorParameters;
75
+ /** Validator-configured field ownership override. */
76
+ targetField?: LineagePathsPartial;
77
+ /** Lineage of the field or form control that produced the issue. */
78
+ lineagePaths?: LineagePathsOptional;
79
+ }
80
+ /** True only for root or syntactically valid RFC 6901 JSON pointers. */
81
+ export declare function isRecordSaveJsonPointer(value: unknown): value is string;
82
+ /** Remove non-allowlisted, executable, excessive, and otherwise unsafe validator parameters. */
83
+ export declare function sanitizeRecordSaveValidatorParameters(value: unknown, validatorClass?: unknown): RecordSaveValidatorParameters | undefined;
84
+ /**
85
+ * Copy only the public issue allowlist and normalize bounded validator/lineage
86
+ * metadata. This is suitable for a response serialization boundary.
87
+ */
88
+ export declare function sanitizeRecordSaveIssue(value: unknown): RecordSaveIssue;
89
+ export interface RecordSaveSchemaProblem {
90
+ kind: RecordSaveProblemKind;
91
+ source: RecordSaveProblemSource;
92
+ phase: 'schema';
93
+ issues: RecordSaveIssue[];
94
+ }
95
+ export interface RecordSaveLifecycleProblem {
96
+ kind: RecordSaveProblemKind;
97
+ source?: never;
98
+ phase: RecordSaveLifecyclePhase;
99
+ issues: RecordSaveIssue[];
100
+ }
101
+ /** A nonblocking form suggestion, distinct from incomplete save work. */
102
+ export interface RecordSaveAdvisoryProblem {
103
+ kind: 'validation';
104
+ source: 'advisory';
105
+ phase: 'pre-save' | 'post-save';
106
+ issues: RecordSaveIssue[];
107
+ }
108
+ /** Provenance and phase form one discriminated contract. */
109
+ export type RecordSaveProblem = RecordSaveSchemaProblem | RecordSaveLifecycleProblem | RecordSaveAdvisoryProblem;
110
+ export type RecordAttachmentOperation = 'add' | 'finalize' | 'delete';
111
+ export type RecordAttachmentItemStatus = 'completed' | 'incomplete' | 'unknown';
112
+ export type RecordAttachmentCompletionStatus = 'not-required' | 'completed' | 'incomplete' | 'unknown';
113
+ export interface RecordAttachmentCompletionItem {
114
+ field: string;
115
+ attachmentId: string;
116
+ fileId?: string;
117
+ operation: RecordAttachmentOperation;
118
+ status: RecordAttachmentItemStatus;
119
+ /** A safe, bounded code such as attachment-reupload-required. */
120
+ code?: string;
121
+ }
122
+ export interface RecordAttachmentCompletion {
123
+ status: RecordAttachmentCompletionStatus;
124
+ items: RecordAttachmentCompletionItem[];
125
+ }
126
+ export interface RecordSaveCompletion {
127
+ attachments: RecordAttachmentCompletion;
128
+ }
129
+ export interface RecordSaveResult extends ActionResult {
130
+ outcome: RecordSaveOutcome;
131
+ problems: RecordSaveProblem[];
132
+ completion: RecordSaveCompletion;
133
+ requestId: string;
134
+ concurrency?: RecordConcurrencyMetadata;
135
+ }
136
+ /** A schema warning can coexist with a complete save; unfinished work cannot. */
137
+ export declare function isRecordSaveComplete(result: Pick<RecordSaveResult, 'outcome' | 'problems' | 'completion'>): boolean;
138
+ export type StorageMutationApplicationState = 'applied' | 'not-applied' | 'unknown';
139
+ export declare function emptyRecordSaveCompletion(): RecordSaveCompletion;
140
+ /**
141
+ * Reduce item-level attachment facts into the public aggregate status.
142
+ * Unknown takes precedence over incomplete because it represents less
143
+ * certainty about the physical operation.
144
+ */
145
+ export declare function reduceAttachmentStatus(items: readonly RecordAttachmentCompletionItem[]): RecordAttachmentCompletionStatus;
146
+ export declare function isRecordSaveOutcome(value: unknown): value is RecordSaveOutcome;
147
+ export declare function isRecordSaveProblemKind(value: unknown): value is RecordSaveProblemKind;
148
+ /**
149
+ * Canonical save request-correlation identifier: one RFC 4122 UUID. It is
150
+ * correlation only and is never treated as an idempotency key.
151
+ */
152
+ export declare const RECORD_SAVE_REQUEST_ID_PATTERN: RegExp;
153
+ export declare const RECORD_SAVE_REQUEST_ID_MAX_LENGTH = 36;
154
+ export declare function isRecordSaveRequestId(value: unknown): value is string;
@@ -0,0 +1,289 @@
1
+ "use strict";
2
+ /**
3
+ * Contracts shared by the browser and server for record-save operations.
4
+ *
5
+ * These are deliberately data-only contracts. The server and Angular
6
+ * packages provide their own runtime response classes while this package
7
+ * remains safe to consume from either side of the application.
8
+ */
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.RECORD_SAVE_REQUEST_ID_MAX_LENGTH = exports.RECORD_SAVE_REQUEST_ID_PATTERN = exports.RECORD_SAVE_LINEAGE_LIMITS = exports.RECORD_SAVE_EXPECTED_JSON_TYPES = exports.RECORD_SAVE_PUBLIC_IDENTIFIER_PATTERN = exports.RECORD_SAVE_PUBLIC_FIELD_LIMITS = exports.RECORD_SAVE_VALIDATOR_PARAMETER_KEY_PATTERN = exports.RECORD_SAVE_MESSAGE_MAX_LENGTH = exports.RECORD_SAVE_VALIDATOR_CLASS_MAX_LENGTH = exports.RECORD_SAVE_VALIDATOR_PARAMETER_LIMITS = exports.RECORD_SAVE_PROBLEM_KINDS = void 0;
11
+ exports.isRecordSaveJsonPointer = isRecordSaveJsonPointer;
12
+ exports.sanitizeRecordSaveValidatorParameters = sanitizeRecordSaveValidatorParameters;
13
+ exports.sanitizeRecordSaveIssue = sanitizeRecordSaveIssue;
14
+ exports.isRecordSaveComplete = isRecordSaveComplete;
15
+ exports.emptyRecordSaveCompletion = emptyRecordSaveCompletion;
16
+ exports.reduceAttachmentStatus = reduceAttachmentStatus;
17
+ exports.isRecordSaveOutcome = isRecordSaveOutcome;
18
+ exports.isRecordSaveProblemKind = isRecordSaveProblemKind;
19
+ exports.isRecordSaveRequestId = isRecordSaveRequestId;
20
+ const plain_record_1 = require("./internal/plain-record");
21
+ exports.RECORD_SAVE_PROBLEM_KINDS = [
22
+ 'validation',
23
+ 'processing',
24
+ 'authorization',
25
+ 'conflict',
26
+ 'system',
27
+ 'network',
28
+ ];
29
+ exports.RECORD_SAVE_VALIDATOR_PARAMETER_LIMITS = {
30
+ maxEntries: 16,
31
+ maxKeyLength: 64,
32
+ maxStringLength: 256,
33
+ maxArrayLength: 16,
34
+ maxSerializedLength: 4_096,
35
+ };
36
+ exports.RECORD_SAVE_VALIDATOR_CLASS_MAX_LENGTH = 128;
37
+ exports.RECORD_SAVE_MESSAGE_MAX_LENGTH = 1_024;
38
+ exports.RECORD_SAVE_VALIDATOR_PARAMETER_KEY_PATTERN = /^[A-Za-z][A-Za-z0-9_.-]*$/;
39
+ exports.RECORD_SAVE_PUBLIC_FIELD_LIMITS = {
40
+ maxCodeLength: 128,
41
+ maxFieldLength: 128,
42
+ maxPointerLength: 2_048,
43
+ maxAttachmentIdLength: 128,
44
+ };
45
+ exports.RECORD_SAVE_PUBLIC_IDENTIFIER_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]*$/;
46
+ exports.RECORD_SAVE_EXPECTED_JSON_TYPES = [
47
+ 'array',
48
+ 'boolean',
49
+ 'integer',
50
+ 'null',
51
+ 'number',
52
+ 'object',
53
+ 'string',
54
+ ];
55
+ exports.RECORD_SAVE_LINEAGE_LIMITS = {
56
+ maxSegments: 64,
57
+ maxSegmentLength: 128,
58
+ maxPointerLength: 2_048,
59
+ };
60
+ /** True only for root or syntactically valid RFC 6901 JSON pointers. */
61
+ function isRecordSaveJsonPointer(value) {
62
+ if (typeof value !== 'string' || (value !== '' && !value.startsWith('/'))) {
63
+ return false;
64
+ }
65
+ for (let index = 0; index < value.length; index += 1) {
66
+ if (value[index] !== '~')
67
+ continue;
68
+ const escaped = value[index + 1];
69
+ if (escaped !== '0' && escaped !== '1')
70
+ return false;
71
+ index += 1;
72
+ }
73
+ return true;
74
+ }
75
+ function sanitizeRecordSaveIssueExpected(value) {
76
+ if (!(0, plain_record_1.isPlainRecord)(value))
77
+ return undefined;
78
+ const type = value.type;
79
+ return typeof type === 'string' && exports.RECORD_SAVE_EXPECTED_JSON_TYPES.includes(type)
80
+ ? { type: type }
81
+ : undefined;
82
+ }
83
+ /**
84
+ * Validator parameters are not a generic public bag. This allowlist contains
85
+ * only bounded derived facts needed by shipped translations; submitted values,
86
+ * configured patterns/expressions/descriptions, and provider details stay
87
+ * server-side.
88
+ */
89
+ const PUBLIC_VALIDATOR_PARAMETER_RULES = {
90
+ min: { requiredThreshold: 'number' },
91
+ max: { requiredThreshold: 'number' },
92
+ minLength: { actualLength: 'number', requiredLength: 'number' },
93
+ maxLength: { actualLength: 'number', requiredLength: 'number' },
94
+ required: { required: 'boolean' },
95
+ requiredTrue: { required: 'boolean' },
96
+ 'different-values': { controlCount: 'number', valueCount: 'number' },
97
+ 'typeahead-source': { multiSelect: 'boolean', sourceType: 'source-type' },
98
+ };
99
+ function safeValidatorParameterForRule(value, rule) {
100
+ if (rule === 'number')
101
+ return typeof value === 'number' && Number.isFinite(value) ? value : undefined;
102
+ if (rule === 'boolean')
103
+ return typeof value === 'boolean' ? value : undefined;
104
+ return value === 'static' || value === 'vocabulary' || value === 'query' || value === 'service' ? value : undefined;
105
+ }
106
+ /** Remove non-allowlisted, executable, excessive, and otherwise unsafe validator parameters. */
107
+ function sanitizeRecordSaveValidatorParameters(value, validatorClass) {
108
+ if (!(0, plain_record_1.isPlainRecord)(value)) {
109
+ return undefined;
110
+ }
111
+ const rules = typeof validatorClass === 'string' ? PUBLIC_VALIDATOR_PARAMETER_RULES[validatorClass] : undefined;
112
+ if (!rules)
113
+ return undefined;
114
+ const result = {};
115
+ let acceptedEntries = 0;
116
+ for (const [key, rawValue] of Object.entries(value)) {
117
+ if (acceptedEntries >= exports.RECORD_SAVE_VALIDATOR_PARAMETER_LIMITS.maxEntries) {
118
+ break;
119
+ }
120
+ if (!exports.RECORD_SAVE_VALIDATOR_PARAMETER_KEY_PATTERN.test(key) ||
121
+ key.length > exports.RECORD_SAVE_VALIDATOR_PARAMETER_LIMITS.maxKeyLength) {
122
+ continue;
123
+ }
124
+ const rule = rules[key];
125
+ const safeValue = rule ? safeValidatorParameterForRule(rawValue, rule) : undefined;
126
+ if (safeValue === undefined) {
127
+ continue;
128
+ }
129
+ const candidate = { ...result, [key]: safeValue };
130
+ if (JSON.stringify(candidate).length <= exports.RECORD_SAVE_VALIDATOR_PARAMETER_LIMITS.maxSerializedLength) {
131
+ result[key] = safeValue;
132
+ acceptedEntries += 1;
133
+ }
134
+ }
135
+ return acceptedEntries > 0 ? result : undefined;
136
+ }
137
+ function sanitizeLineagePath(value) {
138
+ if (!Array.isArray(value) || value.length > exports.RECORD_SAVE_LINEAGE_LIMITS.maxSegments) {
139
+ return undefined;
140
+ }
141
+ const result = [];
142
+ for (const segment of value) {
143
+ if (typeof segment === 'string') {
144
+ if (segment.length > exports.RECORD_SAVE_LINEAGE_LIMITS.maxSegmentLength) {
145
+ return undefined;
146
+ }
147
+ result.push(segment);
148
+ }
149
+ else if (typeof segment === 'number' && Number.isSafeInteger(segment) && segment >= 0) {
150
+ result.push(segment);
151
+ }
152
+ else {
153
+ return undefined;
154
+ }
155
+ }
156
+ return result;
157
+ }
158
+ function sanitizeLineagePathProperties(value) {
159
+ if (!(0, plain_record_1.isPlainRecord)(value)) {
160
+ return undefined;
161
+ }
162
+ const result = {};
163
+ for (const key of ['formConfig', 'dataModel', 'angularComponents', 'layout']) {
164
+ if (value[key] !== undefined) {
165
+ const path = sanitizeLineagePath(value[key]);
166
+ if (path !== undefined) {
167
+ result[key] = path;
168
+ }
169
+ }
170
+ }
171
+ return Object.keys(result).length > 0 ? result : undefined;
172
+ }
173
+ function sanitizeLineagePaths(value) {
174
+ if (!(0, plain_record_1.isPlainRecord)(value)) {
175
+ return undefined;
176
+ }
177
+ const result = sanitizeLineagePathProperties(value) ?? {};
178
+ for (const key of ['angularComponentsJsonPointer', 'layoutJsonPointer']) {
179
+ const pointer = value[key];
180
+ if (typeof pointer === 'string' && pointer.length <= exports.RECORD_SAVE_LINEAGE_LIMITS.maxPointerLength) {
181
+ result[key] = pointer;
182
+ }
183
+ }
184
+ return Object.keys(result).length > 0 ? result : undefined;
185
+ }
186
+ /**
187
+ * Copy only the public issue allowlist and normalize bounded validator/lineage
188
+ * metadata. This is suitable for a response serialization boundary.
189
+ */
190
+ function sanitizeRecordSaveIssue(value) {
191
+ const item = (0, plain_record_1.isPlainRecord)(value) ? value : {};
192
+ const issue = {
193
+ message: typeof item.message === 'string' ? item.message.slice(0, exports.RECORD_SAVE_MESSAGE_MAX_LENGTH) : '',
194
+ };
195
+ const code = item.code;
196
+ if (typeof code === 'string' &&
197
+ code.length <= exports.RECORD_SAVE_PUBLIC_FIELD_LIMITS.maxCodeLength &&
198
+ exports.RECORD_SAVE_PUBLIC_IDENTIFIER_PATTERN.test(code))
199
+ issue.code = code;
200
+ const field = item.field;
201
+ if (typeof field === 'string' &&
202
+ field.length <= exports.RECORD_SAVE_PUBLIC_FIELD_LIMITS.maxFieldLength &&
203
+ exports.RECORD_SAVE_PUBLIC_IDENTIFIER_PATTERN.test(field))
204
+ issue.field = field;
205
+ const pointer = item.pointer;
206
+ if (isRecordSaveJsonPointer(pointer) && pointer.length <= exports.RECORD_SAVE_PUBLIC_FIELD_LIMITS.maxPointerLength)
207
+ issue.pointer = pointer;
208
+ const expected = sanitizeRecordSaveIssueExpected(item.expected);
209
+ if (expected !== undefined) {
210
+ issue.expected = expected;
211
+ }
212
+ const attachmentId = item.attachmentId;
213
+ if (typeof attachmentId === 'string' &&
214
+ attachmentId.length <= exports.RECORD_SAVE_PUBLIC_FIELD_LIMITS.maxAttachmentIdLength &&
215
+ exports.RECORD_SAVE_PUBLIC_IDENTIFIER_PATTERN.test(attachmentId))
216
+ issue.attachmentId = attachmentId;
217
+ if (typeof item.class === 'string' &&
218
+ item.class.length <= exports.RECORD_SAVE_VALIDATOR_CLASS_MAX_LENGTH &&
219
+ exports.RECORD_SAVE_PUBLIC_IDENTIFIER_PATTERN.test(item.class)) {
220
+ issue.class = item.class;
221
+ }
222
+ const params = sanitizeRecordSaveValidatorParameters(item.params, issue.class);
223
+ if (params !== undefined) {
224
+ issue.params = params;
225
+ }
226
+ const targetField = sanitizeLineagePathProperties(item.targetField);
227
+ if (targetField !== undefined) {
228
+ issue.targetField = targetField;
229
+ }
230
+ const lineagePaths = sanitizeLineagePaths(item.lineagePaths);
231
+ if (lineagePaths !== undefined) {
232
+ issue.lineagePaths = lineagePaths;
233
+ }
234
+ return issue;
235
+ }
236
+ /** A schema warning can coexist with a complete save; unfinished work cannot. */
237
+ function isRecordSaveComplete(result) {
238
+ const attachmentStatus = result.completion?.attachments?.status;
239
+ if (attachmentStatus !== 'not-required' && attachmentStatus !== 'completed') {
240
+ return false;
241
+ }
242
+ if (result.outcome === 'saved')
243
+ return true;
244
+ if (result.outcome !== 'saved-with-warnings')
245
+ return false;
246
+ return result.problems.length > 0 &&
247
+ result.problems.every(problem => problem.source === 'schema' || problem.source === 'advisory');
248
+ }
249
+ function emptyRecordSaveCompletion() {
250
+ return {
251
+ attachments: {
252
+ status: 'not-required',
253
+ items: [],
254
+ },
255
+ };
256
+ }
257
+ /**
258
+ * Reduce item-level attachment facts into the public aggregate status.
259
+ * Unknown takes precedence over incomplete because it represents less
260
+ * certainty about the physical operation.
261
+ */
262
+ function reduceAttachmentStatus(items) {
263
+ if (items.length === 0) {
264
+ return 'not-required';
265
+ }
266
+ if (items.some(item => item.status === 'unknown')) {
267
+ return 'unknown';
268
+ }
269
+ if (items.some(item => item.status === 'incomplete')) {
270
+ return 'incomplete';
271
+ }
272
+ return 'completed';
273
+ }
274
+ function isRecordSaveOutcome(value) {
275
+ return value === 'saved' || value === 'saved-with-warnings' || value === 'not-saved' || value === 'unknown';
276
+ }
277
+ function isRecordSaveProblemKind(value) {
278
+ return typeof value === 'string' && exports.RECORD_SAVE_PROBLEM_KINDS.includes(value);
279
+ }
280
+ /**
281
+ * Canonical save request-correlation identifier: one RFC 4122 UUID. It is
282
+ * correlation only and is never treated as an idempotency key.
283
+ */
284
+ exports.RECORD_SAVE_REQUEST_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
285
+ exports.RECORD_SAVE_REQUEST_ID_MAX_LENGTH = 36;
286
+ function isRecordSaveRequestId(value) {
287
+ return typeof value === 'string' && exports.RECORD_SAVE_REQUEST_ID_PATTERN.test(value);
288
+ }
289
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb3JkLXNhdmUubW9kZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvcmVjb3JkLXNhdmUubW9kZWwudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7R0FNRzs7O0FBb0hILDBEQVdDO0FBd0NELHNGQWtDQztBQXdERCwwREFxREM7QUEyREQsb0RBU0M7QUFJRCw4REFPQztBQU9ELHdEQWFDO0FBRUQsa0RBRUM7QUFFRCwwREFFQztBQVdELHNEQUVDO0FBM2FELDBEQUF3RDtBQW9CM0MsUUFBQSx5QkFBeUIsR0FBRztJQUN2QyxZQUFZO0lBQ1osWUFBWTtJQUNaLGVBQWU7SUFDZixVQUFVO0lBQ1YsUUFBUTtJQUNSLFNBQVM7Q0FDRCxDQUFDO0FBcUJFLFFBQUEsc0NBQXNDLEdBQUc7SUFDcEQsVUFBVSxFQUFFLEVBQUU7SUFDZCxZQUFZLEVBQUUsRUFBRTtJQUNoQixlQUFlLEVBQUUsR0FBRztJQUNwQixjQUFjLEVBQUUsRUFBRTtJQUNsQixtQkFBbUIsRUFBRSxLQUFLO0NBQ2xCLENBQUM7QUFFRSxRQUFBLHNDQUFzQyxHQUFHLEdBQUcsQ0FBQztBQUM3QyxRQUFBLDhCQUE4QixHQUFHLEtBQUssQ0FBQztBQUN2QyxRQUFBLDJDQUEyQyxHQUFHLDJCQUEyQixDQUFDO0FBQzFFLFFBQUEsK0JBQStCLEdBQUc7SUFDN0MsYUFBYSxFQUFFLEdBQUc7SUFDbEIsY0FBYyxFQUFFLEdBQUc7SUFDbkIsZ0JBQWdCLEVBQUUsS0FBSztJQUN2QixxQkFBcUIsRUFBRSxHQUFHO0NBQ2xCLENBQUM7QUFDRSxRQUFBLHFDQUFxQyxHQUFHLCtCQUErQixDQUFDO0FBRXhFLFFBQUEsK0JBQStCLEdBQUc7SUFDN0MsT0FBTztJQUNQLFNBQVM7SUFDVCxTQUFTO0lBQ1QsTUFBTTtJQUNOLFFBQVE7SUFDUixRQUFRO0lBQ1IsUUFBUTtDQUNBLENBQUM7QUFRRSxRQUFBLDBCQUEwQixHQUFHO0lBQ3hDLFdBQVcsRUFBRSxFQUFFO0lBQ2YsZ0JBQWdCLEVBQUUsR0FBRztJQUNyQixnQkFBZ0IsRUFBRSxLQUFLO0NBQ2YsQ0FBQztBQXlCWCx3RUFBd0U7QUFDeEUsU0FBZ0IsdUJBQXVCLENBQUMsS0FBYztJQUNwRCxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxDQUFDLEtBQUssS0FBSyxFQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQztRQUMxRSxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxLQUFLLElBQUksS0FBSyxHQUFHLENBQUMsRUFBRSxLQUFLLEdBQUcsS0FBSyxDQUFDLE1BQU0sRUFBRSxLQUFLLElBQUksQ0FBQyxFQUFFLENBQUM7UUFDckQsSUFBSSxLQUFLLENBQUMsS0FBSyxDQUFDLEtBQUssR0FBRztZQUFFLFNBQVM7UUFDbkMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQztRQUNqQyxJQUFJLE9BQU8sS0FBSyxHQUFHLElBQUksT0FBTyxLQUFLLEdBQUc7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUNyRCxLQUFLLElBQUksQ0FBQyxDQUFDO0lBQ2IsQ0FBQztJQUNELE9BQU8sSUFBSSxDQUFDO0FBQ2QsQ0FBQztBQUVELFNBQVMsK0JBQStCLENBQUMsS0FBYztJQUNyRCxJQUFJLENBQUMsSUFBQSw0QkFBYSxFQUFDLEtBQUssQ0FBQztRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQzVDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUM7SUFDeEIsT0FBTyxPQUFPLElBQUksS0FBSyxRQUFRLElBQUssdUNBQXFELENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQztRQUN0RyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsSUFBa0MsRUFBRTtRQUM5QyxDQUFDLENBQUMsU0FBUyxDQUFDO0FBQ2hCLENBQUM7QUFHRDs7Ozs7R0FLRztBQUNILE1BQU0sZ0NBQWdDLEdBRWxDO0lBQ0YsR0FBRyxFQUFFLEVBQUUsaUJBQWlCLEVBQUUsUUFBUSxFQUFFO0lBQ3BDLEdBQUcsRUFBRSxFQUFFLGlCQUFpQixFQUFFLFFBQVEsRUFBRTtJQUNwQyxTQUFTLEVBQUUsRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLGNBQWMsRUFBRSxRQUFRLEVBQUU7SUFDL0QsU0FBUyxFQUFFLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSxjQUFjLEVBQUUsUUFBUSxFQUFFO0lBQy9ELFFBQVEsRUFBRSxFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUU7SUFDakMsWUFBWSxFQUFFLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRTtJQUNyQyxrQkFBa0IsRUFBRSxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsVUFBVSxFQUFFLFFBQVEsRUFBRTtJQUNwRSxrQkFBa0IsRUFBRSxFQUFFLFdBQVcsRUFBRSxTQUFTLEVBQUUsVUFBVSxFQUFFLGFBQWEsRUFBRTtDQUMxRSxDQUFDO0FBRUYsU0FBUyw2QkFBNkIsQ0FDcEMsS0FBYyxFQUNkLElBQWtDO0lBRWxDLElBQUksSUFBSSxLQUFLLFFBQVE7UUFBRSxPQUFPLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxNQUFNLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztJQUN0RyxJQUFJLElBQUksS0FBSyxTQUFTO1FBQUUsT0FBTyxPQUFPLEtBQUssS0FBSyxTQUFTLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQzlFLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLEtBQUssWUFBWSxJQUFJLEtBQUssS0FBSyxPQUFPLElBQUksS0FBSyxLQUFLLFNBQVMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDdEgsQ0FBQztBQUVELGdHQUFnRztBQUNoRyxTQUFnQixxQ0FBcUMsQ0FDbkQsS0FBYyxFQUNkLGNBQXdCO0lBRXhCLElBQUksQ0FBQyxJQUFBLDRCQUFhLEVBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUMxQixPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBQ0QsTUFBTSxLQUFLLEdBQUcsT0FBTyxjQUFjLEtBQUssUUFBUSxDQUFDLENBQUMsQ0FBQyxnQ0FBZ0MsQ0FBQyxjQUFjLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDO0lBQ2hILElBQUksQ0FBQyxLQUFLO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDN0IsTUFBTSxNQUFNLEdBQWtDLEVBQUUsQ0FBQztJQUNqRCxJQUFJLGVBQWUsR0FBRyxDQUFDLENBQUM7SUFDeEIsS0FBSyxNQUFNLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztRQUNwRCxJQUFJLGVBQWUsSUFBSSw4Q0FBc0MsQ0FBQyxVQUFVLEVBQUUsQ0FBQztZQUN6RSxNQUFNO1FBQ1IsQ0FBQztRQUNELElBQ0UsQ0FBQyxtREFBMkMsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDO1lBQ3RELEdBQUcsQ0FBQyxNQUFNLEdBQUcsOENBQXNDLENBQUMsWUFBWSxFQUNoRSxDQUFDO1lBQ0QsU0FBUztRQUNYLENBQUM7UUFDRCxNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDeEIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLENBQUMsQ0FBQyw2QkFBNkIsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztRQUVuRixJQUFJLFNBQVMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUM1QixTQUFTO1FBQ1gsQ0FBQztRQUNELE1BQU0sU0FBUyxHQUFHLEVBQUUsR0FBRyxNQUFNLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxTQUFTLEVBQUUsQ0FBQztRQUNsRCxJQUFJLElBQUksQ0FBQyxTQUFTLENBQUMsU0FBUyxDQUFDLENBQUMsTUFBTSxJQUFJLDhDQUFzQyxDQUFDLG1CQUFtQixFQUFFLENBQUM7WUFDbkcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLFNBQVMsQ0FBQztZQUN4QixlQUFlLElBQUksQ0FBQyxDQUFDO1FBQ3ZCLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxlQUFlLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLFNBQVMsQ0FBQztBQUNsRCxDQUFDO0FBRUQsU0FBUyxtQkFBbUIsQ0FBQyxLQUFjO0lBQ3pDLElBQUksQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxJQUFJLEtBQUssQ0FBQyxNQUFNLEdBQUcsa0NBQTBCLENBQUMsV0FBVyxFQUFFLENBQUM7UUFDbkYsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFnQixFQUFFLENBQUM7SUFDL0IsS0FBSyxNQUFNLE9BQU8sSUFBSSxLQUFLLEVBQUUsQ0FBQztRQUM1QixJQUFJLE9BQU8sT0FBTyxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQ2hDLElBQUksT0FBTyxDQUFDLE1BQU0sR0FBRyxrQ0FBMEIsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO2dCQUNqRSxPQUFPLFNBQVMsQ0FBQztZQUNuQixDQUFDO1lBQ0QsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN2QixDQUFDO2FBQU0sSUFBSSxPQUFPLE9BQU8sS0FBSyxRQUFRLElBQUksTUFBTSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUMsSUFBSSxPQUFPLElBQUksQ0FBQyxFQUFFLENBQUM7WUFDeEYsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUN2QixDQUFDO2FBQU0sQ0FBQztZQUNOLE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUM7SUFDSCxDQUFDO0lBQ0QsT0FBTyxNQUFNLENBQUM7QUFDaEIsQ0FBQztBQUVELFNBQVMsNkJBQTZCLENBQUMsS0FBYztJQUNuRCxJQUFJLENBQUMsSUFBQSw0QkFBYSxFQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDMUIsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUF3QixFQUFFLENBQUM7SUFDdkMsS0FBSyxNQUFNLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxXQUFXLEVBQUUsbUJBQW1CLEVBQUUsUUFBUSxDQUFVLEVBQUUsQ0FBQztRQUN0RixJQUFJLEtBQUssQ0FBQyxHQUFHLENBQUMsS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUM3QixNQUFNLElBQUksR0FBRyxtQkFBbUIsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQztZQUM3QyxJQUFJLElBQUksS0FBSyxTQUFTLEVBQUUsQ0FBQztnQkFDdkIsTUFBTSxDQUFDLEdBQUcsQ0FBQyxHQUFHLElBQUksQ0FBQztZQUNyQixDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDN0QsQ0FBQztBQUVELFNBQVMsb0JBQW9CLENBQUMsS0FBYztJQUMxQyxJQUFJLENBQUMsSUFBQSw0QkFBYSxFQUFDLEtBQUssQ0FBQyxFQUFFLENBQUM7UUFDMUIsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUF5Qiw2QkFBNkIsQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDaEYsS0FBSyxNQUFNLEdBQUcsSUFBSSxDQUFDLDhCQUE4QixFQUFFLG1CQUFtQixDQUFVLEVBQUUsQ0FBQztRQUNqRixNQUFNLE9BQU8sR0FBRyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDM0IsSUFBSSxPQUFPLE9BQU8sS0FBSyxRQUFRLElBQUksT0FBTyxDQUFDLE1BQU0sSUFBSSxrQ0FBMEIsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1lBQ2pHLE1BQU0sQ0FBQyxHQUFHLENBQUMsR0FBRyxPQUFPLENBQUM7UUFDeEIsQ0FBQztJQUNILENBQUM7SUFDRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDN0QsQ0FBQztBQUVEOzs7R0FHRztBQUNILFNBQWdCLHVCQUF1QixDQUFDLEtBQWM7SUFDcEQsTUFBTSxJQUFJLEdBQUcsSUFBQSw0QkFBYSxFQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztJQUMvQyxNQUFNLEtBQUssR0FBb0I7UUFDN0IsT0FBTyxFQUFFLE9BQU8sSUFBSSxDQUFDLE9BQU8sS0FBSyxRQUFRLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUMsRUFBRSxzQ0FBOEIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFO0tBQ3ZHLENBQUM7SUFDRixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDO0lBQ3ZCLElBQ0UsT0FBTyxJQUFJLEtBQUssUUFBUTtRQUN4QixJQUFJLENBQUMsTUFBTSxJQUFJLHVDQUErQixDQUFDLGFBQWE7UUFDNUQsNkNBQXFDLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztRQUVoRCxLQUFLLENBQUMsSUFBSSxHQUFHLElBQUksQ0FBQztJQUNwQixNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDO0lBQ3pCLElBQ0UsT0FBTyxLQUFLLEtBQUssUUFBUTtRQUN6QixLQUFLLENBQUMsTUFBTSxJQUFJLHVDQUErQixDQUFDLGNBQWM7UUFDOUQsNkNBQXFDLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQztRQUVqRCxLQUFLLENBQUMsS0FBSyxHQUFHLEtBQUssQ0FBQztJQUN0QixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDO0lBQzdCLElBQUksdUJBQXVCLENBQUMsT0FBTyxDQUFDLElBQUksT0FBTyxDQUFDLE1BQU0sSUFBSSx1Q0FBK0IsQ0FBQyxnQkFBZ0I7UUFDeEcsS0FBSyxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUM7SUFDMUIsTUFBTSxRQUFRLEdBQUcsK0JBQStCLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO0lBQ2hFLElBQUksUUFBUSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQzNCLEtBQUssQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDO0lBQzVCLENBQUM7SUFDRCxNQUFNLFlBQVksR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDO0lBQ3ZDLElBQ0UsT0FBTyxZQUFZLEtBQUssUUFBUTtRQUNoQyxZQUFZLENBQUMsTUFBTSxJQUFJLHVDQUErQixDQUFDLHFCQUFxQjtRQUM1RSw2Q0FBcUMsQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDO1FBRXhELEtBQUssQ0FBQyxZQUFZLEdBQUcsWUFBWSxDQUFDO0lBQ3BDLElBQ0UsT0FBTyxJQUFJLENBQUMsS0FBSyxLQUFLLFFBQVE7UUFDOUIsSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLElBQUksOENBQXNDO1FBQzNELDZDQUFxQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQ3RELENBQUM7UUFDRCxLQUFLLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUM7SUFDM0IsQ0FBQztJQUNELE1BQU0sTUFBTSxHQUFHLHFDQUFxQyxDQUFDLElBQUksQ0FBQyxNQUFNLEVBQUUsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQy9FLElBQUksTUFBTSxLQUFLLFNBQVMsRUFBRSxDQUFDO1FBQ3pCLEtBQUssQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO0lBQ3hCLENBQUM7SUFDRCxNQUFNLFdBQVcsR0FBRyw2QkFBNkIsQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLENBQUM7SUFDcEUsSUFBSSxXQUFXLEtBQUssU0FBUyxFQUFFLENBQUM7UUFDOUIsS0FBSyxDQUFDLFdBQVcsR0FBRyxXQUFXLENBQUM7SUFDbEMsQ0FBQztJQUNELE1BQU0sWUFBWSxHQUFHLG9CQUFvQixDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsQ0FBQztJQUM3RCxJQUFJLFlBQVksS0FBSyxTQUFTLEVBQUUsQ0FBQztRQUMvQixLQUFLLENBQUMsWUFBWSxHQUFHLFlBQVksQ0FBQztJQUNwQyxDQUFDO0lBQ0QsT0FBTyxLQUFLLENBQUM7QUFDZixDQUFDO0FBMERELGlGQUFpRjtBQUNqRixTQUFnQixvQkFBb0IsQ0FBQyxNQUFxRTtJQUN4RyxNQUFNLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxVQUFVLEVBQUUsV0FBVyxFQUFFLE1BQU0sQ0FBQztJQUNoRSxJQUFJLGdCQUFnQixLQUFLLGNBQWMsSUFBSSxnQkFBZ0IsS0FBSyxXQUFXLEVBQUUsQ0FBQztRQUM1RSxPQUFPLEtBQUssQ0FBQztJQUNmLENBQUM7SUFDRCxJQUFJLE1BQU0sQ0FBQyxPQUFPLEtBQUssT0FBTztRQUFFLE9BQU8sSUFBSSxDQUFDO0lBQzVDLElBQUksTUFBTSxDQUFDLE9BQU8sS0FBSyxxQkFBcUI7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUMzRCxPQUFPLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxHQUFHLENBQUM7UUFDL0IsTUFBTSxDQUFDLFFBQVEsQ0FBQyxLQUFLLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxLQUFLLFFBQVEsSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLFVBQVUsQ0FBQyxDQUFDO0FBQ25HLENBQUM7QUFJRCxTQUFnQix5QkFBeUI7SUFDdkMsT0FBTztRQUNMLFdBQVcsRUFBRTtZQUNYLE1BQU0sRUFBRSxjQUFjO1lBQ3RCLEtBQUssRUFBRSxFQUFFO1NBQ1Y7S0FDRixDQUFDO0FBQ0osQ0FBQztBQUVEOzs7O0dBSUc7QUFDSCxTQUFnQixzQkFBc0IsQ0FDcEMsS0FBZ0Q7SUFFaEQsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1FBQ3ZCLE9BQU8sY0FBYyxDQUFDO0lBQ3hCLENBQUM7SUFDRCxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsTUFBTSxLQUFLLFNBQVMsQ0FBQyxFQUFFLENBQUM7UUFDbEQsT0FBTyxTQUFTLENBQUM7SUFDbkIsQ0FBQztJQUNELElBQUksS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxNQUFNLEtBQUssWUFBWSxDQUFDLEVBQUUsQ0FBQztRQUNyRCxPQUFPLFlBQVksQ0FBQztJQUN0QixDQUFDO0lBQ0QsT0FBTyxXQUFXLENBQUM7QUFDckIsQ0FBQztBQUVELFNBQWdCLG1CQUFtQixDQUFDLEtBQWM7SUFDaEQsT0FBTyxLQUFLLEtBQUssT0FBTyxJQUFJLEtBQUssS0FBSyxxQkFBcUIsSUFBSSxLQUFLLEtBQUssV0FBVyxJQUFJLEtBQUssS0FBSyxTQUFTLENBQUM7QUFDOUcsQ0FBQztBQUVELFNBQWdCLHVCQUF1QixDQUFDLEtBQWM7SUFDcEQsT0FBTyxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUssaUNBQStDLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBQ3ZHLENBQUM7QUFFRDs7O0dBR0c7QUFDVSxRQUFBLDhCQUE4QixHQUN6Qyw0RUFBNEUsQ0FBQztBQUVsRSxRQUFBLGlDQUFpQyxHQUFHLEVBQUUsQ0FBQztBQUVwRCxTQUFnQixxQkFBcUIsQ0FBQyxLQUFjO0lBQ2xELE9BQU8sT0FBTyxLQUFLLEtBQUssUUFBUSxJQUFJLHNDQUE4QixDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztBQUNqRixDQUFDIn0=
@@ -0,0 +1,3 @@
1
+ /** Testing-only shared fixtures. This module is intentionally outside the production root barrel. */
2
+ export * from './jsonata-parity.fixtures';
3
+ export * from './validation/validation-groups.fixtures';
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ /** Testing-only shared fixtures. This module is intentionally outside the production root barrel. */
18
+ __exportStar(require("./jsonata-parity.fixtures"), exports);
19
+ __exportStar(require("./validation/validation-groups.fixtures"), exports);
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidGVzdGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy90ZXN0aW5nLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7QUFBQSxxR0FBcUc7QUFDckcsNERBQTBDO0FBQzFDLDBFQUF3RCJ9
@@ -0,0 +1,84 @@
1
+ /** Public operation names are small, case-sensitive identifiers. */
2
+ export declare const VALIDATION_OPERATION_NAME_MAX_LENGTH = 64;
3
+ export declare const VALIDATION_OPERATION_NAME_PATTERN: RegExp;
4
+ /** Bounded display metadata limits used at the public discovery boundary. */
5
+ export declare const VALIDATION_OPERATION_LABEL_MAX_LENGTH = 256;
6
+ export declare const VALIDATION_OPERATION_DESCRIPTION_MAX_LENGTH = 1024;
7
+ /** Safe server-owned references used by validation workflow/form discovery. */
8
+ export declare const RECORD_VALIDATION_REFERENCE_PATTERN: RegExp;
9
+ /** Deterministic ordering for public validation identifiers. */
10
+ export declare function compareRecordValidationIdentifiers(left: string, right: string): number;
11
+ /** Normalize bounded public display text without coercing hostile values. */
12
+ export declare function safeValidationDiscoveryText(value: unknown, maxLength: number): string | undefined;
13
+ /**
14
+ * A server-owned validation intent and its form-level defaults.
15
+ *
16
+ * Operation names are configuration keys (for example `draft` or `publish`),
17
+ * rather than values from a fixed framework enum.
18
+ */
19
+ export interface ValidationOperationDefinition {
20
+ /** The exact validation-group set to use for this operation. */
21
+ enabledValidationGroups: string[];
22
+ /** Optional safe display label. */
23
+ label?: string;
24
+ /** Optional safe display description. */
25
+ description?: string;
26
+ /** Roles allowed to use the operation. Omission adds no role restriction. */
27
+ roles?: string[];
28
+ /** Workflow targets allowed for the operation. Omission adds no target restriction. */
29
+ allowedTargetSteps?: string[];
30
+ }
31
+ /**
32
+ * A more-specific operation layer. Defined properties replace or restrict the
33
+ * corresponding form-level defaults; omitted properties inherit them.
34
+ */
35
+ export interface ValidationOperationOverride extends Partial<ValidationOperationDefinition> {
36
+ /** Optional rollout-mode override for this operation. */
37
+ mode?: ValidationMode;
38
+ }
39
+ /**
40
+ * Workflow stages may refine operation policy, but rollout mode is deliberately
41
+ * not stage-scoped. Enforcement remains a `(record type, operation)` decision.
42
+ */
43
+ export type ValidationOperationPolicyOverride = Omit<ValidationOperationOverride, 'mode'> & {
44
+ mode?: never;
45
+ };
46
+ /** Safe operation metadata suitable for discovery responses. */
47
+ export interface ValidationOperationDiscovery {
48
+ name: string;
49
+ label?: string;
50
+ description?: string;
51
+ /**
52
+ * Actor-authorized transition targets applicable to this operation. An
53
+ * unrestricted operation receives every actor-authorized target.
54
+ */
55
+ allowedTargetSteps?: string[];
56
+ }
57
+ /**
58
+ * Project an untrusted service result onto the complete public discovery
59
+ * contract. Optional target authorization can only narrow reported targets.
60
+ */
61
+ export declare function sanitizeValidationOperationDiscovery(value: unknown, authorizedTargetSteps?: ReadonlySet<string>): ValidationOperationDiscovery | undefined;
62
+ /** Whether authoritative validation observes or rejects a failed save. */
63
+ export type ValidationMode = 'shadow' | 'enforce';
64
+ /** Safe diagnostic severity shared by group resolution and server validation. */
65
+ export type RecordValidationDiagnosticSeverity = 'info' | 'warning' | 'error';
66
+ /**
67
+ * A safe diagnostic from validation configuration or execution.
68
+ *
69
+ * This contract intentionally has no arbitrary details bag: raw records,
70
+ * requests, users, parameters, and exceptions must not enter diagnostics.
71
+ */
72
+ export interface RecordValidationDiagnostic {
73
+ code: string;
74
+ severity: RecordValidationDiagnosticSeverity;
75
+ message: string;
76
+ formName?: string;
77
+ operation?: string;
78
+ group?: string;
79
+ field?: string;
80
+ pointer?: string;
81
+ /** Safe configured expression name; never an expression source or value. */
82
+ expressionName?: string;
83
+ validatorClass?: string;
84
+ }
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.RECORD_VALIDATION_REFERENCE_PATTERN = exports.VALIDATION_OPERATION_DESCRIPTION_MAX_LENGTH = exports.VALIDATION_OPERATION_LABEL_MAX_LENGTH = exports.VALIDATION_OPERATION_NAME_PATTERN = exports.VALIDATION_OPERATION_NAME_MAX_LENGTH = void 0;
4
+ exports.compareRecordValidationIdentifiers = compareRecordValidationIdentifiers;
5
+ exports.safeValidationDiscoveryText = safeValidationDiscoveryText;
6
+ exports.sanitizeValidationOperationDiscovery = sanitizeValidationOperationDiscovery;
7
+ /** Public operation names are small, case-sensitive identifiers. */
8
+ exports.VALIDATION_OPERATION_NAME_MAX_LENGTH = 64;
9
+ exports.VALIDATION_OPERATION_NAME_PATTERN = /^[A-Za-z][A-Za-z0-9._-]{0,63}$/;
10
+ /** Bounded display metadata limits used at the public discovery boundary. */
11
+ exports.VALIDATION_OPERATION_LABEL_MAX_LENGTH = 256;
12
+ exports.VALIDATION_OPERATION_DESCRIPTION_MAX_LENGTH = 1024;
13
+ /** Safe server-owned references used by validation workflow/form discovery. */
14
+ exports.RECORD_VALIDATION_REFERENCE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/;
15
+ /** Deterministic ordering for public validation identifiers. */
16
+ function compareRecordValidationIdentifiers(left, right) {
17
+ return left < right ? -1 : left > right ? 1 : 0;
18
+ }
19
+ /** Normalize bounded public display text without coercing hostile values. */
20
+ function safeValidationDiscoveryText(value, maxLength) {
21
+ if (typeof value !== 'string')
22
+ return undefined;
23
+ const normalized = value.trim();
24
+ return normalized && normalized.length <= maxLength ? normalized : undefined;
25
+ }
26
+ /**
27
+ * Project an untrusted service result onto the complete public discovery
28
+ * contract. Optional target authorization can only narrow reported targets.
29
+ */
30
+ function sanitizeValidationOperationDiscovery(value, authorizedTargetSteps) {
31
+ if (!value || typeof value !== 'object' || Array.isArray(value))
32
+ return undefined;
33
+ const candidate = value;
34
+ const name = typeof candidate.name === 'string' ? candidate.name.trim() : '';
35
+ if (!exports.VALIDATION_OPERATION_NAME_PATTERN.test(name))
36
+ return undefined;
37
+ const label = safeValidationDiscoveryText(candidate.label, exports.VALIDATION_OPERATION_LABEL_MAX_LENGTH);
38
+ const description = safeValidationDiscoveryText(candidate.description, exports.VALIDATION_OPERATION_DESCRIPTION_MAX_LENGTH);
39
+ const allowedTargetSteps = Array.isArray(candidate.allowedTargetSteps)
40
+ ? [...new Set(candidate.allowedTargetSteps
41
+ .filter((step) => typeof step === 'string')
42
+ .map(step => step.trim())
43
+ .filter(step => exports.RECORD_VALIDATION_REFERENCE_PATTERN.test(step) &&
44
+ (authorizedTargetSteps === undefined || authorizedTargetSteps.has(step))))].sort(compareRecordValidationIdentifiers)
45
+ : [];
46
+ return {
47
+ name,
48
+ ...(label ? { label } : {}),
49
+ ...(description ? { description } : {}),
50
+ ...(allowedTargetSteps.length > 0 ? { allowedTargetSteps } : {}),
51
+ };
52
+ }
53
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVjb3JkLXZhbGlkYXRpb24ubW9kZWwuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvdmFsaWRhdGlvbi9yZWNvcmQtdmFsaWRhdGlvbi5tb2RlbC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFZQSxnRkFFQztBQUdELGtFQUlDO0FBc0RELG9GQTRCQztBQXZHRCxvRUFBb0U7QUFDdkQsUUFBQSxvQ0FBb0MsR0FBRyxFQUFFLENBQUM7QUFDMUMsUUFBQSxpQ0FBaUMsR0FBRyxnQ0FBZ0MsQ0FBQztBQUVsRiw2RUFBNkU7QUFDaEUsUUFBQSxxQ0FBcUMsR0FBRyxHQUFHLENBQUM7QUFDNUMsUUFBQSwyQ0FBMkMsR0FBRyxJQUFJLENBQUM7QUFFaEUsK0VBQStFO0FBQ2xFLFFBQUEsbUNBQW1DLEdBQUcscUNBQXFDLENBQUM7QUFFekYsZ0VBQWdFO0FBQ2hFLFNBQWdCLGtDQUFrQyxDQUFDLElBQVksRUFBRSxLQUFhO0lBQzVFLE9BQU8sSUFBSSxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0FBQ2xELENBQUM7QUFFRCw2RUFBNkU7QUFDN0UsU0FBZ0IsMkJBQTJCLENBQUMsS0FBYyxFQUFFLFNBQWlCO0lBQzNFLElBQUksT0FBTyxLQUFLLEtBQUssUUFBUTtRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ2hELE1BQU0sVUFBVSxHQUFHLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNoQyxPQUFPLFVBQVUsSUFBSSxVQUFVLENBQUMsTUFBTSxJQUFJLFNBQVMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDL0UsQ0FBQztBQWtERDs7O0dBR0c7QUFDSCxTQUFnQixvQ0FBb0MsQ0FDbEQsS0FBYyxFQUNkLHFCQUEyQztJQUUzQyxJQUFJLENBQUMsS0FBSyxJQUFJLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQztRQUFFLE9BQU8sU0FBUyxDQUFDO0lBQ2xGLE1BQU0sU0FBUyxHQUFHLEtBQWdDLENBQUM7SUFDbkQsTUFBTSxJQUFJLEdBQUcsT0FBTyxTQUFTLENBQUMsSUFBSSxLQUFLLFFBQVEsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQzdFLElBQUksQ0FBQyx5Q0FBaUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQUUsT0FBTyxTQUFTLENBQUM7SUFDcEUsTUFBTSxLQUFLLEdBQUcsMkJBQTJCLENBQUMsU0FBUyxDQUFDLEtBQUssRUFBRSw2Q0FBcUMsQ0FBQyxDQUFDO0lBQ2xHLE1BQU0sV0FBVyxHQUFHLDJCQUEyQixDQUM3QyxTQUFTLENBQUMsV0FBVyxFQUNyQixtREFBMkMsQ0FDNUMsQ0FBQztJQUNGLE1BQU0sa0JBQWtCLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsa0JBQWtCLENBQUM7UUFDcEUsQ0FBQyxDQUFDLENBQUMsR0FBRyxJQUFJLEdBQUcsQ0FBQyxTQUFTLENBQUMsa0JBQWtCO2lCQUNyQyxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQWtCLEVBQUUsQ0FBQyxPQUFPLElBQUksS0FBSyxRQUFRLENBQUM7aUJBQzFELEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztpQkFDeEIsTUFBTSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQ2IsMkNBQW1DLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztnQkFDOUMsQ0FBQyxxQkFBcUIsS0FBSyxTQUFTLElBQUkscUJBQXFCLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQ3pFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQyxrQ0FBa0MsQ0FBQztRQUNoRCxDQUFDLENBQUMsRUFBRSxDQUFDO0lBQ1AsT0FBTztRQUNMLElBQUk7UUFDSixHQUFHLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDM0IsR0FBRyxDQUFDLFdBQVcsQ0FBQyxDQUFDLENBQUMsRUFBRSxXQUFXLEVBQUUsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDO1FBQ3ZDLEdBQUcsQ0FBQyxrQkFBa0IsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLGtCQUFrQixFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQztLQUNqRSxDQUFDO0FBQ0osQ0FBQyJ9
@@ -0,0 +1,29 @@
1
+ import { FormFieldValidationGroup, FormValidationGroups } from './form.model';
2
+ import { RecordValidationDiagnostic } from './record-validation.model';
3
+ /** Initial source used by a validation-group change. */
4
+ export declare const formValidationGroupsChangeInitial: readonly ["all", "none", "current", "empty"];
5
+ /**
6
+ * `empty` is retained as a deprecated alias for `none` so stored legacy form
7
+ * expressions continue to work while producing an observable diagnostic.
8
+ */
9
+ export type FormValidationGroupsChangeInitial = (typeof formValidationGroupsChangeInitial)[number];
10
+ export interface ValidationGroupCalculationResult {
11
+ enabledValidationGroups: string[];
12
+ diagnostics: RecordValidationDiagnostic[];
13
+ }
14
+ export declare const VALIDATION_GROUP_EMPTY_INITIAL_DIAGNOSTIC: "validation-group-initial-empty-deprecated";
15
+ export declare const VALIDATION_GROUP_UNKNOWN_INITIAL_DIAGNOSTIC: "validation-group-initial-unknown";
16
+ /**
17
+ * Fold one validation-group change using the historical Angular semantics.
18
+ *
19
+ * Important compatibility behavior:
20
+ * - an empty resulting array is preserved (ValidatorsSupport interprets it as
21
+ * all validators);
22
+ * - `none`/legacy `empty` start from an empty array, while the configured
23
+ * `none` group is represented by the literal group name `none`;
24
+ * - includes append only missing names and excludes remove the first present
25
+ * occurrence, matching the original client implementation;
26
+ * - unknown names are retained for the authoritative caller to diagnose;
27
+ * - an operation group array, when supplied, replaces the folded array last.
28
+ */
29
+ export declare function calculateValidationGroups(currentValidationGroups: readonly string[], validationGroups: Readonly<FormValidationGroups>, initial?: FormValidationGroupsChangeInitial, groups?: FormFieldValidationGroup, operationEnabledValidationGroups?: readonly string[]): ValidationGroupCalculationResult;