cdk-nextjs 0.7.6 → 0.7.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/.jsii +3 -3
- package/.jsii.tabl.json +1 -1
- package/README.md +12 -3
- package/assets/lambdas/post-deploy/post-deploy.lambda/index.js +31 -13
- package/docs/adapter-runtime.md +1 -1
- package/docs/caching-guide.md +11 -1
- package/docs/harness-coverage.md +154 -73
- package/lib/adapter/adapter.mjs +12 -3
- package/lib/adapter/aws-cache-store.d.ts +221 -3
- package/lib/adapter/aws-cache-store.js +481 -35
- package/lib/adapter/aws-cache-store.test.js +706 -3
- package/lib/adapter/cache-handler.d.ts +5 -3
- package/lib/adapter/cache-handler.js +16 -10
- package/lib/adapter/cache-handler.mjs +517 -49
- package/lib/adapter/cache-handler.test.js +44 -1
- package/lib/adapter/cache-utils.d.ts +22 -0
- package/lib/adapter/cache-utils.js +44 -1
- package/lib/adapter/function-groups.js +17 -4
- package/lib/adapter/function-groups.test.js +33 -1
- package/lib/adapter/memory-cache-handler.d.ts +5 -1
- package/lib/adapter/memory-cache-handler.js +6 -2
- package/lib/adapter/s3-cache-handler.d.ts +12 -1
- package/lib/adapter/s3-cache-handler.js +30 -8
- package/lib/adapter/s3-cache-handler.test.js +84 -2
- package/lib/adapter/use-cache-common.d.ts +66 -1
- package/lib/adapter/use-cache-common.js +142 -19
- package/lib/adapter/use-cache-common.test.js +174 -1
- package/lib/adapter/use-cache-default-handler.js +36 -6
- package/lib/adapter/use-cache-default-handler.mjs +553 -47
- package/lib/adapter/use-cache-handlers.test.js +247 -7
- package/lib/adapter/use-cache-remote-handler.js +9 -7
- package/lib/adapter/use-cache-remote-handler.mjs +542 -45
- package/lib/lambdas/post-deploy/prune-revalidation-table.d.ts +2 -1
- package/lib/lambdas/post-deploy/prune-revalidation-table.js +35 -13
- package/lib/lambdas/post-deploy/prune-revalidation-table.test.js +19 -1
- package/lib/nextjs-api.js +1 -1
- package/lib/nextjs-build/nextjs-build.js +1 -1
- package/lib/nextjs-cache.js +1 -1
- package/lib/nextjs-compute/nextjs-containers.js +1 -1
- package/lib/nextjs-compute/nextjs-functions.js +1 -1
- package/lib/nextjs-distribution.js +1 -1
- package/lib/nextjs-post-deploy.js +1 -1
- package/lib/nextjs-static-assets.js +1 -1
- package/lib/root-constructs/nextjs-base-construct.js +1 -1
- package/lib/root-constructs/nextjs-global-containers.js +1 -1
- package/lib/root-constructs/nextjs-global-functions.js +1 -1
- package/lib/root-constructs/nextjs-regional-containers.js +1 -1
- package/lib/root-constructs/nextjs-regional-functions.js +1 -1
- package/lib/runtime/core.js +20 -4
- package/lib/runtime/core.test.js +17 -1
- package/lib/runtime/image-utils.d.ts +8 -9
- package/lib/runtime/image-utils.js +16 -1
- package/lib/runtime/image-utils.test.js +13 -1
- package/lib/runtime/image.js +9 -3
- package/lib/runtime/lambda.mjs +66 -18
- package/lib/runtime/server.mjs +66 -18
- package/lib/runtime/tag-manifest.d.ts +40 -0
- package/lib/runtime/tag-manifest.js +59 -0
- package/lib/runtime/tag-manifest.test.d.ts +1 -0
- package/lib/runtime/tag-manifest.test.js +47 -0
- package/package.json +3 -3
- package/scripts/e2e-deploy.sh +7 -2
- package/scripts/e2e-harness/README.md +72 -35
- package/scripts/e2e-harness/screen.mjs +148 -7
- package/scripts/playwright-install-deps.sh +40 -0
|
@@ -116,6 +116,13 @@ export declare const BATCH_GET_MAX_KEYS = 100;
|
|
|
116
116
|
* revalidation log, the reads scale with instances instead of requests or tags.
|
|
117
117
|
*/
|
|
118
118
|
export declare const DEFAULT_TAG_REFRESH_MS = 1000;
|
|
119
|
+
/**
|
|
120
|
+
* How far past `refreshIntervalMs` the last refresh may have settled before a
|
|
121
|
+
* `'use cache'` request waits for the next one (see
|
|
122
|
+
* {@link TrackedTagMarkers.behind}). An instance serving steady traffic stays
|
|
123
|
+
* inside it; one that sat idle, or frozen between Lambda invocations, does not.
|
|
124
|
+
*/
|
|
125
|
+
export declare const TAG_REFRESH_GRACE_MS = 1000;
|
|
119
126
|
/** DynamoDB's limit on a sort key, in UTF-8 bytes. */
|
|
120
127
|
export declare const MAX_SORT_KEY_BYTES = 1024;
|
|
121
128
|
/**
|
|
@@ -302,6 +309,14 @@ export type TrackedTagMarkersOptions = TagTable & {
|
|
|
302
309
|
/** `Math.random`, for when each tag's re-read comes due. */
|
|
303
310
|
random?: () => number;
|
|
304
311
|
debug?: (message: string) => void;
|
|
312
|
+
/**
|
|
313
|
+
* Whether the process can be frozen with a refresh in flight, as a Lambda
|
|
314
|
+
* sandbox is between invocations: then a timer checks it kept running, and
|
|
315
|
+
* one that spanned a freeze does not count. A container is never frozen,
|
|
316
|
+
* so it skips the timer and waits for the refresh in flight, however slow.
|
|
317
|
+
* @default false
|
|
318
|
+
*/
|
|
319
|
+
canFreeze?: boolean;
|
|
305
320
|
};
|
|
306
321
|
/**
|
|
307
322
|
* One instance's copy of the marker rows of the tags it has needed, kept
|
|
@@ -322,15 +337,19 @@ export type TrackedTagMarkersOptions = TagTable & {
|
|
|
322
337
|
* The cost is bounded per instance, not per request:
|
|
323
338
|
* - {@link ensure} reads a tag's marker the first time it is needed and not
|
|
324
339
|
* again until it is evicted, so a tag costs one read per instance, not one
|
|
325
|
-
* per request.
|
|
340
|
+
* per request. An entry created since {@link completeSince} needs no read
|
|
341
|
+
* at all.
|
|
326
342
|
* - {@link refresh}, at most once per `refreshIntervalMs`, sends one `Query`
|
|
327
343
|
* for the log rows written since the last one, and applies those of tags
|
|
328
344
|
* this instance tracks. Concurrent callers share it. Alongside, it re-reads
|
|
329
345
|
* the markers of up to {@link BATCH_GET_MAX_KEYS} tags not read for
|
|
330
346
|
* {@link DEFAULT_TAG_RESYNC_MS}, in one `BatchGetItem`.
|
|
331
347
|
* A revalidation on another instance is therefore seen within
|
|
332
|
-
* `refreshIntervalMs` (plus the query itself)
|
|
333
|
-
*
|
|
348
|
+
* `refreshIntervalMs` (plus the query itself) - by `'use cache'`, from the
|
|
349
|
+
* first request after the query returns, since its `refreshTags` does not wait
|
|
350
|
+
* for it (see `tagMethods`) unless the instance is {@link behind}, which the
|
|
351
|
+
* runtime settles before a page render starts ({@link catchUp}). The instance
|
|
352
|
+
* that ran it applies it itself, at once, with {@link set}.
|
|
334
353
|
*/
|
|
335
354
|
export declare class TrackedTagMarkers {
|
|
336
355
|
private readonly markers;
|
|
@@ -356,10 +375,64 @@ export declare class TrackedTagMarkers {
|
|
|
356
375
|
* result rather than dropped.
|
|
357
376
|
*/
|
|
358
377
|
private readonly pendingRows;
|
|
378
|
+
/**
|
|
379
|
+
* Log rows for tags not tracked and not being read, merged by tag, oldest
|
|
380
|
+
* first: what the log has said about them since {@link completeSince}. Taken
|
|
381
|
+
* into a tag's marker when it is read or written.
|
|
382
|
+
*/
|
|
383
|
+
private readonly logOnly;
|
|
384
|
+
/** See {@link completeSince}. */
|
|
385
|
+
private floor;
|
|
386
|
+
/**
|
|
387
|
+
* The future `expiredAt`s of markers dropped since, as `[from, to]`, in
|
|
388
|
+
* order: once `from` is past, {@link completeSince} moves to `to`, and not
|
|
389
|
+
* before, since only then does it expire anything. `from` and `to` are the
|
|
390
|
+
* same until spans are merged for space ({@link laterFloor}).
|
|
391
|
+
*/
|
|
392
|
+
private readonly laterFloors;
|
|
393
|
+
/** The in-memory entry stores judged by {@link completeSince}. */
|
|
394
|
+
private readonly entryStores;
|
|
395
|
+
/** How many times {@link forget} ran: a read started before one is made again. */
|
|
396
|
+
private forgotten;
|
|
359
397
|
/** Tracked tags whose read failed, for the next refresh to read again. */
|
|
360
398
|
private readonly unread;
|
|
399
|
+
/**
|
|
400
|
+
* Set inside a page render {@link catchUp} let go, for that render alone.
|
|
401
|
+
* See {@link behindInRender}.
|
|
402
|
+
*/
|
|
403
|
+
private readonly caughtUpRender;
|
|
404
|
+
/** When `sync` last scanned the entry stores ({@link oldestEntry}). */
|
|
405
|
+
private lastEntryScan;
|
|
406
|
+
/**
|
|
407
|
+
* No `logOnly` row is known by it or earlier, so a {@link pruneLogged}
|
|
408
|
+
* against it or earlier drops nothing: a marker is only ever known by later,
|
|
409
|
+
* as its `expiredAt` passes.
|
|
410
|
+
*/
|
|
411
|
+
private prunedAgainst;
|
|
412
|
+
/** When the last refresh started, or was skipped. */
|
|
361
413
|
private lastRefresh;
|
|
414
|
+
/**
|
|
415
|
+
* The refresh in flight. One left open across a freeze comes back after the
|
|
416
|
+
* thaw with what it read before, so {@link refresh} waits for it and then
|
|
417
|
+
* for a fresh one, rather than the runtime waiting for it before the freeze:
|
|
418
|
+
* that would bill every Lambda invocation for the query's tail.
|
|
419
|
+
*/
|
|
362
420
|
private refreshing;
|
|
421
|
+
/**
|
|
422
|
+
* When {@link refreshing} last showed the process running: a timer ticks
|
|
423
|
+
* while it is in flight, and a tick that comes late, or none at all, means
|
|
424
|
+
* the process was paused - frozen - since it started.
|
|
425
|
+
*/
|
|
426
|
+
private lastTick;
|
|
427
|
+
/** Whether a tick came late since {@link refreshing} started. */
|
|
428
|
+
private pausedWhileRefreshing;
|
|
429
|
+
private ticker;
|
|
430
|
+
private readonly canFreeze;
|
|
431
|
+
/**
|
|
432
|
+
* When the last refresh settled, either way, unless it spanned a pause: what
|
|
433
|
+
* it knows is from then. See {@link behind}.
|
|
434
|
+
*/
|
|
435
|
+
private settledAt;
|
|
363
436
|
/**
|
|
364
437
|
* Where the next log query starts (`clock()`): the last successful one's
|
|
365
438
|
* start, less {@link REVALIDATION_LOG_LOOKBACK_MS}.
|
|
@@ -374,6 +447,41 @@ export declare class TrackedTagMarkers {
|
|
|
374
447
|
constructor(options: TrackedTagMarkersOptions);
|
|
375
448
|
/** `tag`'s marker as this instance knows it, if it tracks `tag`. */
|
|
376
449
|
get(tag: string): TagMarker | undefined;
|
|
450
|
+
/**
|
|
451
|
+
* Since when (`markerClock()`) this instance knows of every revalidation of
|
|
452
|
+
* every tag, tracked or not: tracked ones from their markers and the log,
|
|
453
|
+
* the others from the log alone (`logOnly`). So an entry created at or after
|
|
454
|
+
* it can be judged by {@link state} and {@link expiration} without
|
|
455
|
+
* {@link ensure} reading anything - which matters inside a `'use cache'`
|
|
456
|
+
* lookup, where Next.js waits for the answer and a read pushes the entry out
|
|
457
|
+
* of the static stage of a staged render.
|
|
458
|
+
*
|
|
459
|
+
* Starts at construction: the log is followed from before it. Moves to now
|
|
460
|
+
* when the tracked markers are forgotten, and past the revalidations of
|
|
461
|
+
* whatever else it lets go of - a marker evicted for space, a log row
|
|
462
|
+
* pruned - which are no longer known: to its `expiredAt` only once that is
|
|
463
|
+
* past, since a profile's `expire` can be a year out, and moving there at
|
|
464
|
+
* once would turn the read-free path off for the instance's life.
|
|
465
|
+
*
|
|
466
|
+
* A row is pruned only once it is no later than every entry held, so that
|
|
467
|
+
* costs those entries nothing. An entry stored afterwards with an older
|
|
468
|
+
* `timestamp` - Next.js stamps the start of its generation, which can
|
|
469
|
+
* outlast a lookback - is older than this too, and is read first.
|
|
470
|
+
*
|
|
471
|
+
* It does not cover a revalidation older than the log's first lookback
|
|
472
|
+
* whose `expiredAt` is still to come, which would expire an entry created
|
|
473
|
+
* after it. So the `'use cache'` handler reads an entry's tags in the
|
|
474
|
+
* background as it stores it.
|
|
475
|
+
*/
|
|
476
|
+
get completeSince(): number;
|
|
477
|
+
/**
|
|
478
|
+
* Register an in-memory store whose entries are judged by
|
|
479
|
+
* {@link completeSince}, by the `timestamp` of the oldest entry it holds:
|
|
480
|
+
* `logOnly` keeps the rows that could still apply to one of them, and no
|
|
481
|
+
* others. With none registered it keeps nothing. Asked with `scan` false,
|
|
482
|
+
* `oldestTimestamp` may answer early, but never late, without a scan.
|
|
483
|
+
*/
|
|
484
|
+
judgeEntriesOf(oldestTimestamp: (scan: boolean) => number, holdsAny?: () => boolean): void;
|
|
377
485
|
/**
|
|
378
486
|
* Track `tag` with `marker`: what this instance just wrote, which it knows
|
|
379
487
|
* without reading it back.
|
|
@@ -405,11 +513,80 @@ export declare class TrackedTagMarkers {
|
|
|
405
513
|
* tags may have been revalidated at any time before.
|
|
406
514
|
*/
|
|
407
515
|
ensure(tags: readonly string[]): Promise<void>;
|
|
516
|
+
/**
|
|
517
|
+
* {@link readInto} `tags`, as the read of each that whoever needs one of
|
|
518
|
+
* them next waits on ({@link reading}). Never rejects: a failed read leaves
|
|
519
|
+
* the tags tracked.
|
|
520
|
+
*/
|
|
521
|
+
private startRead;
|
|
522
|
+
/**
|
|
523
|
+
* Whether the last refresh settled more than `refreshIntervalMs` plus
|
|
524
|
+
* {@link TAG_REFRESH_GRACE_MS} ago - one that spanned a freeze counts from
|
|
525
|
+
* when it started: after the instance sat idle or frozen - or always, with
|
|
526
|
+
* a `refreshIntervalMs` of `0`. Answering from what it knows then could
|
|
527
|
+
* serve an entry revalidated elsewhere since, however long ago that was, so
|
|
528
|
+
* `refreshTags` waits for the refresh, and the runtime waits for it before
|
|
529
|
+
* a page render starts ({@link catchUp}).
|
|
530
|
+
*
|
|
531
|
+
* From when it settled, not when it started, so a slow query the runtime
|
|
532
|
+
* waited for before the render does not leave the instance behind inside
|
|
533
|
+
* it. A failed one counts too, so one request does not wait for two: the
|
|
534
|
+
* same "assume the entry is valid" a failed read answers with, until the
|
|
535
|
+
* next refresh, at most the interval and the grace later.
|
|
536
|
+
*/
|
|
537
|
+
get behind(): boolean;
|
|
538
|
+
/**
|
|
539
|
+
* {@link behind}, as `refreshTags` asks it: never inside a page's render
|
|
540
|
+
* {@link catchUp} caught up, since the runtime settled it for that request
|
|
541
|
+
* before the render started, and a wait inside a `'use cache'` lookup is
|
|
542
|
+
* what it settled it to avoid - a render crossing the line partway through
|
|
543
|
+
* would otherwise wait after all. So a revalidation elsewhere can go unseen
|
|
544
|
+
* for a render's duration on top of the usual window.
|
|
545
|
+
*
|
|
546
|
+
* A route handler, which no catch-up precedes, waits at the plain line.
|
|
547
|
+
*/
|
|
548
|
+
get behindInRender(): boolean;
|
|
549
|
+
/**
|
|
550
|
+
* Whether a registered store ({@link judgeEntriesOf}) holds any entry: one
|
|
551
|
+
* a refresh could expire. With none there is nothing to wait for even when
|
|
552
|
+
* the instance is {@link behind}, since whatever is stored from here on is
|
|
553
|
+
* newer than what the log would say - which covers the first `'use cache'`
|
|
554
|
+
* call of a process, which creates the handler inside the render.
|
|
555
|
+
*/
|
|
556
|
+
get holdsEntries(): boolean;
|
|
557
|
+
/**
|
|
558
|
+
* {@link refresh}, waited for when the instance is {@link behind}. The
|
|
559
|
+
* runtime calls it before handing a page request to Next.js, outside the
|
|
560
|
+
* staged render whose static stage a wait inside a `'use cache'` lookup
|
|
561
|
+
* would cut short. Only for the `'use cache'` handler's entries
|
|
562
|
+
* ({@link judgeEntriesOf}): the other caches wait for the refresh where they
|
|
563
|
+
* read anyway. Not with a `refreshIntervalMs` of `0` either, where
|
|
564
|
+
* `refreshTags` asks again regardless. Then `render`, marked as caught up
|
|
565
|
+
* for ({@link behindInRender}). Rejects only as `render` does.
|
|
566
|
+
*/
|
|
567
|
+
catchUp<T>(render: () => Promise<T>): Promise<T>;
|
|
568
|
+
/**
|
|
569
|
+
* Run `fn` outside the request's context (`outsideRequest`), keeping only
|
|
570
|
+
* whether the render was {@link catchUp caught up}: a cache handler method
|
|
571
|
+
* called from inside a staged render, whose clock reads and AWS SDK calls
|
|
572
|
+
* would otherwise end its static stage.
|
|
573
|
+
*/
|
|
574
|
+
outsideRender<T>(fn: () => T): T;
|
|
575
|
+
/** Whether `at` is more than the interval and the grace ago. */
|
|
576
|
+
private overdue;
|
|
408
577
|
/**
|
|
409
578
|
* Catch up on revalidations other instances ran, at most once per
|
|
410
579
|
* `refreshIntervalMs`. See {@link TrackedTagMarkers} for the cost.
|
|
411
580
|
*/
|
|
412
581
|
refresh(): Promise<void>;
|
|
582
|
+
private startTicking;
|
|
583
|
+
private stopTicking;
|
|
584
|
+
/**
|
|
585
|
+
* Whether the process was paused since {@link refreshing} started: a tick
|
|
586
|
+
* came late, or the next one is overdue (after a thaw, a request can run
|
|
587
|
+
* before the timer does).
|
|
588
|
+
*/
|
|
589
|
+
private pausedSinceRefreshStarted;
|
|
413
590
|
/**
|
|
414
591
|
* Record a revalidation of `tags`: here at once, and in the revalidation
|
|
415
592
|
* table for every other instance - the marker row plus a log row per tag.
|
|
@@ -482,6 +659,47 @@ export declare class TrackedTagMarkers {
|
|
|
482
659
|
*/
|
|
483
660
|
private readInto;
|
|
484
661
|
private takePendingRows;
|
|
662
|
+
/**
|
|
663
|
+
* What this instance knows of `tag`: tracked, or from the log alone -
|
|
664
|
+
* including rows that arrived while its first read is in flight.
|
|
665
|
+
*/
|
|
666
|
+
private knownMarker;
|
|
667
|
+
/**
|
|
668
|
+
* Keep `tag`'s log rows in `logOnly`, unless they cannot apply to an entry
|
|
669
|
+
* held, `oldest` or newer (see {@link pruneLogged}), as bounded as the
|
|
670
|
+
* tracked tags. Either way a row let go of takes what it knew with it, so
|
|
671
|
+
* `completeSince` moves past it.
|
|
672
|
+
*/
|
|
673
|
+
private rememberLogged;
|
|
674
|
+
/**
|
|
675
|
+
* Drop the `logOnly` rows that cannot apply to an entry held, `oldest` or
|
|
676
|
+
* newer: every revalidation they name so far is no later than it. That
|
|
677
|
+
* moves `completeSince` no further than `oldest`, which costs the entries
|
|
678
|
+
* held nothing, and a profile's `expiredAt` still to come waits in
|
|
679
|
+
* `laterFloors`. Without this, a deployment revalidating many distinct tags
|
|
680
|
+
* filled `logOnly` with tags no entry here carries, and the evictions past
|
|
681
|
+
* its bound kept moving `completeSince` up to the present.
|
|
682
|
+
*/
|
|
683
|
+
private pruneLogged;
|
|
684
|
+
/**
|
|
685
|
+
* The oldest entry timestamp of any registered store, `Infinity` with none:
|
|
686
|
+
* early, never late, unless `scan`.
|
|
687
|
+
*/
|
|
688
|
+
private oldestEntry;
|
|
689
|
+
/**
|
|
690
|
+
* Move `completeSince` past `marker`'s revalidations: what is no longer
|
|
691
|
+
* known about a tag once its marker is dropped. A future `expiredAt` waits
|
|
692
|
+
* in `laterFloors` until it is past.
|
|
693
|
+
*/
|
|
694
|
+
private raiseFloor;
|
|
695
|
+
/**
|
|
696
|
+
* Add `time` to `laterFloors`, in order. Past the tracked-tag bound the two
|
|
697
|
+
* spans closest together are merged: from the first's start,
|
|
698
|
+
* `completeSince` is the second's end, early - which only costs reads, and
|
|
699
|
+
* for as short a time as any merge allows. Never later than its time, which
|
|
700
|
+
* would let an entry expire unseen.
|
|
701
|
+
*/
|
|
702
|
+
private laterFloor;
|
|
485
703
|
/** Record that `tag`'s marker was known from the table at `at`. */
|
|
486
704
|
private known;
|
|
487
705
|
private remember;
|