@adobe-commerce/elsie 1.2.2-alpha1 → 1.3.0-alpha01
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/config/vite.mjs +5 -12
- package/package.json +1 -1
- package/src/lib/aem/configs.ts +237 -0
package/config/vite.mjs
CHANGED
|
@@ -25,18 +25,11 @@ import banner from 'vite-plugin-banner';
|
|
|
25
25
|
const env = loadEnv('', process.cwd());
|
|
26
26
|
|
|
27
27
|
// Load Elsie Config
|
|
28
|
-
const elsieConfig = await import(
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const packageJSON =
|
|
33
|
-
path.resolve(process.cwd(), './package.json'),
|
|
34
|
-
{
|
|
35
|
-
assert: {
|
|
36
|
-
type: 'json',
|
|
37
|
-
},
|
|
38
|
-
}
|
|
39
|
-
).then((m) => m.default);
|
|
28
|
+
const elsieConfig = await import(path.resolve(process.cwd(), './.elsie.js')).then((m) => m.default);
|
|
29
|
+
|
|
30
|
+
// Read package.json using createRequire (compatible with Node 20 and 22)
|
|
31
|
+
const require = createRequire(import.meta.url);
|
|
32
|
+
const packageJSON = require(path.resolve(process.cwd(), './package.json'));
|
|
40
33
|
|
|
41
34
|
// Paths
|
|
42
35
|
const paths = {
|
package/package.json
CHANGED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
import { deepmerge } from '../deepmerge';
|
|
2
|
+
|
|
3
|
+
interface ConfigHeaders {
|
|
4
|
+
all?: Record<string, string>;
|
|
5
|
+
[key: string]: Record<string, string> | undefined;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
interface ConfigPublic {
|
|
9
|
+
default: ConfigRoot;
|
|
10
|
+
[key: string]: ConfigRoot;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
interface ConfigRoot {
|
|
14
|
+
headers?: ConfigHeaders;
|
|
15
|
+
[key: string]: any;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Config {
|
|
19
|
+
public: ConfigPublic;
|
|
20
|
+
[key: string]: any;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Private state
|
|
24
|
+
let config: Config | null = null;
|
|
25
|
+
let rootPath: string | null = null;
|
|
26
|
+
let rootConfig: ConfigRoot | null = null;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Reset the config state
|
|
30
|
+
*/
|
|
31
|
+
function resetConfig() {
|
|
32
|
+
config = null;
|
|
33
|
+
rootPath = null;
|
|
34
|
+
rootConfig = null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Builds the URL for the config file.
|
|
39
|
+
*
|
|
40
|
+
* @returns {URL} - The URL for the config file.
|
|
41
|
+
*/
|
|
42
|
+
function buildConfigURL() {
|
|
43
|
+
return new URL(`${window.location.origin}/config.json`);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Retrieves a value from a config object using dot notation.
|
|
48
|
+
*
|
|
49
|
+
* @param {Object} obj - The config object.
|
|
50
|
+
* @param {string} key - The key to retrieve (supports dot notation).
|
|
51
|
+
* @returns {any} - The value of the key.
|
|
52
|
+
*/
|
|
53
|
+
function getValue(obj: Record<string, any>, key: string): any {
|
|
54
|
+
return key.split('.').reduce((current: Record<string, any>, part: string) => {
|
|
55
|
+
if (!Object.prototype.hasOwnProperty.call(current, part)) {
|
|
56
|
+
console.warn(`Property ${key} does not exist in the object`);
|
|
57
|
+
return undefined;
|
|
58
|
+
}
|
|
59
|
+
return current[part];
|
|
60
|
+
}, obj);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Get cookie
|
|
65
|
+
* @param {string} cookieName - The name of the cookie to get
|
|
66
|
+
* @returns {string} - The value of the cookie
|
|
67
|
+
*/
|
|
68
|
+
function getCookie(cookieName: string): string | undefined {
|
|
69
|
+
const cookies = document.cookie.split(';');
|
|
70
|
+
let foundValue;
|
|
71
|
+
|
|
72
|
+
cookies.forEach((cookie) => {
|
|
73
|
+
const [name, value] = cookie.trim().split('=');
|
|
74
|
+
if (name === cookieName) {
|
|
75
|
+
foundValue = decodeURIComponent(value);
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
return foundValue;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get root path
|
|
84
|
+
* @param {Object} [configObj=config] - The config object.
|
|
85
|
+
* @returns {string} - The root path.
|
|
86
|
+
*/
|
|
87
|
+
function getRootPath(configObj: Config | null = config): string {
|
|
88
|
+
if (!configObj) {
|
|
89
|
+
console.warn('No config found. Please call initializeConfig() first.');
|
|
90
|
+
return '/';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const value = Object.keys(configObj?.public)
|
|
94
|
+
// Sort by number of non-empty segments to find the deepest path
|
|
95
|
+
.sort((a, b) => {
|
|
96
|
+
const aSegments = a.split('/').filter(Boolean).length;
|
|
97
|
+
const bSegments = b.split('/').filter(Boolean).length;
|
|
98
|
+
return bSegments - aSegments;
|
|
99
|
+
})
|
|
100
|
+
.find(
|
|
101
|
+
(key) =>
|
|
102
|
+
window.location.pathname === key ||
|
|
103
|
+
window.location.pathname.startsWith(key)
|
|
104
|
+
);
|
|
105
|
+
|
|
106
|
+
return value ?? '/';
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* Get list of root paths from public config
|
|
111
|
+
* @returns {Array} - The list of root paths.
|
|
112
|
+
*/
|
|
113
|
+
function getListOfRootPaths(): string[] {
|
|
114
|
+
if (!config) {
|
|
115
|
+
console.warn('No config found. Please call initializeConfig() first.');
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return Object.keys(config.public).filter((root) => root !== 'default');
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Checks if the public config contains more than "default"
|
|
124
|
+
* @returns {boolean} - true if public config contains more than "default"
|
|
125
|
+
*/
|
|
126
|
+
function isMultistore(): boolean {
|
|
127
|
+
return getListOfRootPaths().length >= 1;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Retrieves headers from config entries like commerce.headers.pdp.my-header, etc and
|
|
132
|
+
* returns as object of all headers like { my-header: value, ... }
|
|
133
|
+
* @param {string} scope - The scope of the headers to retrieve.
|
|
134
|
+
* @returns {Object} - The headers.
|
|
135
|
+
*/
|
|
136
|
+
function getHeaders(scope: string): Record<string, string> {
|
|
137
|
+
if (!rootConfig) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
'Configuration not initialized. Call initializeConfig() first.'
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
const headers = rootConfig.headers ?? {};
|
|
143
|
+
return {
|
|
144
|
+
...(headers.all ?? {}),
|
|
145
|
+
...(headers[scope] ?? {}),
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Applies config overrides from metadata.
|
|
151
|
+
*
|
|
152
|
+
* @param {Object} [configObj=config] - The base config.
|
|
153
|
+
* @param {string} [root=rootPath] - The root path.
|
|
154
|
+
* @returns {Object} - The config with overrides applied.
|
|
155
|
+
*/
|
|
156
|
+
function applyConfigOverrides(
|
|
157
|
+
configObj: Config | null,
|
|
158
|
+
root: string | null
|
|
159
|
+
): ConfigRoot {
|
|
160
|
+
const defaultConfig = configObj!.public?.default;
|
|
161
|
+
|
|
162
|
+
if (root === '/' || !configObj!.public[root as keyof ConfigPublic])
|
|
163
|
+
return defaultConfig;
|
|
164
|
+
|
|
165
|
+
return deepmerge(
|
|
166
|
+
defaultConfig,
|
|
167
|
+
configObj!.public[root as keyof ConfigPublic]
|
|
168
|
+
);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Fetches config from remote and saves in session, then returns it, otherwise
|
|
173
|
+
* returns if it already exists.
|
|
174
|
+
*
|
|
175
|
+
* @returns {Promise<Object>} - The config JSON from session storage
|
|
176
|
+
*/
|
|
177
|
+
async function getConfigFromSession(): Promise<Config> {
|
|
178
|
+
try {
|
|
179
|
+
const configJSON = window.sessionStorage.getItem('config');
|
|
180
|
+
if (!configJSON) {
|
|
181
|
+
throw new Error('No config in session storage');
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const parsedConfig = JSON.parse(configJSON);
|
|
185
|
+
if (
|
|
186
|
+
!parsedConfig[':expiry'] ||
|
|
187
|
+
parsedConfig[':expiry'] < Math.round(Date.now() / 1000)
|
|
188
|
+
) {
|
|
189
|
+
throw new Error('Config expired');
|
|
190
|
+
}
|
|
191
|
+
return parsedConfig;
|
|
192
|
+
} catch (e) {
|
|
193
|
+
const config = await fetch(buildConfigURL());
|
|
194
|
+
if (!config.ok) throw new Error('Failed to fetch config');
|
|
195
|
+
const configJSON = await config.json();
|
|
196
|
+
configJSON[':expiry'] = Math.round(Date.now() / 1000) + 7200;
|
|
197
|
+
window.sessionStorage.setItem('config', JSON.stringify(configJSON));
|
|
198
|
+
return configJSON;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Initializes the configuration system.
|
|
204
|
+
* @returns {Promise<void>}
|
|
205
|
+
*/
|
|
206
|
+
async function initializeConfig(): Promise<ConfigRoot> {
|
|
207
|
+
config = await getConfigFromSession();
|
|
208
|
+
rootPath = getRootPath(config);
|
|
209
|
+
rootConfig = applyConfigOverrides(config, rootPath);
|
|
210
|
+
return rootConfig;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Retrieves a configuration value.
|
|
215
|
+
*
|
|
216
|
+
* @param {string} configParam - The configuration parameter to retrieve.
|
|
217
|
+
* @returns {string|undefined} - The value of the configuration parameter, or undefined.
|
|
218
|
+
*/
|
|
219
|
+
function getConfigValue(configParam: string): any {
|
|
220
|
+
if (!rootConfig) {
|
|
221
|
+
throw new Error(
|
|
222
|
+
'Configuration not initialized. Call initializeConfig() first.'
|
|
223
|
+
);
|
|
224
|
+
}
|
|
225
|
+
return getValue(rootConfig, configParam);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
export {
|
|
229
|
+
initializeConfig,
|
|
230
|
+
getCookie,
|
|
231
|
+
getRootPath,
|
|
232
|
+
getListOfRootPaths,
|
|
233
|
+
isMultistore,
|
|
234
|
+
getConfigValue,
|
|
235
|
+
getHeaders,
|
|
236
|
+
resetConfig,
|
|
237
|
+
};
|