@projectdochelp/s3te 3.3.2 → 3.3.3
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/package.json
CHANGED
|
@@ -76,8 +76,37 @@ function localeMatchScore(itemLocale, language, languageLocaleMap) {
|
|
|
76
76
|
return 0;
|
|
77
77
|
}
|
|
78
78
|
|
|
79
|
-
function
|
|
80
|
-
|
|
79
|
+
function comparableTimestamp(value) {
|
|
80
|
+
if (typeof value === "number" && Number.isFinite(value)) {
|
|
81
|
+
return value;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const timestamp = Date.parse(String(value ?? ""));
|
|
85
|
+
return Number.isFinite(timestamp) ? timestamp : -1;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function compareContentFreshness(left, right) {
|
|
89
|
+
const updatedDiff = comparableTimestamp(right.updatedAt) - comparableTimestamp(left.updatedAt);
|
|
90
|
+
if (updatedDiff !== 0) {
|
|
91
|
+
return updatedDiff;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
const changedDiff = comparableTimestamp(right.lastChangedAt) - comparableTimestamp(left.lastChangedAt);
|
|
95
|
+
if (changedDiff !== 0) {
|
|
96
|
+
return changedDiff;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
const createdDiff = comparableTimestamp(right.createdAt) - comparableTimestamp(left.createdAt);
|
|
100
|
+
if (createdDiff !== 0) {
|
|
101
|
+
return createdDiff;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const versionDiff = Number(right.version ?? -1) - Number(left.version ?? -1);
|
|
105
|
+
if (versionDiff !== 0) {
|
|
106
|
+
return versionDiff;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return String(right.id ?? "").localeCompare(String(left.id ?? ""));
|
|
81
110
|
}
|
|
82
111
|
|
|
83
112
|
function filterItemsByRequestedLocale(items, language, languageLocaleMap) {
|
|
@@ -103,7 +132,11 @@ function filterItemsByRequestedLocale(items, language, languageLocaleMap) {
|
|
|
103
132
|
}
|
|
104
133
|
|
|
105
134
|
const bestScore = Math.max(...scored.map((entry) => entry.score));
|
|
106
|
-
return scored
|
|
135
|
+
return scored
|
|
136
|
+
.filter((entry) => entry.score === bestScore)
|
|
137
|
+
.map((entry) => entry.item)
|
|
138
|
+
.sort(compareContentFreshness)
|
|
139
|
+
.slice(0, 1);
|
|
107
140
|
});
|
|
108
141
|
}
|
|
109
142
|
|
|
@@ -390,14 +423,7 @@ export class DynamoContentRepository {
|
|
|
390
423
|
}
|
|
391
424
|
}).promise();
|
|
392
425
|
const items = response.Items ?? [];
|
|
393
|
-
|
|
394
|
-
.map((item) => ({
|
|
395
|
-
item,
|
|
396
|
-
score: localeMatchScore(item.locale, language, this.languageLocaleMap)
|
|
397
|
-
}))
|
|
398
|
-
.filter((entry) => entry.score > 0)
|
|
399
|
-
.sort((left, right) => right.score - left.score || String(left.item.id).localeCompare(String(right.item.id)));
|
|
400
|
-
return candidates[0]?.item ?? null;
|
|
426
|
+
return filterItemsByRequestedLocale(items, language, this.languageLocaleMap)[0] ?? null;
|
|
401
427
|
}
|
|
402
428
|
|
|
403
429
|
async query(query, language) {
|
|
@@ -314,6 +314,17 @@ function extractWebinyTenant(item) {
|
|
|
314
314
|
?? null;
|
|
315
315
|
}
|
|
316
316
|
|
|
317
|
+
function normalizeMirrorLocale(value) {
|
|
318
|
+
return value == null ? "" : String(value).trim().toLowerCase();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
function isSameMirroredContentIdentity(existingItem, contentItem) {
|
|
322
|
+
return String(existingItem.contentId ?? "") === String(contentItem.contentId ?? "")
|
|
323
|
+
&& String(existingItem.model ?? "") === String(contentItem.model ?? "")
|
|
324
|
+
&& String(existingItem.tenant ?? "") === String(contentItem.tenant ?? "")
|
|
325
|
+
&& normalizeMirrorLocale(existingItem.locale) === normalizeMirrorLocale(contentItem.locale);
|
|
326
|
+
}
|
|
327
|
+
|
|
317
328
|
export function normalizeContentItem(item, options = {}) {
|
|
318
329
|
const root = getItemRoot(item);
|
|
319
330
|
const values = normalizeValues(item, options.modelFields);
|
|
@@ -369,12 +380,53 @@ async function loadModelFields(clients, sourceTableName, tenant, modelId, cache)
|
|
|
369
380
|
return fields;
|
|
370
381
|
}
|
|
371
382
|
|
|
383
|
+
async function listMirroredContentItems(clients, tableName, indexName, contentId) {
|
|
384
|
+
const items = [];
|
|
385
|
+
let lastEvaluatedKey;
|
|
386
|
+
|
|
387
|
+
do {
|
|
388
|
+
const response = await clients.dynamo.query({
|
|
389
|
+
TableName: tableName,
|
|
390
|
+
IndexName: indexName,
|
|
391
|
+
KeyConditionExpression: "contentId = :contentId",
|
|
392
|
+
ExpressionAttributeValues: {
|
|
393
|
+
":contentId": contentId
|
|
394
|
+
},
|
|
395
|
+
ExclusiveStartKey: lastEvaluatedKey
|
|
396
|
+
}).promise();
|
|
397
|
+
items.push(...(response.Items ?? []));
|
|
398
|
+
lastEvaluatedKey = response.LastEvaluatedKey;
|
|
399
|
+
} while (lastEvaluatedKey);
|
|
400
|
+
|
|
401
|
+
return items;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
async function removeMirroredContentRevisions(clients, tableName, indexName, contentItem, excludeId = null) {
|
|
405
|
+
const mirroredItems = await listMirroredContentItems(clients, tableName, indexName, contentItem.contentId);
|
|
406
|
+
const removals = mirroredItems.filter((existingItem) => (
|
|
407
|
+
isSameMirroredContentIdentity(existingItem, contentItem)
|
|
408
|
+
&& existingItem.id !== excludeId
|
|
409
|
+
));
|
|
410
|
+
|
|
411
|
+
for (const existingItem of removals) {
|
|
412
|
+
await clients.dynamo.delete({
|
|
413
|
+
TableName: tableName,
|
|
414
|
+
Key: {
|
|
415
|
+
id: existingItem.id
|
|
416
|
+
}
|
|
417
|
+
}).promise();
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
return removals.length;
|
|
421
|
+
}
|
|
422
|
+
|
|
372
423
|
export async function handler(event) {
|
|
373
424
|
const clients = createAwsClients();
|
|
374
425
|
const tableName = process.env.S3TE_CONTENT_TABLE;
|
|
375
426
|
const renderWorkerName = process.env.S3TE_RENDER_WORKER_NAME;
|
|
376
427
|
const environmentName = process.env.S3TE_ENVIRONMENT;
|
|
377
428
|
const sourceTableName = process.env.S3TE_WEBINY_SOURCE_TABLE;
|
|
429
|
+
const contentIndexName = process.env.S3TE_CONTENT_ID_INDEX_NAME ?? "contentid";
|
|
378
430
|
const configuredTenant = String(process.env.S3TE_WEBINY_TENANT ?? "").trim();
|
|
379
431
|
const relevantModels = new Set(String(process.env.S3TE_RELEVANT_MODELS ?? "")
|
|
380
432
|
.split(",")
|
|
@@ -411,13 +463,7 @@ export async function handler(event) {
|
|
|
411
463
|
|
|
412
464
|
const shouldDelete = record.eventName === "REMOVE" || !isPublished(item);
|
|
413
465
|
if (shouldDelete) {
|
|
414
|
-
await clients
|
|
415
|
-
TableName: tableName,
|
|
416
|
-
Key: {
|
|
417
|
-
id: contentItem.id
|
|
418
|
-
}
|
|
419
|
-
}).promise();
|
|
420
|
-
deleted += 1;
|
|
466
|
+
deleted += await removeMirroredContentRevisions(clients, tableName, contentIndexName, contentItem);
|
|
421
467
|
await invokeLambdaEvent(clients.lambda, renderWorkerName, {
|
|
422
468
|
type: "content-item",
|
|
423
469
|
action: "delete",
|
|
@@ -429,6 +475,7 @@ export async function handler(event) {
|
|
|
429
475
|
continue;
|
|
430
476
|
}
|
|
431
477
|
|
|
478
|
+
await removeMirroredContentRevisions(clients, tableName, contentIndexName, contentItem, contentItem.id);
|
|
432
479
|
await clients.dynamo.put({
|
|
433
480
|
TableName: tableName,
|
|
434
481
|
Item: contentItem
|
|
@@ -631,6 +631,7 @@ export function buildWebinyCloudFormationTemplate({ config, environment }) {
|
|
|
631
631
|
Variables: {
|
|
632
632
|
S3TE_ENVIRONMENT: environment,
|
|
633
633
|
S3TE_CONTENT_TABLE: runtimeConfig.tables.content,
|
|
634
|
+
S3TE_CONTENT_ID_INDEX_NAME: config.aws.contentStore.contentIdIndexName,
|
|
634
635
|
S3TE_RELEVANT_MODELS: runtimeConfig.integrations.webiny.relevantModels.join(","),
|
|
635
636
|
S3TE_WEBINY_SOURCE_TABLE: runtimeConfig.integrations.webiny.sourceTableName,
|
|
636
637
|
S3TE_WEBINY_TENANT: runtimeConfig.integrations.webiny.tenant ?? "",
|