@aglyn/tenant-runtime 1.0.0-beta.198 → 1.0.0-beta.200
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 +3 -3
- package/src/lib/assign-contact-owner.js +3 -1
- package/src/lib/assign-contact-owner.js.map +1 -1
- package/src/lib/associate-company-by-domain.js +7 -4
- package/src/lib/associate-company-by-domain.js.map +1 -1
- package/src/lib/convert-host-lead.js +10 -6
- package/src/lib/convert-host-lead.js.map +1 -1
- package/src/lib/get-collection-content.d.ts +41 -4
- package/src/lib/get-collection-content.js +98 -50
- package/src/lib/get-collection-content.js.map +1 -1
|
@@ -32,12 +32,13 @@ import { PUBLISHED_SITE_DATA_TTL_SECONDS, tenantDataTag, withRenderCache } from
|
|
|
32
32
|
* cache already holding exactly that.
|
|
33
33
|
*
|
|
34
34
|
* The other half of that argument was real and is answered rather than
|
|
35
|
-
* dropped: `flipDueEntry` is a write, and
|
|
36
|
-
*
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
35
|
+
* dropped: `flipDueEntry` is a write, and a render is the backstop that
|
|
36
|
+
* publishes a content entry when the `apply-entry-schedules` beat has not
|
|
37
|
+
* (AGL-3340), so a cache that stored a collection with a schedule still
|
|
38
|
+
* pending would suppress the render that publishes it.
|
|
39
|
+
* `getPublishedCollectionSource` therefore declines to STORE exactly those
|
|
40
|
+
* collections — see its `store` predicate — which keeps that backstop on the
|
|
41
|
+
* render window, and puts everything else on this TTL.
|
|
41
42
|
*/ const COLLECTION_SOURCE_TTL_SECONDS = PUBLISHED_SITE_DATA_TTL_SECONDS;
|
|
42
43
|
/**
|
|
43
44
|
* Resolve a public content-collection slug (AGL-954). Commerce's product
|
|
@@ -208,12 +209,30 @@ import { PUBLISHED_SITE_DATA_TTL_SECONDS, tenantDataTag, withRenderCache } from
|
|
|
208
209
|
}
|
|
209
210
|
/**
|
|
210
211
|
* A scheduled entry still waiting on its time: not due yet, and not refused.
|
|
211
|
-
*
|
|
212
|
-
* read holding one would withhold the render
|
|
213
|
-
* {@link LiveEntriesRead.pendingSchedule}.
|
|
212
|
+
* A render is the backstop that publishes a content entry the beat has not
|
|
213
|
+
* reached, so a cache that stored a read holding one would withhold the render
|
|
214
|
+
* that notices it come due — see {@link LiveEntriesRead.pendingSchedule}.
|
|
214
215
|
*/ export function isPendingScheduled(value) {
|
|
215
216
|
return value['status'] === 'scheduled' && !scheduleAlreadyRefused(value) && !isDueScheduled(value);
|
|
216
217
|
}
|
|
218
|
+
/**
|
|
219
|
+
* When this entry's schedule comes due, in epoch ms — or null when it holds
|
|
220
|
+
* no schedule to act on: not `scheduled`, already refused, or carrying no
|
|
221
|
+
* `publishAt` (AGL-3340).
|
|
222
|
+
*
|
|
223
|
+
* The beat orders its probe by this instant. A refused schedule keeps
|
|
224
|
+
* `status: 'scheduled'` forever (see {@link ENTRY_SCHEDULE_SKIPPED}), so
|
|
225
|
+
* reading one as due would make every beat re-probe for work that will never
|
|
226
|
+
* be done. Seconds, like {@link isDueScheduled}, so the two agree about the
|
|
227
|
+
* instant an entry comes due.
|
|
228
|
+
*/ export function entryScheduleDueAtMs(value) {
|
|
229
|
+
var _value_publishAt;
|
|
230
|
+
if (value['status'] !== 'scheduled' || scheduleAlreadyRefused(value)) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
const seconds = (_value_publishAt = value['publishAt']) == null ? void 0 : _value_publishAt.seconds;
|
|
234
|
+
return typeof seconds === 'number' ? seconds * 1000 : null;
|
|
235
|
+
}
|
|
217
236
|
export async function scheduledPublishingPermission(hostId) {
|
|
218
237
|
try {
|
|
219
238
|
var _this;
|
|
@@ -232,7 +251,10 @@ export async function scheduledPublishingPermission(hostId) {
|
|
|
232
251
|
/**
|
|
233
252
|
* Scheduled entries (AGL-123) go live lazily like AGL-61: a due
|
|
234
253
|
* `publishAt` counts as published for this render, and the doc is flipped
|
|
235
|
-
* to `published` fail-open so the state becomes durable.
|
|
254
|
+
* to `published` fail-open so the state becomes durable. The tenant's
|
|
255
|
+
* `apply-entry-schedules` beat makes the same flip at the entry's time and
|
|
256
|
+
* drops the pages that list it (AGL-3340); this render-time half stays as the
|
|
257
|
+
* backstop for a beat that is down or has not reached the entry yet.
|
|
236
258
|
*
|
|
237
259
|
* PLAN GATE (AGL-471). `scheduledPublishing` is a Business entitlement, and
|
|
238
260
|
* until now nothing on the entry path checked it: the console let any plan
|
|
@@ -263,28 +285,54 @@ export async function scheduledPublishingPermission(hostId) {
|
|
|
263
285
|
* subsequent render.
|
|
264
286
|
*
|
|
265
287
|
* Both writes fail open: an error leaves today's state, and the next render
|
|
266
|
-
* retries.
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
288
|
+
* retries. A render does not wait for them (`void`); the beat does, because
|
|
289
|
+
* it drops pages only for a flip that landed.
|
|
290
|
+
*
|
|
291
|
+
* `precondition` is the beat's: it read the entry some milliseconds earlier,
|
|
292
|
+
* and an author rescheduling it in between must win. A render passes none —
|
|
293
|
+
* it writes exactly what it just rendered.
|
|
294
|
+
*/ async function flipDueEntry(docRef, value, permission, precondition) {
|
|
295
|
+
if (value['status'] !== 'scheduled') return 'unchanged';
|
|
296
|
+
if (scheduleAlreadyRefused(value)) return 'unchanged';
|
|
270
297
|
// `unresolved` writes NOTHING. It withholds this render and leaves the
|
|
271
298
|
// schedule exactly as it found it, so a later render can still publish it.
|
|
272
|
-
if (permission === 'unresolved') return;
|
|
273
|
-
if (
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
// The console's sort key follows the flip (AGL-3323). It already held
|
|
281
|
-
// `publishAt` while the entry waited, and `publishedAt` takes that same
|
|
282
|
-
// instant, so the entry keeps its place in the console's Published order.
|
|
283
|
-
docRef.update({
|
|
299
|
+
if (permission === 'unresolved') return 'unchanged';
|
|
300
|
+
if (!isDueScheduled(value)) return 'unchanged';
|
|
301
|
+
const update = permission === 'refused' ? {
|
|
302
|
+
scheduleStatus: ENTRY_SCHEDULE_SKIPPED
|
|
303
|
+
} : // `publishAt` while the entry waited, and `publishedAt` takes that
|
|
304
|
+
// same instant, so the entry keeps its place in the console's
|
|
305
|
+
// Published order.
|
|
306
|
+
{
|
|
284
307
|
status: 'published',
|
|
285
308
|
publishedAt: value['publishAt'],
|
|
286
309
|
[ENTRY_PUBLISH_SORT_FIELD]: value['publishAt']
|
|
287
|
-
}
|
|
310
|
+
};
|
|
311
|
+
try {
|
|
312
|
+
if (precondition) await docRef.update(update, precondition);
|
|
313
|
+
else await docRef.update(update);
|
|
314
|
+
return permission === 'refused' ? 'refused' : 'published';
|
|
315
|
+
} catch (error) {
|
|
316
|
+
console.error(error);
|
|
317
|
+
return 'failed';
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Apply one due entry schedule outside a render (AGL-3340) — the executor the
|
|
322
|
+
* `apply-entry-schedules` beat runs, and the same one a render runs, so the
|
|
323
|
+
* two cannot come to disagree about the plan gate or the fields a flip
|
|
324
|
+
* writes.
|
|
325
|
+
*
|
|
326
|
+
* Asks the plan only for an entry that is actually due, as every render path
|
|
327
|
+
* does. Guarded on the snapshot's own `updateTime`: a schedule edited after
|
|
328
|
+
* the beat read it is left for the next beat, which reads it fresh.
|
|
329
|
+
*/ export async function applyDueEntrySchedule(options) {
|
|
330
|
+
const value = options.entry.data();
|
|
331
|
+
if (!value || !isDueScheduled(value)) return 'unchanged';
|
|
332
|
+
const permission = await scheduledPublishingPermission(options.hostId);
|
|
333
|
+
return flipDueEntry(options.entry.ref, value, permission, options.entry.updateTime ? {
|
|
334
|
+
lastUpdateTime: options.entry.updateTime
|
|
335
|
+
} : undefined);
|
|
288
336
|
}
|
|
289
337
|
/**
|
|
290
338
|
* The fields a LISTING read of an entry needs — the field mask on the query
|
|
@@ -340,9 +388,9 @@ export async function scheduledPublishingPermission(hostId) {
|
|
|
340
388
|
*
|
|
341
389
|
* Read by its own query rather than taken from the dated page below, because
|
|
342
390
|
* a schedule is invisible to that page: scheduling writes `publishAt` and
|
|
343
|
-
* never `publishedAt`, and
|
|
344
|
-
* that publishes
|
|
345
|
-
* out. The set is small by nature — a hundred pending schedules on one
|
|
391
|
+
* never `publishedAt`, and when the beat has not reached one, `flipDueEntry`
|
|
392
|
+
* during a render is the only thing that publishes it. A schedule the read
|
|
393
|
+
* misses is then a post that does not go out. The set is small by nature — a hundred pending schedules on one
|
|
346
394
|
* collection is already an unusual editorial calendar.
|
|
347
395
|
*/ const SCHEDULED_SOURCE_MAX = 100;
|
|
348
396
|
/** Everything a public listing may show, before any ordering. */ function liveEntriesBase(entriesRef) {
|
|
@@ -444,7 +492,7 @@ export async function scheduledPublishingPermission(hostId) {
|
|
|
444
492
|
return docs.filter((entryDoc)=>isLive(entryDoc.data(), permission)).map((entryDoc)=>{
|
|
445
493
|
var _value_title, _value_slug, _value_publishedAt, _value_publishedAt1;
|
|
446
494
|
const value = entryDoc.data();
|
|
447
|
-
flipDueEntry(entryDoc.ref, value, permission);
|
|
495
|
+
void flipDueEntry(entryDoc.ref, value, permission);
|
|
448
496
|
return _extends({
|
|
449
497
|
$id: entryDoc.id,
|
|
450
498
|
title: (_value_title = value['title']) != null ? _value_title : entryDoc.id,
|
|
@@ -478,7 +526,7 @@ export async function scheduledPublishingPermission(hostId) {
|
|
|
478
526
|
// re-reading the org on each one.
|
|
479
527
|
if (permission !== 'allowed') {
|
|
480
528
|
for (const entryDoc of due){
|
|
481
|
-
flipDueEntry(entryDoc.ref, entryDoc.data(), permission);
|
|
529
|
+
void flipDueEntry(entryDoc.ref, entryDoc.data(), permission);
|
|
482
530
|
}
|
|
483
531
|
}
|
|
484
532
|
// Measured on the RAW docs, before the liveness filter (AGL-1516): a
|
|
@@ -553,7 +601,7 @@ export async function scheduledPublishingPermission(hostId) {
|
|
|
553
601
|
const permission = due.length ? await scheduledPublishingPermission(options.hostId) : 'allowed';
|
|
554
602
|
if (permission !== 'allowed') {
|
|
555
603
|
for (const entryDoc of due){
|
|
556
|
-
flipDueEntry(entryDoc.ref, entryDoc.data(), permission);
|
|
604
|
+
void flipDueEntry(entryDoc.ref, entryDoc.data(), permission);
|
|
557
605
|
}
|
|
558
606
|
}
|
|
559
607
|
const entries = toLiveEntries(docs, permission);
|
|
@@ -624,13 +672,13 @@ export async function scheduledPublishingPermission(hostId) {
|
|
|
624
672
|
read: ()=>readPublishedCollectionSource(options),
|
|
625
673
|
// A collection with a schedule still pending is SERVED but not STORED.
|
|
626
674
|
//
|
|
627
|
-
//
|
|
628
|
-
// the
|
|
629
|
-
//
|
|
630
|
-
//
|
|
631
|
-
//
|
|
632
|
-
//
|
|
633
|
-
// allowed to reduce.
|
|
675
|
+
// The beat publishes a due entry and drops this tag (AGL-3340); when
|
|
676
|
+
// the beat is down, `flipDueEntry` during a render is what publishes
|
|
677
|
+
// it, so storing this source would suppress the very renders that would
|
|
678
|
+
// have noticed the entry coming due, and the post would wait out the
|
|
679
|
+
// TTL rather than land at its time. Declining to store leaves those
|
|
680
|
+
// collections exactly as uncached as they were before this cache
|
|
681
|
+
// existed, which is the only cost this cache is not allowed to reduce.
|
|
634
682
|
//
|
|
635
683
|
// Also refuses a collection that resolved to nothing, for the reason
|
|
636
684
|
// `withRenderCache` states about negatives generally: a slug that
|
|
@@ -912,19 +960,19 @@ async function readPublishedCollectionSource(options) {
|
|
|
912
960
|
// something is due, and record the refusal on its own pass because a
|
|
913
961
|
// refused entry never becomes the `entryDoc` below (AGL-471).
|
|
914
962
|
//
|
|
915
|
-
// A PREVIEW RENDER SKIPS BOTH WRITES (AGL-3205). `flipDueEntry` is
|
|
916
|
-
//
|
|
917
|
-
//
|
|
918
|
-
// one post through a link, and it must not be
|
|
919
|
-
// burn its schedule with the terminal refusal
|
|
920
|
-
// costs nothing — the
|
|
921
|
-
// writes the same answers — and it is
|
|
922
|
-
//
|
|
963
|
+
// A PREVIEW RENDER SKIPS BOTH WRITES (AGL-3205). `flipDueEntry` is how a
|
|
964
|
+
// content entry is published — by the beat, or by a render as its
|
|
965
|
+
// backstop — and the render half belongs to the PUBLIC render: a preview
|
|
966
|
+
// is one person looking at one post through a link, and it must not be
|
|
967
|
+
// able to publish it, nor to burn its schedule with the terminal refusal
|
|
968
|
+
// marker. Skipping the writes costs nothing — the beat or the next public
|
|
969
|
+
// render asks the same questions and writes the same answers — and it is
|
|
970
|
+
// what keeps a preview link from publishing anything.
|
|
923
971
|
const dueHere = entryQuery.docs.filter((docSnapshot)=>isDueScheduled(docSnapshot.data()));
|
|
924
972
|
const permission = dueHere.length ? await scheduledPublishingPermission(hostId) : 'allowed';
|
|
925
973
|
if (permission !== 'allowed' && !preview) {
|
|
926
974
|
for (const docSnapshot of dueHere){
|
|
927
|
-
flipDueEntry(docSnapshot.ref, docSnapshot.data(), permission);
|
|
975
|
+
void flipDueEntry(docSnapshot.ref, docSnapshot.data(), permission);
|
|
928
976
|
}
|
|
929
977
|
}
|
|
930
978
|
/**
|
|
@@ -944,7 +992,7 @@ async function readPublishedCollectionSource(options) {
|
|
|
944
992
|
if (entryDoc) {
|
|
945
993
|
var _value_title, _value_body, _value_publishedAt, _value_publishedAt1;
|
|
946
994
|
const value = entryDoc.data();
|
|
947
|
-
if (!preview) flipDueEntry(entryDoc.ref, value, permission);
|
|
995
|
+
if (!preview) void flipDueEntry(entryDoc.ref, value, permission);
|
|
948
996
|
if (preview && !isLive(value, permission)) {
|
|
949
997
|
var _value_status;
|
|
950
998
|
var _value_publishAt;
|