@valtimo/bootstrap 13.46.0 → 13.47.1
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.
|
@@ -3,11 +3,11 @@ import { APP_INITIALIZER, Injector, NgModule } from '@angular/core';
|
|
|
3
3
|
import { NGXLogger } from 'ngx-logger';
|
|
4
4
|
import { accountInitializer } from '@valtimo/account';
|
|
5
5
|
import { HttpClient } from '@angular/common/http';
|
|
6
|
-
import { AdminSettingsService, menuInitializer } from '@valtimo/components';
|
|
6
|
+
import { AdminSettingsService, hasSavedMenuConfiguration, resolveMenuConfiguration, menuInitializer } from '@valtimo/components';
|
|
7
|
+
import { initializeCsp } from '@valtimo/security';
|
|
7
8
|
import { firstValueFrom } from 'rxjs';
|
|
8
9
|
import { INITIALIZERS, ConfigService } from '@valtimo/shared';
|
|
9
10
|
import { TranslateService } from '@ngx-translate/core';
|
|
10
|
-
import { initializeCsp } from '@valtimo/security';
|
|
11
11
|
import { DOCUMENT } from '@angular/common';
|
|
12
12
|
import { DomSanitizer } from '@angular/platform-browser';
|
|
13
13
|
|
|
@@ -46,13 +46,15 @@ initializers, logger) {
|
|
|
46
46
|
}
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
|
-
function initializerFactory(configService, injector, logger, translateService) {
|
|
49
|
+
function initializerFactory(configService, injector, logger, translateService, document, domSanitizer) {
|
|
50
50
|
logger.debug('Provided app initializers ', configService.initializers);
|
|
51
51
|
const initializersArray = [];
|
|
52
52
|
// Auth-initializer
|
|
53
53
|
initializersArray.push(configService.config.authentication.initializer(injector));
|
|
54
54
|
// Fetch feature toggle overrides from the backend and patch them into the config
|
|
55
55
|
// before other initializers run, so all reactive consumers see the correct merged values.
|
|
56
|
+
// Kept sequential (before the parallel batch below) because later initializers and reactive
|
|
57
|
+
// consumers must observe the merged toggle values.
|
|
56
58
|
initializersArray.push(async () => {
|
|
57
59
|
try {
|
|
58
60
|
const adminSettingsService = injector.get(AdminSettingsService);
|
|
@@ -68,7 +70,7 @@ function initializerFactory(configService, injector, logger, translateService) {
|
|
|
68
70
|
});
|
|
69
71
|
// Fetch accent colors from the backend and apply them as CSS custom properties
|
|
70
72
|
// before other initializers run, so the UI renders with the correct colors immediately.
|
|
71
|
-
|
|
73
|
+
const accentColorsInitializer = async () => {
|
|
72
74
|
try {
|
|
73
75
|
const adminSettingsService = injector.get(AdminSettingsService);
|
|
74
76
|
const colors = await firstValueFrom(adminSettingsService.getAccentColors());
|
|
@@ -80,9 +82,52 @@ function initializerFactory(configService, injector, logger, translateService) {
|
|
|
80
82
|
catch (error) {
|
|
81
83
|
logger.warn('Failed to fetch accent colors, using defaults', error);
|
|
82
84
|
}
|
|
83
|
-
}
|
|
85
|
+
};
|
|
86
|
+
// Initialize CSP after auth so we can fetch external plugin host origins and add them to
|
|
87
|
+
// frame-src before the meta tag is inserted (CSP meta is immutable once parsed).
|
|
88
|
+
const cspInitializer = async () => {
|
|
89
|
+
const pluginHostOrigins = new Set();
|
|
90
|
+
const collectOrigin = (value) => {
|
|
91
|
+
if (!value)
|
|
92
|
+
return;
|
|
93
|
+
try {
|
|
94
|
+
pluginHostOrigins.add(new URL(value).origin);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
// ignore unparseable URLs
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
const http = injector.get(HttpClient);
|
|
101
|
+
const apiBase = configService.config?.valtimoApi?.endpointUri;
|
|
102
|
+
if (apiBase) {
|
|
103
|
+
// host-origins is authenticated (not ADMIN-only) so every user who renders a plugin surface
|
|
104
|
+
// gets the host origins into frame-src/connect-src; it exposes derived origins only.
|
|
105
|
+
await firstValueFrom(http.get(`${apiBase}v1/external-plugin/host-origins`))
|
|
106
|
+
.then(origins => origins.forEach(origin => collectOrigin(origin)))
|
|
107
|
+
.catch(error => logger.debug('No external plugin host origins found for CSP augmentation:', error));
|
|
108
|
+
}
|
|
109
|
+
await initializeCsp(logger, configService, document, domSanitizer, [...pluginHostOrigins])();
|
|
110
|
+
};
|
|
111
|
+
// Fetch the persisted menu configuration and, when one exists, resolve it into MenuItem[] and
|
|
112
|
+
// patch config.menu.menuItems BEFORE the menu initializer runs (mirrors the feature-toggle/accent
|
|
113
|
+
// patches above). When the DB has no saved config (every existing installation) or the call
|
|
114
|
+
// errors, do nothing — config.menu is left untouched so the static environment.ts menu (custom
|
|
115
|
+
// links included) renders byte-identically. Backwards compatible by construction.
|
|
116
|
+
const menuConfigurationInitializer = async () => {
|
|
117
|
+
try {
|
|
118
|
+
const adminSettingsService = injector.get(AdminSettingsService);
|
|
119
|
+
const dto = await firstValueFrom(adminSettingsService.getMenuConfiguration());
|
|
120
|
+
if (hasSavedMenuConfiguration(dto)) {
|
|
121
|
+
configService.config.menu.menuItems = resolveMenuConfiguration(dto.configuration, logger);
|
|
122
|
+
logger.debug('Persisted menu configuration applied');
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
catch (error) {
|
|
126
|
+
logger.warn('Failed to fetch menu configuration, using default menu', error);
|
|
127
|
+
}
|
|
128
|
+
};
|
|
84
129
|
// Check OpenSearch availability and patch feature toggle
|
|
85
|
-
|
|
130
|
+
const openSearchInitializer = async () => {
|
|
86
131
|
try {
|
|
87
132
|
const httpClient = injector.get(HttpClient);
|
|
88
133
|
const response = await firstValueFrom(httpClient.get(`${configService.config.valtimoApi.endpointUri}management/v1/search-engine`));
|
|
@@ -93,7 +138,18 @@ function initializerFactory(configService, injector, logger, translateService) {
|
|
|
93
138
|
catch {
|
|
94
139
|
// OpenSearch not available
|
|
95
140
|
}
|
|
96
|
-
}
|
|
141
|
+
};
|
|
142
|
+
// These four initializers are order-independent (accent colors touch CSS custom properties, CSP
|
|
143
|
+
// inserts the meta tag, the menu patch only reads the DTO, and the OpenSearch check only patches
|
|
144
|
+
// its own toggle), so run them in parallel instead of serially blocking bootstrap on each round
|
|
145
|
+
// trip. Each one handles its own failures, so this combined initializer cannot reject for
|
|
146
|
+
// recoverable reasons.
|
|
147
|
+
initializersArray.push(() => Promise.all([
|
|
148
|
+
accentColorsInitializer(),
|
|
149
|
+
cspInitializer(),
|
|
150
|
+
menuConfigurationInitializer(),
|
|
151
|
+
openSearchInitializer(),
|
|
152
|
+
]));
|
|
97
153
|
// Use environment config initializers to be used in app startup.
|
|
98
154
|
configService.initializers.forEach(initializer => {
|
|
99
155
|
initializersArray.push(initializer(injector));
|
|
@@ -131,13 +187,7 @@ class BootstrapModule {
|
|
|
131
187
|
{
|
|
132
188
|
provide: INITIALIZERS,
|
|
133
189
|
useFactory: initializerFactory,
|
|
134
|
-
deps: [ConfigService, Injector, NGXLogger, TranslateService],
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
provide: APP_INITIALIZER,
|
|
138
|
-
useFactory: initializeCsp,
|
|
139
|
-
multi: true,
|
|
140
|
-
deps: [NGXLogger, ConfigService, DOCUMENT, DomSanitizer],
|
|
190
|
+
deps: [ConfigService, Injector, NGXLogger, TranslateService, DOCUMENT, DomSanitizer],
|
|
141
191
|
},
|
|
142
192
|
] }); }
|
|
143
193
|
}
|
|
@@ -156,13 +206,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.25", ngImpo
|
|
|
156
206
|
{
|
|
157
207
|
provide: INITIALIZERS,
|
|
158
208
|
useFactory: initializerFactory,
|
|
159
|
-
deps: [ConfigService, Injector, NGXLogger, TranslateService],
|
|
160
|
-
},
|
|
161
|
-
{
|
|
162
|
-
provide: APP_INITIALIZER,
|
|
163
|
-
useFactory: initializeCsp,
|
|
164
|
-
multi: true,
|
|
165
|
-
deps: [NGXLogger, ConfigService, DOCUMENT, DomSanitizer],
|
|
209
|
+
deps: [ConfigService, Injector, NGXLogger, TranslateService, DOCUMENT, DomSanitizer],
|
|
166
210
|
},
|
|
167
211
|
],
|
|
168
212
|
exports: [],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"valtimo-bootstrap.mjs","sources":["../../../../projects/valtimo/bootstrap/src/lib/init.ts","../../../../projects/valtimo/bootstrap/src/lib/bootstrap.module.ts","../../../../projects/valtimo/bootstrap/src/public-api.ts","../../../../projects/valtimo/bootstrap/src/valtimo-bootstrap.ts"],"sourcesContent":["/*\n * Copyright 2015-2026 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {NGXLogger} from 'ngx-logger';\nimport {TranslateService} from '@ngx-translate/core';\nimport {accountInitializer} from '@valtimo/account';\nimport {Injector} from '@angular/core';\nimport {HttpClient} from '@angular/common/http';\nimport {ConfigService} from '@valtimo/shared';\nimport {AdminSettingsService, menuInitializer} from '@valtimo/components';\nimport {firstValueFrom} from 'rxjs';\n\nexport function initialize(\n // eslint-disable-next-line\n initializers: (() => Function)[],\n logger: NGXLogger\n): () => Promise<any> {\n return (): Promise<any> =>\n new Promise<void>(async (resolve, reject) => {\n logger.debug('Initializing application');\n try {\n logger.debug('Running', initializers.length);\n for (const [index, initializer] of initializers.entries()) {\n logger.debug('Executing app initializer:', index, initializer.name);\n await initializer();\n logger.debug('Executed app initializer:', index, initializer.name);\n }\n logger.debug('Application initialized');\n resolve();\n } catch (err) {\n reject(err);\n }\n });\n}\n\nexport function initializerFactory(\n configService: ConfigService,\n injector: Injector,\n logger: NGXLogger,\n translateService: TranslateService\n) {\n logger.debug('Provided app initializers ', configService.initializers);\n\n const initializersArray = [];\n\n // Auth-initializer\n initializersArray.push(configService.config.authentication.initializer(injector));\n\n // Fetch feature toggle overrides from the backend and patch them into the config\n // before other initializers run, so all reactive consumers see the correct merged values.\n initializersArray.push(async () => {\n try {\n const adminSettingsService = injector.get(AdminSettingsService);\n const overrides = await firstValueFrom(adminSettingsService.getFeatureToggleOverrides());\n if (overrides && Object.keys(overrides).length > 0) {\n configService.patchFeatureToggles(overrides);\n logger.debug('Feature toggle overrides applied', overrides);\n }\n } catch (error) {\n logger.warn('Failed to fetch feature toggle overrides, using defaults', error);\n }\n });\n\n // Fetch accent colors from the backend and apply them as CSS custom properties\n // before other initializers run, so the UI renders with the correct colors immediately.\n initializersArray.push(async () => {\n try {\n const adminSettingsService = injector.get(AdminSettingsService);\n const colors = await firstValueFrom(adminSettingsService.getAccentColors());\n if (colors && Object.keys(colors).length > 0) {\n adminSettingsService.applyAccentColors(colors);\n logger.debug('Accent colors applied', colors);\n }\n } catch (error) {\n logger.warn('Failed to fetch accent colors, using defaults', error);\n }\n });\n\n // Check OpenSearch availability and patch feature toggle\n initializersArray.push(async () => {\n try {\n const httpClient = injector.get(HttpClient);\n const response = await firstValueFrom(\n httpClient.get<{available: boolean}>(\n `${configService.config.valtimoApi.endpointUri}management/v1/search-engine`\n )\n );\n if (response?.available) {\n configService.patchFeatureToggles({enableOpenSearch: true});\n }\n } catch {\n // OpenSearch not available\n }\n });\n\n // Use environment config initializers to be used in app startup.\n configService.initializers.forEach(initializer => {\n initializersArray.push(initializer(injector));\n });\n\n initializersArray.push(menuInitializer(injector, logger));\n initializersArray.push(accountInitializer(translateService, logger, configService));\n return initializersArray;\n}\n","/*\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {APP_INITIALIZER, Injector, NgModule} from '@angular/core';\nimport {NGXLogger} from 'ngx-logger';\nimport {initialize, initializerFactory} from './init';\nimport {ConfigService, INITIALIZERS} from '@valtimo/shared';\nimport {TranslateService} from '@ngx-translate/core';\nimport {initializeCsp} from '@valtimo/security';\nimport {DOCUMENT} from '@angular/common';\nimport {DomSanitizer} from '@angular/platform-browser';\n\n@NgModule({\n declarations: [],\n imports: [],\n providers: [\n {\n provide: APP_INITIALIZER,\n useFactory: initialize,\n multi: true,\n deps: [INITIALIZERS, NGXLogger],\n },\n {\n provide: INITIALIZERS,\n useFactory: initializerFactory,\n deps: [ConfigService, Injector, NGXLogger, TranslateService],\n },\n {\n provide: APP_INITIALIZER,\n useFactory: initializeCsp,\n multi: true,\n deps: [NGXLogger, ConfigService, DOCUMENT, DomSanitizer],\n },\n ],\n exports: [],\n})\nexport class BootstrapModule {}\n","/*\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Public API Surface of bootstrap\n */\n\nexport * from './lib/bootstrap.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"valtimo-bootstrap.mjs","sources":["../../../../projects/valtimo/bootstrap/src/lib/init.ts","../../../../projects/valtimo/bootstrap/src/lib/bootstrap.module.ts","../../../../projects/valtimo/bootstrap/src/public-api.ts","../../../../projects/valtimo/bootstrap/src/valtimo-bootstrap.ts"],"sourcesContent":["/*\n * Copyright 2015-2026 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {NGXLogger} from 'ngx-logger';\nimport {TranslateService} from '@ngx-translate/core';\nimport {accountInitializer} from '@valtimo/account';\nimport {Injector} from '@angular/core';\nimport {HttpClient} from '@angular/common/http';\nimport {ConfigService} from '@valtimo/shared';\nimport {\n AdminSettingsService,\n hasSavedMenuConfiguration,\n menuInitializer,\n resolveMenuConfiguration,\n} from '@valtimo/components';\nimport {initializeCsp} from '@valtimo/security';\nimport {DomSanitizer} from '@angular/platform-browser';\nimport {firstValueFrom} from 'rxjs';\n\nexport function initialize(\n // eslint-disable-next-line\n initializers: (() => Function)[],\n logger: NGXLogger\n): () => Promise<any> {\n return (): Promise<any> =>\n new Promise<void>(async (resolve, reject) => {\n logger.debug('Initializing application');\n try {\n logger.debug('Running', initializers.length);\n for (const [index, initializer] of initializers.entries()) {\n logger.debug('Executing app initializer:', index, initializer.name);\n await initializer();\n logger.debug('Executed app initializer:', index, initializer.name);\n }\n logger.debug('Application initialized');\n resolve();\n } catch (err) {\n reject(err);\n }\n });\n}\n\nexport function initializerFactory(\n configService: ConfigService,\n injector: Injector,\n logger: NGXLogger,\n translateService: TranslateService,\n document: Document,\n domSanitizer: DomSanitizer\n) {\n logger.debug('Provided app initializers ', configService.initializers);\n\n const initializersArray = [];\n\n // Auth-initializer\n initializersArray.push(configService.config.authentication.initializer(injector));\n\n // Fetch feature toggle overrides from the backend and patch them into the config\n // before other initializers run, so all reactive consumers see the correct merged values.\n // Kept sequential (before the parallel batch below) because later initializers and reactive\n // consumers must observe the merged toggle values.\n initializersArray.push(async () => {\n try {\n const adminSettingsService = injector.get(AdminSettingsService);\n const overrides = await firstValueFrom(adminSettingsService.getFeatureToggleOverrides());\n if (overrides && Object.keys(overrides).length > 0) {\n configService.patchFeatureToggles(overrides);\n logger.debug('Feature toggle overrides applied', overrides);\n }\n } catch (error) {\n logger.warn('Failed to fetch feature toggle overrides, using defaults', error);\n }\n });\n\n // Fetch accent colors from the backend and apply them as CSS custom properties\n // before other initializers run, so the UI renders with the correct colors immediately.\n const accentColorsInitializer = async (): Promise<void> => {\n try {\n const adminSettingsService = injector.get(AdminSettingsService);\n const colors = await firstValueFrom(adminSettingsService.getAccentColors());\n if (colors && Object.keys(colors).length > 0) {\n adminSettingsService.applyAccentColors(colors);\n logger.debug('Accent colors applied', colors);\n }\n } catch (error) {\n logger.warn('Failed to fetch accent colors, using defaults', error);\n }\n };\n\n // Initialize CSP after auth so we can fetch external plugin host origins and add them to\n // frame-src before the meta tag is inserted (CSP meta is immutable once parsed).\n const cspInitializer = async (): Promise<void> => {\n const pluginHostOrigins = new Set<string>();\n const collectOrigin = (value: string | null | undefined): void => {\n if (!value) return;\n try {\n pluginHostOrigins.add(new URL(value).origin);\n } catch {\n // ignore unparseable URLs\n }\n };\n\n const http = injector.get(HttpClient);\n const apiBase = configService.config?.valtimoApi?.endpointUri;\n\n if (apiBase) {\n // host-origins is authenticated (not ADMIN-only) so every user who renders a plugin surface\n // gets the host origins into frame-src/connect-src; it exposes derived origins only.\n await firstValueFrom(http.get<string[]>(`${apiBase}v1/external-plugin/host-origins`))\n .then(origins => origins.forEach(origin => collectOrigin(origin)))\n .catch(error =>\n logger.debug('No external plugin host origins found for CSP augmentation:', error)\n );\n }\n\n await initializeCsp(logger, configService, document, domSanitizer, [...pluginHostOrigins])();\n };\n\n // Fetch the persisted menu configuration and, when one exists, resolve it into MenuItem[] and\n // patch config.menu.menuItems BEFORE the menu initializer runs (mirrors the feature-toggle/accent\n // patches above). When the DB has no saved config (every existing installation) or the call\n // errors, do nothing — config.menu is left untouched so the static environment.ts menu (custom\n // links included) renders byte-identically. Backwards compatible by construction.\n const menuConfigurationInitializer = async (): Promise<void> => {\n try {\n const adminSettingsService = injector.get(AdminSettingsService);\n const dto = await firstValueFrom(adminSettingsService.getMenuConfiguration());\n if (hasSavedMenuConfiguration(dto)) {\n configService.config.menu.menuItems = resolveMenuConfiguration(dto.configuration, logger);\n logger.debug('Persisted menu configuration applied');\n }\n } catch (error) {\n logger.warn('Failed to fetch menu configuration, using default menu', error);\n }\n };\n\n // Check OpenSearch availability and patch feature toggle\n const openSearchInitializer = async (): Promise<void> => {\n try {\n const httpClient = injector.get(HttpClient);\n const response = await firstValueFrom(\n httpClient.get<{available: boolean}>(\n `${configService.config.valtimoApi.endpointUri}management/v1/search-engine`\n )\n );\n if (response?.available) {\n configService.patchFeatureToggles({enableOpenSearch: true});\n }\n } catch {\n // OpenSearch not available\n }\n };\n\n // These four initializers are order-independent (accent colors touch CSS custom properties, CSP\n // inserts the meta tag, the menu patch only reads the DTO, and the OpenSearch check only patches\n // its own toggle), so run them in parallel instead of serially blocking bootstrap on each round\n // trip. Each one handles its own failures, so this combined initializer cannot reject for\n // recoverable reasons.\n initializersArray.push(() =>\n Promise.all([\n accentColorsInitializer(),\n cspInitializer(),\n menuConfigurationInitializer(),\n openSearchInitializer(),\n ])\n );\n\n // Use environment config initializers to be used in app startup.\n configService.initializers.forEach(initializer => {\n initializersArray.push(initializer(injector));\n });\n\n initializersArray.push(menuInitializer(injector, logger));\n initializersArray.push(accountInitializer(translateService, logger, configService));\n return initializersArray;\n}\n","/*\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {APP_INITIALIZER, Injector, NgModule} from '@angular/core';\nimport {NGXLogger} from 'ngx-logger';\nimport {initialize, initializerFactory} from './init';\nimport {ConfigService, INITIALIZERS} from '@valtimo/shared';\nimport {TranslateService} from '@ngx-translate/core';\nimport {DOCUMENT} from '@angular/common';\nimport {DomSanitizer} from '@angular/platform-browser';\n\n@NgModule({\n declarations: [],\n imports: [],\n providers: [\n {\n provide: APP_INITIALIZER,\n useFactory: initialize,\n multi: true,\n deps: [INITIALIZERS, NGXLogger],\n },\n {\n provide: INITIALIZERS,\n useFactory: initializerFactory,\n deps: [ConfigService, Injector, NGXLogger, TranslateService, DOCUMENT, DomSanitizer],\n },\n ],\n exports: [],\n})\nexport class BootstrapModule {}\n","/*\n * Copyright 2015-2025 Ritense BV, the Netherlands.\n *\n * Licensed under EUPL, Version 1.2 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * https://joinup.ec.europa.eu/collection/eupl/eupl-text-eupl-12\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" basis,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/*\n * Public API Surface of bootstrap\n */\n\nexport * from './lib/bootstrap.module';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
package/lib/init.d.ts
CHANGED
|
@@ -2,5 +2,6 @@ import { NGXLogger } from 'ngx-logger';
|
|
|
2
2
|
import { TranslateService } from '@ngx-translate/core';
|
|
3
3
|
import { Injector } from '@angular/core';
|
|
4
4
|
import { ConfigService } from '@valtimo/shared';
|
|
5
|
+
import { DomSanitizer } from '@angular/platform-browser';
|
|
5
6
|
export declare function initialize(initializers: (() => Function)[], logger: NGXLogger): () => Promise<any>;
|
|
6
|
-
export declare function initializerFactory(configService: ConfigService, injector: Injector, logger: NGXLogger, translateService: TranslateService): any[];
|
|
7
|
+
export declare function initializerFactory(configService: ConfigService, injector: Injector, logger: NGXLogger, translateService: TranslateService, document: Document, domSanitizer: DomSanitizer): any[];
|