@plusscommunities/pluss-core-aws 2.0.25-beta.7 → 2.0.25-beta.8
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/helper/hqPublishing.js +77 -1
- package/package.json +1 -1
package/helper/hqPublishing.js
CHANGED
|
@@ -144,6 +144,23 @@ const fanOutHqSource = async (hqSourceRow, tableName) => {
|
|
|
144
144
|
if (targets.length === 0) {
|
|
145
145
|
return [];
|
|
146
146
|
}
|
|
147
|
+
return writeCopiesForTargets(hqSourceRow, targets, tableName);
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Write one community-copy row per site in `targetSites` (all of the source's
|
|
152
|
+
* PublishedToSites on INSERT fan-out, or just the newly-added subset on a
|
|
153
|
+
* MODIFY target-set change). Shared by fanOutHqSource and syncHqTargets. The
|
|
154
|
+
* deterministic RowId makes each write idempotent AND makes re-adding a
|
|
155
|
+
* previously-removed (soft-deleted) site a lossless resurrection — the PUT
|
|
156
|
+
* overwrites the row and drops the Deleted flag.
|
|
157
|
+
*
|
|
158
|
+
* @param {object} hqSourceRow — the HQ-source row.
|
|
159
|
+
* @param {string[]} targetSites — sites to write copies for.
|
|
160
|
+
* @param {string} tableName — entity's table name.
|
|
161
|
+
* @returns {Promise<object[]>} the copy rows written.
|
|
162
|
+
*/
|
|
163
|
+
const writeCopiesForTargets = (hqSourceRow, targetSites, tableName) => {
|
|
147
164
|
const copyId = `hqcopy-${hqSourceRow.Id}`;
|
|
148
165
|
// Preserve the HQ-source row's own UnixTimestamp on each copy rather than
|
|
149
166
|
// stamping "now". For an immediate publish the source timestamp already IS
|
|
@@ -163,7 +180,7 @@ const fanOutHqSource = async (hqSourceRow, tableName) => {
|
|
|
163
180
|
const now = moment.utc().valueOf();
|
|
164
181
|
const publishTs = hqSourceRow.UnixTimestamp || now;
|
|
165
182
|
|
|
166
|
-
const writes =
|
|
183
|
+
const writes = targetSites.map((targetSiteId) => {
|
|
167
184
|
// Spread + override pattern: keep all content fields, swap identity
|
|
168
185
|
// fields, drop HQ-only fields. Spread is shallow — nested objects
|
|
169
186
|
// (Author, etc.) share references with the source row, which is fine
|
|
@@ -192,6 +209,63 @@ const fanOutHqSource = async (hqSourceRow, tableName) => {
|
|
|
192
209
|
return Promise.all(writes);
|
|
193
210
|
};
|
|
194
211
|
|
|
212
|
+
/**
|
|
213
|
+
* Reconcile community copies when an HQ-source MODIFY changes PublishedToSites:
|
|
214
|
+
* fan out copies for newly-ADDED sites, soft-delete copies for REMOVED sites.
|
|
215
|
+
* Content propagation to surviving copies is propagateHqEdit's job; this only
|
|
216
|
+
* reconciles the target SET. Re-adding a removed site resurrects its copy
|
|
217
|
+
* losslessly (deterministic RowId + PUT — see writeCopiesForTargets).
|
|
218
|
+
*
|
|
219
|
+
* MUST run sequentially relative to propagateHqEdit (never concurrently): both
|
|
220
|
+
* use editRef (get-merge-put), and two concurrent writes to the same removed-
|
|
221
|
+
* copy RowId would race (one clobbering the other's Deleted flag).
|
|
222
|
+
*
|
|
223
|
+
* @param {object} prevRow — OldImage of the HQ-source row.
|
|
224
|
+
* @param {object} nextRow — NewImage of the HQ-source row.
|
|
225
|
+
* @param {string} tableName — entity's table name.
|
|
226
|
+
* @param {object} [options]
|
|
227
|
+
* @param {string} [options.indexName="NewsletterEntriesHqSourceIdIndex"]
|
|
228
|
+
* @returns {Promise<{added: number, removed: number}>}
|
|
229
|
+
*/
|
|
230
|
+
const syncHqTargets = async (prevRow, nextRow, tableName, options = {}) => {
|
|
231
|
+
const indexName = options.indexName || "NewsletterEntriesHqSourceIdIndex";
|
|
232
|
+
if (!nextRow || nextRow.Site !== "hq" || nextRow.Deleted) {
|
|
233
|
+
return { added: 0, removed: 0 };
|
|
234
|
+
}
|
|
235
|
+
const prev = Array.isArray(prevRow?.PublishedToSites)
|
|
236
|
+
? prevRow.PublishedToSites
|
|
237
|
+
: [];
|
|
238
|
+
const next = Array.isArray(nextRow.PublishedToSites)
|
|
239
|
+
? nextRow.PublishedToSites
|
|
240
|
+
: [];
|
|
241
|
+
const added = next.filter((s) => !prev.includes(s));
|
|
242
|
+
const removed = prev.filter((s) => !next.includes(s));
|
|
243
|
+
|
|
244
|
+
if (added.length > 0) {
|
|
245
|
+
await writeCopiesForTargets(nextRow, added, tableName);
|
|
246
|
+
}
|
|
247
|
+
if (removed.length > 0) {
|
|
248
|
+
const copies = await findCopiesByHqSourceId(
|
|
249
|
+
nextRow.Id,
|
|
250
|
+
tableName,
|
|
251
|
+
indexName,
|
|
252
|
+
);
|
|
253
|
+
const toRemove = copies.filter((c) => removed.includes(c.Site));
|
|
254
|
+
// Per-call fresh payload — editRef sync-mutates updates[keyCol]; sharing
|
|
255
|
+
// across Promise.all(map) would leak RowId between iterations (same
|
|
256
|
+
// rationale as propagateHqEdit / cascadeHqRetract).
|
|
257
|
+
await Promise.all(
|
|
258
|
+
toRemove.map((c) =>
|
|
259
|
+
editRef(tableName, "RowId", c.RowId, {
|
|
260
|
+
Deleted: true,
|
|
261
|
+
Changed: moment.utc().unix(),
|
|
262
|
+
}),
|
|
263
|
+
),
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
return { added: added.length, removed: removed.length };
|
|
267
|
+
};
|
|
268
|
+
|
|
195
269
|
/**
|
|
196
270
|
* Propagate an HQ-source MODIFY to every community copy via the GSI lookup.
|
|
197
271
|
* Skips the retract case (where `Deleted: true`) — that flows through
|
|
@@ -370,6 +444,8 @@ module.exports = {
|
|
|
370
444
|
// Story B
|
|
371
445
|
findCopiesByHqSourceId,
|
|
372
446
|
fanOutHqSource,
|
|
447
|
+
writeCopiesForTargets,
|
|
448
|
+
syncHqTargets,
|
|
373
449
|
propagateHqEdit,
|
|
374
450
|
cascadeHqRetract,
|
|
375
451
|
incrementTemplateUseCount,
|
package/package.json
CHANGED