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,168 @@
1
+ import { Injectable, inject } from '@angular/core';
2
+ import { buildReferenceCacheKey, entityKeyFromCacheKey, normalizeReferenceOptions, resolveLabel, valuesMatch, } from '@dynamic-entity/core';
3
+ import { ENTITY_REF_CACHE_STORE } from '../tokens/injection-tokens';
4
+ import { EntityRefRegistryService } from './entity-ref-registry.service';
5
+ import * as i0 from "@angular/core";
6
+ /** Label-cache field separator. Kept out of template literals so it stays visible in source. */
7
+ const LABEL_SEP = '|';
8
+ /**
9
+ * EntityReferenceService — the cache in front of consumer-registered option loaders.
10
+ *
11
+ * Three layers, matching the reference implementation:
12
+ * 1. **options** — resolved `ReferenceOption[]` per (entity, lang, displayFields, filters).
13
+ * 2. **in-flight** — the pending Promise, so N fields referencing one entity trigger one
14
+ * load rather than N. This is the layer that actually removes duplicate HTTP calls;
15
+ * an options cache alone does nothing for concurrent first loads.
16
+ * 3. **labels** — synchronous value → text, for rendering a stored reference without
17
+ * waiting on a load.
18
+ *
19
+ * Invalidation is per entity, not global. The reference could only `clearCache()` everything
20
+ * (issue #16), so saving one record re-fetched every entity's options.
21
+ */
22
+ export class EntityReferenceService {
23
+ registry = inject(EntityRefRegistryService);
24
+ store = inject(ENTITY_REF_CACHE_STORE);
25
+ /** Loads in progress, keyed the same way as the options cache. */
26
+ inFlight = new Map();
27
+ /** `entityKey|lang|canonicalValue` -> display text. */
28
+ labels = new Map();
29
+ /**
30
+ * Options for an entity, from cache when present.
31
+ * Concurrent callers with the same key share one load.
32
+ */
33
+ async load(entityKey, ctx = {}) {
34
+ const key = buildReferenceCacheKey(entityKey, {
35
+ lang: ctx.lang,
36
+ filters: ctx.filters,
37
+ displayFields: ctx.displayFields,
38
+ parentValue: ctx.parentValue,
39
+ });
40
+ const cached = this.store.get(key);
41
+ if (cached)
42
+ return cached;
43
+ const pending = this.inFlight.get(key);
44
+ if (pending)
45
+ return pending;
46
+ const loader = this.registry.resolve(entityKey);
47
+ if (!loader)
48
+ return [];
49
+ const load = this.invoke(loader, ctx)
50
+ .then(raw => {
51
+ // displayFields drive label building, which is why they are part of the cache key.
52
+ const options = normalizeReferenceOptions(raw, ctx.displayFields ? { enabled: true, displayFields: ctx.displayFields } : undefined, ctx.lang ?? 'en');
53
+ this.store.set(key, options);
54
+ this.rememberLabels(entityKey, ctx.lang ?? 'en', options);
55
+ return options;
56
+ });
57
+ // A failed load resolves to [] for the caller but is never written to the store, so a
58
+ // transient error is retried on the next call instead of poisoning the cache. Only the
59
+ // `.then` above caches, and a rejection skips it.
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 cached. */
67
+ peek(entityKey, ctx = {}) {
68
+ return this.store.get(buildReferenceCacheKey(entityKey, {
69
+ lang: ctx.lang,
70
+ filters: ctx.filters,
71
+ displayFields: ctx.displayFields,
72
+ parentValue: ctx.parentValue,
73
+ }));
74
+ }
75
+ /**
76
+ * Display text for a stored reference value, synchronously.
77
+ * Returns `undefined` when the entity's options have never been loaded.
78
+ */
79
+ labelFor(entityKey, value, lang = 'en') {
80
+ return this.labels.get(this.labelKey(entityKey, lang, value));
81
+ }
82
+ /** Drop everything cached for one entity, leaving other entities intact. */
83
+ invalidate(entityKey) {
84
+ for (const key of this.store.keys()) {
85
+ if (entityKeyFromCacheKey(key) === entityKey)
86
+ this.store.delete(key);
87
+ }
88
+ for (const key of [...this.inFlight.keys()]) {
89
+ if (entityKeyFromCacheKey(key) === entityKey)
90
+ this.inFlight.delete(key);
91
+ }
92
+ const prefix = `${entityKey}${LABEL_SEP}`;
93
+ for (const key of [...this.labels.keys()]) {
94
+ if (key.startsWith(prefix))
95
+ this.labels.delete(key);
96
+ }
97
+ }
98
+ clear() {
99
+ this.store.clear();
100
+ this.inFlight.clear();
101
+ this.labels.clear();
102
+ }
103
+ rememberLabels(entityKey, lang, options) {
104
+ for (const option of options) {
105
+ this.labels.set(this.labelKey(entityKey, lang, option.value), option.label);
106
+ }
107
+ }
108
+ /** Label-cache key. An object value collapses to its resolved text for the active language. */
109
+ labelKey(entityKey, lang, value) {
110
+ const canonical = value !== null && typeof value === 'object'
111
+ ? resolveLabel(value, lang)
112
+ : String(value ?? '');
113
+ return [entityKey, lang, canonical].join(LABEL_SEP);
114
+ }
115
+ // ─── Loader result coercion (array | Promise | Observable) ──────────────────
116
+ invoke(loader, ctx) {
117
+ let result;
118
+ try {
119
+ result = loader(ctx);
120
+ }
121
+ catch (err) {
122
+ // Reject rather than resolve empty: `load` must be able to tell failure from
123
+ // "no matches", or it would cache the failure.
124
+ return Promise.reject(err);
125
+ }
126
+ return this.toPromise(result);
127
+ }
128
+ toPromise(result) {
129
+ if (Array.isArray(result))
130
+ return Promise.resolve(result);
131
+ if (this.isSubscribable(result)) {
132
+ // First emission wins, so an Observable that stays open still resolves the load.
133
+ return new Promise((resolve, reject) => {
134
+ let settled = false;
135
+ const settle = (fn) => {
136
+ if (settled)
137
+ return;
138
+ settled = true;
139
+ fn();
140
+ };
141
+ result.subscribe({
142
+ next: value => settle(() => resolve(value ?? [])),
143
+ // An erroring stream is a failed load, not an empty one — see `invoke`.
144
+ error: err => settle(() => reject(err)),
145
+ // Completing without emitting is a legitimate empty result, and is cached.
146
+ complete: () => settle(() => resolve([])),
147
+ });
148
+ });
149
+ }
150
+ return Promise.resolve(result);
151
+ }
152
+ isSubscribable(value) {
153
+ return (typeof value === 'object' &&
154
+ value !== null &&
155
+ typeof value.subscribe === 'function');
156
+ }
157
+ /** Exposed for cascade filtering, which matches a parent value against option values. */
158
+ matches(a, b, lang = 'en') {
159
+ return valuesMatch(a, b, lang);
160
+ }
161
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityReferenceService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
162
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityReferenceService, providedIn: 'root' });
163
+ }
164
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EntityReferenceService, decorators: [{
165
+ type: Injectable,
166
+ args: [{ providedIn: 'root' }]
167
+ }] });
168
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZW50aXR5LXJlZmVyZW5jZS5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9lbnRpdHktcmVmZXJlbmNlLnNlcnZpY2UudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFTbkQsT0FBTyxFQUNMLHNCQUFzQixFQUN0QixxQkFBcUIsRUFDckIseUJBQXlCLEVBQ3pCLFlBQVksRUFDWixXQUFXLEdBQ1osTUFBTSxzQkFBc0IsQ0FBQztBQUM5QixPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUNwRSxPQUFPLEVBQUUsd0JBQXdCLEVBQUUsTUFBTSwrQkFBK0IsQ0FBQzs7QUFFekUsZ0dBQWdHO0FBQ2hHLE1BQU0sU0FBUyxHQUFHLEdBQUcsQ0FBQztBQUV0Qjs7Ozs7Ozs7Ozs7OztHQWFHO0FBRUgsTUFBTSxPQUFPLHNCQUFzQjtJQUNoQixRQUFRLEdBQUcsTUFBTSxDQUFDLHdCQUF3QixDQUFDLENBQUM7SUFDNUMsS0FBSyxHQUFHLE1BQU0sQ0FBQyxzQkFBc0IsQ0FBQyxDQUFDO0lBRXhELGtFQUFrRTtJQUNqRCxRQUFRLEdBQUcsSUFBSSxHQUFHLEVBQXNDLENBQUM7SUFDMUUsdURBQXVEO0lBQ3RDLE1BQU0sR0FBRyxJQUFJLEdBQUcsRUFBa0IsQ0FBQztJQUVwRDs7O09BR0c7SUFDSCxLQUFLLENBQUMsSUFBSSxDQUFDLFNBQWlCLEVBQUUsTUFBOEIsRUFBRTtRQUM1RCxNQUFNLEdBQUcsR0FBRyxzQkFBc0IsQ0FBQyxTQUFTLEVBQUU7WUFDNUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxJQUFJO1lBQ2QsT0FBTyxFQUFFLEdBQUcsQ0FBQyxPQUFPO1lBQ3BCLGFBQWEsRUFBRSxHQUFHLENBQUMsYUFBYTtZQUNoQyxXQUFXLEVBQUUsR0FBRyxDQUFDLFdBQVc7U0FDN0Is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QUFFLENBQUMsT0FBTyxDQUFDLEtBQUssSUFBSSxFQUFFLENBQUMsQ0FBQztvQkFDakQsd0VBQXdFO29CQUN4RSxLQUFLLEVBQUUsR0FBRyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO29CQUN2QywyRUFBMkU7b0JBQzNFLFFBQVEsRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDO2lCQUMxQyxDQUFDLENBQUM7WUFDTCxDQUFDLENBQUMsQ0FBQztRQUNMLENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsTUFBb0MsQ0FBQyxDQUFDO0lBQy9ELENBQUM7SUFFTyxjQUFjLENBQUMsS0FBYztRQUNuQyxPQUFPLENBQ0wsT0FBTyxLQUFLLEtBQUssUUFBUTtZQUN6QixLQUFLLEtBQUssSUFBSTtZQUNkLE9BQVEsS0FBeUMsQ0FBQyxTQUFTLEtBQUssVUFBVSxDQUMzRSxDQUFDO0lBQ0osQ0FBQztJQUVELHlGQUF5RjtJQUN6RixPQUFPLENBQUMsQ0FBVSxFQUFFLENBQVUsRUFBRSxJQUFJLEdBQUcsSUFBSTtRQUN6QyxPQUFPLFdBQVcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ2pDLENBQUM7d0dBaEtVLHNCQUFzQjs0R0FBdEIsc0JBQXNCLGNBRFQsTUFBTTs7NEZBQ25CLHNCQUFzQjtrQkFEbEMsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB0eXBlIHtcbiAgRW50aXR5UmVmZXJlbmNlTG9hZGVyLFxuICBSYXdSZWZlcmVuY2VJdGVtLFxuICBSZWZlcmVuY2VMb2FkZXJDb250ZXh0LFxuICBSZWZlcmVuY2VMb2FkZXJSZXN1bHQsXG4gIFJlZmVyZW5jZU9wdGlvbixcbiAgU3Vic2NyaWJhYmxlLFxufSBmcm9tICdAZHluYW1pYy1lbnRpdHkvY29yZSc7XG5pbXBvcnQge1xuICBidWlsZFJlZmVyZW5jZUNhY2hlS2V5LFxuICBlbnRpdHlLZXlGcm9tQ2FjaGVLZXksXG4gIG5vcm1hbGl6ZVJlZmVyZW5jZU9wdGlvbnMsXG4gIHJlc29sdmVMYWJlbCxcbiAgdmFsdWVzTWF0Y2gsXG59IGZyb20gJ0BkeW5hbWljLWVudGl0eS9jb3JlJztcbmltcG9ydCB7IEVOVElUWV9SRUZfQ0FDSEVfU1RPUkUgfSBmcm9tICcuLi90b2tlbnMvaW5qZWN0aW9uLXRva2Vucyc7XG5pbXBvcnQgeyBFbnRpdHlSZWZSZWdpc3RyeVNlcnZpY2UgfSBmcm9tICcuL2VudGl0eS1yZWYtcmVnaXN0cnkuc2VydmljZSc7XG5cbi8qKiBMYWJlbC1jYWNoZSBmaWVsZCBzZXBhcmF0b3IuIEtlcHQgb3V0IG9mIHRlbXBsYXRlIGxpdGVyYWxzIHNvIGl0IHN0YXlzIHZpc2libGUgaW4gc291cmNlLiAqL1xuY29uc3QgTEFCRUxfU0VQID0gJ3wnO1xuXG4vKipcbiAqIEVudGl0eVJlZmVyZW5jZVNlcnZpY2Ug4oCUIHRoZSBjYWNoZSBpbiBmcm9udCBvZiBjb25zdW1lci1yZWdpc3RlcmVkIG9wdGlvbiBsb2FkZXJzLlxuICpcbiAqIFRocmVlIGxheWVycywgbWF0Y2hpbmcgdGhlIHJlZmVyZW5jZSBpbXBsZW1lbnRhdGlvbjpcbiAqICAxLiAqKm9wdGlvbnMqKiDigJQgcmVzb2x2ZWQgYFJlZmVyZW5jZU9wdGlvbltdYCBwZXIgKGVudGl0eSwgbGFuZywgZGlzcGxheUZpZWxkcywgZmlsdGVycykuXG4gKiAgMi4gKippbi1mbGlnaHQqKiDigJQgdGhlIHBlbmRpbmcgUHJvbWlzZSwgc28gTiBmaWVsZHMgcmVmZXJlbmNpbmcgb25lIGVudGl0eSB0cmlnZ2VyIG9uZVxuICogICAgIGxvYWQgcmF0aGVyIHRoYW4gTi4gVGhpcyBpcyB0aGUgbGF5ZXIgdGhhdCBhY3R1YWxseSByZW1vdmVzIGR1cGxpY2F0ZSBIVFRQIGNhbGxzO1xuICogICAgIGFuIG9wdGlvbnMgY2FjaGUgYWxvbmUgZG9lcyBub3RoaW5nIGZvciBjb25jdXJyZW50IGZpcnN0IGxvYWRzLlxuICogIDMuICoqbGFiZWxzKiog4oCUIHN5bmNocm9ub3VzIHZhbHVlIOKGkiB0ZXh0LCBmb3IgcmVuZGVyaW5nIGEgc3RvcmVkIHJlZmVyZW5jZSB3aXRob3V0XG4gKiAgICAgd2FpdGluZyBvbiBhIGxvYWQuXG4gKlxuICogSW52YWxpZGF0aW9uIGlzIHBlciBlbnRpdHksIG5vdCBnbG9iYWwuIFRoZSByZWZlcmVuY2UgY291bGQgb25seSBgY2xlYXJDYWNoZSgpYCBldmVyeXRoaW5nXG4gKiAoaXNzdWUgIzE2KSwgc28gc2F2aW5nIG9uZSByZWNvcmQgcmUtZmV0Y2hlZCBldmVyeSBlbnRpdHkncyBvcHRpb25zLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIEVudGl0eVJlZmVyZW5jZVNlcnZpY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IHJlZ2lzdHJ5ID0gaW5qZWN0KEVudGl0eVJlZlJlZ2lzdHJ5U2VydmljZSk7XG4gIHByaXZhdGUgcmVhZG9ubHkgc3RvcmUgPSBpbmplY3QoRU5USVRZX1JFRl9DQUNIRV9TVE9SRSk7XG5cbiAgLyoqIExvYWRzIGluIHByb2dyZXNzLCBrZXllZCB0aGUgc2FtZSB3YXkgYXMgdGhlIG9wdGlvbnMgY2FjaGUuICovXG4gIHByaXZhdGUgcmVhZG9ubHkgaW5GbGlnaHQgPSBuZXcgTWFwPHN0cmluZywgUHJvbWlzZTxSZWZlcmVuY2VPcHRpb25bXT4+KCk7XG4gIC8qKiBgZW50aXR5S2V5fGxhbmd8Y2Fub25pY2FsVmFsdWVgIC0+IGRpc3BsYXkgdGV4dC4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBsYWJlbHMgPSBuZXcgTWFwPHN0cmluZywgc3RyaW5nPigpO1xuXG4gIC8qKlxuICAgKiBPcHRpb25zIGZvciBhbiBlbnRpdHksIGZyb20gY2FjaGUgd2hlbiBwcmVzZW50LlxuICAgKiBDb25jdXJyZW50IGNhbGxlcnMgd2l0aCB0aGUgc2FtZSBrZXkgc2hhcmUgb25lIGxvYWQuXG4gICAqL1xuICBhc3luYyBsb2FkKGVudGl0eUtleTogc3RyaW5nLCBjdHg6IFJlZmVyZW5jZUxvYWRlckNvbnRleHQgPSB7fSk6IFByb21pc2U8UmVmZXJlbmNlT3B0aW9uW10+IHtcbiAgICBjb25zdCBrZXkgPSBidWlsZFJlZmVyZW5jZUNhY2hlS2V5KGVudGl0eUtleSwge1xuICAgICAgbGFuZzogY3R4LmxhbmcsXG4gICAgICBmaWx0ZXJzOiBjdHguZmlsdGVycyxcbiAgICAgIGRpc3BsYXlGaWVsZHM6IGN0eC5kaXNwbGF5RmllbGRzLFxuICAgICAgcGFyZW50VmFsdWU6IGN0eC5wYXJlbnRWYWx1ZSxcbiAgICB9KTtcblxuICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMuc3RvcmUuZ2V0KGtleSk7XG4gICAgaWYgKGNhY2hlZCkgcmV0dXJuIGNhY2hlZDtcblxuICAgIGNvbnN0IHBlbmRpbmcgPSB0aGlzLmluRmxpZ2h0LmdldChrZXkpO1xuICAgIGlmIChwZW5kaW5nKSByZXR1cm4gcGVuZGluZztcblxuICAgIGNvbnN0IGxvYWRlciA9IHRoaXMucmVnaXN0cnkucmVzb2x2ZShlbnRpdHlLZXkpO1xuICAgIGlmICghbG9hZGVyKSByZXR1cm4gW107XG5cbiAgICBjb25zdCBsb2FkID0gdGhpcy5pbnZva2UobG9hZGVyLCBjdHgpXG4gICAgICAudGhlbihyYXcgPT4ge1xuICAgICAgICAvLyBkaXNwbGF5RmllbGRzIGRyaXZlIGxhYmVsIGJ1aWxkaW5nLCB3aGljaCBpcyB3aHkgdGhleSBhcmUgcGFydCBvZiB0aGUgY2FjaGUga2V5LlxuICAgICAgICBjb25zdCBvcHRpb25zID0gbm9ybWFsaXplUmVmZXJlbmNlT3B0aW9ucyhcbiAgICAgICAgICByYXcgYXMgUmF3UmVmZXJlbmNlSXRlbVtdLFxuICAgICAgICAgIGN0eC5kaXNwbGF5RmllbGRzID8geyBlbmFibGVkOiB0cnVlLCBkaXNwbGF5RmllbGRzOiBjdHguZGlzcGxheUZpZWxkcyB9IDogdW5kZWZpbmVkLFxuICAgICAgICAgIGN0eC5sYW5nID8/ICdlbicsXG4gICAgICAgICk7XG4gICAgICAgIHRoaXMuc3RvcmUuc2V0KGtleSwgb3B0aW9ucyk7XG4gICAgICAgIHRoaXMucmVtZW1iZXJMYWJlbHMoZW50aXR5S2V5LCBjdHgubGFuZyA/PyAnZW4nLCBvcHRpb25zKTtcbiAgICAgICAgcmV0dXJuIG9wdGlvbnM7XG4gICAgICB9KTtcblxuICAgIC8vIEEgZmFpbGVkIGxvYWQgcmVzb2x2ZXMgdG8gW10gZm9yIHRoZSBjYWxsZXIgYnV0IGlzIG5ldmVyIHdyaXR0ZW4gdG8gdGhlIHN0b3JlLCBzbyBhXG4gICAgLy8gdHJhbnNpZW50IGVycm9yIGlzIHJldHJpZWQgb24gdGhlIG5leHQgY2FsbCBpbnN0ZWFkIG9mIHBvaXNvbmluZyB0aGUgY2FjaGUuIE9ubHkgdGhlXG4gICAgLy8gYC50aGVuYCBhYm92ZSBjYWNoZXMsIGFuZCBhIHJlamVjdGlvbiBza2lwcyBpdC5cbiAgICBjb25zdCBndWFyZGVkID0gbG9hZFxuICAgICAgLmNhdGNoKCgpID0+IFtdIGFzIFJlZmVyZW5jZU9wdGlvbltdKVxuICAgICAgLmZpbmFsbHkoKCkgPT4gdGhpcy5pbkZsaWdodC5kZWxldGUoa2V5KSk7XG5cbiAgICB0aGlzLmluRmxpZ2h0LnNldChrZXksIGd1YXJkZWQpO1xuICAgIHJldHVybiBndWFyZGVkO1xuICB9XG5cbiAgLyoqIENhY2hlZCBvcHRpb25zIHdpdGhvdXQgdHJpZ2dlcmluZyBhIGxvYWQuIGB1bmRlZmluZWRgIHdoZW4gbm90IGNhY2hlZC4gKi9cbiAgcGVlayhlbnRpdHlLZXk6IHN0cmluZywgY3R4OiBSZWZlcmVuY2VMb2FkZXJDb250ZXh0ID0ge30pOiBSZWZlcmVuY2VPcHRpb25bXSB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMuc3RvcmUuZ2V0KFxuICAgICAgYnVpbGRSZWZlcmVuY2VDYWNoZUtleShlbnRpdHlLZXksIHtcbiAgICAgICAgbGFuZzogY3R4LmxhbmcsXG4gICAgICAgIGZpbHRlcnM6IGN0eC5maWx0ZXJzLFxuICAgICAgICBkaXNwbGF5RmllbGRzOiBjdHguZGlzcGxheUZpZWxkcyxcbiAgICAgICAgcGFyZW50VmFsdWU6IGN0eC5wYXJlbnRWYWx1ZSxcbiAgICAgIH0pLFxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogRGlzcGxheSB0ZXh0IGZvciBhIHN0b3JlZCByZWZlcmVuY2UgdmFsdWUsIHN5bmNocm9ub3VzbHkuXG4gICAqIFJldHVybnMgYHVuZGVmaW5lZGAgd2hlbiB0aGUgZW50aXR5J3Mgb3B0aW9ucyBoYXZlIG5ldmVyIGJlZW4gbG9hZGVkLlxuICAgKi9cbiAgbGFiZWxGb3IoZW50aXR5S2V5OiBzdHJpbmcsIHZhbHVlOiB1bmtub3duLCBsYW5nID0gJ2VuJyk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gICAgcmV0dXJuIHRoaXMubGFiZWxzLmdldCh0aGlzLmxhYmVsS2V5KGVudGl0eUtleSwgbGFuZywgdmFsdWUpKTtcbiAgfVxuXG4gIC8qKiBEcm9wIGV2ZXJ5dGhpbmcgY2FjaGVkIGZvciBvbmUgZW50aXR5LCBsZWF2aW5nIG90aGVyIGVudGl0aWVzIGludGFjdC4gKi9cbiAgaW52YWxpZGF0ZShlbnRpdHlLZXk6IHN0cmluZyk6IHZvaWQge1xuICAgIGZvciAoY29uc3Qga2V5IG9mIHRoaXMuc3RvcmUua2V5cygpKSB7XG4gICAgICBpZiAoZW50aXR5S2V5RnJvbUNhY2hlS2V5KGtleSkgPT09IGVudGl0eUtleSkgdGhpcy5zdG9yZS5kZWxldGUoa2V5KTtcbiAgICB9XG4gICAgZm9yIChjb25zdCBrZXkgb2YgWy4uLnRoaXMuaW5GbGlnaHQua2V5cygpXSkge1xuICAgICAgaWYgKGVudGl0eUtleUZyb21DYWNoZUtleShrZXkpID09PSBlbnRpdHlLZXkpIHRoaXMuaW5GbGlnaHQuZGVsZXRlKGtleSk7XG4gICAgfVxuICAgIGNvbnN0IHByZWZpeCA9IGAke2VudGl0eUtleX0ke0xBQkVMX1NFUH1gO1xuICAgIGZvciAoY29uc3Qga2V5IG9mIFsuLi50aGlzLmxhYmVscy5rZXlzKCldKSB7XG4gICAgICBpZiAoa2V5LnN0YXJ0c1dpdGgocHJlZml4KSkgdGhpcy5sYWJlbHMuZGVsZXRlKGtleSk7XG4gICAgfVxuICB9XG5cbiAgY2xlYXIoKTogdm9pZCB7XG4gICAgdGhpcy5zdG9yZS5jbGVhcigpO1xuICAgIHRoaXMuaW5GbGlnaHQuY2xlYXIoKTtcbiAgICB0aGlzLmxhYmVscy5jbGVhcigpO1xuICB9XG5cbiAgcHJpdmF0ZSByZW1lbWJlckxhYmVscyhlbnRpdHlLZXk6IHN0cmluZywgbGFuZzogc3RyaW5nLCBvcHRpb25zOiBSZWZlcmVuY2VPcHRpb25bXSk6IHZvaWQge1xuICAgIGZvciAoY29uc3Qgb3B0aW9uIG9mIG9wdGlvbnMpIHtcbiAgICAgIHRoaXMubGFiZWxzLnNldCh0aGlzLmxhYmVsS2V5KGVudGl0eUtleSwgbGFuZywgb3B0aW9uLnZhbHVlKSwgb3B0aW9uLmxhYmVsKTtcbiAgICB9XG4gIH1cblxuICAvKiogTGFiZWwtY2FjaGUga2V5LiBBbiBvYmplY3QgdmFsdWUgY29sbGFwc2VzIHRvIGl0cyByZXNvbHZlZCB0ZXh0IGZvciB0aGUgYWN0aXZlIGxhbmd1YWdlLiAqL1xuICBwcml2YXRlIGxhYmVsS2V5KGVudGl0eUtleTogc3RyaW5nLCBsYW5nOiBzdHJpbmcsIHZhbHVlOiB1bmtub3duKTogc3RyaW5nIHtcbiAgICBjb25zdCBjYW5vbmljYWwgPVxuICAgICAgdmFsdWUgIT09IG51bGwgJiYgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0J1xuICAgICAgICA/IHJlc29sdmVMYWJlbCh2YWx1ZSBhcyBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+LCBsYW5nKVxuICAgICAgICA6IFN0cmluZyh2YWx1ZSA/PyAnJyk7XG4gICAgcmV0dXJuIFtlbnRpdHlLZXksIGxhbmcsIGNhbm9uaWNhbF0uam9pbihMQUJFTF9TRVApO1xuICB9XG5cbiAgLy8g4pSA4pSA4pSAIExvYWRlciByZXN1bHQgY29lcmNpb24gKGFycmF5IHwgUHJvbWlzZSB8IE9ic2VydmFibGUpIOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgOKUgFxuXG4gIHByaXZhdGUgaW52b2tlKFxuICAgIGxvYWRlcjogRW50aXR5UmVmZXJlbmNlTG9hZGVyLFxuICAgIGN0eDogUmVmZXJlbmNlTG9hZGVyQ29udGV4dCxcbiAgKTogUHJvbWlzZTxSZWZlcmVuY2VPcHRpb25bXT4ge1xuICAgIGxldCByZXN1bHQ6IFJlZmVyZW5jZUxvYWRlclJlc3VsdDtcbiAgICB0cnkge1xuICAgICAgcmVzdWx0ID0gbG9hZGVyKGN0eCk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICAvLyBSZWplY3QgcmF0aGVyIHRoYW4gcmVzb2x2ZSBlbXB0eTogYGxvYWRgIG11c3QgYmUgYWJsZSB0byB0ZWxsIGZhaWx1cmUgZnJvbVxuICAgICAgLy8gXCJubyBtYXRjaGVzXCIsIG9yIGl0IHdvdWxkIGNhY2hlIHRoZSBmYWlsdXJlLlxuICAgICAgcmV0dXJuIFByb21pc2UucmVqZWN0KGVycik7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLnRvUHJvbWlzZShyZXN1bHQpO1xuICB9XG5cbiAgcHJpdmF0ZSB0b1Byb21pc2UocmVzdWx0OiBSZWZlcmVuY2VMb2FkZXJSZXN1bHQpOiBQcm9taXNlPFJlZmVyZW5jZU9wdGlvbltdPiB7XG4gICAgaWYgKEFycmF5LmlzQXJyYXkocmVzdWx0KSkgcmV0dXJuIFByb21pc2UucmVzb2x2ZShyZXN1bHQpO1xuICAgIGlmICh0aGlzLmlzU3Vic2NyaWJhYmxlKHJlc3VsdCkpIHtcbiAgICAgIC8vIEZpcnN0IGVtaXNzaW9uIHdpbnMsIHNvIGFuIE9ic2VydmFibGUgdGhhdCBzdGF5cyBvcGVuIHN0aWxsIHJlc29sdmVzIHRoZSBsb2FkLlxuICAgICAgcmV0dXJuIG5ldyBQcm9taXNlPFJlZmVyZW5jZU9wdGlvbltdPigocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICAgIGxldCBzZXR0bGVkID0gZmFsc2U7XG4gICAgICAgIGNvbnN0IHNldHRsZSA9IChmbjogKCkgPT4gdm9pZCkgPT4ge1xuICAgICAgICAgIGlmIChzZXR0bGVkKSByZXR1cm47XG4gICAgICAgICAgc2V0dGxlZCA9IHRydWU7XG4gICAgICAgICAgZm4oKTtcbiAgICAgICAgfTtcbiAgICAgICAgcmVzdWx0LnN1YnNjcmliZSh7XG4gICAgICAgICAgbmV4dDogdmFsdWUgPT4gc2V0dGxlKCgpID0+IHJlc29sdmUodmFsdWUgPz8gW10pKSxcbiAgICAgICAgICAvLyBBbiBlcnJvcmluZyBzdHJlYW0gaXMgYSBmYWlsZWQgbG9hZCwgbm90IGFuIGVtcHR5IG9uZSDigJQgc2VlIGBpbnZva2VgLlxuICAgICAgICAgIGVycm9yOiBlcnIgPT4gc2V0dGxlKCgpID0+IHJlamVjdChlcnIpKSxcbiAgICAgICAgICAvLyBDb21wbGV0aW5nIHdpdGhvdXQgZW1pdHRpbmcgaXMgYSBsZWdpdGltYXRlIGVtcHR5IHJlc3VsdCwgYW5kIGlzIGNhY2hlZC5cbiAgICAgICAgICBjb21wbGV0ZTogKCkgPT4gc2V0dGxlKCgpID0+IHJlc29sdmUoW10pKSxcbiAgICAgICAgfSk7XG4gICAgICB9KTtcbiAgICB9XG4gICAgcmV0dXJuIFByb21pc2UucmVzb2x2ZShyZXN1bHQgYXMgUHJvbWlzZTxSZWZlcmVuY2VPcHRpb25bXT4pO1xuICB9XG5cbiAgcHJpdmF0ZSBpc1N1YnNjcmliYWJsZSh2YWx1ZTogdW5rbm93bik6IHZhbHVlIGlzIFN1YnNjcmliYWJsZTxSZWZlcmVuY2VPcHRpb25bXT4ge1xuICAgIHJldHVybiAoXG4gICAgICB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnICYmXG4gICAgICB2YWx1ZSAhPT0gbnVsbCAmJlxuICAgICAgdHlwZW9mICh2YWx1ZSBhcyBTdWJzY3JpYmFibGU8UmVmZXJlbmNlT3B0aW9uW10+KS5zdWJzY3JpYmUgPT09ICdmdW5jdGlvbidcbiAgICApO1xuICB9XG5cbiAgLyoqIEV4cG9zZWQgZm9yIGNhc2NhZGUgZmlsdGVyaW5nLCB3aGljaCBtYXRjaGVzIGEgcGFyZW50IHZhbHVlIGFnYWluc3Qgb3B0aW9uIHZhbHVlcy4gKi9cbiAgbWF0Y2hlcyhhOiB1bmtub3duLCBiOiB1bmtub3duLCBsYW5nID0gJ2VuJyk6IGJvb2xlYW4ge1xuICAgIHJldHVybiB2YWx1ZXNNYXRjaChhLCBiLCBsYW5nKTtcbiAgfVxufVxuIl19
@@ -1,44 +1,49 @@
1
1
  import { Injectable, inject } from '@angular/core';
2
- import { FIELD_TYPE_REGISTRY } from '../tokens/injection-tokens';
3
- // Built-in field components — pre-registered in this service
4
- import { TextFieldComponent } from '../field-types/text-field.component';
5
- import { TextareaFieldComponent } from '../field-types/textarea-field.component';
6
- import { NumberFieldComponent } from '../field-types/number-field.component';
7
- import { CheckboxFieldComponent } from '../field-types/checkbox-field.component';
8
- import { DateFieldComponent } from '../field-types/date-field.component';
9
- import { DropdownFieldComponent } from '../field-types/dropdown-field.component';
10
- import { MultiSelectFieldComponent } from '../field-types/multi-select-field.component';
11
- import { EntityRefFieldComponent } from '../field-types/entity-ref-field.component';
2
+ import { FIELD_TYPE_REGISTRY, FIELD_TYPE_SETS } from '../tokens/injection-tokens';
12
3
  import * as i0 from "@angular/core";
13
4
  /**
14
5
  * FieldRegistryService — resolves field type strings to Angular component classes.
15
- * Open/Closed: open for extension via consumer fieldTypes config, closed for modification.
16
- * DynamicFieldComponent uses this to mount the right component via createComponent().
6
+ *
7
+ * **Tree-shaking contract:** this service holds *no* static imports of field components.
8
+ * Nothing is bundled until something registers it, which is what makes the built-ins
9
+ * opt-in. Register them with `provideBuiltInFieldTypes()` (all 19 keys) or a narrower
10
+ * subset via `provideFieldTypes({ ... })` — see `providers/provide-field-types.ts`.
11
+ *
12
+ * Resolution order: consumer token registry → runtime registrations → nothing.
17
13
  */
18
14
  export class FieldRegistryService {
19
15
  consumerRegistry = inject(FIELD_TYPE_REGISTRY, { optional: true }) ?? new Map();
20
- /** Built-in field type → component map. Never remove an entry. */
21
- builtInRegistry = new Map([
22
- ['text', TextFieldComponent],
23
- ['textarea', TextareaFieldComponent],
24
- ['number', NumberFieldComponent],
25
- ['checkbox', CheckboxFieldComponent],
26
- ['date', DateFieldComponent],
27
- ['dropdown', DropdownFieldComponent],
28
- ['multiSelect', MultiSelectFieldComponent],
29
- ['entity-ref', EntityRefFieldComponent],
30
- ]);
16
+ dynamicRegistry = new Map();
17
+ constructor() {
18
+ // Sets contributed by provideFieldTypes()/provideBuiltInFieldTypes(), in declaration order.
19
+ for (const set of inject(FIELD_TYPE_SETS, { optional: true }) ?? []) {
20
+ this.registerAll(set);
21
+ }
22
+ }
23
+ /** Register a field type component mapping at runtime. */
24
+ register(type, component) {
25
+ this.dynamicRegistry.set(type, component);
26
+ }
27
+ /** Register multiple field type component mappings at runtime. */
28
+ registerAll(map) {
29
+ for (const [type, comp] of Object.entries(map)) {
30
+ this.dynamicRegistry.set(type, comp);
31
+ }
32
+ }
31
33
  /**
32
34
  * Resolve a field type string to a component class.
33
- * Consumer registry takes precedence over built-ins (open for extension).
34
- * Returns null if type is unknown — caller must handle gracefully.
35
+ * Consumer token registry takes priority over runtime registrations.
35
36
  */
36
37
  resolve(fieldType) {
37
- return this.consumerRegistry.get(fieldType) ?? this.builtInRegistry.get(fieldType) ?? null;
38
+ return this.consumerRegistry.get(fieldType) ?? this.dynamicRegistry.get(fieldType) ?? null;
38
39
  }
39
- /** Check if a field type has a registered component */
40
+ /** Check if a field type has a registered component. */
40
41
  has(fieldType) {
41
- return this.consumerRegistry.has(fieldType) || this.builtInRegistry.has(fieldType);
42
+ return this.consumerRegistry.has(fieldType) || this.dynamicRegistry.has(fieldType);
43
+ }
44
+ /** Every registered field type key. Consumer overrides and runtime registrations combined. */
45
+ registeredTypes() {
46
+ return [...new Set([...this.dynamicRegistry.keys(), ...this.consumerRegistry.keys()])].sort();
42
47
  }
43
48
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FieldRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
44
49
  static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FieldRegistryService, providedIn: 'root' });
@@ -46,5 +51,5 @@ export class FieldRegistryService {
46
51
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FieldRegistryService, decorators: [{
47
52
  type: Injectable,
48
53
  args: [{ providedIn: 'root' }]
49
- }] });
50
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmllbGQtcmVnaXN0cnkuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvc2VydmljZXMvZmllbGQtcmVnaXN0cnkuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFRLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6RCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVqRSw2REFBNkQ7QUFDN0QsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDekUsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDakYsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0sdUNBQXVDLENBQUM7QUFDN0UsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDakYsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0scUNBQXFDLENBQUM7QUFDekUsT0FBTyxFQUFFLHNCQUFzQixFQUFFLE1BQU0seUNBQXlDLENBQUM7QUFDakYsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sNkNBQTZDLENBQUM7QUFDeEYsT0FBTyxFQUFFLHVCQUF1QixFQUFFLE1BQU0sMkNBQTJDLENBQUM7O0FBRXBGOzs7O0dBSUc7QUFFSCxNQUFNLE9BQU8sb0JBQW9CO0lBQ2QsZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLG1CQUFtQixFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLElBQUksSUFBSSxHQUFHLEVBQUUsQ0FBQztJQUVqRyxrRUFBa0U7SUFDakQsZUFBZSxHQUFHLElBQUksR0FBRyxDQUFvQjtRQUM1RCxDQUFDLE1BQU0sRUFBRSxrQkFBa0IsQ0FBQztRQUM1QixDQUFDLFVBQVUsRUFBRSxzQkFBc0IsQ0FBQztRQUNwQyxDQUFDLFFBQVEsRUFBRSxvQkFBb0IsQ0FBQztRQUNoQyxDQUFDLFVBQVUsRUFBRSxzQkFBc0IsQ0FBQztRQUNwQyxDQUFDLE1BQU0sRUFBRSxrQkFBa0IsQ0FBQztRQUM1QixDQUFDLFVBQVUsRUFBRSxzQkFBc0IsQ0FBQztRQUNwQyxDQUFDLGFBQWEsRUFBRSx5QkFBeUIsQ0FBQztRQUMxQyxDQUFDLFlBQVksRUFBRSx1QkFBdUIsQ0FBQztLQUN4QyxDQUFDLENBQUM7SUFFSDs7OztPQUlHO0lBQ0gsT0FBTyxDQUFDLFNBQWlCO1FBQ3ZCLE9BQU8sSUFBSSxDQUFDLGdCQUFnQixDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsSUFBSSxJQUFJLENBQUM7SUFDN0YsQ0FBQztJQUVELHVEQUF1RDtJQUN2RCxHQUFHLENBQUMsU0FBaUI7UUFDbkIsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQ3JGLENBQUM7d0dBM0JVLG9CQUFvQjs0R0FBcEIsb0JBQW9CLGNBRFAsTUFBTTs7NEZBQ25CLG9CQUFvQjtrQkFEaEMsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBJbmplY3RhYmxlLCBUeXBlLCBpbmplY3QgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IEZJRUxEX1RZUEVfUkVHSVNUUlkgfSBmcm9tICcuLi90b2tlbnMvaW5qZWN0aW9uLXRva2Vucyc7XG5cbi8vIEJ1aWx0LWluIGZpZWxkIGNvbXBvbmVudHMg4oCUIHByZS1yZWdpc3RlcmVkIGluIHRoaXMgc2VydmljZVxuaW1wb3J0IHsgVGV4dEZpZWxkQ29tcG9uZW50IH0gZnJvbSAnLi4vZmllbGQtdHlwZXMvdGV4dC1maWVsZC5jb21wb25lbnQnO1xuaW1wb3J0IHsgVGV4dGFyZWFGaWVsZENvbXBvbmVudCB9IGZyb20gJy4uL2ZpZWxkLXR5cGVzL3RleHRhcmVhLWZpZWxkLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBOdW1iZXJGaWVsZENvbXBvbmVudCB9IGZyb20gJy4uL2ZpZWxkLXR5cGVzL251bWJlci1maWVsZC5jb21wb25lbnQnO1xuaW1wb3J0IHsgQ2hlY2tib3hGaWVsZENvbXBvbmVudCB9IGZyb20gJy4uL2ZpZWxkLXR5cGVzL2NoZWNrYm94LWZpZWxkLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBEYXRlRmllbGRDb21wb25lbnQgfSBmcm9tICcuLi9maWVsZC10eXBlcy9kYXRlLWZpZWxkLmNvbXBvbmVudCc7XG5pbXBvcnQgeyBEcm9wZG93bkZpZWxkQ29tcG9uZW50IH0gZnJvbSAnLi4vZmllbGQtdHlwZXMvZHJvcGRvd24tZmllbGQuY29tcG9uZW50JztcbmltcG9ydCB7IE11bHRpU2VsZWN0RmllbGRDb21wb25lbnQgfSBmcm9tICcuLi9maWVsZC10eXBlcy9tdWx0aS1zZWxlY3QtZmllbGQuY29tcG9uZW50JztcbmltcG9ydCB7IEVudGl0eVJlZkZpZWxkQ29tcG9uZW50IH0gZnJvbSAnLi4vZmllbGQtdHlwZXMvZW50aXR5LXJlZi1maWVsZC5jb21wb25lbnQnO1xuXG4vKipcbiAqIEZpZWxkUmVnaXN0cnlTZXJ2aWNlIOKAlCByZXNvbHZlcyBmaWVsZCB0eXBlIHN0cmluZ3MgdG8gQW5ndWxhciBjb21wb25lbnQgY2xhc3Nlcy5cbiAqIE9wZW4vQ2xvc2VkOiBvcGVuIGZvciBleHRlbnNpb24gdmlhIGNvbnN1bWVyIGZpZWxkVHlwZXMgY29uZmlnLCBjbG9zZWQgZm9yIG1vZGlmaWNhdGlvbi5cbiAqIER5bmFtaWNGaWVsZENvbXBvbmVudCB1c2VzIHRoaXMgdG8gbW91bnQgdGhlIHJpZ2h0IGNvbXBvbmVudCB2aWEgY3JlYXRlQ29tcG9uZW50KCkuXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgRmllbGRSZWdpc3RyeVNlcnZpY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IGNvbnN1bWVyUmVnaXN0cnkgPSBpbmplY3QoRklFTERfVFlQRV9SRUdJU1RSWSwgeyBvcHRpb25hbDogdHJ1ZSB9KSA/PyBuZXcgTWFwKCk7XG5cbiAgLyoqIEJ1aWx0LWluIGZpZWxkIHR5cGUg4oaSIGNvbXBvbmVudCBtYXAuIE5ldmVyIHJlbW92ZSBhbiBlbnRyeS4gKi9cbiAgcHJpdmF0ZSByZWFkb25seSBidWlsdEluUmVnaXN0cnkgPSBuZXcgTWFwPHN0cmluZywgVHlwZTxhbnk+PihbXG4gICAgWyd0ZXh0JywgVGV4dEZpZWxkQ29tcG9uZW50XSxcbiAgICBbJ3RleHRhcmVhJywgVGV4dGFyZWFGaWVsZENvbXBvbmVudF0sXG4gICAgWydudW1iZXInLCBOdW1iZXJGaWVsZENvbXBvbmVudF0sXG4gICAgWydjaGVja2JveCcsIENoZWNrYm94RmllbGRDb21wb25lbnRdLFxuICAgIFsnZGF0ZScsIERhdGVGaWVsZENvbXBvbmVudF0sXG4gICAgWydkcm9wZG93bicsIERyb3Bkb3duRmllbGRDb21wb25lbnRdLFxuICAgIFsnbXVsdGlTZWxlY3QnLCBNdWx0aVNlbGVjdEZpZWxkQ29tcG9uZW50XSxcbiAgICBbJ2VudGl0eS1yZWYnLCBFbnRpdHlSZWZGaWVsZENvbXBvbmVudF0sXG4gIF0pO1xuXG4gIC8qKlxuICAgKiBSZXNvbHZlIGEgZmllbGQgdHlwZSBzdHJpbmcgdG8gYSBjb21wb25lbnQgY2xhc3MuXG4gICAqIENvbnN1bWVyIHJlZ2lzdHJ5IHRha2VzIHByZWNlZGVuY2Ugb3ZlciBidWlsdC1pbnMgKG9wZW4gZm9yIGV4dGVuc2lvbikuXG4gICAqIFJldHVybnMgbnVsbCBpZiB0eXBlIGlzIHVua25vd24g4oCUIGNhbGxlciBtdXN0IGhhbmRsZSBncmFjZWZ1bGx5LlxuICAgKi9cbiAgcmVzb2x2ZShmaWVsZFR5cGU6IHN0cmluZyk6IFR5cGU8YW55PiB8IG51bGwge1xuICAgIHJldHVybiB0aGlzLmNvbnN1bWVyUmVnaXN0cnkuZ2V0KGZpZWxkVHlwZSkgPz8gdGhpcy5idWlsdEluUmVnaXN0cnkuZ2V0KGZpZWxkVHlwZSkgPz8gbnVsbDtcbiAgfVxuXG4gIC8qKiBDaGVjayBpZiBhIGZpZWxkIHR5cGUgaGFzIGEgcmVnaXN0ZXJlZCBjb21wb25lbnQgKi9cbiAgaGFzKGZpZWxkVHlwZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMuY29uc3VtZXJSZWdpc3RyeS5oYXMoZmllbGRUeXBlKSB8fCB0aGlzLmJ1aWx0SW5SZWdpc3RyeS5oYXMoZmllbGRUeXBlKTtcbiAgfVxufVxuIl19
54
+ }], ctorParameters: () => [] });
55
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmllbGQtcmVnaXN0cnkuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvc2VydmljZXMvZmllbGQtcmVnaXN0cnkuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFRLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUN6RCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsZUFBZSxFQUFFLE1BQU0sNEJBQTRCLENBQUM7O0FBRWxGOzs7Ozs7Ozs7R0FTRztBQUVILE1BQU0sT0FBTyxvQkFBb0I7SUFDZCxnQkFBZ0IsR0FDL0IsTUFBTSxDQUFDLG1CQUFtQixFQUFFLEVBQUUsUUFBUSxFQUFFLElBQUksRUFBRSxDQUFDLElBQUksSUFBSSxHQUFHLEVBQXFCLENBQUM7SUFDakUsZUFBZSxHQUFHLElBQUksR0FBRyxFQUFxQixDQUFDO0lBRWhFO1FBQ0UsNEZBQTRGO1FBQzVGLEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLGVBQWUsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxJQUFJLEVBQUUsRUFBRSxDQUFDO1lBQ3BFLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDeEIsQ0FBQztJQUNILENBQUM7SUFFRCwwREFBMEQ7SUFDMUQsUUFBUSxDQUFDLElBQVksRUFBRSxTQUFvQjtRQUN6QyxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUVELGtFQUFrRTtJQUNsRSxXQUFXLENBQUMsR0FBOEI7UUFDeEMsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztZQUMvQyxJQUFJLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7UUFDdkMsQ0FBQztJQUNILENBQUM7SUFFRDs7O09BR0c7SUFDSCxPQUFPLENBQUMsU0FBaUI7UUFDdkIsT0FBTyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxJQUFJLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxJQUFJLElBQUksQ0FBQztJQUM3RixDQUFDO0lBRUQsd0RBQXdEO0lBQ3hELEdBQUcsQ0FBQyxTQUFpQjtRQUNuQixPQUFPLElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDckYsQ0FBQztJQUVELDhGQUE4RjtJQUM5RixlQUFlO1FBQ2IsT0FBTyxDQUFDLEdBQUcsSUFBSSxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsSUFBSSxFQUFFLEVBQUUsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7SUFDaEcsQ0FBQzt3R0F4Q1Usb0JBQW9COzRHQUFwQixvQkFBb0IsY0FEUCxNQUFNOzs0RkFDbkIsb0JBQW9CO2tCQURoQyxVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUsIFR5cGUsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgRklFTERfVFlQRV9SRUdJU1RSWSwgRklFTERfVFlQRV9TRVRTIH0gZnJvbSAnLi4vdG9rZW5zL2luamVjdGlvbi10b2tlbnMnO1xuXG4vKipcbiAqIEZpZWxkUmVnaXN0cnlTZXJ2aWNlIOKAlCByZXNvbHZlcyBmaWVsZCB0eXBlIHN0cmluZ3MgdG8gQW5ndWxhciBjb21wb25lbnQgY2xhc3Nlcy5cbiAqXG4gKiAqKlRyZWUtc2hha2luZyBjb250cmFjdDoqKiB0aGlzIHNlcnZpY2UgaG9sZHMgKm5vKiBzdGF0aWMgaW1wb3J0cyBvZiBmaWVsZCBjb21wb25lbnRzLlxuICogTm90aGluZyBpcyBidW5kbGVkIHVudGlsIHNvbWV0aGluZyByZWdpc3RlcnMgaXQsIHdoaWNoIGlzIHdoYXQgbWFrZXMgdGhlIGJ1aWx0LWluc1xuICogb3B0LWluLiBSZWdpc3RlciB0aGVtIHdpdGggYHByb3ZpZGVCdWlsdEluRmllbGRUeXBlcygpYCAoYWxsIDE5IGtleXMpIG9yIGEgbmFycm93ZXJcbiAqIHN1YnNldCB2aWEgYHByb3ZpZGVGaWVsZFR5cGVzKHsgLi4uIH0pYCDigJQgc2VlIGBwcm92aWRlcnMvcHJvdmlkZS1maWVsZC10eXBlcy50c2AuXG4gKlxuICogUmVzb2x1dGlvbiBvcmRlcjogY29uc3VtZXIgdG9rZW4gcmVnaXN0cnkg4oaSIHJ1bnRpbWUgcmVnaXN0cmF0aW9ucyDihpIgbm90aGluZy5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBGaWVsZFJlZ2lzdHJ5U2VydmljZSB7XG4gIHByaXZhdGUgcmVhZG9ubHkgY29uc3VtZXJSZWdpc3RyeSA9XG4gICAgaW5qZWN0KEZJRUxEX1RZUEVfUkVHSVNUUlksIHsgb3B0aW9uYWw6IHRydWUgfSkgPz8gbmV3IE1hcDxzdHJpbmcsIFR5cGU8YW55Pj4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSBkeW5hbWljUmVnaXN0cnkgPSBuZXcgTWFwPHN0cmluZywgVHlwZTxhbnk+PigpO1xuXG4gIGNvbnN0cnVjdG9yKCkge1xuICAgIC8vIFNldHMgY29udHJpYnV0ZWQgYnkgcHJvdmlkZUZpZWxkVHlwZXMoKS9wcm92aWRlQnVpbHRJbkZpZWxkVHlwZXMoKSwgaW4gZGVjbGFyYXRpb24gb3JkZXIuXG4gICAgZm9yIChjb25zdCBzZXQgb2YgaW5qZWN0KEZJRUxEX1RZUEVfU0VUUywgeyBvcHRpb25hbDogdHJ1ZSB9KSA/PyBbXSkge1xuICAgICAgdGhpcy5yZWdpc3RlckFsbChzZXQpO1xuICAgIH1cbiAgfVxuXG4gIC8qKiBSZWdpc3RlciBhIGZpZWxkIHR5cGUgY29tcG9uZW50IG1hcHBpbmcgYXQgcnVudGltZS4gKi9cbiAgcmVnaXN0ZXIodHlwZTogc3RyaW5nLCBjb21wb25lbnQ6IFR5cGU8YW55Pik6IHZvaWQge1xuICAgIHRoaXMuZHluYW1pY1JlZ2lzdHJ5LnNldCh0eXBlLCBjb21wb25lbnQpO1xuICB9XG5cbiAgLyoqIFJlZ2lzdGVyIG11bHRpcGxlIGZpZWxkIHR5cGUgY29tcG9uZW50IG1hcHBpbmdzIGF0IHJ1bnRpbWUuICovXG4gIHJlZ2lzdGVyQWxsKG1hcDogUmVjb3JkPHN0cmluZywgVHlwZTxhbnk+Pik6IHZvaWQge1xuICAgIGZvciAoY29uc3QgW3R5cGUsIGNvbXBdIG9mIE9iamVjdC5lbnRyaWVzKG1hcCkpIHtcbiAgICAgIHRoaXMuZHluYW1pY1JlZ2lzdHJ5LnNldCh0eXBlLCBjb21wKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmVzb2x2ZSBhIGZpZWxkIHR5cGUgc3RyaW5nIHRvIGEgY29tcG9uZW50IGNsYXNzLlxuICAgKiBDb25zdW1lciB0b2tlbiByZWdpc3RyeSB0YWtlcyBwcmlvcml0eSBvdmVyIHJ1bnRpbWUgcmVnaXN0cmF0aW9ucy5cbiAgICovXG4gIHJlc29sdmUoZmllbGRUeXBlOiBzdHJpbmcpOiBUeXBlPGFueT4gfCBudWxsIHtcbiAgICByZXR1cm4gdGhpcy5jb25zdW1lclJlZ2lzdHJ5LmdldChmaWVsZFR5cGUpID8/IHRoaXMuZHluYW1pY1JlZ2lzdHJ5LmdldChmaWVsZFR5cGUpID8/IG51bGw7XG4gIH1cblxuICAvKiogQ2hlY2sgaWYgYSBmaWVsZCB0eXBlIGhhcyBhIHJlZ2lzdGVyZWQgY29tcG9uZW50LiAqL1xuICBoYXMoZmllbGRUeXBlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgICByZXR1cm4gdGhpcy5jb25zdW1lclJlZ2lzdHJ5LmhhcyhmaWVsZFR5cGUpIHx8IHRoaXMuZHluYW1pY1JlZ2lzdHJ5LmhhcyhmaWVsZFR5cGUpO1xuICB9XG5cbiAgLyoqIEV2ZXJ5IHJlZ2lzdGVyZWQgZmllbGQgdHlwZSBrZXkuIENvbnN1bWVyIG92ZXJyaWRlcyBhbmQgcnVudGltZSByZWdpc3RyYXRpb25zIGNvbWJpbmVkLiAqL1xuICByZWdpc3RlcmVkVHlwZXMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBbLi4ubmV3IFNldChbLi4udGhpcy5keW5hbWljUmVnaXN0cnkua2V5cygpLCAuLi50aGlzLmNvbnN1bWVyUmVnaXN0cnkua2V5cygpXSldLnNvcnQoKTtcbiAgfVxufVxuIl19
@@ -0,0 +1,89 @@
1
+ import { Injectable, inject } from '@angular/core';
2
+ import { UPLOAD_HANDLER } from '../tokens/injection-tokens';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * FileUploadService — the single place image-field and file-field agree on how a
6
+ * selected `File` becomes a `FileRef`.
7
+ *
8
+ * With `UPLOAD_HANDLER` registered the file is persisted and stored as `{ url }`;
9
+ * without one it is stored as `{ file }` for the consumer to upload at submit time.
10
+ */
11
+ export class FileUploadService {
12
+ handler = inject(UPLOAD_HANDLER, { optional: true });
13
+ get hasHandler() {
14
+ return !!this.handler;
15
+ }
16
+ /** Metadata common to both persisted and unpersisted refs. */
17
+ describe(file) {
18
+ return { name: file.name, size: file.size, mimeType: file.type };
19
+ }
20
+ /**
21
+ * Turn a selected File into the value to store on the control.
22
+ * @throws when a registered handler rejects — callers surface it as a field error.
23
+ */
24
+ async toFileRef(file) {
25
+ const meta = this.describe(file);
26
+ if (!this.handler)
27
+ return { ...meta, file };
28
+ const result = await this.normalize(this.handler(file));
29
+ return { ...meta, url: result.url, name: result.name ?? meta.name };
30
+ }
31
+ /** Object URL for previewing an unpersisted File. Callers must revoke it. */
32
+ previewUrlFor(ref) {
33
+ if (!ref)
34
+ return null;
35
+ if (ref.url)
36
+ return ref.url;
37
+ if (ref.file && typeof URL !== 'undefined' && typeof URL.createObjectURL === 'function') {
38
+ return URL.createObjectURL(ref.file);
39
+ }
40
+ return null;
41
+ }
42
+ revokePreviewUrl(url) {
43
+ if (!url || !url.startsWith('blob:'))
44
+ return;
45
+ if (typeof URL !== 'undefined' && typeof URL.revokeObjectURL === 'function') {
46
+ URL.revokeObjectURL(url);
47
+ }
48
+ }
49
+ normalize(result) {
50
+ if (this.isSubscribable(result)) {
51
+ return new Promise((resolve, reject) => {
52
+ let settled = false;
53
+ result.subscribe({
54
+ next: value => {
55
+ if (settled)
56
+ return;
57
+ settled = true;
58
+ resolve(value);
59
+ },
60
+ error: err => {
61
+ if (settled)
62
+ return;
63
+ settled = true;
64
+ reject(err);
65
+ },
66
+ complete: () => {
67
+ if (settled)
68
+ return;
69
+ settled = true;
70
+ reject(new Error('Upload handler completed without emitting a result.'));
71
+ },
72
+ });
73
+ });
74
+ }
75
+ return Promise.resolve(result);
76
+ }
77
+ isSubscribable(value) {
78
+ return (typeof value === 'object' &&
79
+ value !== null &&
80
+ typeof value.subscribe === 'function');
81
+ }
82
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
83
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadService, providedIn: 'root' });
84
+ }
85
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: FileUploadService, decorators: [{
86
+ type: Injectable,
87
+ args: [{ providedIn: 'root' }]
88
+ }] });
89
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlsZS11cGxvYWQuc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy9saWIvc2VydmljZXMvZmlsZS11cGxvYWQuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUVuRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sNEJBQTRCLENBQUM7O0FBRTVEOzs7Ozs7R0FNRztBQUVILE1BQU0sT0FBTyxpQkFBaUI7SUFDWCxPQUFPLEdBQUcsTUFBTSxDQUFDLGNBQWMsRUFBRSxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBRXRFLElBQUksVUFBVTtRQUNaLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7SUFDeEIsQ0FBQztJQUVELDhEQUE4RDtJQUN0RCxRQUFRLENBQUMsSUFBVTtRQUN6QixPQUFPLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNuRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFVO1FBQ3hCLE1BQU0sSUFBSSxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDakMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTyxFQUFFLEdBQUcsSUFBSSxFQUFFLElBQUksRUFBRSxDQUFDO1FBRTVDLE1BQU0sTUFBTSxHQUFHLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7UUFDeEQsT0FBTyxFQUFFLEdBQUcsSUFBSSxFQUFFLEdBQUcsRUFBRSxNQUFNLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxNQUFNLENBQUMsSUFBSSxJQUFJLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUN0RSxDQUFDO0lBRUQsNkVBQTZFO0lBQzdFLGFBQWEsQ0FBQyxHQUErQjtRQUMzQyxJQUFJLENBQUMsR0FBRztZQUFFLE9BQU8sSUFBSSxDQUFDO1FBQ3RCLElBQUksR0FBRyxDQUFDLEdBQUc7WUFBRSxPQUFPLEdBQUcsQ0FBQyxHQUFHLENBQUM7UUFDNUIsSUFBSSxHQUFHLENBQUMsSUFBSSxJQUFJLE9BQU8sR0FBRyxLQUFLLFdBQVcsSUFBSSxPQUFPLEdBQUcsQ0FBQyxlQUFlLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDeEYsT0FBTyxHQUFHLENBQUMsZUFBZSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUN2QyxDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUM7SUFDZCxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsR0FBa0I7UUFDakMsSUFBSSxDQUFDLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDO1lBQUUsT0FBTztRQUM3QyxJQUFJLE9BQU8sR0FBRyxLQUFLLFdBQVcsSUFBSSxPQUFPLEdBQUcsQ0FBQyxlQUFlLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDNUUsR0FBRyxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUMzQixDQUFDO0lBQ0gsQ0FBQztJQUVPLFNBQVMsQ0FDZixNQUF5RTtRQUV6RSxJQUFJLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztZQUNoQyxPQUFPLElBQUksT0FBTyxDQUFlLENBQUMsT0FBTyxFQUFFLE1BQU0sRUFBRSxFQUFFO2dCQUNuRCxJQUFJLE9BQU8sR0FBRyxLQUFLLENBQUM7Z0JBQ3BCLE1BQU0sQ0FBQyxTQUFTLENBQUM7b0JBQ2YsSUFBSSxFQUFFLEtBQUssQ0FBQyxFQUFFO3dCQUNaLElBQUksT0FBTzs0QkFBRSxPQUFPO3dCQUNwQixPQUFPLEdBQUcsSUFBSSxDQUFDO3dCQUNmLE9BQU8sQ0FBQyxLQUFLLENBQUMsQ0FBQztvQkFDakIsQ0FBQztvQkFDRCxLQUFLLEVBQUUsR0FBRyxDQUFDLEVBQUU7d0JBQ1gsSUFBSSxPQUFPOzRCQUFFLE9BQU87d0JBQ3BCLE9BQU8sR0FBRyxJQUFJLENBQUM7d0JBQ2YsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO29CQUNkLENBQUM7b0JBQ0QsUUFBUSxFQUFFLEdBQUcsRUFBRTt3QkFDYixJQUFJLE9BQU87NEJBQUUsT0FBTzt3QkFDcEIsT0FBTyxHQUFHLElBQUksQ0FBQzt3QkFDZixNQUFNLENBQUMsSUFBSSxLQUFLLENBQUMscURBQXFELENBQUMsQ0FBQyxDQUFDO29CQUMzRSxDQUFDO2lCQUNGLENBQUMsQ0FBQztZQUNMLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztRQUNELE9BQU8sT0FBTyxDQUFDLE9BQU8sQ0FBQyxNQUE4QyxDQUFDLENBQUM7SUFDekUsQ0FBQztJQUVPLGNBQWMsQ0FBQyxLQUFjO1FBQ25DLE9BQU8sQ0FDTCxPQUFPLEtBQUssS0FBSyxRQUFRO1lBQ3pCLEtBQUssS0FBSyxJQUFJO1lBQ2QsT0FBUSxLQUFvQyxDQUFDLFNBQVMsS0FBSyxVQUFVLENBQ3RFLENBQUM7SUFDSixDQUFDO3dHQTNFVSxpQkFBaUI7NEdBQWpCLGlCQUFpQixjQURKLE1BQU07OzRGQUNuQixpQkFBaUI7a0JBRDdCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgdHlwZSB7IEZpbGVSZWYsIFN1YnNjcmliYWJsZSwgVXBsb2FkUmVzdWx0IH0gZnJvbSAnQGR5bmFtaWMtZW50aXR5L2NvcmUnO1xuaW1wb3J0IHsgVVBMT0FEX0hBTkRMRVIgfSBmcm9tICcuLi90b2tlbnMvaW5qZWN0aW9uLXRva2Vucyc7XG5cbi8qKlxuICogRmlsZVVwbG9hZFNlcnZpY2Ug4oCUIHRoZSBzaW5nbGUgcGxhY2UgaW1hZ2UtZmllbGQgYW5kIGZpbGUtZmllbGQgYWdyZWUgb24gaG93IGFcbiAqIHNlbGVjdGVkIGBGaWxlYCBiZWNvbWVzIGEgYEZpbGVSZWZgLlxuICpcbiAqIFdpdGggYFVQTE9BRF9IQU5ETEVSYCByZWdpc3RlcmVkIHRoZSBmaWxlIGlzIHBlcnNpc3RlZCBhbmQgc3RvcmVkIGFzIGB7IHVybCB9YDtcbiAqIHdpdGhvdXQgb25lIGl0IGlzIHN0b3JlZCBhcyBgeyBmaWxlIH1gIGZvciB0aGUgY29uc3VtZXIgdG8gdXBsb2FkIGF0IHN1Ym1pdCB0aW1lLlxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIEZpbGVVcGxvYWRTZXJ2aWNlIHtcbiAgcHJpdmF0ZSByZWFkb25seSBoYW5kbGVyID0gaW5qZWN0KFVQTE9BRF9IQU5ETEVSLCB7IG9wdGlvbmFsOiB0cnVlIH0pO1xuXG4gIGdldCBoYXNIYW5kbGVyKCk6IGJvb2xlYW4ge1xuICAgIHJldHVybiAhIXRoaXMuaGFuZGxlcjtcbiAgfVxuXG4gIC8qKiBNZXRhZGF0YSBjb21tb24gdG8gYm90aCBwZXJzaXN0ZWQgYW5kIHVucGVyc2lzdGVkIHJlZnMuICovXG4gIHByaXZhdGUgZGVzY3JpYmUoZmlsZTogRmlsZSk6IEZpbGVSZWYge1xuICAgIHJldHVybiB7IG5hbWU6IGZpbGUubmFtZSwgc2l6ZTogZmlsZS5zaXplLCBtaW1lVHlwZTogZmlsZS50eXBlIH07XG4gIH1cblxuICAvKipcbiAgICogVHVybiBhIHNlbGVjdGVkIEZpbGUgaW50byB0aGUgdmFsdWUgdG8gc3RvcmUgb24gdGhlIGNvbnRyb2wuXG4gICAqIEB0aHJvd3Mgd2hlbiBhIHJlZ2lzdGVyZWQgaGFuZGxlciByZWplY3RzIOKAlCBjYWxsZXJzIHN1cmZhY2UgaXQgYXMgYSBmaWVsZCBlcnJvci5cbiAgICovXG4gIGFzeW5jIHRvRmlsZVJlZihmaWxlOiBGaWxlKTogUHJvbWlzZTxGaWxlUmVmPiB7XG4gICAgY29uc3QgbWV0YSA9IHRoaXMuZGVzY3JpYmUoZmlsZSk7XG4gICAgaWYgKCF0aGlzLmhhbmRsZXIpIHJldHVybiB7IC4uLm1ldGEsIGZpbGUgfTtcblxuICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMubm9ybWFsaXplKHRoaXMuaGFuZGxlcihmaWxlKSk7XG4gICAgcmV0dXJuIHsgLi4ubWV0YSwgdXJsOiByZXN1bHQudXJsLCBuYW1lOiByZXN1bHQubmFtZSA/PyBtZXRhLm5hbWUgfTtcbiAgfVxuXG4gIC8qKiBPYmplY3QgVVJMIGZvciBwcmV2aWV3aW5nIGFuIHVucGVyc2lzdGVkIEZpbGUuIENhbGxlcnMgbXVzdCByZXZva2UgaXQuICovXG4gIHByZXZpZXdVcmxGb3IocmVmOiBGaWxlUmVmIHwgbnVsbCB8IHVuZGVmaW5lZCk6IHN0cmluZyB8IG51bGwge1xuICAgIGlmICghcmVmKSByZXR1cm4gbnVsbDtcbiAgICBpZiAocmVmLnVybCkgcmV0dXJuIHJlZi51cmw7XG4gICAgaWYgKHJlZi5maWxlICYmIHR5cGVvZiBVUkwgIT09ICd1bmRlZmluZWQnICYmIHR5cGVvZiBVUkwuY3JlYXRlT2JqZWN0VVJMID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICByZXR1cm4gVVJMLmNyZWF0ZU9iamVjdFVSTChyZWYuZmlsZSk7XG4gICAgfVxuICAgIHJldHVybiBudWxsO1xuICB9XG5cbiAgcmV2b2tlUHJldmlld1VybCh1cmw6IHN0cmluZyB8IG51bGwpOiB2b2lkIHtcbiAgICBpZiAoIXVybCB8fCAhdXJsLnN0YXJ0c1dpdGgoJ2Jsb2I6JykpIHJldHVybjtcbiAgICBpZiAodHlwZW9mIFVSTCAhPT0gJ3VuZGVmaW5lZCcgJiYgdHlwZW9mIFVSTC5yZXZva2VPYmplY3RVUkwgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIFVSTC5yZXZva2VPYmplY3RVUkwodXJsKTtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG5vcm1hbGl6ZShcbiAgICByZXN1bHQ6IFVwbG9hZFJlc3VsdCB8IFByb21pc2U8VXBsb2FkUmVzdWx0PiB8IFN1YnNjcmliYWJsZTxVcGxvYWRSZXN1bHQ+LFxuICApOiBQcm9taXNlPFVwbG9hZFJlc3VsdD4ge1xuICAgIGlmICh0aGlzLmlzU3Vic2NyaWJhYmxlKHJlc3VsdCkpIHtcbiAgICAgIHJldHVybiBuZXcgUHJvbWlzZTxVcGxvYWRSZXN1bHQ+KChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgICAgbGV0IHNldHRsZWQgPSBmYWxzZTtcbiAgICAgICAgcmVzdWx0LnN1YnNjcmliZSh7XG4gICAgICAgICAgbmV4dDogdmFsdWUgPT4ge1xuICAgICAgICAgICAgaWYgKHNldHRsZWQpIHJldHVybjtcbiAgICAgICAgICAgIHNldHRsZWQgPSB0cnVlO1xuICAgICAgICAgICAgcmVzb2x2ZSh2YWx1ZSk7XG4gICAgICAgICAgfSxcbiAgICAgICAgICBlcnJvcjogZXJyID0+IHtcbiAgICAgICAgICAgIGlmIChzZXR0bGVkKSByZXR1cm47XG4gICAgICAgICAgICBzZXR0bGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHJlamVjdChlcnIpO1xuICAgICAgICAgIH0sXG4gICAgICAgICAgY29tcGxldGU6ICgpID0+IHtcbiAgICAgICAgICAgIGlmIChzZXR0bGVkKSByZXR1cm47XG4gICAgICAgICAgICBzZXR0bGVkID0gdHJ1ZTtcbiAgICAgICAgICAgIHJlamVjdChuZXcgRXJyb3IoJ1VwbG9hZCBoYW5kbGVyIGNvbXBsZXRlZCB3aXRob3V0IGVtaXR0aW5nIGEgcmVzdWx0LicpKTtcbiAgICAgICAgICB9LFxuICAgICAgICB9KTtcbiAgICAgIH0pO1xuICAgIH1cbiAgICByZXR1cm4gUHJvbWlzZS5yZXNvbHZlKHJlc3VsdCBhcyBVcGxvYWRSZXN1bHQgfCBQcm9taXNlPFVwbG9hZFJlc3VsdD4pO1xuICB9XG5cbiAgcHJpdmF0ZSBpc1N1YnNjcmliYWJsZSh2YWx1ZTogdW5rbm93bik6IHZhbHVlIGlzIFN1YnNjcmliYWJsZTxVcGxvYWRSZXN1bHQ+IHtcbiAgICByZXR1cm4gKFxuICAgICAgdHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJlxuICAgICAgdmFsdWUgIT09IG51bGwgJiZcbiAgICAgIHR5cGVvZiAodmFsdWUgYXMgU3Vic2NyaWJhYmxlPFVwbG9hZFJlc3VsdD4pLnN1YnNjcmliZSA9PT0gJ2Z1bmN0aW9uJ1xuICAgICk7XG4gIH1cbn1cbiJdfQ==