@quvel-kit/core 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.
- package/README.md +670 -0
- package/dist/auth/boot/defineAuthGuard.d.ts +54 -0
- package/dist/auth/boot/defineAuthGuard.d.ts.map +1 -0
- package/dist/auth/boot/defineAuthGuard.js +72 -0
- package/dist/auth/enums/AuthStatusEnum.d.ts +13 -0
- package/dist/auth/enums/AuthStatusEnum.d.ts.map +1 -0
- package/dist/auth/enums/AuthStatusEnum.js +13 -0
- package/dist/auth/index.d.ts +13 -0
- package/dist/auth/index.d.ts.map +1 -0
- package/dist/auth/index.js +13 -0
- package/dist/auth/services/AuthGuard.d.ts +58 -0
- package/dist/auth/services/AuthGuard.d.ts.map +1 -0
- package/dist/auth/services/AuthGuard.js +51 -0
- package/dist/auth/services/AuthService.d.ts +52 -0
- package/dist/auth/services/AuthService.d.ts.map +1 -0
- package/dist/auth/services/AuthService.js +67 -0
- package/dist/auth/services/PasswordResetService.d.ts +34 -0
- package/dist/auth/services/PasswordResetService.d.ts.map +1 -0
- package/dist/auth/services/PasswordResetService.js +45 -0
- package/dist/auth/services/TwoFactorChallengeService.d.ts +22 -0
- package/dist/auth/services/TwoFactorChallengeService.d.ts.map +1 -0
- package/dist/auth/services/TwoFactorChallengeService.js +29 -0
- package/dist/auth/services/TwoFactorService.d.ts +64 -0
- package/dist/auth/services/TwoFactorService.d.ts.map +1 -0
- package/dist/auth/services/TwoFactorService.js +68 -0
- package/dist/auth/services/index.d.ts +8 -0
- package/dist/auth/services/index.d.ts.map +1 -0
- package/dist/auth/services/index.js +5 -0
- package/dist/auth/types/auth-meta.d.ts +54 -0
- package/dist/auth/types/auth-meta.d.ts.map +1 -0
- package/dist/auth/types/auth-meta.js +6 -0
- package/dist/auth/types/index.d.ts +5 -0
- package/dist/auth/types/index.d.ts.map +1 -0
- package/dist/auth/types/index.js +4 -0
- package/dist/auth/utils/auth-meta.d.ts +75 -0
- package/dist/auth/utils/auth-meta.d.ts.map +1 -0
- package/dist/auth/utils/auth-meta.js +93 -0
- package/dist/boot/quvel.d.ts +26 -0
- package/dist/boot/quvel.d.ts.map +1 -0
- package/dist/boot/quvel.js +38 -0
- package/dist/build/index.d.ts +9 -0
- package/dist/build/index.d.ts.map +1 -0
- package/dist/build/index.js +8 -0
- package/dist/build/loadEnv.d.ts +14 -0
- package/dist/build/loadEnv.d.ts.map +1 -0
- package/dist/build/loadEnv.js +33 -0
- package/dist/build/quasarConfig.d.ts +67 -0
- package/dist/build/quasarConfig.d.ts.map +1 -0
- package/dist/build/quasarConfig.js +126 -0
- package/dist/components/Common/TaskErrors.vue +47 -0
- package/dist/components/Inputs/BaseInput.vue +88 -0
- package/dist/components/Misc/ClientOnly.vue +22 -0
- package/dist/components/Transitions/FadeInOut.vue +9 -0
- package/dist/components/Transitions/SlowExpand.vue +13 -0
- package/dist/components/WebSocketChannelManager.vue +634 -0
- package/dist/components/index.d.ts +12 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +16 -0
- package/dist/composables/index.d.ts +19 -0
- package/dist/composables/index.d.ts.map +1 -0
- package/dist/composables/index.js +16 -0
- package/dist/composables/useClient.d.ts +16 -0
- package/dist/composables/useClient.d.ts.map +1 -0
- package/dist/composables/useClient.js +28 -0
- package/dist/composables/useMetaConfig.d.ts +14 -0
- package/dist/composables/useMetaConfig.d.ts.map +1 -0
- package/dist/composables/useMetaConfig.js +77 -0
- package/dist/composables/useQueryMessageHandler.d.ts +44 -0
- package/dist/composables/useQueryMessageHandler.d.ts.map +1 -0
- package/dist/composables/useQueryMessageHandler.js +74 -0
- package/dist/composables/useQuvel.d.ts +15 -0
- package/dist/composables/useQuvel.d.ts.map +1 -0
- package/dist/composables/useQuvel.js +38 -0
- package/dist/composables/useRecaptcha.d.ts +35 -0
- package/dist/composables/useRecaptcha.d.ts.map +1 -0
- package/dist/composables/useRecaptcha.js +87 -0
- package/dist/composables/useScopedService.d.ts +18 -0
- package/dist/composables/useScopedService.d.ts.map +1 -0
- package/dist/composables/useScopedService.js +25 -0
- package/dist/composables/useScript.d.ts +25 -0
- package/dist/composables/useScript.d.ts.map +1 -0
- package/dist/composables/useScript.js +106 -0
- package/dist/composables/useUrlQueryHandler.d.ts +38 -0
- package/dist/composables/useUrlQueryHandler.d.ts.map +1 -0
- package/dist/composables/useUrlQueryHandler.js +76 -0
- package/dist/composables/useWebSockets.d.ts +18 -0
- package/dist/composables/useWebSockets.d.ts.map +1 -0
- package/dist/composables/useWebSockets.js +55 -0
- package/dist/composables/useWindowEvent.d.ts +16 -0
- package/dist/composables/useWindowEvent.d.ts.map +1 -0
- package/dist/composables/useWindowEvent.js +27 -0
- package/dist/composables/useXsrf.d.ts +29 -0
- package/dist/composables/useXsrf.d.ts.map +1 -0
- package/dist/composables/useXsrf.js +59 -0
- package/dist/config/QuasarConfigBuilder.d.ts +100 -0
- package/dist/config/QuasarConfigBuilder.d.ts.map +1 -0
- package/dist/config/QuasarConfigBuilder.js +98 -0
- package/dist/config/i18n.d.ts +23 -0
- package/dist/config/i18n.d.ts.map +1 -0
- package/dist/config/i18n.js +43 -0
- package/dist/config/index.d.ts +8 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +7 -0
- package/dist/config/moduleTransformer.d.ts +18 -0
- package/dist/config/moduleTransformer.d.ts.map +1 -0
- package/dist/config/moduleTransformer.js +76 -0
- package/dist/config/quvel.d.ts +40 -0
- package/dist/config/quvel.d.ts.map +1 -0
- package/dist/config/quvel.js +59 -0
- package/dist/config/quvel.types.d.ts +59 -0
- package/dist/config/quvel.types.d.ts.map +1 -0
- package/dist/config/quvel.types.js +6 -0
- package/dist/container/ServiceContainer.d.ts +107 -0
- package/dist/container/ServiceContainer.d.ts.map +1 -0
- package/dist/container/ServiceContainer.js +201 -0
- package/dist/container/types/vue.d.ts +9 -0
- package/dist/container/types.d.ts +81 -0
- package/dist/container/types.d.ts.map +1 -0
- package/dist/container/types.js +1 -0
- package/dist/i18n/en-US/common.d.ts +19 -0
- package/dist/i18n/en-US/common.d.ts.map +1 -0
- package/dist/i18n/en-US/common.js +17 -0
- package/dist/i18n/en-US/index.d.ts +21 -0
- package/dist/i18n/en-US/index.d.ts.map +1 -0
- package/dist/i18n/en-US/index.js +4 -0
- package/dist/i18n/es-MX/common.d.ts +19 -0
- package/dist/i18n/es-MX/common.d.ts.map +1 -0
- package/dist/i18n/es-MX/common.js +17 -0
- package/dist/i18n/es-MX/index.d.ts +21 -0
- package/dist/i18n/es-MX/index.d.ts.map +1 -0
- package/dist/i18n/es-MX/index.js +4 -0
- package/dist/index.d.ts +54 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +67 -0
- package/dist/models/User.d.ts +32 -0
- package/dist/models/User.d.ts.map +1 -0
- package/dist/models/User.js +48 -0
- package/dist/module.d.ts +21 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +45 -0
- package/dist/modules/helpers.d.ts +30 -0
- package/dist/modules/helpers.d.ts.map +1 -0
- package/dist/modules/helpers.js +45 -0
- package/dist/modules/index.d.ts +8 -0
- package/dist/modules/index.d.ts.map +1 -0
- package/dist/modules/index.js +6 -0
- package/dist/modules/types.d.ts +141 -0
- package/dist/modules/types.d.ts.map +1 -0
- package/dist/modules/types.js +7 -0
- package/dist/pages/ErrorNotFound.vue +300 -0
- package/dist/pages/index.d.ts +7 -0
- package/dist/pages/index.d.ts.map +1 -0
- package/dist/pages/index.js +6 -0
- package/dist/services/ApiService.d.ts +90 -0
- package/dist/services/ApiService.d.ts.map +1 -0
- package/dist/services/ApiService.js +159 -0
- package/dist/services/I18nService.d.ts +67 -0
- package/dist/services/I18nService.d.ts.map +1 -0
- package/dist/services/I18nService.js +92 -0
- package/dist/services/LogService.d.ts +31 -0
- package/dist/services/LogService.d.ts.map +1 -0
- package/dist/services/LogService.js +49 -0
- package/dist/services/Service.d.ts +10 -0
- package/dist/services/Service.d.ts.map +1 -0
- package/dist/services/Service.js +8 -0
- package/dist/services/TaskService.d.ts +64 -0
- package/dist/services/TaskService.d.ts.map +1 -0
- package/dist/services/TaskService.js +188 -0
- package/dist/services/ThemeService.d.ts +28 -0
- package/dist/services/ThemeService.d.ts.map +1 -0
- package/dist/services/ThemeService.js +77 -0
- package/dist/services/ValidationService.d.ts +55 -0
- package/dist/services/ValidationService.d.ts.map +1 -0
- package/dist/services/ValidationService.js +81 -0
- package/dist/services/WebSocketService.d.ts +59 -0
- package/dist/services/WebSocketService.d.ts.map +1 -0
- package/dist/services/WebSocketService.js +148 -0
- package/dist/services/logger/BaseLogger.d.ts +35 -0
- package/dist/services/logger/BaseLogger.d.ts.map +1 -0
- package/dist/services/logger/BaseLogger.js +66 -0
- package/dist/services/logger/ConsoleLogger.d.ts +21 -0
- package/dist/services/logger/ConsoleLogger.d.ts.map +1 -0
- package/dist/services/logger/ConsoleLogger.js +60 -0
- package/dist/services/logger/NullLogger.d.ts +10 -0
- package/dist/services/logger/NullLogger.d.ts.map +1 -0
- package/dist/services/logger/NullLogger.js +10 -0
- package/dist/stores/plugins/serviceContainer.d.ts +10 -0
- package/dist/stores/plugins/serviceContainer.d.ts.map +1 -0
- package/dist/stores/plugins/serviceContainer.js +14 -0
- package/dist/stores/sessionStore.d.ts +71 -0
- package/dist/stores/sessionStore.d.ts.map +1 -0
- package/dist/stores/sessionStore.js +125 -0
- package/dist/types/app.types.d.ts +202 -0
- package/dist/types/app.types.d.ts.map +1 -0
- package/dist/types/app.types.js +6 -0
- package/dist/types/config.types.d.ts +2 -0
- package/dist/types/config.types.d.ts.map +1 -0
- package/dist/types/config.types.js +1 -0
- package/dist/types/global.d.ts +33 -0
- package/dist/types/i18n.types.d.ts +21 -0
- package/dist/types/i18n.types.d.ts.map +1 -0
- package/dist/types/i18n.types.js +6 -0
- package/dist/types/laravel.types.d.ts +167 -0
- package/dist/types/laravel.types.d.ts.map +1 -0
- package/dist/types/laravel.types.js +6 -0
- package/dist/types/logging.types.d.ts +81 -0
- package/dist/types/logging.types.d.ts.map +1 -0
- package/dist/types/logging.types.js +22 -0
- package/dist/types/pinia.d.ts +24 -0
- package/dist/types/scripts.types.d.ts +31 -0
- package/dist/types/scripts.types.d.ts.map +1 -0
- package/dist/types/scripts.types.js +6 -0
- package/dist/types/ssr.d.ts +11 -0
- package/dist/types/task.types.d.ts +121 -0
- package/dist/types/task.types.d.ts.map +1 -0
- package/dist/types/task.types.js +7 -0
- package/dist/types/theme.types.d.ts +13 -0
- package/dist/types/theme.types.d.ts.map +1 -0
- package/dist/types/theme.types.js +17 -0
- package/dist/types/user.types.d.ts +24 -0
- package/dist/types/user.types.d.ts.map +1 -0
- package/dist/types/user.types.js +1 -0
- package/dist/types/vue-shim.d.ts +11 -0
- package/dist/types/websocket.types.d.ts +62 -0
- package/dist/types/websocket.types.d.ts.map +1 -0
- package/dist/types/websocket.types.js +6 -0
- package/dist/utils/apiInterceptors.d.ts +76 -0
- package/dist/utils/apiInterceptors.d.ts.map +1 -0
- package/dist/utils/apiInterceptors.js +149 -0
- package/dist/utils/assets.d.ts +40 -0
- package/dist/utils/assets.d.ts.map +1 -0
- package/dist/utils/assets.js +340 -0
- package/dist/utils/axios.d.ts +19 -0
- package/dist/utils/axios.d.ts.map +1 -0
- package/dist/utils/axios.js +113 -0
- package/dist/utils/config.d.ts +16 -0
- package/dist/utils/config.d.ts.map +1 -0
- package/dist/utils/config.js +48 -0
- package/dist/utils/container.d.ts +12 -0
- package/dist/utils/container.d.ts.map +1 -0
- package/dist/utils/container.js +11 -0
- package/dist/utils/deepMerge.d.ts +28 -0
- package/dist/utils/deepMerge.d.ts.map +1 -0
- package/dist/utils/deepMerge.js +59 -0
- package/dist/utils/envConfig.d.ts +73 -0
- package/dist/utils/envConfig.d.ts.map +1 -0
- package/dist/utils/envConfig.js +161 -0
- package/dist/utils/error.d.ts +44 -0
- package/dist/utils/error.d.ts.map +1 -0
- package/dist/utils/error.js +67 -0
- package/dist/utils/headers.d.ts +36 -0
- package/dist/utils/headers.d.ts.map +1 -0
- package/dist/utils/headers.js +54 -0
- package/dist/utils/i18n.d.ts +26 -0
- package/dist/utils/i18n.d.ts.map +1 -0
- package/dist/utils/i18n.js +56 -0
- package/dist/utils/index.d.ts +14 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +13 -0
- package/dist/utils/loading.d.ts +29 -0
- package/dist/utils/loading.d.ts.map +1 -0
- package/dist/utils/loading.js +46 -0
- package/dist/utils/logging.d.ts +20 -0
- package/dist/utils/logging.d.ts.map +1 -0
- package/dist/utils/logging.js +54 -0
- package/dist/utils/notify.d.ts +15 -0
- package/dist/utils/notify.d.ts.map +1 -0
- package/dist/utils/notify.js +30 -0
- package/dist/utils/object.d.ts +28 -0
- package/dist/utils/object.d.ts.map +1 -0
- package/dist/utils/object.js +48 -0
- package/dist/utils/pagination.d.ts +60 -0
- package/dist/utils/pagination.d.ts.map +1 -0
- package/dist/utils/pagination.js +252 -0
- package/dist/utils/paths.d.ts +54 -0
- package/dist/utils/paths.d.ts.map +1 -0
- package/dist/utils/paths.js +48 -0
- package/dist/utils/platform.d.ts +25 -0
- package/dist/utils/platform.d.ts.map +1 -0
- package/dist/utils/platform.js +64 -0
- package/dist/utils/scripts.d.ts +20 -0
- package/dist/utils/scripts.d.ts.map +1 -0
- package/dist/utils/scripts.js +39 -0
- package/global.d.ts +29 -0
- package/package.json +119 -0
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Asset Loading Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for dynamically loading CSS and JS assets
|
|
5
|
+
* Support both client-side and SSR asset injection
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Validates if a URL is safe to load as an asset
|
|
9
|
+
* Prevents loading from potentially malicious sources
|
|
10
|
+
*/
|
|
11
|
+
export function isValidAssetUrl(url) {
|
|
12
|
+
try {
|
|
13
|
+
// Allow relative URLs
|
|
14
|
+
if (url.startsWith('/')) {
|
|
15
|
+
return true;
|
|
16
|
+
}
|
|
17
|
+
const parsedUrl = new URL(url);
|
|
18
|
+
// Only allow HTTPS in production
|
|
19
|
+
if (import.meta.env.MODE === 'production' && parsedUrl.protocol !== 'https:') {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
// Allow HTTP/HTTPS
|
|
23
|
+
if (!['http:', 'https:'].includes(parsedUrl.protocol)) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
return true;
|
|
27
|
+
}
|
|
28
|
+
catch {
|
|
29
|
+
return false;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Sanitizes inline content to prevent XSS attacks
|
|
34
|
+
* Basic implementation - consider using DOMPurify for more robust protection
|
|
35
|
+
*/
|
|
36
|
+
export function sanitizeInlineContent(content) {
|
|
37
|
+
// Remove script tags and event handlers
|
|
38
|
+
return content
|
|
39
|
+
.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
|
|
40
|
+
.replace(/on\w+\s*=\s*"[^"]*"/gi, '')
|
|
41
|
+
.replace(/on\w+\s*=\s*'[^']*'/gi, '')
|
|
42
|
+
.replace(/javascript:/gi, '');
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Creates a CSS link or style element from configuration
|
|
46
|
+
*/
|
|
47
|
+
export function createCSSElement(config) {
|
|
48
|
+
if (config.url) {
|
|
49
|
+
if (!isValidAssetUrl(config.url)) {
|
|
50
|
+
console.warn('Invalid CSS URL:', config.url);
|
|
51
|
+
return null;
|
|
52
|
+
}
|
|
53
|
+
const link = document.createElement('link');
|
|
54
|
+
link.rel = 'stylesheet';
|
|
55
|
+
link.href = config.url;
|
|
56
|
+
if (config.media) {
|
|
57
|
+
link.media = config.media;
|
|
58
|
+
}
|
|
59
|
+
if (config.integrity) {
|
|
60
|
+
link.integrity = config.integrity;
|
|
61
|
+
}
|
|
62
|
+
if (config.crossorigin) {
|
|
63
|
+
link.crossOrigin = config.crossorigin;
|
|
64
|
+
}
|
|
65
|
+
// Handle loading priority for CSS
|
|
66
|
+
if (config.priority === 'critical') {
|
|
67
|
+
link.rel = 'preload';
|
|
68
|
+
link.as = 'style';
|
|
69
|
+
link.onload = () => {
|
|
70
|
+
link.rel = 'stylesheet';
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
else if (config.priority === 'low') {
|
|
74
|
+
link.media = 'print';
|
|
75
|
+
link.onload = () => {
|
|
76
|
+
link.media = config.media || 'all';
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
return link;
|
|
80
|
+
}
|
|
81
|
+
else if (config.inline) {
|
|
82
|
+
const style = document.createElement('style');
|
|
83
|
+
style.textContent = sanitizeInlineContent(config.inline);
|
|
84
|
+
if (config.priority) {
|
|
85
|
+
style.setAttribute('data-priority', config.priority);
|
|
86
|
+
}
|
|
87
|
+
return style;
|
|
88
|
+
}
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Creates a JavaScript script element from configuration
|
|
93
|
+
*/
|
|
94
|
+
export function createJSElement(config) {
|
|
95
|
+
const script = document.createElement('script');
|
|
96
|
+
if (config.url) {
|
|
97
|
+
if (!isValidAssetUrl(config.url)) {
|
|
98
|
+
console.warn('Invalid JS URL:', config.url);
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
script.src = config.url;
|
|
102
|
+
if (config.integrity) {
|
|
103
|
+
script.integrity = config.integrity;
|
|
104
|
+
}
|
|
105
|
+
if (config.crossorigin) {
|
|
106
|
+
script.crossOrigin = config.crossorigin;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
else if (config.inline) {
|
|
110
|
+
script.textContent = sanitizeInlineContent(config.inline);
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
return null;
|
|
114
|
+
}
|
|
115
|
+
if (config.loading === 'immediate') {
|
|
116
|
+
// No defer/async - loads and executes immediately
|
|
117
|
+
}
|
|
118
|
+
else if (config.loading === 'deferred') {
|
|
119
|
+
script.defer = true;
|
|
120
|
+
}
|
|
121
|
+
else if (config.loading === 'lazy') {
|
|
122
|
+
script.async = true;
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
if (config.defer) {
|
|
126
|
+
script.defer = true;
|
|
127
|
+
}
|
|
128
|
+
if (config.async) {
|
|
129
|
+
script.async = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
if (config.priority) {
|
|
133
|
+
script.setAttribute('data-priority', config.priority);
|
|
134
|
+
}
|
|
135
|
+
if (config.position) {
|
|
136
|
+
script.setAttribute('data-position', config.position);
|
|
137
|
+
}
|
|
138
|
+
return script;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Injects an element at the specified position in the document
|
|
142
|
+
*/
|
|
143
|
+
function injectElementAtPosition(element, position) {
|
|
144
|
+
switch (position) {
|
|
145
|
+
case 'head':
|
|
146
|
+
document.head.appendChild(element);
|
|
147
|
+
break;
|
|
148
|
+
case 'body-start':
|
|
149
|
+
if (document.body.firstChild) {
|
|
150
|
+
document.body.insertBefore(element, document.body.firstChild);
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
document.body.appendChild(element);
|
|
154
|
+
}
|
|
155
|
+
break;
|
|
156
|
+
case 'body-end':
|
|
157
|
+
default:
|
|
158
|
+
document.body.appendChild(element);
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Injects app assets into the document
|
|
164
|
+
* Used by client-side asset loading (non-SSR modes)
|
|
165
|
+
*/
|
|
166
|
+
export function injectAssets(assets) {
|
|
167
|
+
if (!assets)
|
|
168
|
+
return;
|
|
169
|
+
// Sort and inject CSS assets by priority
|
|
170
|
+
if (assets.css?.length) {
|
|
171
|
+
const sortedCSS = [...assets.css].sort((a, b) => {
|
|
172
|
+
const priorityOrder = { critical: 0, normal: 1, low: 2 };
|
|
173
|
+
const aPriority = priorityOrder[a.priority || 'normal'];
|
|
174
|
+
const bPriority = priorityOrder[b.priority || 'normal'];
|
|
175
|
+
return aPriority - bPriority;
|
|
176
|
+
});
|
|
177
|
+
sortedCSS.forEach((cssConfig) => {
|
|
178
|
+
const element = createCSSElement(cssConfig);
|
|
179
|
+
if (element) {
|
|
180
|
+
const position = cssConfig.position || 'head';
|
|
181
|
+
injectElementAtPosition(element, position);
|
|
182
|
+
}
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (assets.js?.length) {
|
|
186
|
+
const sortedJS = [...assets.js].sort((a, b) => {
|
|
187
|
+
const priorityOrder = { critical: 0, normal: 1, low: 2 };
|
|
188
|
+
const loadingOrder = { immediate: 0, deferred: 1, lazy: 2 };
|
|
189
|
+
const aPriority = priorityOrder[a.priority || 'normal'];
|
|
190
|
+
const bPriority = priorityOrder[b.priority || 'normal'];
|
|
191
|
+
if (aPriority !== bPriority)
|
|
192
|
+
return aPriority - bPriority;
|
|
193
|
+
const aLoading = loadingOrder[a.loading || 'deferred'];
|
|
194
|
+
const bLoading = loadingOrder[b.loading || 'deferred'];
|
|
195
|
+
return aLoading - bLoading;
|
|
196
|
+
});
|
|
197
|
+
const immediateScripts = sortedJS.filter((js) => js.loading === 'immediate');
|
|
198
|
+
const deferredScripts = sortedJS.filter((js) => js.loading !== 'immediate');
|
|
199
|
+
immediateScripts.forEach((jsConfig) => {
|
|
200
|
+
const element = createJSElement(jsConfig);
|
|
201
|
+
if (element) {
|
|
202
|
+
const position = jsConfig.position || 'head';
|
|
203
|
+
injectElementAtPosition(element, position);
|
|
204
|
+
}
|
|
205
|
+
});
|
|
206
|
+
if (deferredScripts.length > 0) {
|
|
207
|
+
const processDeferred = () => {
|
|
208
|
+
deferredScripts.forEach((jsConfig) => {
|
|
209
|
+
const element = createJSElement(jsConfig);
|
|
210
|
+
if (element) {
|
|
211
|
+
const position = jsConfig.position || 'body-end';
|
|
212
|
+
injectElementAtPosition(element, position);
|
|
213
|
+
}
|
|
214
|
+
});
|
|
215
|
+
};
|
|
216
|
+
if ('requestIdleCallback' in window) {
|
|
217
|
+
requestIdleCallback(processDeferred);
|
|
218
|
+
}
|
|
219
|
+
else {
|
|
220
|
+
setTimeout(processDeferred, 0);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
/**
|
|
226
|
+
* Generates HTML strings for server-side asset injection
|
|
227
|
+
* Used by SSR asset injection
|
|
228
|
+
*/
|
|
229
|
+
export function generateAssetHTML(assets) {
|
|
230
|
+
let headHTML = '';
|
|
231
|
+
let bodyStartHTML = '';
|
|
232
|
+
let bodyEndHTML = '';
|
|
233
|
+
if (!assets) {
|
|
234
|
+
return { headHTML, bodyStartHTML, bodyEndHTML };
|
|
235
|
+
}
|
|
236
|
+
const sortedCSS = assets.css
|
|
237
|
+
? [...assets.css].sort((a, b) => {
|
|
238
|
+
const priorityOrder = { critical: 0, normal: 1, low: 2 };
|
|
239
|
+
const aPriority = priorityOrder[a.priority || 'normal'];
|
|
240
|
+
const bPriority = priorityOrder[b.priority || 'normal'];
|
|
241
|
+
return aPriority - bPriority;
|
|
242
|
+
})
|
|
243
|
+
: [];
|
|
244
|
+
const sortedJS = assets.js
|
|
245
|
+
? [...assets.js].sort((a, b) => {
|
|
246
|
+
const priorityOrder = { critical: 0, normal: 1, low: 2 };
|
|
247
|
+
const loadingOrder = { immediate: 0, deferred: 1, lazy: 2 };
|
|
248
|
+
const aPriority = priorityOrder[a.priority || 'normal'];
|
|
249
|
+
const bPriority = priorityOrder[b.priority || 'normal'];
|
|
250
|
+
if (aPriority !== bPriority)
|
|
251
|
+
return aPriority - bPriority;
|
|
252
|
+
const aLoading = loadingOrder[a.loading || 'deferred'];
|
|
253
|
+
const bLoading = loadingOrder[b.loading || 'deferred'];
|
|
254
|
+
return aLoading - bLoading;
|
|
255
|
+
})
|
|
256
|
+
: [];
|
|
257
|
+
sortedCSS.forEach((config) => {
|
|
258
|
+
let cssHTML = '';
|
|
259
|
+
if (config.url && isValidAssetUrl(config.url)) {
|
|
260
|
+
const attrs = [];
|
|
261
|
+
if (config.media)
|
|
262
|
+
attrs.push(`media="${config.media}"`);
|
|
263
|
+
if (config.integrity)
|
|
264
|
+
attrs.push(`integrity="${config.integrity}"`);
|
|
265
|
+
if (config.crossorigin)
|
|
266
|
+
attrs.push(`crossorigin="${config.crossorigin}"`);
|
|
267
|
+
if (config.priority)
|
|
268
|
+
attrs.push(`data-priority="${config.priority}"`);
|
|
269
|
+
if (config.priority === 'critical') {
|
|
270
|
+
cssHTML = `<link rel="preload" href="${config.url}" as="style" onload="this.rel='stylesheet'" ${attrs.join(' ')}>`;
|
|
271
|
+
}
|
|
272
|
+
else if (config.priority === 'low') {
|
|
273
|
+
cssHTML = `<link rel="stylesheet" href="${config.url}" media="print" onload="this.media='${config.media || 'all'}'" ${attrs.join(' ')}>`;
|
|
274
|
+
}
|
|
275
|
+
else {
|
|
276
|
+
cssHTML = `<link rel="stylesheet" href="${config.url}" ${attrs.join(' ')}>`;
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
else if (config.inline) {
|
|
280
|
+
const priorityAttr = config.priority ? ` data-priority="${config.priority}"` : '';
|
|
281
|
+
cssHTML = `<style${priorityAttr}>${sanitizeInlineContent(config.inline)}</style>`;
|
|
282
|
+
}
|
|
283
|
+
const position = config.position || 'head';
|
|
284
|
+
if (position === 'head') {
|
|
285
|
+
headHTML += cssHTML;
|
|
286
|
+
}
|
|
287
|
+
else if (position === 'body-start') {
|
|
288
|
+
bodyStartHTML += cssHTML;
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
bodyEndHTML += cssHTML;
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
// Generate JS HTML
|
|
295
|
+
sortedJS.forEach((config) => {
|
|
296
|
+
let jsHTML = '';
|
|
297
|
+
if (config.url && isValidAssetUrl(config.url)) {
|
|
298
|
+
const attrs = [];
|
|
299
|
+
if (config.loading === 'immediate') {
|
|
300
|
+
}
|
|
301
|
+
else if (config.loading === 'deferred') {
|
|
302
|
+
attrs.push('defer');
|
|
303
|
+
}
|
|
304
|
+
else if (config.loading === 'lazy') {
|
|
305
|
+
attrs.push('async');
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
if (config.defer)
|
|
309
|
+
attrs.push('defer');
|
|
310
|
+
if (config.async)
|
|
311
|
+
attrs.push('async');
|
|
312
|
+
}
|
|
313
|
+
if (config.integrity)
|
|
314
|
+
attrs.push(`integrity="${config.integrity}"`);
|
|
315
|
+
if (config.crossorigin)
|
|
316
|
+
attrs.push(`crossorigin="${config.crossorigin}"`);
|
|
317
|
+
if (config.priority)
|
|
318
|
+
attrs.push(`data-priority="${config.priority}"`);
|
|
319
|
+
if (config.position)
|
|
320
|
+
attrs.push(`data-position="${config.position}"`);
|
|
321
|
+
jsHTML = `<script src="${config.url}" ${attrs.join(' ')}></script>`;
|
|
322
|
+
}
|
|
323
|
+
else if (config.inline) {
|
|
324
|
+
const priorityAttr = config.priority ? ` data-priority="${config.priority}"` : '';
|
|
325
|
+
const positionAttr = config.position ? ` data-position="${config.position}"` : '';
|
|
326
|
+
jsHTML = `<script${priorityAttr}${positionAttr}>${sanitizeInlineContent(config.inline)}</script>`;
|
|
327
|
+
}
|
|
328
|
+
const position = config.position || (config.loading === 'immediate' ? 'head' : 'body-end');
|
|
329
|
+
if (position === 'head') {
|
|
330
|
+
headHTML += jsHTML;
|
|
331
|
+
}
|
|
332
|
+
else if (position === 'body-start') {
|
|
333
|
+
bodyStartHTML += jsHTML;
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
bodyEndHTML += jsHTML;
|
|
337
|
+
}
|
|
338
|
+
});
|
|
339
|
+
return { headHTML, bodyStartHTML, bodyEndHTML };
|
|
340
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Axios Utility Functions
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for creating and configuring Axios instances
|
|
5
|
+
*/
|
|
6
|
+
import type { AxiosInstance } from 'axios';
|
|
7
|
+
import type { QSsrContext } from '@quasar/app-vite';
|
|
8
|
+
import type { AppConfig } from '../types/app.types.js';
|
|
9
|
+
/**
|
|
10
|
+
* Validate session token format
|
|
11
|
+
*/
|
|
12
|
+
export declare function isValidSessionToken(token: unknown): token is string;
|
|
13
|
+
/**
|
|
14
|
+
* Create Axios instance configured for API requests
|
|
15
|
+
*
|
|
16
|
+
* Handles SSR context, XSRF tokens, session cookies, and base URL resolution
|
|
17
|
+
*/
|
|
18
|
+
export declare function createApiInstance(ssrContext?: QSsrContext, appConfig?: Readonly<AppConfig>): AxiosInstance;
|
|
19
|
+
//# sourceMappingURL=axios.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"axios.d.ts","sourceRoot":"","sources":["../../src/utils/axios.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAC,aAAa,EAAqB,MAAM,OAAO,CAAC;AAE7D,OAAO,KAAK,EAAC,WAAW,EAAC,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAC,SAAS,EAAC,MAAM,uBAAuB,CAAC;AAqCrD;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CASnE;AAoBD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,CAAC,EAAE,WAAW,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,SAAS,CAAC,GAAG,aAAa,CAmD1G"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Axios Utility Functions
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for creating and configuring Axios instances
|
|
5
|
+
*/
|
|
6
|
+
import axios from 'axios';
|
|
7
|
+
import { getSsrKeyHeader } from './headers.js';
|
|
8
|
+
/**
|
|
9
|
+
* Get default XSRF cookie name
|
|
10
|
+
*/
|
|
11
|
+
function getDefaultXsrfCookieName() {
|
|
12
|
+
return import.meta.env.XSRF_COOKIE_NAME || 'XSRF-TOKEN';
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Get default session cookie name
|
|
16
|
+
*/
|
|
17
|
+
function getDefaultSessionCookieName() {
|
|
18
|
+
return import.meta.env.SESSION_COOKIE_NAME || 'laravel_session';
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Get XSRF cookie name from AppConfig or SSR context or default
|
|
22
|
+
*/
|
|
23
|
+
function getXsrfCookieName(appConfig, ssrContext) {
|
|
24
|
+
// Priority: AppConfig > SSR quvelContext > env default
|
|
25
|
+
return appConfig?.session?.xsrf_cookie
|
|
26
|
+
|| ssrContext?.req?.quvelContext?.appConfig?.session?.xsrf_cookie
|
|
27
|
+
|| getDefaultXsrfCookieName();
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get the session cookie name from AppConfig or SSR context or default
|
|
31
|
+
*/
|
|
32
|
+
function getSessionCookieName(appConfig, ssrContext) {
|
|
33
|
+
// Priority: AppConfig > SSR quvelContext > env default
|
|
34
|
+
return appConfig?.session?.cookie
|
|
35
|
+
|| ssrContext?.req?.quvelContext?.appConfig?.session?.cookie
|
|
36
|
+
|| getDefaultSessionCookieName();
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Validate session token format
|
|
40
|
+
*/
|
|
41
|
+
export function isValidSessionToken(token) {
|
|
42
|
+
if (typeof token !== 'string')
|
|
43
|
+
return false;
|
|
44
|
+
try {
|
|
45
|
+
const decoded = decodeURIComponent(token);
|
|
46
|
+
return /^[A-Za-z0-9+/=]{20,512}$/.test(decoded);
|
|
47
|
+
}
|
|
48
|
+
catch {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Parse cookies from SSR request
|
|
54
|
+
*/
|
|
55
|
+
function parseSsrCookies(ssrServiceOptions) {
|
|
56
|
+
const cookieHeader = ssrServiceOptions?.req?.headers?.cookie;
|
|
57
|
+
if (!cookieHeader)
|
|
58
|
+
return {};
|
|
59
|
+
const cookies = {};
|
|
60
|
+
cookieHeader.split(';').forEach((cookie) => {
|
|
61
|
+
const [name, ...rest] = cookie.split('=');
|
|
62
|
+
if (name && rest.length > 0) {
|
|
63
|
+
cookies[name.trim()] = rest.join('=').trim();
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
return cookies;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Create Axios instance configured for API requests
|
|
70
|
+
*
|
|
71
|
+
* Handles SSR context, XSRF tokens, session cookies, and base URL resolution
|
|
72
|
+
*/
|
|
73
|
+
export function createApiInstance(ssrContext, appConfig) {
|
|
74
|
+
const baseURL = appConfig?.app?.url || import.meta.env.VITE_API_URL || '';
|
|
75
|
+
if (!baseURL) {
|
|
76
|
+
throw new Error('No API URL configured. Set VITE_API_URL or configure app.url in AppConfig');
|
|
77
|
+
}
|
|
78
|
+
const axiosConfig = {
|
|
79
|
+
baseURL,
|
|
80
|
+
withCredentials: true,
|
|
81
|
+
withXSRFToken: true,
|
|
82
|
+
xsrfCookieName: getXsrfCookieName(appConfig, ssrContext),
|
|
83
|
+
xsrfHeaderName: 'X-XSRF-TOKEN',
|
|
84
|
+
headers: {
|
|
85
|
+
Accept: 'application/json',
|
|
86
|
+
},
|
|
87
|
+
};
|
|
88
|
+
const instance = axios.create(axiosConfig);
|
|
89
|
+
// Detect session cookie presence from AppConfig
|
|
90
|
+
let hasSessionCookie = false;
|
|
91
|
+
if (ssrContext) {
|
|
92
|
+
// SSR: Set up SSR-specific headers and session detection
|
|
93
|
+
if (appConfig?.api?.ssrKey) {
|
|
94
|
+
const ssrKeyHeaderName = getSsrKeyHeader(appConfig);
|
|
95
|
+
instance.defaults.headers.common[ssrKeyHeaderName] = appConfig.api.ssrKey;
|
|
96
|
+
}
|
|
97
|
+
const sessionCookie = getSessionCookieName(appConfig, ssrContext);
|
|
98
|
+
const xsrfCookieName = getXsrfCookieName(appConfig, ssrContext);
|
|
99
|
+
const cookies = parseSsrCookies(ssrContext);
|
|
100
|
+
const sessionToken = cookies[sessionCookie];
|
|
101
|
+
const xsrfToken = cookies[xsrfCookieName];
|
|
102
|
+
instance.defaults.maxRedirects = Number(import.meta.env.SSR_AXIOS_MAX_REDIRECTS || 0);
|
|
103
|
+
instance.defaults.timeout = Number(import.meta.env.SSR_AXIOS_TIMEOUT || 5000);
|
|
104
|
+
if (isValidSessionToken(sessionToken)) {
|
|
105
|
+
instance.defaults.headers.Cookie = `${sessionCookie}=${sessionToken}`;
|
|
106
|
+
if (xsrfToken) {
|
|
107
|
+
hasSessionCookie = true;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
instance.defaults.hasSessionCookie = hasSessionCookie;
|
|
112
|
+
return instance;
|
|
113
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config utility functions
|
|
3
|
+
*/
|
|
4
|
+
import type { QSsrContext } from '@quasar/app-vite';
|
|
5
|
+
import type { AppConfig } from '../types/app.types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Create app config from environment variables
|
|
8
|
+
* Works in both client (import.meta.env) and server (process.env) contexts
|
|
9
|
+
*/
|
|
10
|
+
export declare function createConfigFromEnv(): AppConfig;
|
|
11
|
+
/**
|
|
12
|
+
* Create app config from SSR context, window, or environment variables
|
|
13
|
+
* Always starts with env baseline, then merges overrides from SSR context or window
|
|
14
|
+
*/
|
|
15
|
+
export declare function createConfig(ssrContext?: QSsrContext | null): AppConfig;
|
|
16
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/utils/config.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAEvD;;;GAGG;AACH,wBAAgB,mBAAmB,IAAI,SAAS,CA0B/C;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,UAAU,CAAC,EAAE,WAAW,GAAG,IAAI,GAAG,SAAS,CAUvE"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config utility functions
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Create app config from environment variables
|
|
6
|
+
* Works in both client (import.meta.env) and server (process.env) contexts
|
|
7
|
+
*/
|
|
8
|
+
export function createConfigFromEnv() {
|
|
9
|
+
const env = (typeof import.meta !== 'undefined' && import.meta.env)
|
|
10
|
+
? import.meta.env
|
|
11
|
+
: (typeof process !== 'undefined' ? process.env : {});
|
|
12
|
+
const config = {
|
|
13
|
+
app: {
|
|
14
|
+
name: env.VITE_APP_NAME || 'Quasar App',
|
|
15
|
+
url: env.VITE_API_URL || '',
|
|
16
|
+
env: env.VITE_APP_ENV || undefined,
|
|
17
|
+
debug: env.VITE_DEBUG === 'true' ? true : undefined,
|
|
18
|
+
timezone: env.VITE_TIMEZONE || undefined,
|
|
19
|
+
locale: env.VITE_LOCALE || undefined,
|
|
20
|
+
fallback_locale: env.VITE_FALLBACK_LOCALE || undefined,
|
|
21
|
+
},
|
|
22
|
+
frontend: {
|
|
23
|
+
url: env.VITE_APP_URL || '',
|
|
24
|
+
custom_scheme: env.VITE_CUSTOM_SCHEME || undefined,
|
|
25
|
+
},
|
|
26
|
+
session: {
|
|
27
|
+
xsrf_cookie: env.XSRF_COOKIE_NAME || undefined,
|
|
28
|
+
},
|
|
29
|
+
i18nCookie: env.VITE_I18N_COOKIE || undefined,
|
|
30
|
+
};
|
|
31
|
+
return config;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Create app config from SSR context, window, or environment variables
|
|
35
|
+
* Always starts with env baseline, then merges overrides from SSR context or window
|
|
36
|
+
*/
|
|
37
|
+
export function createConfig(ssrContext) {
|
|
38
|
+
const baseConfig = createConfigFromEnv();
|
|
39
|
+
if (ssrContext?.req?.quvelContext?.appConfig) {
|
|
40
|
+
return { ...baseConfig, ...ssrContext.req.quvelContext.appConfig };
|
|
41
|
+
}
|
|
42
|
+
else if (typeof window !== 'undefined' && window.__APP_CONFIG__) {
|
|
43
|
+
return { ...baseConfig, ...window.__APP_CONFIG__ };
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
return baseConfig;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { QSsrContext } from '@quasar/app-vite';
|
|
2
|
+
import { ServiceContainer } from '../container/ServiceContainer.js';
|
|
3
|
+
import type { ServiceClass } from '../container/types.js';
|
|
4
|
+
/**
|
|
5
|
+
* Creates the service container per request
|
|
6
|
+
*
|
|
7
|
+
* @param ssrContext - The SSR context from Quasar (if in SSR mode)
|
|
8
|
+
* @param serviceClasses - Map of service classes to instantiate
|
|
9
|
+
* @returns The fully initialized service container
|
|
10
|
+
*/
|
|
11
|
+
export declare function createContainer(ssrContext?: QSsrContext | null, serviceClasses?: Map<string, ServiceClass>): ServiceContainer;
|
|
12
|
+
//# sourceMappingURL=container.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../src/utils/container.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AACpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAgB,eAAe,CAC7B,UAAU,CAAC,EAAE,WAAW,GAAG,IAAI,EAC/B,cAAc,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,YAAY,CAAC,GACzC,gBAAgB,CAElB"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { ServiceContainer } from '../container/ServiceContainer.js';
|
|
2
|
+
/**
|
|
3
|
+
* Creates the service container per request
|
|
4
|
+
*
|
|
5
|
+
* @param ssrContext - The SSR context from Quasar (if in SSR mode)
|
|
6
|
+
* @param serviceClasses - Map of service classes to instantiate
|
|
7
|
+
* @returns The fully initialized service container
|
|
8
|
+
*/
|
|
9
|
+
export function createContainer(ssrContext, serviceClasses) {
|
|
10
|
+
return new ServiceContainer(ssrContext, serviceClasses);
|
|
11
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep merge utility for configuration objects
|
|
3
|
+
*
|
|
4
|
+
* Recursively merges two objects with the following behavior:
|
|
5
|
+
* - Nested objects are merged recursively
|
|
6
|
+
* - Arrays are concatenated (not replaced)
|
|
7
|
+
* - Primitives from source override target
|
|
8
|
+
* - Null and undefined values are preserved
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const base = { plugins: ['A'], options: { debug: true } };
|
|
13
|
+
* const override = { plugins: ['B'], options: { verbose: true } };
|
|
14
|
+
* deepMerge(base, override);
|
|
15
|
+
* // Result: { plugins: ['A', 'B'], options: { debug: true, verbose: true } }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export declare function deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T;
|
|
19
|
+
/**
|
|
20
|
+
* Merge multiple configuration objects from left to right
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```ts
|
|
24
|
+
* const merged = mergeConfigs(base, mode, module, override);
|
|
25
|
+
* ```
|
|
26
|
+
*/
|
|
27
|
+
export declare function mergeConfigs<T extends Record<string, unknown>>(...configs: Array<Partial<T> | T>): T;
|
|
28
|
+
//# sourceMappingURL=deepMerge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"deepMerge.d.ts","sourceRoot":"","sources":["../../src/utils/deepMerge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACzD,MAAM,EAAE,CAAC,EACT,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,GACjB,CAAC,CA+BH;AAeD;;;;;;;GAOG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5D,GAAG,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,GAChC,CAAC,CAKH"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Deep merge utility for configuration objects
|
|
3
|
+
*
|
|
4
|
+
* Recursively merges two objects with the following behavior:
|
|
5
|
+
* - Nested objects are merged recursively
|
|
6
|
+
* - Arrays are concatenated (not replaced)
|
|
7
|
+
* - Primitives from source override target
|
|
8
|
+
* - Null and undefined values are preserved
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```ts
|
|
12
|
+
* const base = { plugins: ['A'], options: { debug: true } };
|
|
13
|
+
* const override = { plugins: ['B'], options: { verbose: true } };
|
|
14
|
+
* deepMerge(base, override);
|
|
15
|
+
* // Result: { plugins: ['A', 'B'], options: { debug: true, verbose: true } }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function deepMerge(target, source) {
|
|
19
|
+
const result = { ...target };
|
|
20
|
+
for (const key in source) {
|
|
21
|
+
if (!Object.prototype.hasOwnProperty.call(source, key)) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
const sourceValue = source[key];
|
|
25
|
+
const targetValue = result[key];
|
|
26
|
+
if (Array.isArray(sourceValue) && Array.isArray(targetValue)) {
|
|
27
|
+
result[key] = [...targetValue, ...sourceValue];
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (isPlainObject(sourceValue) &&
|
|
31
|
+
isPlainObject(targetValue)) {
|
|
32
|
+
result[key] = deepMerge(targetValue, sourceValue);
|
|
33
|
+
continue;
|
|
34
|
+
}
|
|
35
|
+
result[key] = sourceValue;
|
|
36
|
+
}
|
|
37
|
+
return result;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Checks if a value is a plain object (not Array, Date, null, etc.)
|
|
41
|
+
*/
|
|
42
|
+
function isPlainObject(value) {
|
|
43
|
+
if (typeof value !== 'object' || value === null) {
|
|
44
|
+
return false;
|
|
45
|
+
}
|
|
46
|
+
const proto = Object.getPrototypeOf(value);
|
|
47
|
+
return proto === Object.prototype || proto === null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Merge multiple configuration objects from left to right
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```ts
|
|
54
|
+
* const merged = mergeConfigs(base, mode, module, override);
|
|
55
|
+
* ```
|
|
56
|
+
*/
|
|
57
|
+
export function mergeConfigs(...configs) {
|
|
58
|
+
return configs.reduce((acc, config) => deepMerge(acc, config), {});
|
|
59
|
+
}
|