@adobe/helix-config-storage 1.2.3 → 1.3.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.
- package/CHANGELOG.md +14 -0
- package/package.json +1 -1
- package/src/config-store.js +98 -38
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [1.3.1](https://github.com/adobe/helix-config-storage/compare/v1.3.0...v1.3.1) (2024-08-29)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* Add site access entry in the config store ([#11](https://github.com/adobe/helix-config-storage/issues/11)) ([9fa8439](https://github.com/adobe/helix-config-storage/commit/9fa843923a89ca6a360e122c7ebb94dbac1c09ce))
|
|
7
|
+
|
|
8
|
+
# [1.3.0](https://github.com/adobe/helix-config-storage/compare/v1.2.3...v1.3.0) (2024-08-26)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* include profile aggregate in purge call ([02a3580](https://github.com/adobe/helix-config-storage/commit/02a3580bbae7f4d2f646f8de4e92a9efc0bedd60))
|
|
14
|
+
|
|
1
15
|
## [1.2.3](https://github.com/adobe/helix-config-storage/compare/v1.2.2...v1.2.3) (2024-08-24)
|
|
2
16
|
|
|
3
17
|
|
package/package.json
CHANGED
package/src/config-store.js
CHANGED
|
@@ -38,6 +38,7 @@ const FRAGMENTS_COMMON = {
|
|
|
38
38
|
},
|
|
39
39
|
access: {
|
|
40
40
|
'.': 'object',
|
|
41
|
+
site: 'object',
|
|
41
42
|
admin: 'object',
|
|
42
43
|
preview: 'object',
|
|
43
44
|
live: 'object',
|
|
@@ -158,6 +159,31 @@ function redact(config, frag) {
|
|
|
158
159
|
* General purpose config store.
|
|
159
160
|
*/
|
|
160
161
|
export class ConfigStore {
|
|
162
|
+
/**
|
|
163
|
+
* @member {string} org the org id
|
|
164
|
+
*/
|
|
165
|
+
org;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* @member {string} type store type (org, sites, profiles, secrets, users)
|
|
169
|
+
*/
|
|
170
|
+
type;
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @member {string} name config name
|
|
174
|
+
*/
|
|
175
|
+
name;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* @member {string} key storage key
|
|
179
|
+
*/
|
|
180
|
+
key;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* @member {object} profiles the cached profiles config
|
|
184
|
+
*/
|
|
185
|
+
#profiles = {};
|
|
186
|
+
|
|
161
187
|
/**
|
|
162
188
|
* @param {string} org the org id
|
|
163
189
|
* @param {string} type store type (org, sites, profiles, secrets, users)
|
|
@@ -174,8 +200,54 @@ export class ConfigStore {
|
|
|
174
200
|
this.type = type;
|
|
175
201
|
this.name = name;
|
|
176
202
|
this.key = type === 'org'
|
|
177
|
-
? `/orgs/${
|
|
178
|
-
: `/orgs/${
|
|
203
|
+
? `/orgs/${org}/${name || 'config'}.json`
|
|
204
|
+
: `/orgs/${org}/${type}/${name}.json`;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
async #list(ctx) {
|
|
208
|
+
const storage = HelixStorage.fromContext(ctx).configBus();
|
|
209
|
+
const key = `orgs/${this.org}/${this.type}/`;
|
|
210
|
+
const list = await storage.list(key);
|
|
211
|
+
return {
|
|
212
|
+
[this.type]: list.map((entry) => {
|
|
213
|
+
const siteKey = entry.key;
|
|
214
|
+
if (siteKey.endsWith('.json')) {
|
|
215
|
+
const name = siteKey.split('/').pop();
|
|
216
|
+
return {
|
|
217
|
+
path: `/config/${this.org}/${this.type}/${name}`,
|
|
218
|
+
name: name.substring(0, name.length - 5),
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
return null;
|
|
222
|
+
}).filter((entry) => !!entry),
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
async #getProfile(ctx, data) {
|
|
227
|
+
const profileName = data.extends?.profile || 'default';
|
|
228
|
+
let profile = this.#profiles[profileName];
|
|
229
|
+
if (profile !== undefined) {
|
|
230
|
+
return profile;
|
|
231
|
+
}
|
|
232
|
+
const storage = HelixStorage.fromContext(ctx).configBus();
|
|
233
|
+
const profileJson = await storage.get(`/orgs/${this.org}/profiles/${profileName}.json`);
|
|
234
|
+
profile = profileJson ? JSON.parse(profileJson) : null;
|
|
235
|
+
this.#profiles[profileName] = profile;
|
|
236
|
+
return profile;
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Returns the aggregated config. For site configs, this includes the profile config.
|
|
241
|
+
* @param {AdminContext} ctx
|
|
242
|
+
* @param {HelixSiteConfig|HelixProfileConfig} data the data of the config to be updated
|
|
243
|
+
* @returns {Promise<HelixSiteConfig|HelixProfileConfig>}
|
|
244
|
+
*/
|
|
245
|
+
async getAggregatedConfig(ctx, data) {
|
|
246
|
+
if (this.type !== 'sites' || !data) {
|
|
247
|
+
return data;
|
|
248
|
+
}
|
|
249
|
+
const profile = await this.#getProfile(ctx, data);
|
|
250
|
+
return getMergedConfig(data, profile);
|
|
179
251
|
}
|
|
180
252
|
|
|
181
253
|
/**
|
|
@@ -185,16 +257,7 @@ export class ConfigStore {
|
|
|
185
257
|
* @returns {Promise<boolean|undefined>}
|
|
186
258
|
*/
|
|
187
259
|
async validate(ctx, data) {
|
|
188
|
-
|
|
189
|
-
if (this.type === 'sites') {
|
|
190
|
-
// validate the config after merging with the profile
|
|
191
|
-
const storage = HelixStorage.fromContext(ctx).configBus();
|
|
192
|
-
const profileName = data.extends?.profile || 'default';
|
|
193
|
-
const profileJson = await storage.get(`/orgs/${this.org}/profiles/${profileName}.json`);
|
|
194
|
-
const profile = profileJson ? JSON.parse(profileJson) : null;
|
|
195
|
-
config = getMergedConfig(config, profile);
|
|
196
|
-
}
|
|
197
|
-
return validateSchema(config, this.type);
|
|
260
|
+
return validateSchema(data, this.type);
|
|
198
261
|
}
|
|
199
262
|
|
|
200
263
|
async create(ctx, data, relPath = '') {
|
|
@@ -215,28 +278,10 @@ export class ConfigStore {
|
|
|
215
278
|
updateContentSource(ctx, data.content);
|
|
216
279
|
updateCodeSource(ctx, data.code);
|
|
217
280
|
}
|
|
218
|
-
await this.
|
|
281
|
+
const config = await this.getAggregatedConfig(ctx, data);
|
|
282
|
+
await this.validate(ctx, config);
|
|
219
283
|
await storage.put(this.key, JSON.stringify(data), 'application/json');
|
|
220
|
-
await this.purge(ctx, null,
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
async #list(ctx) {
|
|
224
|
-
const storage = HelixStorage.fromContext(ctx).configBus();
|
|
225
|
-
const key = `orgs/${this.org}/${this.type}/`;
|
|
226
|
-
const list = await storage.list(key);
|
|
227
|
-
return {
|
|
228
|
-
[this.type]: list.map((entry) => {
|
|
229
|
-
const siteKey = entry.key;
|
|
230
|
-
if (siteKey.endsWith('.json')) {
|
|
231
|
-
const name = siteKey.split('/').pop();
|
|
232
|
-
return {
|
|
233
|
-
path: `/config/${this.org}/${this.type}/${name}`,
|
|
234
|
-
name: name.substring(0, name.length - 5),
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
return null;
|
|
238
|
-
}).filter((entry) => entry),
|
|
239
|
-
};
|
|
284
|
+
await this.purge(ctx, null, config);
|
|
240
285
|
}
|
|
241
286
|
|
|
242
287
|
async read(ctx, relPath = '') {
|
|
@@ -337,9 +382,17 @@ export class ConfigStore {
|
|
|
337
382
|
updateContentSource(ctx, config.content);
|
|
338
383
|
updateCodeSource(ctx, config.code);
|
|
339
384
|
}
|
|
340
|
-
|
|
385
|
+
let oldConfig = buf ? JSON.parse(buf) : null;
|
|
386
|
+
let newConfig = config;
|
|
387
|
+
if (this.type === 'sites') {
|
|
388
|
+
// apply profile
|
|
389
|
+
oldConfig = await this.getAggregatedConfig(ctx, oldConfig);
|
|
390
|
+
newConfig = await this.getAggregatedConfig(ctx, newConfig);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
await this.validate(ctx, newConfig);
|
|
341
394
|
await storage.put(this.key, JSON.stringify(config), 'application/json');
|
|
342
|
-
await this.purge(ctx,
|
|
395
|
+
await this.purge(ctx, oldConfig, newConfig);
|
|
343
396
|
return ret ?? redact(data, frag);
|
|
344
397
|
}
|
|
345
398
|
|
|
@@ -350,16 +403,23 @@ export class ConfigStore {
|
|
|
350
403
|
throw new StatusCodeError(404, 'config not found.');
|
|
351
404
|
}
|
|
352
405
|
const frag = getFragmentInfo(this.type, relPath);
|
|
406
|
+
let oldConfig = JSON.parse(buf);
|
|
407
|
+
if (this.type === 'sites') {
|
|
408
|
+
// apply profile
|
|
409
|
+
oldConfig = await this.getAggregatedConfig(ctx, oldConfig);
|
|
410
|
+
}
|
|
411
|
+
|
|
353
412
|
if (frag) {
|
|
354
413
|
const data = deepPut(JSON.parse(buf), relPath, null);
|
|
355
|
-
await this.
|
|
414
|
+
const newConfig = await this.getAggregatedConfig(ctx, data);
|
|
415
|
+
await this.validate(ctx, newConfig);
|
|
356
416
|
await storage.put(this.key, JSON.stringify(data), 'application/json');
|
|
357
|
-
await this.purge(ctx,
|
|
417
|
+
await this.purge(ctx, oldConfig, newConfig);
|
|
358
418
|
return;
|
|
359
419
|
}
|
|
360
420
|
|
|
361
421
|
await storage.remove(this.key);
|
|
362
|
-
await this.purge(ctx,
|
|
422
|
+
await this.purge(ctx, oldConfig, null);
|
|
363
423
|
}
|
|
364
424
|
|
|
365
425
|
// eslint-disable-next-line class-methods-use-this,no-unused-vars
|