ngx-dynamic-entity 0.0.1 → 1.1.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.
Files changed (84) hide show
  1. package/README.md +129 -0
  2. package/esm2022/lib/field-types/array-field.component.mjs +160 -0
  3. package/esm2022/lib/field-types/boolean-field.component.mjs +100 -0
  4. package/esm2022/lib/field-types/checkbox-field.component.mjs +25 -17
  5. package/esm2022/lib/field-types/currency-field.component.mjs +101 -0
  6. package/esm2022/lib/field-types/date-field.component.mjs +21 -13
  7. package/esm2022/lib/field-types/dropdown-field.component.mjs +120 -29
  8. package/esm2022/lib/field-types/email-field.component.mjs +101 -0
  9. package/esm2022/lib/field-types/entity-ref-field.component.mjs +96 -32
  10. package/esm2022/lib/field-types/file-field.component.mjs +156 -0
  11. package/esm2022/lib/field-types/group-field.component.mjs +89 -0
  12. package/esm2022/lib/field-types/image-field.component.mjs +168 -0
  13. package/esm2022/lib/field-types/month-year-field.component.mjs +151 -0
  14. package/esm2022/lib/field-types/multi-select-field.component.mjs +79 -25
  15. package/esm2022/lib/field-types/number-field.component.mjs +60 -17
  16. package/esm2022/lib/field-types/password-field.component.mjs +109 -0
  17. package/esm2022/lib/field-types/radio-field.component.mjs +152 -0
  18. package/esm2022/lib/field-types/text-field.component.mjs +58 -18
  19. package/esm2022/lib/field-types/textarea-field.component.mjs +26 -15
  20. package/esm2022/lib/form/dynamic-field/dynamic-field.component.mjs +44 -26
  21. package/esm2022/lib/form/dynamic-form.component.mjs +676 -69
  22. package/esm2022/lib/form/dynamic-record-form.component.mjs +494 -0
  23. package/esm2022/lib/providers/provide-field-types.mjs +72 -0
  24. package/esm2022/lib/providers/provide-ngx-dynamic-entity.mjs +4 -5
  25. package/esm2022/lib/services/cascade-data.service.mjs +129 -0
  26. package/esm2022/lib/services/config-source.service.mjs +67 -0
  27. package/esm2022/lib/services/entity-ref-cache.mjs +20 -0
  28. package/esm2022/lib/services/entity-ref-registry.service.mjs +3 -3
  29. package/esm2022/lib/services/entity-ref-selection.service.mjs +27 -0
  30. package/esm2022/lib/services/entity-reference.service.mjs +168 -0
  31. package/esm2022/lib/services/field-registry.service.mjs +35 -30
  32. package/esm2022/lib/services/file-upload.service.mjs +89 -0
  33. package/esm2022/lib/services/lookup-registry.service.mjs +246 -0
  34. package/esm2022/lib/services/rbac.service.mjs +5 -11
  35. package/esm2022/lib/services/rules-evaluation.service.mjs +27 -0
  36. package/esm2022/lib/services/validator-registry.service.mjs +35 -7
  37. package/esm2022/lib/tokens/injection-tokens.mjs +104 -7
  38. package/esm2022/public-api.mjs +31 -6
  39. package/fesm2022/ngx-dynamic-entity.mjs +4094 -759
  40. package/fesm2022/ngx-dynamic-entity.mjs.map +1 -1
  41. package/lib/field-types/array-field.component.d.ts +22 -0
  42. package/lib/field-types/boolean-field.component.d.ts +18 -0
  43. package/lib/field-types/checkbox-field.component.d.ts +3 -2
  44. package/lib/field-types/currency-field.component.d.ts +17 -0
  45. package/lib/field-types/date-field.component.d.ts +3 -2
  46. package/lib/field-types/dropdown-field.component.d.ts +24 -4
  47. package/lib/field-types/email-field.component.d.ts +15 -0
  48. package/lib/field-types/entity-ref-field.component.d.ts +24 -11
  49. package/lib/field-types/file-field.component.d.ts +25 -0
  50. package/lib/field-types/group-field.component.d.ts +17 -0
  51. package/lib/field-types/image-field.component.d.ts +30 -0
  52. package/lib/field-types/month-year-field.component.d.ts +28 -0
  53. package/lib/field-types/multi-select-field.component.d.ts +18 -4
  54. package/lib/field-types/number-field.component.d.ts +5 -2
  55. package/lib/field-types/password-field.component.d.ts +17 -0
  56. package/lib/field-types/radio-field.component.d.ts +33 -0
  57. package/lib/field-types/text-field.component.d.ts +5 -3
  58. package/lib/field-types/textarea-field.component.d.ts +4 -2
  59. package/lib/form/dynamic-field/dynamic-field.component.d.ts +20 -7
  60. package/lib/form/dynamic-form.component.d.ts +203 -24
  61. package/lib/form/dynamic-record-form.component.d.ts +180 -0
  62. package/lib/providers/provide-field-types.d.ts +24 -0
  63. package/lib/providers/provide-ngx-dynamic-entity.d.ts +19 -8
  64. package/lib/services/cascade-data.service.d.ts +45 -0
  65. package/lib/services/config-source.service.d.ts +14 -0
  66. package/lib/services/entity-ref-cache.d.ts +27 -0
  67. package/lib/services/entity-ref-registry.service.d.ts +4 -3
  68. package/lib/services/entity-ref-selection.service.d.ts +24 -0
  69. package/lib/services/entity-reference.service.d.ts +49 -0
  70. package/lib/services/field-registry.service.d.ts +17 -7
  71. package/lib/services/file-upload.service.d.ts +27 -0
  72. package/lib/services/lookup-registry.service.d.ts +94 -0
  73. package/lib/services/rbac.service.d.ts +4 -9
  74. package/lib/services/rules-evaluation.service.d.ts +17 -0
  75. package/lib/services/validator-registry.service.d.ts +5 -4
  76. package/lib/tokens/injection-tokens.d.ts +113 -8
  77. package/package.json +18 -8
  78. package/public-api.d.ts +21 -4
  79. package/esm2022/lib/services/config.service.mjs +0 -58
  80. package/esm2022/lib/services/version.service.mjs +0 -40
  81. package/esm2022/lib/table/dynamic-table.component.mjs +0 -160
  82. package/lib/services/config.service.d.ts +0 -25
  83. package/lib/services/version.service.d.ts +0 -26
  84. package/lib/table/dynamic-table.component.d.ts +0 -56
@@ -0,0 +1,246 @@
1
+ import { Injectable, inject } from '@angular/core';
2
+ import { lookupValuesToOptions, normalizeLookupValues, resolveLabel } from '@dynamic-entity/core';
3
+ import { LOOKUP_REGISTRY } from '../tokens/injection-tokens';
4
+ import * as i0 from "@angular/core";
5
+ /** Cache-key field separator. Kept out of template literals so it stays visible in source. */
6
+ const SEP = '|';
7
+ /**
8
+ * LookupRegistryService — the cache in front of consumer-registered master lists.
9
+ *
10
+ * Three layers, deliberately the same shape as `EntityReferenceService`, because the problem is
11
+ * the same: one list is typically used by many fields across many entities.
12
+ * 1. **options** — resolved `DropdownOption[]` per (list name, lang).
13
+ * 2. **in-flight** — the pending Promise, so N fields on one list trigger one load, not N.
14
+ * 3. **labels** — synchronous value → text (parity plan §6.2). This is not a nicety: since
15
+ * `viewMode` defaults to true a record opens read-only, so rendering a stored value as
16
+ * text is the *first* thing a `listName` field has to do. An async-only registry would
17
+ * paint the raw stored value and then flip, on every record open.
18
+ *
19
+ * A failed load rejects and caches nothing, so one transient error does not serve an empty
20
+ * list forever — the same fix made for entity references in phase 5.
21
+ */
22
+ export class LookupRegistryService {
23
+ registry = inject(LOOKUP_REGISTRY, { optional: true }) ?? new Map();
24
+ /** `listName|lang` -> resolved options. */
25
+ options = new Map();
26
+ /** `listName|lang` -> normalised values, so a consumer can reach `code` / `isSystemDefined`. */
27
+ values = new Map();
28
+ /** Loads in progress, keyed as above. */
29
+ inFlight = new Map();
30
+ /** `listName|lang|text` -> display text, for the synchronous read-only path. */
31
+ labels = new Map();
32
+ has(listName) {
33
+ return this.registry.has(listName);
34
+ }
35
+ /**
36
+ * Options for a named list, from cache when present.
37
+ * Concurrent callers with the same key share one load.
38
+ */
39
+ async load(listName, lang = 'en') {
40
+ const key = this.cacheKey(listName, lang);
41
+ const cached = this.options.get(key);
42
+ if (cached)
43
+ return cached;
44
+ const pending = this.inFlight.get(key);
45
+ if (pending)
46
+ return pending;
47
+ const source = this.registry.get(listName);
48
+ if (source === undefined)
49
+ return [];
50
+ const load = this.invoke(source, lang).then(raw => {
51
+ const values = normalizeLookupValues(raw);
52
+ const options = lookupValuesToOptions(values);
53
+ this.values.set(key, values);
54
+ this.options.set(key, options);
55
+ this.rememberLabels(listName, lang, options);
56
+ return options;
57
+ });
58
+ // Only the `.then` above writes to the cache, and a rejection skips it: the caller still
59
+ // gets an empty list, but the next call retries instead of reading a poisoned entry.
60
+ const guarded = load
61
+ .catch(() => [])
62
+ .finally(() => this.inFlight.delete(key));
63
+ this.inFlight.set(key, guarded);
64
+ return guarded;
65
+ }
66
+ /** Cached options without triggering a load. `undefined` when not loaded. */
67
+ peek(listName, lang = 'en') {
68
+ return this.options.get(this.cacheKey(listName, lang));
69
+ }
70
+ /**
71
+ * Cached list values, carrying `_id`, `code`, `isSystemDefined` and `from`.
72
+ * The library never reads those; this is the seam for a consumer that needs them.
73
+ */
74
+ valuesFor(listName, lang = 'en') {
75
+ return this.values.get(this.cacheKey(listName, lang));
76
+ }
77
+ /**
78
+ * Display text for a stored value, synchronously. `undefined` when the list has not loaded
79
+ * or holds no matching value — the caller keeps its own fallback, which is the stored text.
80
+ *
81
+ * Every language of an option is indexed, so a record saved under one language renders in
82
+ * another: a value stored as `'Aktiv'` resolves to `'Active'` under `lang: 'en'`.
83
+ */
84
+ labelFor(listName, value, lang = 'en') {
85
+ if (!listName || value === null || value === undefined || value === '')
86
+ return undefined;
87
+ for (const text of this.candidateTexts(value, lang)) {
88
+ const hit = this.labels.get(this.labelKey(listName, lang, text));
89
+ if (hit)
90
+ return hit;
91
+ }
92
+ return undefined;
93
+ }
94
+ // ─── Field-level resolution — inline options win, else `listName` ────────────
95
+ /** True when this field's options have to come from the registry. */
96
+ needsResolve(field) {
97
+ return !!field?.listName && !field.options?.length;
98
+ }
99
+ /**
100
+ * The options to render right now, without awaiting: inline options, else whatever the
101
+ * registry already holds. Empty on a cold miss — pair with `resolveOptions`.
102
+ */
103
+ optionsFor(field, lang = 'en') {
104
+ if (!field)
105
+ return [];
106
+ if (field.options?.length)
107
+ return field.options;
108
+ if (!field.listName)
109
+ return [];
110
+ return this.peek(field.listName, lang) ?? [];
111
+ }
112
+ /** The options for a field, loading the named list if needed. */
113
+ resolveOptions(field, lang = 'en') {
114
+ if (!this.needsResolve(field))
115
+ return Promise.resolve(this.optionsFor(field, lang));
116
+ return this.load(field.listName, lang);
117
+ }
118
+ /** Drop everything cached for one list, leaving other lists intact. */
119
+ invalidate(listName) {
120
+ const prefix = `${listName}${SEP}`;
121
+ for (const map of [this.options, this.values, this.inFlight]) {
122
+ for (const key of [...map.keys()]) {
123
+ if (key.startsWith(prefix))
124
+ map.delete(key);
125
+ }
126
+ }
127
+ for (const key of [...this.labels.keys()]) {
128
+ if (key.startsWith(prefix))
129
+ this.labels.delete(key);
130
+ }
131
+ }
132
+ clear() {
133
+ this.options.clear();
134
+ this.values.clear();
135
+ this.inFlight.clear();
136
+ this.labels.clear();
137
+ }
138
+ // ─── Internals ──────────────────────────────────────────────────────────────
139
+ cacheKey(listName, lang) {
140
+ return [listName, lang].join(SEP);
141
+ }
142
+ labelKey(listName, lang, text) {
143
+ return [listName, lang, text].join(SEP);
144
+ }
145
+ /** Index an option under every language it carries, so any stored spelling finds it. */
146
+ rememberLabels(listName, lang, options) {
147
+ for (const option of options) {
148
+ const display = resolveLabel(option, lang);
149
+ if (!display)
150
+ continue;
151
+ for (const text of Object.values(option)) {
152
+ if (typeof text === 'string' && text !== '') {
153
+ this.labels.set(this.labelKey(listName, lang, text), display);
154
+ }
155
+ }
156
+ }
157
+ }
158
+ /** The texts a stored value could have been indexed under. */
159
+ candidateTexts(value, lang) {
160
+ if (typeof value === 'object') {
161
+ const texts = Object.values(value).filter((v) => typeof v === 'string' && v !== '');
162
+ const resolved = resolveLabel(value, lang);
163
+ return resolved ? [resolved, ...texts] : texts;
164
+ }
165
+ return [String(value)];
166
+ }
167
+ // ─── Source coercion (values | loader, array | Promise | Observable) ─────────
168
+ invoke(source, lang) {
169
+ let result;
170
+ try {
171
+ result = typeof source === 'function' ? source({ lang }) : source;
172
+ }
173
+ catch (err) {
174
+ // Reject rather than resolve empty: `load` must be able to tell failure from an empty
175
+ // list, or it would cache the failure.
176
+ return Promise.reject(err);
177
+ }
178
+ return this.toPromise(result);
179
+ }
180
+ toPromise(result) {
181
+ if (Array.isArray(result))
182
+ return Promise.resolve(result);
183
+ if (this.isSubscribable(result)) {
184
+ // First emission wins, so a stream that stays open still resolves the load.
185
+ return new Promise((resolve, reject) => {
186
+ let settled = false;
187
+ const settle = (fn) => {
188
+ if (settled)
189
+ return;
190
+ settled = true;
191
+ fn();
192
+ };
193
+ result.subscribe({
194
+ next: value => settle(() => resolve(value ?? [])),
195
+ error: err => settle(() => reject(err)),
196
+ // Completing without emitting is a legitimate empty list, and is cached.
197
+ complete: () => settle(() => resolve([])),
198
+ });
199
+ });
200
+ }
201
+ return Promise.resolve(result);
202
+ }
203
+ isSubscribable(value) {
204
+ return (typeof value === 'object' &&
205
+ value !== null &&
206
+ typeof value.subscribe === 'function');
207
+ }
208
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LookupRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
209
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LookupRegistryService, providedIn: 'root' });
210
+ }
211
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: LookupRegistryService, decorators: [{
212
+ type: Injectable,
213
+ args: [{ providedIn: 'root' }]
214
+ }] });
215
+ const hostLastConfig = new WeakMap();
216
+ /**
217
+ * Point a choice component's `options` signal at the right source (parity plan §6.3).
218
+ *
219
+ * Called from the `field` / `language` input setters of `dropdown`, `radio` and `multiSelect` —
220
+ * the wiring is theirs, the decision is the service's, which is what keeps the ADR-008
221
+ * five-input contract intact: options are never pushed in as a sixth input.
222
+ *
223
+ * Setters rather than `ngOnChanges` on purpose. `ngOnChanges` only fires for inputs Angular
224
+ * itself sets, so a component whose `field` is assigned directly — which the field specs do,
225
+ * and any consumer holding a `ComponentRef` may do — would render no options at all.
226
+ *
227
+ * Paints synchronously first (inline options, or a warm list), then fills in when a cold list
228
+ * lands. The late result is dropped if the field or language changed while it was in flight.
229
+ */
230
+ export function refreshChoiceOptions(host, lookups) {
231
+ const last = hostLastConfig.get(host);
232
+ if (last && last.field === host.field && last.lang === host.language) {
233
+ return;
234
+ }
235
+ hostLastConfig.set(host, { field: host.field, lang: host.language });
236
+ host.options.set(lookups.optionsFor(host.field, host.language));
237
+ if (!lookups.needsResolve(host.field))
238
+ return;
239
+ const listName = host.field?.listName;
240
+ const lang = host.language;
241
+ void lookups.resolveOptions(host.field, host.language).then(options => {
242
+ if (host.field?.listName === listName && host.language === lang)
243
+ host.options.set(options);
244
+ });
245
+ }
246
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9va3VwLXJlZ2lzdHJ5LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2xvb2t1cC1yZWdpc3RyeS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUF1QixNQUFNLGVBQWUsQ0FBQztBQVd4RSxPQUFPLEVBQUUscUJBQXFCLEVBQUUscUJBQXFCLEVBQUUsWUFBWSxFQUFFLE1BQU0sc0JBQXNCLENBQUM7QUFDbEcsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDRCQUE0QixDQUFDOztBQUU3RCw4RkFBOEY7QUFDOUYsTUFBTSxHQUFHLEdBQUcsR0FBRyxDQUFDO0FBRWhCOzs7Ozs7Ozs7Ozs7OztHQWNHO0FBRUgsTUFBTSxPQUFPLHFCQUFxQjtJQUNmLFFBQVEsR0FDdkIsTUFBTSxDQUFDLGVBQWUsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxJQUFJLElBQUksR0FBRyxFQUE0QixDQUFDO0lBRXJGLDJDQUEyQztJQUMxQixPQUFPLEdBQUcsSUFBSSxHQUFHLEVBQTRCLENBQUM7SUFDL0QsZ0dBQWdHO0lBQy9FLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBNkIsQ0FBQztJQUMvRCx5Q0FBeUM7SUFDeEIsUUFBUSxHQUFHLElBQUksR0FBRyxFQUFxQyxDQUFDO0lBQ3pFLGdGQUFnRjtJQUMvRCxNQUFNLEdBQUcsSUFBSSxHQUFHLEVBQWtCLENBQUM7SUFFcEQsR0FBRyxDQUFDLFFBQWdCO1FBQ2xCLE9BQU8sSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDckMsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxJQUFJLENBQUMsUUFBZ0IsRUFBRSxJQUFJLEdBQUcsSUFBSTtRQUN0QyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLFFBQVEs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QUFPO0lBRTlDLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDO0lBQ3RDLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUM7SUFDM0IsS0FBSyxPQUFPLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxLQUFLLEVBQUUsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRTtRQUNwRSxJQUFJLElBQUksQ0FBQyxLQUFLLEVBQUUsUUFBUSxLQUFLLFFBQVEsSUFBSSxJQUFJLENBQUMsUUFBUSxLQUFLLElBQUk7WUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUM3RixDQUFDLENBQUMsQ0FBQztBQUNMLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBpbmplY3QsIHR5cGUgV3JpdGFibGVTaWduYWwgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB0eXBlIHtcbiAgRHJvcGRvd25PcHRpb24sXG4gIExvb2t1cExpc3RMb2FkZXIsXG4gIExvb2t1cExpc3RSZXN1bHQsXG4gIExvb2t1cExpc3RTb3VyY2UsXG4gIExvb2t1cExpc3RWYWx1ZSxcbiAgTmVzdGVkRmllbGRDb25maWcsXG4gIFJhd0xvb2t1cExpc3RWYWx1ZSxcbiAgU3Vic2NyaWJhYmxlLFxufSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQgeyBsb29rdXBWYWx1ZXNUb09wdGlvbnMsIG5vcm1hbGl6ZUxvb2t1cFZhbHVlcywgcmVzb2x2ZUxhYmVsIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgTE9PS1VQX1JFR0lTVFJZIH0gZnJvbSAnLi4vdG9rZW5zL2luamVjdGlvbi10b2tlbnMnO1xuXG4vKiogQ2FjaGUta2V5IGZpZWxkIHNlcGFyYXRvci4gS2VwdCBvdXQgb2YgdGVtcGxhdGUgbGl0ZXJhbHMgc28gaXQgc3RheXMgdmlzaWJsZSBpbiBzb3VyY2UuICovXG5jb25zdCBTRVAgPSAnfCc7XG5cbi8qKlxuICogTG9va3VwUmVnaXN0cnlTZXJ2aWNlIOKAlCB0aGUgY2FjaGUgaW4gZnJvbnQgb2YgY29uc3VtZXItcmVnaXN0ZXJlZCBtYXN0ZXIgbGlzdHMuXG4gKlxuICogVGhyZWUgbGF5ZXJzLCBkZWxpYmVyYXRlbHkgdGhlIHNhbWUgc2hhcGUgYXMgYEVudGl0eVJlZmVyZW5jZVNlcnZpY2VgLCBiZWNhdXNlIHRoZSBwcm9ibGVtIGlzXG4gKiB0aGUgc2FtZTogb25lIGxpc3QgaXMgdHlwaWNhbGx5IHVzZWQgYnkgbWFueSBmaWVsZHMgYWNyb3NzIG1hbnkgZW50aXRpZXMuXG4gKiAgMS4gKipvcHRpb25zKiog4oCUIHJlc29sdmVkIGBEcm9wZG93bk9wdGlvbltdYCBwZXIgKGxpc3QgbmFtZSwgbGFuZykuXG4gKiAgMi4gKippbi1mbGlnaHQqKiDigJQgdGhlIHBlbmRpbmcgUHJvbWlzZSwgc28gTiBmaWVsZHMgb24gb25lIGxpc3QgdHJpZ2dlciBvbmUgbG9hZCwgbm90IE4uXG4gKiAgMy4gKipsYWJlbHMqKiDigJQgc3luY2hyb25vdXMgdmFsdWUg4oaSIHRleHQgKHBhcml0eSBwbGFuIMKnNi4yKS4gVGhpcyBpcyBub3QgYSBuaWNldHk6IHNpbmNlXG4gKiAgICAgYHZpZXdNb2RlYCBkZWZhdWx0cyB0byB0cnVlIGEgcmVjb3JkIG9wZW5zIHJlYWQtb25seSwgc28gcmVuZGVyaW5nIGEgc3RvcmVkIHZhbHVlIGFzXG4gKiAgICAgdGV4dCBpcyB0aGUgKmZpcnN0KiB0aGluZyBhIGBsaXN0TmFtZWAgZmllbGQgaGFzIHRvIGRvLiBBbiBhc3luYy1vbmx5IHJlZ2lzdHJ5IHdvdWxkXG4gKiAgICAgcGFpbnQgdGhlIHJhdyBzdG9yZWQgdmFsdWUgYW5kIHRoZW4gZmxpcCwgb24gZXZlcnkgcmVjb3JkIG9wZW4uXG4gKlxuICogQSBmYWlsZWQgbG9hZCByZWplY3RzIGFuZCBjYWNoZXMgbm90aGluZywgc28gb25lIHRyYW5zaWVudCBlcnJvciBkb2VzIG5vdCBzZXJ2ZSBhbiBlbXB0eVxuICogbGlzdCBmb3JldmVyIOKAlCB0aGUgc2FtZSBmaXggbWFkZSBmb3IgZW50aXR5IHJlZmVyZW5jZXMgaW4gcGhhc2UgNS5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBMb29rdXBSZWdpc3RyeVNlcnZpY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lzdHJ5ID1cbiAgICBpbmplY3QoTE9PS1VQX1JFR0lTVFJZLCB7IG9wdGlvbmFsOiB0cnVlIH0pID8/IG5ldyBNYXA8c3RyaW5nLCBMb29rdXBMaXN0U291cmNlPigpO1xuXG4gIC8qKiBgbGlzdE5hbWV8bGFuZ2AgLT4gcmVzb2x2ZWQgb3B0aW9ucy4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBvcHRpb25zID0gbmV3IE1hcDxzdHJpbmcsIERyb3Bkb3duT3B0aW9uW10+KCk7XG4gIC8qKiBgbGlzdE5hbWV8bGFuZ2AgLT4gbm9ybWFsaXNlZCB2YWx1ZXMsIHNvIGEgY29uc3VtZXIgY2FuIHJlYWNoIGBjb2RlYCAvIGBpc1N5c3RlbURlZmluZWRgLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IHZhbHVlcyA9IG5ldyBNYXA8c3RyaW5nLCBMb29rdXBMaXN0VmFsdWVbXT4oKTtcbiAgLyoqIExvYWRzIGluIHByb2dyZXNzLCBrZXllZCBhcyBhYm92ZS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBpbkZsaWdodCA9IG5ldyBNYXA8c3RyaW5nLCBQcm9taXNlPERyb3Bkb3duT3B0aW9uW10+PigpO1xuICAvKiogYGxpc3ROYW1lfGxhbmd8dGV4dGAgLT4gZGlzcGxheSB0ZXh0LCBmb3IgdGhlIHN5bmNocm9ub3VzIHJlYWQtb25seSBwYXRoLiAqL1xuICBwcml2YXRlIHJlYWRvbmx5IGxhYmVscyA9IG5ldyBNYXA8c3RyaW5nLCBzdHJpbmc+KCk7XG5cbiAgaGFzKGxpc3ROYW1lOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5yZWdpc3RyeS5oYXMobGlzdE5hbWUpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9wdGlvbnMgZm9yIGEgbmFtZWQgbGlzdCwgZnJvbSBjYWNoZSB3aGVuIHByZXNlbnQuXG4gICAqIENvbmN1cnJlbnQgY2FsbGVycyB3aXRoIHRoZSBzYW1lIGtleSBzaGFyZSBvbmUgbG9hZC5cbiAgICovXG4gIGFzeW5jIGxvYWQobGlzdE5hbWU6IHN0cmluZywgbGFuZyA9ICdlbicpOiBQcm9taXNlPERyb3Bkb3duT3B0aW9uW10+IHtcbiAgICBjb25zdCBrZXkgPSB0aGlzLmNhY2hlS2V5KGxpc3ROYW1lLCBsYW5nKTtcblxuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMub3B0aW9ucy5nZXQoa2V5KTtcbiAgICBpZiAoY2FjaGVkKSByZXR1cm4gY2FjaGVkO1xuXG4gICAgY29uc3QgcGVuZGluZyA9IHRoaXMuaW5GbGlnaHQuZ2V0KGtleSk7XG4gICAgaWYgKHBlbmRpbmcpIHJldHVybiBwZW5kaW5nO1xuXG4gICAgY29uc3Qgc291cmNlID0gdGhpcy5yZWdpc3RyeS5nZXQobGlzdE5hbWUpO1xuICAgIGlmIChzb3VyY2UgPT09IHVuZGVmaW5lZCkgcmV0dXJuIFtdO1xuXG4gICAgY29uc3QgbG9hZCA9IHRoaXMuaW52b2tlKHNvdXJjZSwgbGFuZykudGhlbihyYXcgPT4ge1xuICAgICAgY29uc3QgdmFsdWVzID0gbm9ybWFsaXplTG9va3VwVmFsdWVzKHJhdyk7XG4gICAgICBjb25zdCBvcHRpb25zID0gbG9va3VwVmFsdWVzVG9PcHRpb25zKHZhbHVlcyk7XG4gICAgICB0aGlzLnZhbHVlcy5zZXQoa2V5LCB2YWx1ZXMpO1xuICAgICAgdGhpcy5vcHRpb25zLnNldChrZXksIG9wdGlvbnMpO1xuICAgICAgdGhpcy5yZW1lbWJlckxhYmVscyhsaXN0TmFtZSwgbGFuZywgb3B0aW9ucyk7XG4gICAgICByZXR1cm4gb3B0aW9ucztcbiAgICB9KTtcblxuICAgIC8vIE9ubHkgdGhlIGAudGhlbmAgYWJvdmUgd3JpdGVzIHRvIHRoZSBjYWNoZSwgYW5kIGEgcmVqZWN0aW9uIHNraXBzIGl0OiB0aGUgY2FsbGVyIHN0aWxsXG4gICAgLy8gZ2V0cyBhbiBlbXB0eSBsaXN0LCBidXQgdGhlIG5leHQgY2FsbCByZXRyaWVzIGluc3RlYWQgb2YgcmVhZGluZyBhIHBvaXNvbmVkIGVudHJ5LlxuICAgIGNvbnN0IGd1YXJkZWQgPSBsb2FkXG4gICAgICAuY2F0Y2goKCkgPT4gW10gYXMgRHJvcGRvd25PcHRpb25bXSlcbiAgICAgIC5maW5hbGx5KCgpID0+IHRoaXMuaW5GbGlnaHQuZGVsZXRlKGtleSkpO1xuXG4gICAgdGhpcy5pbkZsaWdodC5zZXQoa2V5LCBndWFyZGVkKTtcbiAgICByZXR1cm4gZ3VhcmRlZDtcbiAgfVxuXG4gIC8qKiBDYWNoZWQgb3B0aW9ucyB3aXRob3V0IHRyaWdnZXJpbmcgYSBsb2FkLiBgdW5kZWZpbmVkYCB3aGVuIG5vdCBsb2FkZWQuICovXG4gIHBlZWsobGlzdE5hbWU6IHN0cmluZywgbGFuZyA9ICdlbicpOiBEcm9wZG93bk9wdGlvbltdIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5vcHRpb25zLmdldCh0aGlzLmNhY2hlS2V5KGxpc3ROYW1lLCBsYW5nKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2FjaGVkIGxpc3QgdmFsdWVzLCBjYXJyeWluZyBgX2lkYCwgYGNvZGVgLCBgaXNTeXN0ZW1EZWZpbmVkYCBhbmQgYGZyb21gLlxuICAgKiBUaGUgbGlicmFyeSBuZXZlciByZWFkcyB0aG9zZTsgdGhpcyBpcyB0aGUgc2VhbSBmb3IgYSBjb25zdW1lciB0aGF0IG5lZWRzIHRoZW0uXG4gICAqL1xuICB2YWx1ZXNGb3IobGlzdE5hbWU6IHN0cmluZywgbGFuZyA9ICdlbicpOiBMb29rdXBMaXN0VmFsdWVbXSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMudmFsdWVzLmdldCh0aGlzLmNhY2hlS2V5KGxpc3ROYW1lLCBsYW5nKSk7XG4gIH1cblxuICAvKipcbiAgICogRGlzcGxheSB0ZXh0IGZvciBhIHN0b3JlZCB2YWx1ZSwgc3luY2hyb25vdXNseS4gYHVuZGVmaW5lZGAgd2hlbiB0aGUgbGlzdCBoYXMgbm90IGxvYWRlZFxuICAgKiBvciBob2xkcyBubyBtYXRjaGluZyB2YWx1ZSDigJQgdGhlIGNhbGxlciBrZWVwcyBpdHMgb3duIGZhbGxiYWNrLCB3aGljaCBpcyB0aGUgc3RvcmVkIHRleHQuXG4gICAqXG4gICAqIEV2ZXJ5IGxhbmd1YWdlIG9mIGFuIG9wdGlvbiBpcyBpbmRleGVkLCBzbyBhIHJlY29yZCBzYXZlZCB1bmRlciBvbmUgbGFuZ3VhZ2UgcmVuZGVycyBpblxuICAgKiBhbm90aGVyOiBhIHZhbHVlIHN0b3JlZCBhcyBgJ0FrdGl2J2AgcmVzb2x2ZXMgdG8gYCdBY3RpdmUnYCB1bmRlciBgbGFuZzogJ2VuJ2AuXG4gICAqL1xuICBsYWJlbEZvcihsaXN0TmFtZTogc3RyaW5nIHwgdW5kZWZpbmVkLCB2YWx1ZTogdW5rbm93biwgbGFuZyA9ICdlbicpOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICAgIGlmICghbGlzdE5hbWUgfHwgdmFsdWUgPT09IG51bGwgfHwgdmFsdWUgPT09IHVuZGVmaW5lZCB8fCB2YWx1ZSA9PT0gJycpIHJldHVybiB1bmRlZmluZWQ7XG4gICAgZm9yIChjb25zdCB0ZXh0IG9mIHRoaXMuY2FuZGlkYXRlVGV4dHModmFsdWUsIGxhbmcpKSB7XG4gICAgICBjb25zdCBoaXQgPSB0aGlzLmxhYmVscy5nZXQodGhpcy5sYWJlbEtleShsaXN0TmFtZSwgbGFuZywgdGV4dCkpO1xuICAgICAgaWYgKGhpdCkgcmV0dXJuIGhpdDtcbiAgICB9XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBGaWVsZC1sZXZlbCByZXNvbHV0aW9uIOKAlCBpbmxpbmUgb3B0aW9ucyB3aW4sIGVsc2UgYGxpc3ROYW1lYCDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIDilIBcblxuICAvKiogVHJ1ZSB3aGVuIHRoaXMgZmllbGQncyBvcHRpb25zIGhhdmUgdG8gY29tZSBmcm9tIHRoZSByZWdpc3RyeS4gKi9cbiAgbmVlZHNSZXNvbHZlKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyB8IHVuZGVmaW5lZCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIWZpZWxkPy5saXN0TmFtZSAmJiAhZmllbGQub3B0aW9ucz8ubGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIFRoZSBvcHRpb25zIHRvIHJlbmRlciByaWdodCBub3csIHdpdGhvdXQgYXdhaXRpbmc6IGlubGluZSBvcHRpb25zLCBlbHNlIHdoYXRldmVyIHRoZVxuICAgKiByZWdpc3RyeSBhbHJlYWR5IGhvbGRzLiBFbXB0eSBvbiBhIGNvbGQgbWlzcyDigJQgcGFpciB3aXRoIGByZXNvbHZlT3B0aW9uc2AuXG4gICAqL1xuICBvcHRpb25zRm9yKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZyB8IHVuZGVmaW5lZCwgbGFuZyA9ICdlbicpOiBEcm9wZG93bk9wdGlvbltdIHtcbiAgICBpZiAoIWZpZWxkKSByZXR1cm4gW107XG4gICAgaWYgKGZpZWxkLm9wdGlvbnM/Lmxlbmd0aCkgcmV0dXJuIGZpZWxkLm9wdGlvbnM7XG4gICAgaWYgKCFmaWVsZC5saXN0TmFtZSkgcmV0dXJuIFtdO1xuICAgIHJldHVybiB0aGlzLnBlZWsoZmllbGQubGlzdE5hbWUsIGxhbmcpID8/IFtdO1xuICB9XG5cbiAgLyoqIFRoZSBvcHRpb25zIGZvciBhIGZpZWxkLCBsb2FkaW5nIHRoZSBuYW1lZCBsaXN0IGlmIG5lZWRlZC4gKi9cbiAgcmVzb2x2ZU9wdGlvbnMoZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnIHwgdW5kZWZpbmVkLCBsYW5nID0gJ2VuJyk6IFByb21pc2U8RHJvcGRvd25PcHRpb25bXT4ge1xuICAgIGlmICghdGhpcy5uZWVkc1Jlc29sdmUoZmllbGQpKSByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHRoaXMub3B0aW9uc0ZvcihmaWVsZCwgbGFuZykpO1xuICAgIHJldHVybiB0aGlzLmxvYWQoZmllbGQhLmxpc3ROYW1lISwgbGFuZyk7XG4gIH1cblxuICAvKiogRHJvcCBldmVyeXRoaW5nIGNhY2hlZCBmb3Igb25lIGxpc3QsIGxlYXZpbmcgb3RoZXIgbGlzdHMgaW50YWN0LiAqL1xuICBpbnZhbGlkYXRlKGxpc3ROYW1lOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBwcmVmaXggPSBgJHtsaXN0TmFtZX0ke1NFUH1gO1xuICAgIGZvciAoY29uc3QgbWFwIG9mIFt0aGlzLm9wdGlvbnMsIHRoaXMudmFsdWVzLCB0aGlzLmluRmxpZ2h0XSkge1xuICAgICAgZm9yIChjb25zdCBrZXkgb2YgWy4uLm1hcC5rZXlzKCldKSB7XG4gICAgICAgIGlmIChrZXkuc3RhcnRzV2l0aChwcmVmaXgpKSBtYXAuZGVsZXRlKGtleSk7XG4gICAgICB9XG4gICAgfVxuICAgIGZvciAoY29uc3Qga2V5IG9mIFsuLi50aGlzLmxhYmVscy5rZXlzKCldKSB7XG4gICAgICBpZiAoa2V5LnN0YXJ0c1dpdGgocHJlZml4KSkgdGhpcy5sYWJlbHMuZGVsZXRlKGtleSk7XG4gICAgfVxuICB9XG5cbiAgY2xlYXIoKTogdm9pZCB7XG4gICAgdGhpcy5vcHRpb25zLmNsZWFyKCk7XG4gICAgdGhpcy52YWx1ZXMuY2xlYXIoKTtcbiAgICB0aGlzLmluRmxpZ2h0LmNsZWFyKCk7XG4gICAgdGhpcy5sYWJlbHMuY2xlYXIoKTtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBJbnRlcm5hbHMg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJpdmF0ZSBjYWNoZUtleShsaXN0TmFtZTogc3RyaW5nLCBsYW5nOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBbbGlzdE5hbWUsIGxhbmddLmpvaW4oU0VQKTtcbiAgfVxuXG4gIHByaXZhdGUgbGFiZWxLZXkobGlzdE5hbWU6IHN0cmluZywgbGFuZzogc3RyaW5nLCB0ZXh0OiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIHJldHVybiBbbGlzdE5hbWUsIGxhbmcsIHRleHRdLmpvaW4oU0VQKTtcbiAgfVxuXG4gIC8qKiBJbmRleCBhbiBvcHRpb24gdW5kZXIgZXZlcnkgbGFuZ3VhZ2UgaXQgY2Fycmllcywgc28gYW55IHN0b3JlZCBzcGVsbGluZyBmaW5kcyBpdC4gKi9cbiAgcHJpdmF0ZSByZW1lbWJlckxhYmVscyhsaXN0TmFtZTogc3RyaW5nLCBsYW5nOiBzdHJpbmcsIG9wdGlvbnM6IERyb3Bkb3duT3B0aW9uW10pOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IG9wdGlvbiBvZiBvcHRpb25zKSB7XG4gICAgICBjb25zdCBkaXNwbGF5ID0gcmVzb2x2ZUxhYmVsKG9wdGlvbiwgbGFuZyk7XG4gICAgICBpZiAoIWRpc3BsYXkpIGNvbnRpbnVlO1xuICAgICAgZm9yIChjb25zdCB0ZXh0IG9mIE9iamVjdC52YWx1ZXMob3B0aW9uKSkge1xuICAgICAgICBpZiAodHlwZW9mIHRleHQgPT09ICdzdHJpbmcnICYmIHRleHQgIT09ICcnKSB7XG4gICAgICAgICAgdGhpcy5sYWJlbHMuc2V0KHRoaXMubGFiZWxLZXkobGlzdE5hbWUsIGxhbmcsIHRleHQpLCBkaXNwbGF5KTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8qKiBUaGUgdGV4dHMgYSBzdG9yZWQgdmFsdWUgY291bGQgaGF2ZSBiZWVuIGluZGV4ZWQgdW5kZXIuICovXG4gIHByaXZhdGUgY2FuZGlkYXRlVGV4dHModmFsdWU6IHVua25vd24sIGxhbmc6IHN0cmluZyk6IHN0cmluZ1tdIHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnb2JqZWN0Jykge1xuICAgICAgY29uc3QgdGV4dHMgPSBPYmplY3QudmFsdWVzKHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHVua25vd24+KS5maWx0ZXIoXG4gICAgICAgICh2KTogdiBpcyBzdHJpbmcgPT4gdHlwZW9mIHYgPT09ICdzdHJpbmcnICYmIHYgIT09ICcnLFxuICAgICAgKTtcbiAgICAgIGNvbnN0IHJlc29sdmVkID0gcmVzb2x2ZUxhYmVsKHZhbHVlIGFzIFJlY29yZDxzdHJpbmcsIHN0cmluZz4sIGxhbmcpO1xuICAgICAgcmV0dXJuIHJlc29sdmVkID8gW3Jlc29sdmVkLCAuLi50ZXh0c10gOiB0ZXh0cztcbiAgICB9XG4gICAgcmV0dXJuIFtTdHJpbmcodmFsdWUpXTtcbiAgfVxuXG4gIC8vIOKUgOKUgOKUgCBTb3VyY2UgY29lcmNpb24gKHZhbHVlcyB8IGxvYWRlciwgYXJyYXkgfCBQcm9taXNlIHwgT2JzZXJ2YWJsZSkg4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSA4pSAXG5cbiAgcHJpdmF0ZSBpbnZva2Uoc291cmNlOiBMb29rdXBMaXN0U291cmNlLCBsYW5nOiBzdHJpbmcpOiBQcm9taXNlPFJhd0xvb2t1cExpc3RWYWx1ZVtdPiB7XG4gICAgbGV0IHJlc3VsdDogTG9va3VwTGlzdFJlc3VsdDtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gdHlwZW9mIHNvdXJjZSA9PT0gJ2Z1bmN0aW9uJyA/IChzb3VyY2UgYXMgTG9va3VwTGlzdExvYWRlcikoeyBsYW5nIH0pIDogc291cmNlO1xuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgLy8gUmVqZWN0IHJhdGhlciB0aGFuIHJlc29sdmUgZW1wdHk6IGBsb2FkYCBtdXN0IGJlIGFibGUgdG8gdGVsbCBmYWlsdXJlIGZyb20gYW4gZW1wdHlcbiAgICAgIC8vIGxpc3QsIG9yIGl0IHdvdWxkIGNhY2hlIHRoZSBmYWlsdXJlLlxuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGVycik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnRvUHJvbWlzZShyZXN1bHQpO1xuICB9XG5cbiAgcHJpdmF0ZSB0b1Byb21pc2UocmVzdWx0OiBMb29rdXBMaXN0UmVzdWx0KTogUHJvbWlzZTxSYXdMb29rdXBMaXN0VmFsdWVbXT4ge1xuICAgIGlmIChBcnJheS5pc0FycmF5KHJlc3VsdCkpIHJldHVybiBQcm9taXNlLnJlc29sdmUocmVzdWx0KTtcbiAgICBpZiAodGhpcy5pc1N1YnNjcmliYWJsZShyZXN1bHQpKSB7XG4gICAgICAvLyBGaXJzdCBlbWlzc2lvbiB3aW5zLCBzbyBhIHN0cmVhbSB0aGF0IHN0YXlzIG9wZW4gc3RpbGwgcmVzb2x2ZXMgdGhlIGxvYWQuXG4gICAgICByZXR1cm4gbmV3IFByb21pc2U8UmF3TG9va3VwTGlzdFZhbHVlW10+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgbGV0IHNldHRsZWQgPSBmYWxzZTtcbiAgICAgICAgY29uc3Qgc2V0dGxlID0gKGZuOiAoKSA9PiB2b2lkKSA9PiB7XG4gICAgICAgICAgaWYgKHNldHRsZWQpIHJldHVybjtcbiAgICAgICAgICBzZXR0bGVkID0gdHJ1ZTtcbiAgICAgICAgICBmbigpO1xuICAgICAgICB9O1xuICAgICAgICByZXN1bHQuc3Vic2NyaWJlKHtcbiAgICAgICAgICBuZXh0OiB2YWx1ZSA9PiBzZXR0bGUoKCkgPT4gcmVzb2x2ZSh2YWx1ZSA/PyBbXSkpLFxuICAgICAgICAgIGVycm9yOiBlcnIgPT4gc2V0dGxlKCgpID0+IHJlamVjdChlcnIpKSxcbiAgICAgICAgICAvLyBDb21wbGV0aW5nIHdpdGhvdXQgZW1pdHRpbmcgaXMgYSBsZWdpdGltYXRlIGVtcHR5IGxpc3QsIGFuZCBpcyBjYWNoZWQuXG4gICAgICAgICAgY29tcGxldGU6ICgpID0+IHNldHRsZSgoKSA9PiByZXNvbHZlKFtdKSksXG4gICAgICAgIH0pO1xuICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBQcm9taXNlLnJlc29sdmUocmVzdWx0IGFzIFByb21pc2U8UmF3TG9va3VwTGlzdFZhbHVlW10+KTtcbiAgfVxuXG4gIHByaXZhdGUgaXNTdWJzY3JpYmFibGUodmFsdWU6IHVua25vd24pOiB2YWx1ZSBpcyBTdWJzY3JpYmFibGU8UmF3TG9va3VwTGlzdFZhbHVlW10+IHtcbiAgICByZXR1cm4gKFxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJlxuICAgICAgdmFsdWUgIT09IG51bGwgJiZcbiAgICAgIHR5cGVvZiAodmFsdWUgYXMgU3Vic2NyaWJhYmxlPFJhd0xvb2t1cExpc3RWYWx1ZVtdPikuc3Vic2NyaWJlID09PSAnZnVuY3Rpb24nXG4gICAgKTtcbiAgfVxufVxuXG4vKiogQSBjaG9pY2UgZmllbGQgY29tcG9uZW50LCBhcyBmYXIgYXMgb3B0aW9uIHJlc29sdXRpb24gaXMgY29uY2VybmVkLiAqL1xuZXhwb3J0IGludGVyZmFjZSBDaG9pY2VPcHRpb25Ib3N0IHtcbiAgcmVhZG9ubHkgZmllbGQ6IE5lc3RlZEZpZWxkQ29uZmlnIHwgdW5kZWZpbmVkO1xuICByZWFkb25seSBsYW5ndWFnZTogc3RyaW5nO1xuICByZWFkb25seSBvcHRpb25zOiBXcml0YWJsZVNpZ25hbDxEcm9wZG93bk9wdGlvbltdPjtcbn1cblxuY29uc3QgaG9zdExhc3RDb25maWcgPSBuZXcgV2Vha01hcDxDaG9pY2VPcHRpb25Ib3N0LCB7IGZpZWxkPzogTmVzdGVkRmllbGRDb25maWc7IGxhbmc/OiBzdHJpbmcgfT4oKTtcblxuLyoqXG4gKiBQb2ludCBhIGNob2ljZSBjb21wb25lbnQncyBgb3B0aW9uc2Agc2lnbmFsIGF0IHRoZSByaWdodCBzb3VyY2UgKHBhcml0eSBwbGFuIMKnNi4zKS5cbiAqXG4gKiBDYWxsZWQgZnJvbSB0aGUgYGZpZWxkYCAvIGBsYW5ndWFnZWAgaW5wdXQgc2V0dGVycyBvZiBgZHJvcGRvd25gLCBgcmFkaW9gIGFuZCBgbXVsdGlTZWxlY3RgIOKAlFxuICogdGhlIHdpcmluZyBpcyB0aGVpcnMsIHRoZSBkZWNpc2lvbiBpcyB0aGUgc2VydmljZSdzLCB3aGljaCBpcyB3aGF0IGtlZXBzIHRoZSBBRFItMDA4XG4gKiBmaXZlLWlucHV0IGNvbnRyYWN0IGludGFjdDogb3B0aW9ucyBhcmUgbmV2ZXIgcHVzaGVkIGluIGFzIGEgc2l4dGggaW5wdXQuXG4gKlxuICogU2V0dGVycyByYXRoZXIgdGhhbiBgbmdPbkNoYW5nZXNgIG9uIHB1cnBvc2UuIGBuZ09uQ2hhbmdlc2Agb25seSBmaXJlcyBmb3IgaW5wdXRzIEFuZ3VsYXJcbiAqIGl0c2VsZiBzZXRzLCBzbyBhIGNvbXBvbmVudCB3aG9zZSBgZmllbGRgIGlzIGFzc2lnbmVkIGRpcmVjdGx5IOKAlCB3aGljaCB0aGUgZmllbGQgc3BlY3MgZG8sXG4gKiBhbmQgYW55IGNvbnN1bWVyIGhvbGRpbmcgYSBgQ29tcG9uZW50UmVmYCBtYXkgZG8g4oCUIHdvdWxkIHJlbmRlciBubyBvcHRpb25zIGF0IGFsbC5cbiAqXG4gKiBQYWludHMgc3luY2hyb25vdXNseSBmaXJzdCAoaW5saW5lIG9wdGlvbnMsIG9yIGEgd2FybSBsaXN0KSwgdGhlbiBmaWxscyBpbiB3aGVuIGEgY29sZCBsaXN0XG4gKiBsYW5kcy4gVGhlIGxhdGUgcmVzdWx0IGlzIGRyb3BwZWQgaWYgdGhlIGZpZWxkIG9yIGxhbmd1YWdlIGNoYW5nZWQgd2hpbGUgaXQgd2FzIGluIGZsaWdodC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlZnJlc2hDaG9pY2VPcHRpb25zKGhvc3Q6IENob2ljZU9wdGlvbkhvc3QsIGxvb2t1cHM6IExvb2t1cFJlZ2lzdHJ5U2VydmljZSk6IHZvaWQge1xuICBjb25zdCBsYXN0ID0gaG9zdExhc3RDb25maWcuZ2V0KGhvc3QpO1xuICBpZiAobGFzdCAmJiBsYXN0LmZpZWxkID09PSBob3N0LmZpZWxkICYmIGxhc3QubGFuZyA9PT0gaG9zdC5sYW5ndWFnZSkge1xuICAgIHJldHVybjtcbiAgfVxuICBob3N0TGFzdENvbmZpZy5zZXQoaG9zdCwgeyBmaWVsZDogaG9zdC5maWVsZCwgbGFuZzogaG9zdC5sYW5ndWFnZSB9KTtcblxuICBob3N0Lm9wdGlvbnMuc2V0KGxvb2t1cHMub3B0aW9uc0Zvcihob3N0LmZpZWxkLCBob3N0Lmxhbmd1YWdlKSk7XG4gIGlmICghbG9va3Vwcy5uZWVkc1Jlc29sdmUoaG9zdC5maWVsZCkpIHJldHVybjtcblxuICBjb25zdCBsaXN0TmFtZSA9IGhvc3QuZmllbGQ/Lmxpc3ROYW1lO1xuICBjb25zdCBsYW5nID0gaG9zdC5sYW5ndWFnZTtcbiAgdm9pZCBsb29rdXBzLnJlc29sdmVPcHRpb25zKGhvc3QuZmllbGQsIGhvc3QubGFuZ3VhZ2UpLnRoZW4ob3B0aW9ucyA9PiB7XG4gICAgaWYgKGhvc3QuZmllbGQ/Lmxpc3ROYW1lID09PSBsaXN0TmFtZSAmJiBob3N0Lmxhbmd1YWdlID09PSBsYW5nKSBob3N0Lm9wdGlvbnMuc2V0KG9wdGlvbnMpO1xuICB9KTtcbn1cbiJdfQ==
@@ -1,10 +1,9 @@
1
1
  import { Injectable, inject } from '@angular/core';
2
+ import { shouldMaskField as coreShouldMaskField, resolveEffectiveMask as coreResolveEffectiveMask } from '@dynamic-entity/core';
2
3
  import { MASKED_ROLES } from '../tokens/injection-tokens';
3
4
  import * as i0 from "@angular/core";
4
5
  /**
5
6
  * RbacService — ALL permission checks and masking logic live here.
6
- * CRITICAL SYNC: resolveEffectiveMask() must be identical to rbac.utils.js in dynamic-entity-server.
7
- * Changing one without the other is a critical production bug (ADR-003).
8
7
  */
9
8
  export class RbacService {
10
9
  maskedRoles = inject(MASKED_ROLES, { optional: true }) ?? [];
@@ -17,12 +16,9 @@ export class RbacService {
17
16
  return true;
18
17
  return userRoles.some(r => requiredRoles.includes(r));
19
18
  }
20
- /**
21
- * ADR-003: 3-level OR resolution.
22
- * MUST match rbac.utils.js resolveEffectiveMask() exactly.
23
- */
19
+ /** 3-level OR resolution */
24
20
  resolveEffectiveMask(formMask, tabMask, fieldMask) {
25
- return !!(formMask || tabMask || fieldMask);
21
+ return coreResolveEffectiveMask(formMask, tabMask, fieldMask);
26
22
  }
27
23
  /** Check if the user's roles include any masked role */
28
24
  isUserMaskedRole(userRoles) {
@@ -30,9 +26,7 @@ export class RbacService {
30
26
  }
31
27
  /** Determine if a specific field should be masked for this user */
32
28
  shouldMaskField(field, tab, config, userRoles) {
33
- if (!this.isUserMaskedRole(userRoles))
34
- return false;
35
- return this.resolveEffectiveMask(config.maskData, tab?.maskData, field.maskData);
29
+ return coreShouldMaskField(field, tab, config, userRoles, this.maskedRoles);
36
30
  }
37
31
  /** Get view/edit/delete permissions for a config */
38
32
  getPermissions(config, userRoles) {
@@ -49,4 +43,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
49
43
  type: Injectable,
50
44
  args: [{ providedIn: 'root' }]
51
45
  }] });
52
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmJhYy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9yYmFjLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFbkQsT0FBTyxFQUFFLFlBQVksRUFBRSxNQUFNLDRCQUE0QixDQUFDOztBQUUxRDs7OztHQUlHO0FBRUgsTUFBTSxPQUFPLFdBQVc7SUFDTCxXQUFXLEdBQUcsTUFBTSxDQUFDLFlBQVksRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUU5RTs7O09BR0c7SUFDSCxhQUFhLENBQUMsU0FBbUIsRUFBRSxhQUF3QjtRQUN6RCxJQUFJLENBQUMsYUFBYSxFQUFFLE1BQU07WUFBRSxPQUFPLElBQUksQ0FBQztRQUN4QyxPQUFPLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVEOzs7T0FHRztJQUNILG9CQUFvQixDQUFDLFFBQWtCLEVBQUUsT0FBaUIsRUFBRSxTQUFtQjtRQUM3RSxPQUFPLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBSSxPQUFPLElBQUksU0FBUyxDQUFDLENBQUM7SUFDOUMsQ0FBQztJQUVELHdEQUF3RDtJQUN4RCxnQkFBZ0IsQ0FBQyxTQUFtQjtRQUNsQyxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNELENBQUM7SUFFRCxtRUFBbUU7SUFDbkUsZUFBZSxDQUFDLEtBQWtCLEVBQUUsR0FBMEIsRUFBRSxNQUFvQixFQUFFLFNBQW1CO1FBQ3ZHLElBQUksQ0FBQyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxDQUFDO1lBQUUsT0FBTyxLQUFLLENBQUM7UUFDcEQsT0FBTyxJQUFJLENBQUMsb0JBQW9CLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxHQUFHLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxRQUFRLENBQUMsQ0FBQztJQUNuRixDQUFDO0lBRUQsb0RBQW9EO0lBQ3BELGNBQWMsQ0FBQyxNQUFvQixFQUFFLFNBQW1CO1FBQ3RELE9BQU87WUFDTCxPQUFPLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUM7WUFDaEUsT0FBTyxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxXQUFXLEVBQUUsSUFBSSxDQUFDO1lBQ2hFLFNBQVMsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsV0FBVyxFQUFFLE1BQU0sQ0FBQztTQUNyRSxDQUFDO0lBQ0osQ0FBQzt3R0F0Q1UsV0FBVzs0R0FBWCxXQUFXLGNBREUsTUFBTTs7NEZBQ25CLFdBQVc7a0JBRHZCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgdHlwZSB7IEVudGl0eUNvbmZpZywgRmllbGRDb25maWcsIFRhYkNvbmZpZyB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IE1BU0tFRF9ST0xFUyB9IGZyb20gJy4uL3Rva2Vucy9pbmplY3Rpb24tdG9rZW5zJztcblxuLyoqXG4gKiBSYmFjU2VydmljZSDigJQgQUxMIHBlcm1pc3Npb24gY2hlY2tzIGFuZCBtYXNraW5nIGxvZ2ljIGxpdmUgaGVyZS5cbiAqIENSSVRJQ0FMIFNZTkM6IHJlc29sdmVFZmZlY3RpdmVNYXNrKCkgbXVzdCBiZSBpZGVudGljYWwgdG8gcmJhYy51dGlscy5qcyBpbiBkeW5hbWljLWVudGl0eS1zZXJ2ZXIuXG4gKiBDaGFuZ2luZyBvbmUgd2l0aG91dCB0aGUgb3RoZXIgaXMgYSBjcml0aWNhbCBwcm9kdWN0aW9uIGJ1ZyAoQURSLTAwMykuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgUmJhY1NlcnZpY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IG1hc2tlZFJvbGVzID0gaW5qZWN0KE1BU0tFRF9ST0xFUywgeyBvcHRpb25hbDogdHJ1ZSB9KSA/PyBbXTtcblxuICAvKipcbiAgICogQ2hlY2sgaWYgYW55IG9mIHRoZSB1c2VyJ3Mgcm9sZXMgc2F0aXNmeSB0aGUgcmVxdWlyZWQgcm9sZXMuXG4gICAqIGhhc1Blcm1pc3Npb24ocm9sZXMsIHVuZGVmaW5lZCkg4oaSIHRydWUgKG5vIHJlc3RyaWN0aW9uKS5cbiAgICovXG4gIGhhc1Blcm1pc3Npb24odXNlclJvbGVzOiBzdHJpbmdbXSwgcmVxdWlyZWRSb2xlcz86IHN0cmluZ1tdKTogYm9vbGVhbiB7XG4gICAgaWYgKCFyZXF1aXJlZFJvbGVzPy5sZW5ndGgpIHJldHVybiB0cnVlO1xuICAgIHJldHVybiB1c2VyUm9sZXMuc29tZShyID0+IHJlcXVpcmVkUm9sZXMuaW5jbHVkZXMocikpO1xuICB9XG5cbiAgLyoqXG4gICAqIEFEUi0wMDM6IDMtbGV2ZWwgT1IgcmVzb2x1dGlvbi5cbiAgICogTVVTVCBtYXRjaCByYmFjLnV0aWxzLmpzIHJlc29sdmVFZmZlY3RpdmVNYXNrKCkgZXhhY3RseS5cbiAgICovXG4gIHJlc29sdmVFZmZlY3RpdmVNYXNrKGZvcm1NYXNrPzogYm9vbGVhbiwgdGFiTWFzaz86IGJvb2xlYW4sIGZpZWxkTWFzaz86IGJvb2xlYW4pOiBib29sZWFuIHtcbiAgICByZXR1cm4gISEoZm9ybU1hc2sgfHwgdGFiTWFzayB8fCBmaWVsZE1hc2spO1xuICB9XG5cbiAgLyoqIENoZWNrIGlmIHRoZSB1c2VyJ3Mgcm9sZXMgaW5jbHVkZSBhbnkgbWFza2VkIHJvbGUgKi9cbiAgaXNVc2VyTWFza2VkUm9sZSh1c2VyUm9sZXM6IHN0cmluZ1tdKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMubWFza2VkUm9sZXMuc29tZShyID0+IHVzZXJSb2xlcy5pbmNsdWRlcyhyKSk7XG4gIH1cblxuICAvKiogRGV0ZXJtaW5lIGlmIGEgc3BlY2lmaWMgZmllbGQgc2hvdWxkIGJlIG1hc2tlZCBmb3IgdGhpcyB1c2VyICovXG4gIHNob3VsZE1hc2tGaWVsZChmaWVsZDogRmllbGRDb25maWcsIHRhYjogVGFiQ29uZmlnIHwgdW5kZWZpbmVkLCBjb25maWc6IEVudGl0eUNvbmZpZywgdXNlclJvbGVzOiBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICAgIGlmICghdGhpcy5pc1VzZXJNYXNrZWRSb2xlKHVzZXJSb2xlcykpIHJldHVybiBmYWxzZTtcbiAgICByZXR1cm4gdGhpcy5yZXNvbHZlRWZmZWN0aXZlTWFzayhjb25maWcubWFza0RhdGEsIHRhYj8ubWFza0RhdGEsIGZpZWxkLm1hc2tEYXRhKTtcbiAgfVxuXG4gIC8qKiBHZXQgdmlldy9lZGl0L2RlbGV0ZSBwZXJtaXNzaW9ucyBmb3IgYSBjb25maWcgKi9cbiAgZ2V0UGVybWlzc2lvbnMoY29uZmlnOiBFbnRpdHlDb25maWcsIHVzZXJSb2xlczogc3RyaW5nW10pIHtcbiAgICByZXR1cm4ge1xuICAgICAgY2FuVmlldzogdGhpcy5oYXNQZXJtaXNzaW9uKHVzZXJSb2xlcywgY29uZmlnLnBlcm1pc3Npb25zPy52aWV3KSxcbiAgICAgIGNhbkVkaXQ6IHRoaXMuaGFzUGVybWlzc2lvbih1c2VyUm9sZXMsIGNvbmZpZy5wZXJtaXNzaW9ucz8uZWRpdCksXG4gICAgICBjYW5EZWxldGU6IHRoaXMuaGFzUGVybWlzc2lvbih1c2VyUm9sZXMsIGNvbmZpZy5wZXJtaXNzaW9ucz8uZGVsZXRlKSxcbiAgICB9O1xuICB9XG59XG4iXX0=
46
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmJhYy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9yYmFjLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFbkQsT0FBTyxFQUFFLGVBQWUsSUFBSSxtQkFBbUIsRUFBRSxvQkFBb0IsSUFBSSx3QkFBd0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ2hJLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQzs7QUFFMUQ7O0dBRUc7QUFFSCxNQUFNLE9BQU8sV0FBVztJQUNMLFdBQVcsR0FBRyxNQUFNLENBQUMsWUFBWSxFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLElBQUksRUFBRSxDQUFDO0lBRTlFOzs7T0FHRztJQUNILGFBQWEsQ0FBQyxTQUFtQixFQUFFLGFBQXdCO1FBQ3pELElBQUksQ0FBQyxhQUFhLEVBQUUsTUFBTTtZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ3hDLE9BQU8sU0FBUyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztJQUN4RCxDQUFDO0lBRUQsNEJBQTRCO0lBQzVCLG9CQUFvQixDQUFDLFFBQWtCLEVBQUUsT0FBaUIsRUFBRSxTQUFtQjtRQUM3RSxPQUFPLHdCQUF3QixDQUFDLFFBQVEsRUFBRSxPQUFPLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDaEUsQ0FBQztJQUVELHdEQUF3RDtJQUN4RCxnQkFBZ0IsQ0FBQyxTQUFtQjtRQUNsQyxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO0lBQzNELENBQUM7SUFFRCxtRUFBbUU7SUFDbkUsZUFBZSxDQUFDLEtBQXdCLEVBQUUsR0FBZ0MsRUFBRSxNQUF3QixFQUFFLFNBQW1CO1FBQ3ZILE9BQU8sbUJBQW1CLENBQUMsS0FBSyxFQUFFLEdBQUcsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsQ0FBQztJQUM5RSxDQUFDO0lBRUQsb0RBQW9EO0lBQ3BELGNBQWMsQ0FBQyxNQUF3QixFQUFFLFNBQW1CO1FBQzFELE9BQU87WUFDTCxPQUFPLEVBQUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxTQUFTLEVBQUUsTUFBTSxDQUFDLFdBQVcsRUFBRSxJQUFJLENBQUM7WUFDaEUsT0FBTyxFQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxFQUFFLE1BQU0sQ0FBQyxXQUFXLEVBQUUsSUFBSSxDQUFDO1lBQ2hFLFNBQVMsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLFNBQVMsRUFBRSxNQUFNLENBQUMsV0FBVyxFQUFFLE1BQU0sQ0FBQztTQUNyRSxDQUFDO0lBQ0osQ0FBQzt3R0FsQ1UsV0FBVzs0R0FBWCxXQUFXLGNBREUsTUFBTTs7NEZBQ25CLFdBQVc7a0JBRHZCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgdHlwZSB7IEVudGl0eUZvcm1Db25maWcsIE5lc3RlZEZpZWxkQ29uZmlnLCBOZXN0ZWRUYWJDb25maWcgfSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQgeyBzaG91bGRNYXNrRmllbGQgYXMgY29yZVNob3VsZE1hc2tGaWVsZCwgcmVzb2x2ZUVmZmVjdGl2ZU1hc2sgYXMgY29yZVJlc29sdmVFZmZlY3RpdmVNYXNrIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgTUFTS0VEX1JPTEVTIH0gZnJvbSAnLi4vdG9rZW5zL2luamVjdGlvbi10b2tlbnMnO1xuXG4vKipcbiAqIFJiYWNTZXJ2aWNlIOKAlCBBTEwgcGVybWlzc2lvbiBjaGVja3MgYW5kIG1hc2tpbmcgbG9naWMgbGl2ZSBoZXJlLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIFJiYWNTZXJ2aWNlIHtcbiAgcHJpdmF0ZSByZWFkb25seSBtYXNrZWRSb2xlcyA9IGluamVjdChNQVNLRURfUk9MRVMsIHsgb3B0aW9uYWw6IHRydWUgfSkgPz8gW107XG5cbiAgLyoqXG4gICAqIENoZWNrIGlmIGFueSBvZiB0aGUgdXNlcidzIHJvbGVzIHNhdGlzZnkgdGhlIHJlcXVpcmVkIHJvbGVzLlxuICAgKiBoYXNQZXJtaXNzaW9uKHJvbGVzLCB1bmRlZmluZWQpIOKGkiB0cnVlIChubyByZXN0cmljdGlvbikuXG4gICAqL1xuICBoYXNQZXJtaXNzaW9uKHVzZXJSb2xlczogc3RyaW5nW10sIHJlcXVpcmVkUm9sZXM/OiBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICAgIGlmICghcmVxdWlyZWRSb2xlcz8ubGVuZ3RoKSByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gdXNlclJvbGVzLnNvbWUociA9PiByZXF1aXJlZFJvbGVzLmluY2x1ZGVzKHIpKTtcbiAgfVxuXG4gIC8qKiAzLWxldmVsIE9SIHJlc29sdXRpb24gKi9cbiAgcmVzb2x2ZUVmZmVjdGl2ZU1hc2soZm9ybU1hc2s/OiBib29sZWFuLCB0YWJNYXNrPzogYm9vbGVhbiwgZmllbGRNYXNrPzogYm9vbGVhbik6IGJvb2xlYW4ge1xuICAgIHJldHVybiBjb3JlUmVzb2x2ZUVmZmVjdGl2ZU1hc2soZm9ybU1hc2ssIHRhYk1hc2ssIGZpZWxkTWFzayk7XG4gIH1cblxuICAvKiogQ2hlY2sgaWYgdGhlIHVzZXIncyByb2xlcyBpbmNsdWRlIGFueSBtYXNrZWQgcm9sZSAqL1xuICBpc1VzZXJNYXNrZWRSb2xlKHVzZXJSb2xlczogc3RyaW5nW10pOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5tYXNrZWRSb2xlcy5zb21lKHIgPT4gdXNlclJvbGVzLmluY2x1ZGVzKHIpKTtcbiAgfVxuXG4gIC8qKiBEZXRlcm1pbmUgaWYgYSBzcGVjaWZpYyBmaWVsZCBzaG91bGQgYmUgbWFza2VkIGZvciB0aGlzIHVzZXIgKi9cbiAgc2hvdWxkTWFza0ZpZWxkKGZpZWxkOiBOZXN0ZWRGaWVsZENvbmZpZywgdGFiOiBOZXN0ZWRUYWJDb25maWcgfCB1bmRlZmluZWQsIGNvbmZpZzogRW50aXR5Rm9ybUNvbmZpZywgdXNlclJvbGVzOiBzdHJpbmdbXSk6IGJvb2xlYW4ge1xuICAgIHJldHVybiBjb3JlU2hvdWxkTWFza0ZpZWxkKGZpZWxkLCB0YWIsIGNvbmZpZywgdXNlclJvbGVzLCB0aGlzLm1hc2tlZFJvbGVzKTtcbiAgfVxuXG4gIC8qKiBHZXQgdmlldy9lZGl0L2RlbGV0ZSBwZXJtaXNzaW9ucyBmb3IgYSBjb25maWcgKi9cbiAgZ2V0UGVybWlzc2lvbnMoY29uZmlnOiBFbnRpdHlGb3JtQ29uZmlnLCB1c2VyUm9sZXM6IHN0cmluZ1tdKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgIGNhblZpZXc6IHRoaXMuaGFzUGVybWlzc2lvbih1c2VyUm9sZXMsIGNvbmZpZy5wZXJtaXNzaW9ucz8udmlldyksXG4gICAgICBjYW5FZGl0OiB0aGlzLmhhc1Blcm1pc3Npb24odXNlclJvbGVzLCBjb25maWcucGVybWlzc2lvbnM/LmVkaXQpLFxuICAgICAgY2FuRGVsZXRlOiB0aGlzLmhhc1Blcm1pc3Npb24odXNlclJvbGVzLCBjb25maWcucGVybWlzc2lvbnM/LmRlbGV0ZSksXG4gICAgfTtcbiAgfVxufVxuIl19
@@ -0,0 +1,27 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { evaluateFormRules, filterRulesForTab } from '@dynamic-entity/core';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * RulesEvaluationService — evaluates dynamic form rules against active reactive form state.
6
+ */
7
+ export class RulesEvaluationService {
8
+ /**
9
+ * Evaluate rules against form values and optional original baseline values.
10
+ */
11
+ evaluate(rules, values, originalValues) {
12
+ return evaluateFormRules(rules, values, originalValues);
13
+ }
14
+ /**
15
+ * Filter rules pertinent to a single tab.
16
+ */
17
+ filterForTab(rules, tabId, config) {
18
+ return filterRulesForTab(rules, tabId, config);
19
+ }
20
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RulesEvaluationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
21
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RulesEvaluationService, providedIn: 'root' });
22
+ }
23
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: RulesEvaluationService, decorators: [{
24
+ type: Injectable,
25
+ args: [{ providedIn: 'root' }]
26
+ }] });
27
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicnVsZXMtZXZhbHVhdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9ydWxlcy1ldmFsdWF0aW9uLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQzs7QUFFNUU7O0dBRUc7QUFFSCxNQUFNLE9BQU8sc0JBQXNCO0lBQ2pDOztPQUVHO0lBQ0gsUUFBUSxDQUNOLEtBQW9DLEVBQ3BDLE1BQStCLEVBQy9CLGNBQXdDO1FBRXhDLE9BQU8saUJBQWlCLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxjQUFjLENBQUMsQ0FBQztJQUMxRCxDQUFDO0lBRUQ7O09BRUc7SUFDSCxZQUFZLENBQUMsS0FBb0MsRUFBRSxLQUFhLEVBQUUsTUFBd0I7UUFDeEYsT0FBTyxpQkFBaUIsQ0FBQyxLQUFLLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxDQUFDO0lBQ2pELENBQUM7d0dBakJVLHNCQUFzQjs0R0FBdEIsc0JBQXNCLGNBRFQsTUFBTTs7NEZBQ25CLHNCQUFzQjtrQkFEbEMsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgdHlwZSB7IEVudGl0eUZvcm1Db25maWcsIEZvcm1SdWxlLCBSdWxlRXZhbHVhdGlvblJlc3VsdCB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IGV2YWx1YXRlRm9ybVJ1bGVzLCBmaWx0ZXJSdWxlc0ZvclRhYiB9IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcblxuLyoqXG4gKiBSdWxlc0V2YWx1YXRpb25TZXJ2aWNlIOKAlCBldmFsdWF0ZXMgZHluYW1pYyBmb3JtIHJ1bGVzIGFnYWluc3QgYWN0aXZlIHJlYWN0aXZlIGZvcm0gc3RhdGUuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgUnVsZXNFdmFsdWF0aW9uU2VydmljZSB7XG4gIC8qKlxuICAgKiBFdmFsdWF0ZSBydWxlcyBhZ2FpbnN0IGZvcm0gdmFsdWVzIGFuZCBvcHRpb25hbCBvcmlnaW5hbCBiYXNlbGluZSB2YWx1ZXMuXG4gICAqL1xuICBldmFsdWF0ZShcbiAgICBydWxlczogRm9ybVJ1bGVbXSB8IHVuZGVmaW5lZCB8IG51bGwsXG4gICAgdmFsdWVzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPixcbiAgICBvcmlnaW5hbFZhbHVlcz86IFJlY29yZDxzdHJpbmcsIHVua25vd24+LFxuICApOiBSdWxlRXZhbHVhdGlvblJlc3VsdCB7XG4gICAgcmV0dXJuIGV2YWx1YXRlRm9ybVJ1bGVzKHJ1bGVzLCB2YWx1ZXMsIG9yaWdpbmFsVmFsdWVzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaWx0ZXIgcnVsZXMgcGVydGluZW50IHRvIGEgc2luZ2xlIHRhYi5cbiAgICovXG4gIGZpbHRlckZvclRhYihydWxlczogRm9ybVJ1bGVbXSB8IHVuZGVmaW5lZCB8IG51bGwsIHRhYklkOiBzdHJpbmcsIGNvbmZpZzogRW50aXR5Rm9ybUNvbmZpZyk6IEZvcm1SdWxlW10ge1xuICAgIHJldHVybiBmaWx0ZXJSdWxlc0ZvclRhYihydWxlcywgdGFiSWQsIGNvbmZpZyk7XG4gIH1cbn1cbiJdfQ==
@@ -3,22 +3,18 @@ import { Validators } from '@angular/forms';
3
3
  import { VALIDATOR_REGISTRY } from '../tokens/injection-tokens';
4
4
  import * as i0 from "@angular/core";
5
5
  /**
6
- * ValidatorRegistryService — resolves validator key strings to Angular ValidatorFns.
7
- * Built-in validators: 'required', 'email', 'min:N', 'max:N', 'minLength:N', 'maxLength:N'.
8
- * Consumers can register custom validators via provideNgxDynamicEntity({ validators: {...} }).
6
+ * ValidatorRegistryService — resolves validator configs / key strings to Angular ValidatorFns.
9
7
  */
10
8
  export class ValidatorRegistryService {
11
9
  consumerRegistry = inject(VALIDATOR_REGISTRY, { optional: true }) ?? new Map();
12
10
  /**
13
- * Resolve a validator key to a ValidatorFn.
11
+ * Resolve a validator key string to a ValidatorFn.
14
12
  * Supports parameterized built-ins like 'min:0', 'maxLength:255'.
15
13
  */
16
14
  resolve(validatorKey) {
17
- // Consumer validators take precedence
18
15
  if (this.consumerRegistry.has(validatorKey)) {
19
16
  return this.consumerRegistry.get(validatorKey);
20
17
  }
21
- // Built-in validators
22
18
  if (validatorKey === 'required')
23
19
  return Validators.required;
24
20
  if (validatorKey === 'email')
@@ -39,6 +35,38 @@ export class ValidatorRegistryService {
39
35
  resolveAll(validatorKeys = []) {
40
36
  return validatorKeys.map(k => this.resolve(k)).filter((v) => v !== null);
41
37
  }
38
+ /** Resolve a FieldValidators object or string[] into ValidatorFn[] */
39
+ resolveFromConfig(config) {
40
+ if (!config)
41
+ return [];
42
+ if (Array.isArray(config))
43
+ return this.resolveAll(config);
44
+ const fnList = [];
45
+ if (config.required)
46
+ fnList.push(Validators.required);
47
+ if (config.min !== undefined)
48
+ fnList.push(Validators.min(config.min));
49
+ if (config.max !== undefined)
50
+ fnList.push(Validators.max(config.max));
51
+ if (config.minLength !== undefined)
52
+ fnList.push(Validators.minLength(config.minLength));
53
+ if (config.maxLength !== undefined)
54
+ fnList.push(Validators.maxLength(config.maxLength));
55
+ if (config.pattern)
56
+ fnList.push(Validators.pattern(config.pattern));
57
+ if (config.email)
58
+ fnList.push(Validators.email);
59
+ // Named validators from the consumer registry. This branch previously hardcoded the
60
+ // built-ins and consulted the registry only for the `string[]` form of this config, so
61
+ // a validator the consumer had registered could not be named from a typed schema
62
+ // without casting it to `any`.
63
+ for (const key of config.custom ?? []) {
64
+ const fn = this.resolve(key);
65
+ if (fn)
66
+ fnList.push(fn);
67
+ }
68
+ return fnList;
69
+ }
42
70
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ValidatorRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
43
71
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: ValidatorRegistryService, providedIn: 'root' });
44
72
  }
@@ -46,4 +74,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
46
74
  type: Injectable,
47
75
  args: [{ providedIn: 'root' }]
48
76
  }] });
49
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLXJlZ2lzdHJ5LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL3ZhbGlkYXRvci1yZWdpc3RyeS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBZ0MsVUFBVSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDMUUsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7O0FBRWhFOzs7O0dBSUc7QUFFSCxNQUFNLE9BQU8sd0JBQXdCO0lBQ2xCLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxJQUFJLElBQUksR0FBRyxFQUFFLENBQUM7SUFFaEc7OztPQUdHO0lBQ0gsT0FBTyxDQUFDLFlBQW9CO1FBQzFCLHNDQUFzQztRQUN0QyxJQUFJLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztZQUM1QyxPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsWUFBWSxDQUFDLENBQUM7UUFDakQsQ0FBQztRQUVELHNCQUFzQjtRQUN0QixJQUFJLFlBQVksS0FBSyxVQUFVO1lBQUUsT0FBTyxVQUFVLENBQUMsUUFBUSxDQUFDO1FBQzVELElBQUksWUFBWSxLQUFLLE9BQU87WUFBRSxPQUFPLFVBQVUsQ0FBQyxLQUFLLENBQUM7UUFFdEQsTUFBTSxDQUFDLElBQUksRUFBRSxLQUFLLENBQUMsR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDO1FBQzlDLE1BQU0sS0FBSyxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUVoQyxJQUFJLElBQUksS0FBSyxLQUFLLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO1lBQUUsT0FBTyxVQUFVLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2xFLElBQUksSUFBSSxLQUFLLEtBQUssSUFBSSxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUM7WUFBRSxPQUFPLFVBQVUsQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDbEUsSUFBSSxJQUFJLEtBQUssV0FBVyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztZQUFFLE9BQU8sVUFBVSxDQUFDLFNBQVMsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM5RSxJQUFJLElBQUksS0FBSyxXQUFXLElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDO1lBQUUsT0FBTyxVQUFVLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBRTlFLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELDJEQUEyRDtJQUMzRCxVQUFVLENBQUMsZ0JBQTBCLEVBQUU7UUFDckMsT0FBTyxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsRUFBb0IsRUFBRSxDQUFDLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQztJQUM3RixDQUFDO3dHQS9CVSx3QkFBd0I7NEdBQXhCLHdCQUF3QixjQURYLE1BQU07OzRGQUNuQix3QkFBd0I7a0JBRHBDLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBBYnN0cmFjdENvbnRyb2wsIFZhbGlkYXRvckZuLCBWYWxpZGF0b3JzIH0gZnJvbSAnQGFuZ3VsYXIvZm9ybXMnO1xuaW1wb3J0IHsgVkFMSURBVE9SX1JFR0lTVFJZIH0gZnJvbSAnLi4vdG9rZW5zL2luamVjdGlvbi10b2tlbnMnO1xuXG4vKipcbiAqIFZhbGlkYXRvclJlZ2lzdHJ5U2VydmljZSDigJQgcmVzb2x2ZXMgdmFsaWRhdG9yIGtleSBzdHJpbmdzIHRvIEFuZ3VsYXIgVmFsaWRhdG9yRm5zLlxuICogQnVpbHQtaW4gdmFsaWRhdG9yczogJ3JlcXVpcmVkJywgJ2VtYWlsJywgJ21pbjpOJywgJ21heDpOJywgJ21pbkxlbmd0aDpOJywgJ21heExlbmd0aDpOJy5cbiAqIENvbnN1bWVycyBjYW4gcmVnaXN0ZXIgY3VzdG9tIHZhbGlkYXRvcnMgdmlhIHByb3ZpZGVOZ3hEeW5hbWljRW50aXR5KHsgdmFsaWRhdG9yczogey4uLn0gfSkuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgVmFsaWRhdG9yUmVnaXN0cnlTZXJ2aWNlIHtcbiAgcHJpdmF0ZSByZWFkb25seSBjb25zdW1lclJlZ2lzdHJ5ID0gaW5qZWN0KFZBTElEQVRPUl9SRUdJU1RSWSwgeyBvcHRpb25hbDogdHJ1ZSB9KSA/PyBuZXcgTWFwKCk7XG5cbiAgLyoqXG4gICAqIFJlc29sdmUgYSB2YWxpZGF0b3Iga2V5IHRvIGEgVmFsaWRhdG9yRm4uXG4gICAqIFN1cHBvcnRzIHBhcmFtZXRlcml6ZWQgYnVpbHQtaW5zIGxpa2UgJ21pbjowJywgJ21heExlbmd0aDoyNTUnLlxuICAgKi9cbiAgcmVzb2x2ZSh2YWxpZGF0b3JLZXk6IHN0cmluZyk6IFZhbGlkYXRvckZuIHwgbnVsbCB7XG4gICAgLy8gQ29uc3VtZXIgdmFsaWRhdG9ycyB0YWtlIHByZWNlZGVuY2VcbiAgICBpZiAodGhpcy5jb25zdW1lclJlZ2lzdHJ5Lmhhcyh2YWxpZGF0b3JLZXkpKSB7XG4gICAgICByZXR1cm4gdGhpcy5jb25zdW1lclJlZ2lzdHJ5LmdldCh2YWxpZGF0b3JLZXkpO1xuICAgIH1cblxuICAgIC8vIEJ1aWx0LWluIHZhbGlkYXRvcnNcbiAgICBpZiAodmFsaWRhdG9yS2V5ID09PSAncmVxdWlyZWQnKSByZXR1cm4gVmFsaWRhdG9ycy5yZXF1aXJlZDtcbiAgICBpZiAodmFsaWRhdG9yS2V5ID09PSAnZW1haWwnKSByZXR1cm4gVmFsaWRhdG9ycy5lbWFpbDtcblxuICAgIGNvbnN0IFtuYW1lLCBwYXJhbV0gPSB2YWxpZGF0b3JLZXkuc3BsaXQoJzonKTtcbiAgICBjb25zdCB2YWx1ZSA9IHBhcnNlRmxvYXQocGFyYW0pO1xuXG4gICAgaWYgKG5hbWUgPT09ICdtaW4nICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1pbih2YWx1ZSk7XG4gICAgaWYgKG5hbWUgPT09ICdtYXgnICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1heCh2YWx1ZSk7XG4gICAgaWYgKG5hbWUgPT09ICdtaW5MZW5ndGgnICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1pbkxlbmd0aCh2YWx1ZSk7XG4gICAgaWYgKG5hbWUgPT09ICdtYXhMZW5ndGgnICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1heExlbmd0aCh2YWx1ZSk7XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKiBSZXNvbHZlIG11bHRpcGxlIHZhbGlkYXRvciBrZXlzIGludG8gYSBWYWxpZGF0b3JGbltdICovXG4gIHJlc29sdmVBbGwodmFsaWRhdG9yS2V5czogc3RyaW5nW10gPSBbXSk6IFZhbGlkYXRvckZuW10ge1xuICAgIHJldHVybiB2YWxpZGF0b3JLZXlzLm1hcChrID0+IHRoaXMucmVzb2x2ZShrKSkuZmlsdGVyKCh2KTogdiBpcyBWYWxpZGF0b3JGbiA9PiB2ICE9PSBudWxsKTtcbiAgfVxufVxuIl19
77
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidmFsaWRhdG9yLXJlZ2lzdHJ5LnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL3ZhbGlkYXRvci1yZWdpc3RyeS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ25ELE9BQU8sRUFBZSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQztBQUV6RCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQzs7QUFFaEU7O0dBRUc7QUFFSCxNQUFNLE9BQU8sd0JBQXdCO0lBQ2xCLGdCQUFnQixHQUFHLE1BQU0sQ0FBQyxrQkFBa0IsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxJQUFJLElBQUksR0FBRyxFQUFFLENBQUM7SUFFaEc7OztPQUdHO0lBQ0gsT0FBTyxDQUFDLFlBQW9CO1FBQzFCLElBQUksSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsRUFBRSxDQUFDO1lBQzVDLE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQztRQUNqRCxDQUFDO1FBRUQsSUFBSSxZQUFZLEtBQUssVUFBVTtZQUFFLE9BQU8sVUFBVSxDQUFDLFFBQVEsQ0FBQztRQUM1RCxJQUFJLFlBQVksS0FBSyxPQUFPO1lBQUUsT0FBTyxVQUFVLENBQUMsS0FBSyxDQUFDO1FBRXRELE1BQU0sQ0FBQyxJQUFJLEVBQUUsS0FBSyxDQUFDLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUM5QyxNQUFNLEtBQUssR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFaEMsSUFBSSxJQUFJLEtBQUssS0FBSyxJQUFJLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQztZQUFFLE9BQU8sVUFB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RUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBWYWxpZGF0b3JGbiwgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJztcbmltcG9ydCB0eXBlIHsgRmllbGRWYWxpZGF0b3JzIH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgVkFMSURBVE9SX1JFR0lTVFJZIH0gZnJvbSAnLi4vdG9rZW5zL2luamVjdGlvbi10b2tlbnMnO1xuXG4vKipcbiAqIFZhbGlkYXRvclJlZ2lzdHJ5U2VydmljZSDigJQgcmVzb2x2ZXMgdmFsaWRhdG9yIGNvbmZpZ3MgLyBrZXkgc3RyaW5ncyB0byBBbmd1bGFyIFZhbGlkYXRvckZucy5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBWYWxpZGF0b3JSZWdpc3RyeVNlcnZpY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IGNvbnN1bWVyUmVnaXN0cnkgPSBpbmplY3QoVkFMSURBVE9SX1JFR0lTVFJZLCB7IG9wdGlvbmFsOiB0cnVlIH0pID8/IG5ldyBNYXAoKTtcblxuICAvKipcbiAgICogUmVzb2x2ZSBhIHZhbGlkYXRvciBrZXkgc3RyaW5nIHRvIGEgVmFsaWRhdG9yRm4uXG4gICAqIFN1cHBvcnRzIHBhcmFtZXRlcml6ZWQgYnVpbHQtaW5zIGxpa2UgJ21pbjowJywgJ21heExlbmd0aDoyNTUnLlxuICAgKi9cbiAgcmVzb2x2ZSh2YWxpZGF0b3JLZXk6IHN0cmluZyk6IFZhbGlkYXRvckZuIHwgbnVsbCB7XG4gICAgaWYgKHRoaXMuY29uc3VtZXJSZWdpc3RyeS5oYXModmFsaWRhdG9yS2V5KSkge1xuICAgICAgcmV0dXJuIHRoaXMuY29uc3VtZXJSZWdpc3RyeS5nZXQodmFsaWRhdG9yS2V5KTtcbiAgICB9XG5cbiAgICBpZiAodmFsaWRhdG9yS2V5ID09PSAncmVxdWlyZWQnKSByZXR1cm4gVmFsaWRhdG9ycy5yZXF1aXJlZDtcbiAgICBpZiAodmFsaWRhdG9yS2V5ID09PSAnZW1haWwnKSByZXR1cm4gVmFsaWRhdG9ycy5lbWFpbDtcblxuICAgIGNvbnN0IFtuYW1lLCBwYXJhbV0gPSB2YWxpZGF0b3JLZXkuc3BsaXQoJzonKTtcbiAgICBjb25zdCB2YWx1ZSA9IHBhcnNlRmxvYXQocGFyYW0pO1xuXG4gICAgaWYgKG5hbWUgPT09ICdtaW4nICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1pbih2YWx1ZSk7XG4gICAgaWYgKG5hbWUgPT09ICdtYXgnICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1heCh2YWx1ZSk7XG4gICAgaWYgKG5hbWUgPT09ICdtaW5MZW5ndGgnICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1pbkxlbmd0aCh2YWx1ZSk7XG4gICAgaWYgKG5hbWUgPT09ICdtYXhMZW5ndGgnICYmICFpc05hTih2YWx1ZSkpIHJldHVybiBWYWxpZGF0b3JzLm1heExlbmd0aCh2YWx1ZSk7XG5cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIC8qKiBSZXNvbHZlIG11bHRpcGxlIHZhbGlkYXRvciBrZXlzIGludG8gYSBWYWxpZGF0b3JGbltdICovXG4gIHJlc29sdmVBbGwodmFsaWRhdG9yS2V5czogc3RyaW5nW10gPSBbXSk6IFZhbGlkYXRvckZuW10ge1xuICAgIHJldHVybiB2YWxpZGF0b3JLZXlzLm1hcChrID0+IHRoaXMucmVzb2x2ZShrKSkuZmlsdGVyKCh2KTogdiBpcyBWYWxpZGF0b3JGbiA9PiB2ICE9PSBudWxsKTtcbiAgfVxuXG4gIC8qKiBSZXNvbHZlIGEgRmllbGRWYWxpZGF0b3JzIG9iamVjdCBvciBzdHJpbmdbXSBpbnRvIFZhbGlkYXRvckZuW10gKi9cbiAgcmVzb2x2ZUZyb21Db25maWcoY29uZmlnPzogRmllbGRWYWxpZGF0b3JzIHwgc3RyaW5nW10pOiBWYWxpZGF0b3JGbltdIHtcbiAgICBpZiAoIWNvbmZpZykgcmV0dXJuIFtdO1xuICAgIGlmIChBcnJheS5pc0FycmF5KGNvbmZpZykpIHJldHVybiB0aGlzLnJlc29sdmVBbGwoY29uZmlnKTtcblxuICAgIGNvbnN0IGZuTGlzdDogVmFsaWRhdG9yRm5bXSA9IFtdO1xuICAgIGlmIChjb25maWcucmVxdWlyZWQpIGZuTGlzdC5wdXNoKFZhbGlkYXRvcnMucmVxdWlyZWQpO1xuICAgIGlmIChjb25maWcubWluICE9PSB1bmRlZmluZWQpIGZuTGlzdC5wdXNoKFZhbGlkYXRvcnMubWluKGNvbmZpZy5taW4pKTtcbiAgICBpZiAoY29uZmlnLm1heCAhPT0gdW5kZWZpbmVkKSBmbkxpc3QucHVzaChWYWxpZGF0b3JzLm1heChjb25maWcubWF4KSk7XG4gICAgaWYgKGNvbmZpZy5taW5MZW5ndGggIT09IHVuZGVmaW5lZCkgZm5MaXN0LnB1c2goVmFsaWRhdG9ycy5taW5MZW5ndGgoY29uZmlnLm1pbkxlbmd0aCkpO1xuICAgIGlmIChjb25maWcubWF4TGVuZ3RoICE9PSB1bmRlZmluZWQpIGZuTGlzdC5wdXNoKFZhbGlkYXRvcnMubWF4TGVuZ3RoKGNvbmZpZy5tYXhMZW5ndGgpKTtcbiAgICBpZiAoY29uZmlnLnBhdHRlcm4pIGZuTGlzdC5wdXNoKFZhbGlkYXRvcnMucGF0dGVybihjb25maWcucGF0dGVybikpO1xuICAgIGlmIChjb25maWcuZW1haWwpIGZuTGlzdC5wdXNoKFZhbGlkYXRvcnMuZW1haWwpO1xuXG4gICAgLy8gTmFtZWQgdmFsaWRhdG9ycyBmcm9tIHRoZSBjb25zdW1lciByZWdpc3RyeS4gVGhpcyBicmFuY2ggcHJldmlvdXNseSBoYXJkY29kZWQgdGhlXG4gICAgLy8gYnVpbHQtaW5zIGFuZCBjb25zdWx0ZWQgdGhlIHJlZ2lzdHJ5IG9ubHkgZm9yIHRoZSBgc3RyaW5nW11gIGZvcm0gb2YgdGhpcyBjb25maWcsIHNvXG4gICAgLy8gYSB2YWxpZGF0b3IgdGhlIGNvbnN1bWVyIGhhZCByZWdpc3RlcmVkIGNvdWxkIG5vdCBiZSBuYW1lZCBmcm9tIGEgdHlwZWQgc2NoZW1hXG4gICAgLy8gd2l0aG91dCBjYXN0aW5nIGl0IHRvIGBhbnlgLlxuICAgIGZvciAoY29uc3Qga2V5IG9mIGNvbmZpZy5jdXN0b20gPz8gW10pIHtcbiAgICAgIGNvbnN0IGZuID0gdGhpcy5yZXNvbHZlKGtleSk7XG4gICAgICBpZiAoZm4pIGZuTGlzdC5wdXNoKGZuKTtcbiAgICB9XG5cbiAgICByZXR1cm4gZm5MaXN0O1xuICB9XG59XG4iXX0=
@@ -1,16 +1,113 @@
1
1
  import { InjectionToken } from '@angular/core';
2
- /** Base URL for the dynamic-entity-server API */
3
- export const DYNAMIC_ENTITY_API_URL = new InjectionToken('DYNAMIC_ENTITY_API_URL');
2
+ import { InMemoryEntityRefCacheStore } from '../services/entity-ref-cache';
4
3
  /** Roles that see XXXXXXXXX for masked fields (ADR-003) */
5
4
  export const MASKED_ROLES = new InjectionToken('MASKED_ROLES');
6
- /** Migration strategy for the frontend — 'strict' | 'graceful' only (ADR-005, never 'auto') */
7
- export const MIGRATION_STRATEGY = new InjectionToken('MIGRATION_STRATEGY');
8
- /** Registry: fieldType string → Angular component class */
5
+ /**
6
+ * Consumer **overrides**: fieldType string → Angular component class.
7
+ * Highest priority — beats anything registered through `provideFieldTypes()`.
8
+ */
9
9
  export const FIELD_TYPE_REGISTRY = new InjectionToken('FIELD_TYPE_REGISTRY');
10
- /** Registry: entity key → async () => options[] loader function */
10
+ /**
11
+ * Multi-provider of field-type sets, contributed by `provideFieldTypes()` /
12
+ * `provideBuiltInFieldTypes()`. Multi so several calls compose instead of clobbering;
13
+ * later sets win on key collision. This is the seam that keeps unused field components
14
+ * out of the bundle — nothing is imported until a set names it.
15
+ */
16
+ export const FIELD_TYPE_SETS = new InjectionToken('FIELD_TYPE_SETS');
17
+ /**
18
+ * Registry: entity key → option loader.
19
+ *
20
+ * A loader receives a `ReferenceLoaderContext` (`parentValue`, `filters`, `lang`) and may
21
+ * return an array, a Promise, or an Observable of `ReferenceOption[]`. `ctx` is optional,
22
+ * so a zero-arg loader (`() => svc.list()`) is still a valid registration.
23
+ */
11
24
  export const ENTITY_REF_REGISTRY = new InjectionToken('ENTITY_REF_REGISTRY');
25
+ /**
26
+ * Registry: list name → the values of a named master list (`field.listName`).
27
+ *
28
+ * A source may be the values themselves (array / Promise / Observable) or a **loader function**,
29
+ * which is what you want for anything fetched: a bare Promise is created when the provider is
30
+ * built, so every list would load whether or not a form uses it.
31
+ *
32
+ * Values are normalised by `normalizeLookupValues` — bare strings and `LocalizedText` are
33
+ * accepted alongside the full `{ code, name, sortOrder }` shape.
34
+ *
35
+ * @example
36
+ * provideNgxDynamicEntity({
37
+ * lookups: {
38
+ * employeeStatus: () => listService.getByName('employeeStatus'),
39
+ * grades: ['Junior', 'Senior'],
40
+ * },
41
+ * })
42
+ */
43
+ export const LOOKUP_REGISTRY = new InjectionToken('LOOKUP_REGISTRY');
44
+ /**
45
+ * Ordered steps that move a saved record forward when a config's `version` increases.
46
+ *
47
+ * Without these, `EntityFormConfig.version` and `VersionedRecord._configVersion` are
48
+ * declarations nothing acts on: a schema can be edited freely while records keep their old
49
+ * shape, and nothing reconciles the two. Registering migrations makes the version numbers
50
+ * mean something.
51
+ *
52
+ * @example
53
+ * provideNgxDynamicEntity({
54
+ * migrations: [
55
+ * { from: 1, to: 2, description: 'split name', migrate: r => ({ ...r, firstName: r['name'] }) },
56
+ * ],
57
+ * })
58
+ */
59
+ export const RECORD_MIGRATIONS = new InjectionToken('RECORD_MIGRATIONS');
12
60
  /** Registry: validator key → ValidatorFn */
13
61
  export const VALIDATOR_REGISTRY = new InjectionToken('VALIDATOR_REGISTRY');
14
62
  /** Registry: hook key → async (data, context) => data */
15
63
  export const HOOK_REGISTRY = new InjectionToken('HOOK_REGISTRY');
16
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5qZWN0aW9uLXRva2Vucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvdG9rZW5zL2luamVjdGlvbi10b2tlbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUkvQyxpREFBaUQ7QUFDakQsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsSUFBSSxjQUFjLENBQVMsd0JBQXdCLENBQUMsQ0FBQztBQUUzRiwyREFBMkQ7QUFDM0QsTUFBTSxDQUFDLE1BQU0sWUFBWSxHQUFHLElBQUksY0FBYyxDQUFXLGNBQWMsQ0FBQyxDQUFDO0FBRXpFLCtGQUErRjtBQUMvRixNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLGNBQWMsQ0FBd0Isb0JBQW9CLENBQUMsQ0FBQztBQUVsRywyREFBMkQ7QUFDM0QsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsSUFBSSxjQUFjLENBQXlCLHFCQUFxQixDQUFDLENBQUM7QUFFckcsbUVBQW1FO0FBQ25FLE1BQU0sQ0FBQyxNQUFNLG1CQUFtQixHQUFHLElBQUksY0FBYyxDQUNuRCxxQkFBcUIsQ0FDdEIsQ0FBQztBQUVGLDRDQUE0QztBQUM1QyxNQUFNLENBQUMsTUFBTSxrQkFBa0IsR0FBRyxJQUFJLGNBQWMsQ0FBbUIsb0JBQW9CLENBQUMsQ0FBQztBQUU3Rix5REFBeUQ7QUFDekQsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLElBQUksY0FBYyxDQUF3QixlQUFlLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGlvblRva2VuIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgdHlwZSB7IEVudGl0eUNvbmZpZywgRmllbGRDb25maWcsIE1pZ3JhdGlvblN0cmF0ZWd5IH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHR5cGUgeyBUeXBlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5cbi8qKiBCYXNlIFVSTCBmb3IgdGhlIGR5bmFtaWMtZW50aXR5LXNlcnZlciBBUEkgKi9cbmV4cG9ydCBjb25zdCBEWU5BTUlDX0VOVElUWV9BUElfVVJMID0gbmV3IEluamVjdGlvblRva2VuPHN0cmluZz4oJ0RZTkFNSUNfRU5USVRZX0FQSV9VUkwnKTtcblxuLyoqIFJvbGVzIHRoYXQgc2VlIFhYWFhYWFhYWCBmb3IgbWFza2VkIGZpZWxkcyAoQURSLTAwMykgKi9cbmV4cG9ydCBjb25zdCBNQVNLRURfUk9MRVMgPSBuZXcgSW5qZWN0aW9uVG9rZW48c3RyaW5nW10+KCdNQVNLRURfUk9MRVMnKTtcblxuLyoqIE1pZ3JhdGlvbiBzdHJhdGVneSBmb3IgdGhlIGZyb250ZW5kIOKAlCAnc3RyaWN0JyB8ICdncmFjZWZ1bCcgb25seSAoQURSLTAwNSwgbmV2ZXIgJ2F1dG8nKSAqL1xuZXhwb3J0IGNvbnN0IE1JR1JBVElPTl9TVFJBVEVHWSA9IG5ldyBJbmplY3Rpb25Ub2tlbjwnc3RyaWN0JyB8ICdncmFjZWZ1bCc+KCdNSUdSQVRJT05fU1RSQVRFR1knKTtcblxuLyoqIFJlZ2lzdHJ5OiBmaWVsZFR5cGUgc3RyaW5nIOKGkiBBbmd1bGFyIGNvbXBvbmVudCBjbGFzcyAqL1xuZXhwb3J0IGNvbnN0IEZJRUxEX1RZUEVfUkVHSVNUUlkgPSBuZXcgSW5qZWN0aW9uVG9rZW48TWFwPHN0cmluZywgVHlwZTxhbnk+Pj4oJ0ZJRUxEX1RZUEVfUkVHSVNUUlknKTtcblxuLyoqIFJlZ2lzdHJ5OiBlbnRpdHkga2V5IOKGkiBhc3luYyAoKSA9PiBvcHRpb25zW10gbG9hZGVyIGZ1bmN0aW9uICovXG5leHBvcnQgY29uc3QgRU5USVRZX1JFRl9SRUdJU1RSWSA9IG5ldyBJbmplY3Rpb25Ub2tlbjxNYXA8c3RyaW5nLCAoKSA9PiBQcm9taXNlPGFueVtdPj4+KFxuICAnRU5USVRZX1JFRl9SRUdJU1RSWScsXG4pO1xuXG4vKiogUmVnaXN0cnk6IHZhbGlkYXRvciBrZXkg4oaSIFZhbGlkYXRvckZuICovXG5leHBvcnQgY29uc3QgVkFMSURBVE9SX1JFR0lTVFJZID0gbmV3IEluamVjdGlvblRva2VuPE1hcDxzdHJpbmcsIGFueT4+KCdWQUxJREFUT1JfUkVHSVNUUlknKTtcblxuLyoqIFJlZ2lzdHJ5OiBob29rIGtleSDihpIgYXN5bmMgKGRhdGEsIGNvbnRleHQpID0+IGRhdGEgKi9cbmV4cG9ydCBjb25zdCBIT09LX1JFR0lTVFJZID0gbmV3IEluamVjdGlvblRva2VuPE1hcDxzdHJpbmcsIEZ1bmN0aW9uPj4oJ0hPT0tfUkVHSVNUUlknKTtcbiJdfQ==
64
+ /**
65
+ * Consumer-registered list of common module tabs (documents, audit, tasks, etc.).
66
+ * The library ships no built-in implementations. Consumers provide their own list
67
+ * so the builder's module-picker and the renderer's tab switcher know what's available.
68
+ *
69
+ * @example
70
+ * providers: [
71
+ * {
72
+ * provide: COMMON_MODULES_REGISTRY,
73
+ * useValue: [
74
+ * { id: 'documents', label: { en: 'Documents' }, component: 'app-documents-view' },
75
+ * { id: 'audit', label: { en: 'Audit Log' }, component: 'app-audit' },
76
+ * ] satisfies CommonModuleEntry[]
77
+ * }
78
+ * ]
79
+ */
80
+ export const COMMON_MODULES_REGISTRY = new InjectionToken('COMMON_MODULES_REGISTRY');
81
+ /**
82
+ * Consumer-provided file/image upload handler.
83
+ * When supplied, image-field and file-field call it to persist the File and receive a stable
84
+ * URL back. Without it the field stores `{ file, name, size, mimeType }` for the consumer to
85
+ * upload on submit. May return the result directly, as a Promise, or as an Observable.
86
+ *
87
+ * @example
88
+ * { provide: UPLOAD_HANDLER, useFactory: () => (file: File) => myUploadService.upload(file) }
89
+ */
90
+ export const UPLOAD_HANDLER = new InjectionToken('UPLOAD_HANDLER');
91
+ /**
92
+ * Backing store for the entity-reference options cache. Defaults to in-memory.
93
+ * Provide your own to make the cache outlive a page refresh.
94
+ *
95
+ * @example
96
+ * { provide: ENTITY_REF_CACHE_STORE, useClass: SessionStorageRefCache }
97
+ */
98
+ export const ENTITY_REF_CACHE_STORE = new InjectionToken('ENTITY_REF_CACHE_STORE', { providedIn: 'root', factory: () => new InMemoryEntityRefCacheStore() });
99
+ /**
100
+ * Consumer-provided predicate function to check whether user roles can edit system default tabs or fields.
101
+ * Defaults to allowing edits if not provided.
102
+ */
103
+ /**
104
+ * Consumer-provided predicate function to check whether user roles can edit system default tabs or fields.
105
+ * Defaults to allowing edits if not provided.
106
+ */
107
+ export const SYSTEM_DEFAULT_CAN_EDIT = new InjectionToken('SYSTEM_DEFAULT_CAN_EDIT');
108
+ /**
109
+ * Registry/Resolver for resolving an EntityFormConfig by entity key across entities (Phase 8).
110
+ * Enables cross-entity field referencing (`isReferenced`, `referencedEntityKey`, `referencedFieldId`, `hasDrift`).
111
+ */
112
+ export const CONFIG_SOURCE = new InjectionToken('CONFIG_SOURCE');
113
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5qZWN0aW9uLXRva2Vucy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvdG9rZW5zL2luamVjdGlvbi10b2tlbnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLGNBQWMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQVMvQyxPQUFPLEVBQUUsMkJBQTJCLEVBQTRCLE1BQU0sOEJBQThCLENBQUM7QUFFckcsMkRBQTJEO0FBQzNELE1BQU0sQ0FBQyxNQUFNLFlBQVksR0FBRyxJQUFJLGNBQWMsQ0FBVyxjQUFjLENBQUMsQ0FBQztBQUV6RTs7O0dBR0c7QUFDSCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLGNBQWMsQ0FBeUIscUJBQXFCLENBQUMsQ0FBQztBQUVyRzs7Ozs7R0FLRztBQUNILE1BQU0sQ0FBQyxNQUFNLGVBQWUsR0FBRyxJQUFJLGNBQWMsQ0FBOEIsaUJBQWlCLENBQUMsQ0FBQztBQUVsRzs7Ozs7O0dBTUc7QUFDSCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRyxJQUFJLGNBQWMsQ0FDbkQscUJBQXFCLENBQ3RCLENBQUM7QUFFRjs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FpQkc7QUFDSCxNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsSUFBSSxjQUFjLENBQWdDLGlCQUFpQixDQUFDLENBQUM7QUFFcEc7Ozs7Ozs7Ozs7Ozs7O0dBY0c7QUFDSCxNQUFNLENBQUMsTUFBTSxpQkFBaUIsR0FBRyxJQUFJLGNBQWMsQ0FBb0IsbUJBQW1CLENBQUMsQ0FBQztBQUU1Riw0Q0FBNEM7QUFDNUMsTUFBTSxDQUFDLE1BQU0sa0JBQWtCLEdBQUcsSUFBSSxjQUFjLENBQW1CLG9CQUFvQixDQUFDLENBQUM7QUFVN0YseURBQXlEO0FBQ3pELE1BQU0sQ0FBQyxNQUFNLGFBQWEsR0FBRyxJQUFJLGNBQWMsQ0FBc0IsZUFBZSxDQUFDLENBQUM7QUFFdEY7Ozs7Ozs7Ozs7Ozs7OztHQWVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsSUFBSSxjQUFjLENBQ3ZELHlCQUF5QixDQUMxQixDQUFDO0FBRUY7Ozs7Ozs7O0dBUUc7QUFDSCxNQUFNLENBQUMsTUFBTSxjQUFjLEdBQUcsSUFBSSxjQUFjLENBQW9CLGdCQUFnQixDQUFDLENBQUM7QUFFdEY7Ozs7OztHQU1HO0FBQ0gsTUFBTSxDQUFDLE1BQU0sc0JBQXNCLEdBQUcsSUFBSSxjQUFjLENBQ3RELHdCQUF3QixFQUN4QixFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsT0FBTyxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQUksMkJBQTJCLEVBQUUsRUFBRSxDQUN6RSxDQUFDO0FBRUY7OztHQUdHO0FBQ0g7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sdUJBQXVCLEdBQUcsSUFBSSxjQUFjLENBQ3ZELHlCQUF5QixDQUMxQixDQUFDO0FBTUY7OztHQUdHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sYUFBYSxHQUFHLElBQUksY0FBYyxDQUFzQixlQUFlLENBQUMsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGlvblRva2VuIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgdHlwZSB7IFR5cGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB0eXBlIHtcbiAgQ29tbW9uTW9kdWxlRW50cnksXG4gIEVudGl0eVJlZmVyZW5jZUxvYWRlcixcbiAgRmlsZVVwbG9hZEhhbmRsZXIsXG4gIExvb2t1cExpc3RTb3VyY2UsXG4gIFJlY29yZE1pZ3JhdGlvbixcbn0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgSW5NZW1vcnlFbnRpdHlSZWZDYWNoZVN0b3JlLCB0eXBlIEVudGl0eVJlZkNhY2hlU3RvcmUgfSBmcm9tICcuLi9zZXJ2aWNlcy9lbnRpdHktcmVmLWNhY2hlJztcblxuLyoqIFJvbGVzIHRoYXQgc2VlIFhYWFhYWFhYWCBmb3IgbWFza2VkIGZpZWxkcyAoQURSLTAwMykgKi9cbmV4cG9ydCBjb25zdCBNQVNLRURfUk9MRVMgPSBuZXcgSW5qZWN0aW9uVG9rZW48c3RyaW5nW10+KCdNQVNLRURfUk9MRVMnKTtcblxuLyoqXG4gKiBDb25zdW1lciAqKm92ZXJyaWRlcyoqOiBmaWVsZFR5cGUgc3RyaW5nIOKGkiBBbmd1bGFyIGNvbXBvbmVudCBjbGFzcy5cbiAqIEhpZ2hlc3QgcHJpb3JpdHkg4oCUIGJlYXRzIGFueXRoaW5nIHJlZ2lzdGVyZWQgdGhyb3VnaCBgcHJvdmlkZUZpZWxkVHlwZXMoKWAuXG4gKi9cbmV4cG9ydCBjb25zdCBGSUVMRF9UWVBFX1JFR0lTVFJZID0gbmV3IEluamVjdGlvblRva2VuPE1hcDxzdHJpbmcsIFR5cGU8YW55Pj4+KCdGSUVMRF9UWVBFX1JFR0lTVFJZJyk7XG5cbi8qKlxuICogTXVsdGktcHJvdmlkZXIgb2YgZmllbGQtdHlwZSBzZXRzLCBjb250cmlidXRlZCBieSBgcHJvdmlkZUZpZWxkVHlwZXMoKWAgL1xuICogYHByb3ZpZGVCdWlsdEluRmllbGRUeXBlcygpYC4gTXVsdGkgc28gc2V2ZXJhbCBjYWxscyBjb21wb3NlIGluc3RlYWQgb2YgY2xvYmJlcmluZztcbiAqIGxhdGVyIHNldHMgd2luIG9uIGtleSBjb2xsaXNpb24uIFRoaXMgaXMgdGhlIHNlYW0gdGhhdCBrZWVwcyB1bnVzZWQgZmllbGQgY29tcG9uZW50c1xuICogb3V0IG9mIHRoZSBidW5kbGUg4oCUIG5vdGhpbmcgaXMgaW1wb3J0ZWQgdW50aWwgYSBzZXQgbmFtZXMgaXQuXG4gKi9cbmV4cG9ydCBjb25zdCBGSUVMRF9UWVBFX1NFVFMgPSBuZXcgSW5qZWN0aW9uVG9rZW48UmVjb3JkPHN0cmluZywgVHlwZTxhbnk+PltdPignRklFTERfVFlQRV9TRVRTJyk7XG5cbi8qKlxuICogUmVnaXN0cnk6IGVudGl0eSBrZXkg4oaSIG9wdGlvbiBsb2FkZXIuXG4gKlxuICogQSBsb2FkZXIgcmVjZWl2ZXMgYSBgUmVmZXJlbmNlTG9hZGVyQ29udGV4dGAgKGBwYXJlbnRWYWx1ZWAsIGBmaWx0ZXJzYCwgYGxhbmdgKSBhbmQgbWF5XG4gKiByZXR1cm4gYW4gYXJyYXksIGEgUHJvbWlzZSwgb3IgYW4gT2JzZXJ2YWJsZSBvZiBgUmVmZXJlbmNlT3B0aW9uW11gLiBgY3R4YCBpcyBvcHRpb25hbCxcbiAqIHNvIGEgemVyby1hcmcgbG9hZGVyIChgKCkgPT4gc3ZjLmxpc3QoKWApIGlzIHN0aWxsIGEgdmFsaWQgcmVnaXN0cmF0aW9uLlxuICovXG5leHBvcnQgY29uc3QgRU5USVRZX1JFRl9SRUdJU1RSWSA9IG5ldyBJbmplY3Rpb25Ub2tlbjxNYXA8c3RyaW5nLCBFbnRpdHlSZWZlcmVuY2VMb2FkZXI+PihcbiAgJ0VOVElUWV9SRUZfUkVHSVNUUlknLFxuKTtcblxuLyoqXG4gKiBSZWdpc3RyeTogbGlzdCBuYW1lIOKGkiB0aGUgdmFsdWVzIG9mIGEgbmFtZWQgbWFzdGVyIGxpc3QgKGBmaWVsZC5saXN0TmFtZWApLlxuICpcbiAqIEEgc291cmNlIG1heSBiZSB0aGUgdmFsdWVzIHRoZW1zZWx2ZXMgKGFycmF5IC8gUHJvbWlzZSAvIE9ic2VydmFibGUpIG9yIGEgKipsb2FkZXIgZnVuY3Rpb24qKixcbiAqIHdoaWNoIGlzIHdoYXQgeW91IHdhbnQgZm9yIGFueXRoaW5nIGZldGNoZWQ6IGEgYmFyZSBQcm9taXNlIGlzIGNyZWF0ZWQgd2hlbiB0aGUgcHJvdmlkZXIgaXNcbiAqIGJ1aWx0LCBzbyBldmVyeSBsaXN0IHdvdWxkIGxvYWQgd2hldGhlciBvciBub3QgYSBmb3JtIHVzZXMgaXQuXG4gKlxuICogVmFsdWVzIGFyZSBub3JtYWxpc2VkIGJ5IGBub3JtYWxpemVMb29rdXBWYWx1ZXNgIOKAlCBiYXJlIHN0cmluZ3MgYW5kIGBMb2NhbGl6ZWRUZXh0YCBhcmVcbiAqIGFjY2VwdGVkIGFsb25nc2lkZSB0aGUgZnVsbCBgeyBjb2RlLCBuYW1lLCBzb3J0T3JkZXIgfWAgc2hhcGUuXG4gKlxuICogQGV4YW1wbGVcbiAqIHByb3ZpZGVOZ3hEeW5hbWljRW50aXR5KHtcbiAqICAgbG9va3Vwczoge1xuICogICAgIGVtcGxveWVlU3RhdHVzOiAoKSA9PiBsaXN0U2VydmljZS5nZXRCeU5hbWUoJ2VtcGxveWVlU3RhdHVzJyksXG4gKiAgICAgZ3JhZGVzOiBbJ0p1bmlvcicsICdTZW5pb3InXSxcbiAqICAgfSxcbiAqIH0pXG4gKi9cbmV4cG9ydCBjb25zdCBMT09LVVBfUkVHSVNUUlkgPSBuZXcgSW5qZWN0aW9uVG9rZW48TWFwPHN0cmluZywgTG9va3VwTGlzdFNvdXJjZT4+KCdMT09LVVBfUkVHSVNUUlknKTtcblxuLyoqXG4gKiBPcmRlcmVkIHN0ZXBzIHRoYXQgbW92ZSBhIHNhdmVkIHJlY29yZCBmb3J3YXJkIHdoZW4gYSBjb25maWcncyBgdmVyc2lvbmAgaW5jcmVhc2VzLlxuICpcbiAqIFdpdGhvdXQgdGhlc2UsIGBFbnRpdHlGb3JtQ29uZmlnLnZlcnNpb25gIGFuZCBgVmVyc2lvbmVkUmVjb3JkLl9jb25maWdWZXJzaW9uYCBhcmVcbiAqIGRlY2xhcmF0aW9ucyBub3RoaW5nIGFjdHMgb246IGEgc2NoZW1hIGNhbiBiZSBlZGl0ZWQgZnJlZWx5IHdoaWxlIHJlY29yZHMga2VlcCB0aGVpciBvbGRcbiAqIHNoYXBlLCBhbmQgbm90aGluZyByZWNvbmNpbGVzIHRoZSB0d28uIFJlZ2lzdGVyaW5nIG1pZ3JhdGlvbnMgbWFrZXMgdGhlIHZlcnNpb24gbnVtYmVyc1xuICogbWVhbiBzb21ldGhpbmcuXG4gKlxuICogQGV4YW1wbGVcbiAqIHByb3ZpZGVOZ3hEeW5hbWljRW50aXR5KHtcbiAqICAgbWlncmF0aW9uczogW1xuICogICAgIHsgZnJvbTogMSwgdG86IDIsIGRlc2NyaXB0aW9uOiAnc3BsaXQgbmFtZScsIG1pZ3JhdGU6IHIgPT4gKHsgLi4uciwgZmlyc3ROYW1lOiByWyduYW1lJ10gfSkgfSxcbiAqICAgXSxcbiAqIH0pXG4gKi9cbmV4cG9ydCBjb25zdCBSRUNPUkRfTUlHUkFUSU9OUyA9IG5ldyBJbmplY3Rpb25Ub2tlbjxSZWNvcmRNaWdyYXRpb25bXT4oJ1JFQ09SRF9NSUdSQVRJT05TJyk7XG5cbi8qKiBSZWdpc3RyeTogdmFsaWRhdG9yIGtleSDihpIgVmFsaWRhdG9yRm4gKi9cbmV4cG9ydCBjb25zdCBWQUxJREFUT1JfUkVHSVNUUlkgPSBuZXcgSW5qZWN0aW9uVG9rZW48TWFwPHN0cmluZywgYW55Pj4oJ1ZBTElEQVRPUl9SRUdJU1RSWScpO1xuXG4vKipcbiAqIEEgcmVnaXN0ZXJlZCBob29rOiByZWNlaXZlcyB0aGUgcGF5bG9hZCwgcmV0dXJucyBpdCAob3IgYSByZXBsYWNlbWVudCksIHN5bmMgb3IgYXN5bmMuXG4gKlxuICogU3BlbGxlZCBvdXQgcmF0aGVyIHRoYW4gdHlwZWQgYXMgYEZ1bmN0aW9uYCwgd2hpY2ggYWNjZXB0cyBjbGFzcyBkZWNsYXJhdGlvbnMgYW5kIGFueVxuICogYXJpdHkgYW5kIGdpdmVzIGEgY29uc3VtZXIgbm8gc2lnbmF0dXJlIHRvIHdyaXRlIGFnYWluc3QuXG4gKi9cbmV4cG9ydCB0eXBlIEhvb2tGbiA9IChkYXRhOiBhbnksIGNvbnRleHQ/OiB1bmtub3duKSA9PiB1bmtub3duIHwgUHJvbWlzZTx1bmtub3duPjtcblxuLyoqIFJlZ2lzdHJ5OiBob29rIGtleSDihpIgYXN5bmMgKGRhdGEsIGNvbnRleHQpID0+IGRhdGEgKi9cbmV4cG9ydCBjb25zdCBIT09LX1JFR0lTVFJZID0gbmV3IEluamVjdGlvblRva2VuPE1hcDxzdHJpbmcsIEhvb2tGbj4+KCdIT09LX1JFR0lTVFJZJyk7XG5cbi8qKlxuICogQ29uc3VtZXItcmVnaXN0ZXJlZCBsaXN0IG9mIGNvbW1vbiBtb2R1bGUgdGFicyAoZG9jdW1lbnRzLCBhdWRpdCwgdGFza3MsIGV0Yy4pLlxuICogVGhlIGxpYnJhcnkgc2hpcHMgbm8gYnVpbHQtaW4gaW1wbGVtZW50YXRpb25zLiBDb25zdW1lcnMgcHJvdmlkZSB0aGVpciBvd24gbGlzdFxuICogc28gdGhlIGJ1aWxkZXIncyBtb2R1bGUtcGlja2VyIGFuZCB0aGUgcmVuZGVyZXIncyB0YWIgc3dpdGNoZXIga25vdyB3aGF0J3MgYXZhaWxhYmxlLlxuICpcbiAqIEBleGFtcGxlXG4gKiBwcm92aWRlcnM6IFtcbiAqICAge1xuICogICAgIHByb3ZpZGU6IENPTU1PTl9NT0RVTEVTX1JFR0lTVFJZLFxuICogICAgIHVzZVZhbHVlOiBbXG4gKiAgICAgICB7IGlkOiAnZG9jdW1lbnRzJywgbGFiZWw6IHsgZW46ICdEb2N1bWVudHMnIH0sIGNvbXBvbmVudDogJ2FwcC1kb2N1bWVudHMtdmlldycgfSxcbiAqICAgICAgIHsgaWQ6ICdhdWRpdCcsICAgICBsYWJlbDogeyBlbjogJ0F1ZGl0IExvZycgIH0sIGNvbXBvbmVudDogJ2FwcC1hdWRpdCcgfSxcbiAqICAgICBdIHNhdGlzZmllcyBDb21tb25Nb2R1bGVFbnRyeVtdXG4gKiAgIH1cbiAqIF1cbiAqL1xuZXhwb3J0IGNvbnN0IENPTU1PTl9NT0RVTEVTX1JFR0lTVFJZID0gbmV3IEluamVjdGlvblRva2VuPENvbW1vbk1vZHVsZUVudHJ5W10+KFxuICAnQ09NTU9OX01PRFVMRVNfUkVHSVNUUlknLFxuKTtcblxuLyoqXG4gKiBDb25zdW1lci1wcm92aWRlZCBmaWxlL2ltYWdlIHVwbG9hZCBoYW5kbGVyLlxuICogV2hlbiBzdXBwbGllZCwgaW1hZ2UtZmllbGQgYW5kIGZpbGUtZmllbGQgY2FsbCBpdCB0byBwZXJzaXN0IHRoZSBGaWxlIGFuZCByZWNlaXZlIGEgc3RhYmxlXG4gKiBVUkwgYmFjay4gV2l0aG91dCBpdCB0aGUgZmllbGQgc3RvcmVzIGB7IGZpbGUsIG5hbWUsIHNpemUsIG1pbWVUeXBlIH1gIGZvciB0aGUgY29uc3VtZXIgdG9cbiAqIHVwbG9hZCBvbiBzdWJtaXQuIE1heSByZXR1cm4gdGhlIHJlc3VsdCBkaXJlY3RseSwgYXMgYSBQcm9taXNlLCBvciBhcyBhbiBPYnNlcnZhYmxlLlxuICpcbiAqIEBleGFtcGxlXG4gKiB7IHByb3ZpZGU6IFVQTE9BRF9IQU5ETEVSLCB1c2VGYWN0b3J5OiAoKSA9PiAoZmlsZTogRmlsZSkgPT4gbXlVcGxvYWRTZXJ2aWNlLnVwbG9hZChmaWxlKSB9XG4gKi9cbmV4cG9ydCBjb25zdCBVUExPQURfSEFORExFUiA9IG5ldyBJbmplY3Rpb25Ub2tlbjxGaWxlVXBsb2FkSGFuZGxlcj4oJ1VQTE9BRF9IQU5ETEVSJyk7XG5cbi8qKlxuICogQmFja2luZyBzdG9yZSBmb3IgdGhlIGVudGl0eS1yZWZlcmVuY2Ugb3B0aW9ucyBjYWNoZS4gRGVmYXVsdHMgdG8gaW4tbWVtb3J5LlxuICogUHJvdmlkZSB5b3VyIG93biB0byBtYWtlIHRoZSBjYWNoZSBvdXRsaXZlIGEgcGFnZSByZWZyZXNoLlxuICpcbiAqIEBleGFtcGxlXG4gKiB7IHByb3ZpZGU6IEVOVElUWV9SRUZfQ0FDSEVfU1RPUkUsIHVzZUNsYXNzOiBTZXNzaW9uU3RvcmFnZVJlZkNhY2hlIH1cbiAqL1xuZXhwb3J0IGNvbnN0IEVOVElUWV9SRUZfQ0FDSEVfU1RPUkUgPSBuZXcgSW5qZWN0aW9uVG9rZW48RW50aXR5UmVmQ2FjaGVTdG9yZT4oXG4gICdFTlRJVFlfUkVGX0NBQ0hFX1NUT1JFJyxcbiAgeyBwcm92aWRlZEluOiAncm9vdCcsIGZhY3Rvcnk6ICgpID0+IG5ldyBJbk1lbW9yeUVudGl0eVJlZkNhY2hlU3RvcmUoKSB9LFxuKTtcblxuLyoqXG4gKiBDb25zdW1lci1wcm92aWRlZCBwcmVkaWNhdGUgZnVuY3Rpb24gdG8gY2hlY2sgd2hldGhlciB1c2VyIHJvbGVzIGNhbiBlZGl0IHN5c3RlbSBkZWZhdWx0IHRhYnMgb3IgZmllbGRzLlxuICogRGVmYXVsdHMgdG8gYWxsb3dpbmcgZWRpdHMgaWYgbm90IHByb3ZpZGVkLlxuICovXG4vKipcbiAqIENvbnN1bWVyLXByb3ZpZGVkIHByZWRpY2F0ZSBmdW5jdGlvbiB0byBjaGVjayB3aGV0aGVyIHVzZXIgcm9sZXMgY2FuIGVkaXQgc3lzdGVtIGRlZmF1bHQgdGFicyBvciBmaWVsZHMuXG4gKiBEZWZhdWx0cyB0byBhbGxvd2luZyBlZGl0cyBpZiBub3QgcHJvdmlkZWQuXG4gKi9cbmV4cG9ydCBjb25zdCBTWVNURU1fREVGQVVMVF9DQU5fRURJVCA9IG5ldyBJbmplY3Rpb25Ub2tlbjwocm9sZXM6IHN0cmluZ1tdKSA9PiBib29sZWFuPihcbiAgJ1NZU1RFTV9ERUZBVUxUX0NBTl9FRElUJyxcbik7XG5cbmV4cG9ydCB0eXBlIENvbmZpZ1NvdXJjZUhhbmRsZXIgPSAoXG4gIGVudGl0eUtleTogc3RyaW5nLFxuKSA9PiBhbnk7XG5cbi8qKlxuICogUmVnaXN0cnkvUmVzb2x2ZXIgZm9yIHJlc29sdmluZyBhbiBFbnRpdHlGb3JtQ29uZmlnIGJ5IGVudGl0eSBrZXkgYWNyb3NzIGVudGl0aWVzIChQaGFzZSA4KS5cbiAqIEVuYWJsZXMgY3Jvc3MtZW50aXR5IGZpZWxkIHJlZmVyZW5jaW5nIChgaXNSZWZlcmVuY2VkYCwgYHJlZmVyZW5jZWRFbnRpdHlLZXlgLCBgcmVmZXJlbmNlZEZpZWxkSWRgLCBgaGFzRHJpZnRgKS5cbiAqL1xuZXhwb3J0IGNvbnN0IENPTkZJR19TT1VSQ0UgPSBuZXcgSW5qZWN0aW9uVG9rZW48Q29uZmlnU291cmNlSGFuZGxlcj4oJ0NPTkZJR19TT1VSQ0UnKTtcblxuXG4iXX0=