8000 Sync with aws for 3.6 and composable cache (#613) · opennextjs/opennextjs-cloudflare@2d82fad · GitHub
[go: up one dir, main page]

Skip to content

Commit 2d82fad

Browse files
authored
Sync with aws for 3.6 and composable cache (#613)
* bump aws and fix for composable cache * bug fix * changeset and lint fix * lint fix * review fix * lint fix * bump aws to 3.6.0 * lint fix
1 parent f129602 commit 2d82fad

File tree

20 files changed

+414
-209
lines changed
  • cli
  • 20 files changed

    +414
    -209
    lines changed

    .changeset/grumpy-dingos-pretend.md

    Lines changed: 33 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -0,0 +1,33 @@
    1+
    ---
    2+
    "@opennextjs/cloudflare": minor
    3+
    ---
    4+
    5+
    Bump aws to 3.6.0
    6+
    7+
    Introduce support for the composable cache
    8+
    9+
    BREAKING CHANGE: The interface for the Incremental cache has changed. The new interface use a Cache type instead of a boolean to distinguish between the different types of caches. It also includes a new Cache type for the composable cache. The new interface is as follows:
    10+
    11+
    ```ts
    12+
    export type CacheEntryType = "cache" | "fetch" | "composable";
    13+
    14+
    export type IncrementalCache = {
    15+
    get<CacheType extends CacheEntryType = "cache">(
    16+
    key: string,
    17+
    cacheType?: CacheType
    18+
    ): Promise<WithLastModified<CacheValue<CacheType>> | null>;
    19+
    set<CacheType extends CacheEntryType = "cache">(
    20+
    key: string,
    21+
    value: CacheValue<CacheType>,
    22+
    isFetch?: CacheType
    23+
    ): Promise<void>;
    24+
    delete(key: string): Promise<void>;
    25+
    name: string;
    26+
    };
    27+
    ```
    28+
    29+
    NextModeTagCache also get a new function `getLastRevalidated` used for the composable cache:
    30+
    31+
    ```ts
    32+
    getLastRevalidated(tags: string[]): Promise<number>;
    33+
    ```

    packages/cloudflare/package.json

    Lines changed: 1 addition & 1 deletion
    Original file line numberDiff line numberDiff line change
    @@ -53,7 +53,7 @@
    5353
    "homepage": "https://github.com/opennextjs/opennextjs-cloudflare",
    5454
    "dependencies": {
    5555
    "@dotenvx/dotenvx": "catalog:",
    56-
    "@opennextjs/aws": "3.5.8",
    56+
    "@opennextjs/aws": "3.6.0",
    5757
    "enquirer": "^2.4.1",
    5858
    "glob": "catalog:",
    5959
    "ts-tqdm": "^0.8.6"

    packages/cloudflare/src/api/durable-objects/sharded-tag-cache.ts

    Lines changed: 18 additions & 0 deletions
    Original file line numberDiff line numberDiff line change
    @@ -11,6 +11,24 @@ export class DOShardedTagCache extends DurableObject<CloudflareEnv> {
    1111
    });
    1212
    }
    1313

    14+
    async getLastRevalidated(tags: string[]): Promise<number> {
    15+
    try {
    16+
    const result = this.sql
    17+
    .exec(
    18+
    `SELECT MAX(revalidatedAt) AS time FROM revalidations WHERE tag IN (${tags.map(() => "?").join(", ")})`,
    19+
    ...tags
    20+
    )
    21+
    .toArray();
    22+
    if (result.length === 0) return 0;
    23+
    // We only care about the most recent revalidation
    24+
    return result[0]?.time as number;
    25+
    } catch (e) {
    26+
    console.error(e);
    27+
    // By default we don't want to crash here, so we return 0
    28+
    return 0;
    29+
    }
    30+
    }
    31+
    1432
    async hasBeenRevalidated(tags: string[], lastModified?: number): Promise<boolean> {
    1533
    return (
    1634
    this.sql

    packages/cloudflare/src/api/overrides/incremental-cache/kv-incremental-cache.ts

    < F438 button class="Button Button--iconOnly Button--invisible flex-shrink-0 js-expand-all-difflines-button" aria-label="Expand all lines: packages/cloudflare/src/api/overrides/incremental-cache/kv-incremental-cache.ts" data-file-path="packages/cloudflare/src/api/overrides/incremental-cache/kv-incremental-cache.ts" aria-describedby=":R13edlab:">
    Lines changed: 18 additions & 15 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,5 +1,10 @@
    11
    import { error } from "@opennextjs/aws/adapters/logger.js";
    2-
    import type { CacheValue, IncrementalCache, WithLastModified } from "@opennextjs/aws/types/overrides.js";
    2+
    import type {
    3+
    CacheEntryType,
    4+
    CacheValue,
    5+
    IncrementalCache,
    6+
    WithLastModified,
    7+
    } from "@opennextjs/aws/types/overrides.js";
    38
    import { IgnorableError } from "@opennextjs/aws/utils/error.js";
    49

    510
    import { getCloudflareContext } from "../../cloudflare-context.js";
    @@ -24,20 +29,17 @@ export const PREFIX_ENV_NAME = "NEXT_INC_CACHE_KV_PREFIX";
    2429
    class KVIncrementalCache implements IncrementalCache {
    2530
    readonly name = NAME;
    2631

    27-
    async get<IsFetch extends boolean = false>(
    32+
    async get<CacheType extends CacheEntryType = "cache">(
    2833
    key: string,
    29-
    isFetch?: IsFetch
    30-
    ): Promise<WithLastModified<CacheValue<IsFetch>> | null> {
    34+
    cacheType?: CacheType
    35+
    ): Promise<WithLastModified<CacheValue<CacheType>> | null> {
    3136
    const kv = getCloudflareContext().env[BINDING_NAME];
    3237
    if (!kv) throw new IgnorableError("No KV Namespace");
    3338

    3439
    debugCache(`Get ${key}`);
    3540

    3641
    try {
    37-
    const entry = await kv.get<IncrementalCacheEntry<IsFetch> | CacheValue<IsFetch>>(
    38-
    this.getKVKey(key, isFetch),
    39-
    "json"
    40-
    );
    42+
    const entry = await kv.get<IncrementalCacheEntry<CacheType>>(this.getKVKey(key, cacheType), "json");
    4143

    4244
    if (!entry) return null;
    4345

    @@ -56,10 +58,10 @@ class KVIncrementalCache implements IncrementalCache {
    5658
    }
    5759
    }
    5860

    59-
    async set<IsFetch extends boolean = false>(
    61+
    async set<CacheType extends CacheEntryType = "cache">(
    6062
    key: string,
    61-
    value: CacheValue<IsFetch>,
    62-
    isFetch?: IsFetch
    63+
    value: CacheValue<CacheType>,
    64+
    cacheType?: CacheType
    6365
    ): Promise<void> {
    6466
    const kv = getCloudflareContext().env[BINDING_NAME];
    6567
    if (!kv) throw new IgnorableError("No KV Namespace");
    @@ -68,7 +70,7 @@ class KVIncrementalCache implements IncrementalCache {
    6870

    6971
    try {
    7072
    await kv.put(
    71-
    this.getKVKey(key, isFetch),
    73+
    this.getKVKey(key, cacheType),
    7274
    JSON.stringify({
    7375
    value,
    7476
    // Note: `Date.now()` returns the time of the last IO rather than the actual time.
    @@ -90,17 +92,18 @@ class KVIncrementalCache implements IncrementalCache {
    9092
    debugCache(`Delete ${key}`);
    9193

    9294
    try {
    93-
    await kv.delete(this.getKVKey(key, /* isFetch= */ false));
    95+
    // Only cache that gets deleted is the ISR/SSG cache.
    96+
    await kv.delete(this.getKVKey(key, "cache"));
    9497
    } catch (e) {
    9598
    error("Failed to delete from cache", e);
    9699
    }
    97100
    }
    98101

    99-
    protected getKVKey(key: string, isFetch?: boolean): string {
    102+
    protected getKVKey(key: string, cacheType?: CacheEntryType): string {
    100103
    return computeCacheKey(key, {
    101104
    prefix: getCloudflareContext().env[PREFIX_ENV_NAME],
    102105
    buildId: process.env.NEXT_BUILD_ID,
    103-
    isFetch,
    106+
    cacheType,
    104107
    });
    105108
    }
    106109
    }

    packages/cloudflare/src/api/overrides/incremental-cache/r2-incremental-cache.ts

    Lines changed: 16 additions & 11 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,5 +1,10 @@
    11
    import { error } from "@opennextjs/aws/adapters/logger.js";
    2-
    import type { CacheValue, IncrementalCache, WithLastModified } from "@opennextjs/aws/types/overrides.js";
    2+
    import type {
    3+
    CacheEntryType,
    4+
    CacheValue,
    5+
    IncrementalCache,
    6+
    WithLastModified,
    7+
    } from "@opennextjs/aws/types/overrides.js";
    38
    import { IgnorableError } from "@opennextjs/aws/utils/error.js";
    49

    510
    import { getCloudflareContext } from "../../cloudflare-context.js";
    @@ -21,17 +26,17 @@ export const PREFIX_ENV_NAME = "NEXT_INC_CACHE_R2_PREFIX";
    2126
    class R2IncrementalCache implements IncrementalCache {
    2227
    readonly name = NAME;
    2328

    24-
    async get<IsFetch extends boolean = false>(
    29+
    async get<CacheType extends CacheEntryType = "cache">(
    2530
    key: string,
    26-
    isFetch?: IsFetch
    27-
    ): Promise<WithLastModified<CacheValue<IsFetch>> | null> {
    31+
    cacheType?: CacheType
    32+
    ): Promise<WithLastModified<CacheValue<CacheType>> | null> {
    2833
    const r2 = getCloudflareContext().env[BINDING_NAME];
    2934
    if (!r2) throw new IgnorableError("No R2 bucket");
    3035

    3136
    debugCache(`Get ${key}`);
    3237

    3338
    try {
    34-
    const r2Object = await r2.get(this.getR2Key(key, isFetch));
    39+
    const r2Object = await r2.get(this.getR2Key(key, cacheType));
    3540
    if (!r2Object) return null;
    3641

    3742
    return {
    @@ -44,18 +49,18 @@ class R2IncrementalCache implements IncrementalCache {
    4449
    }
    4550
    }
    4651

    47-
    async set<IsFetch extends boolean = false>(
    52+
    async set<CacheType extends CacheEntryType = "cache">(
    4853
    key: string,
    49-
    value: CacheValue<IsFetch>,
    50-
    isFetch?: IsFetch
    54+
    value: CacheValue<CacheType>,
    55+
    cacheType?: CacheType
    5156
    ): Promise<void> {
    5257
    const r2 = getCloudflareContext().env[BINDING_NAME];
    5358
    if (!r2) throw new IgnorableError("No R2 bucket");
    5459

    5560
    debugCache(`Set ${key}`);
    5661

    5762
    try {
    58-
    await r2.put(this.getR2Key(key, isFetch), JSON.stringify(value));
    63+
    await r2.put(this.getR2Key(key, cacheType), JSON.stringify(value));
    5964
    } catch (e) {
    6065
    error("Failed to set to cache", e);
    6166
    }
    @@ -74,11 +79,11 @@ class R2IncrementalCache implements IncrementalCache {
    7479
    }
    7580
    }
    7681

    77-
    protected getR2Key(key: string, isFetch?: boolean): string {
    82+
    protected getR2Key(key: string, cacheType?: CacheEntryType): string {
    7883
    return computeCacheKey(key, {
    7984
    prefix: getCloudflareContext().env[PREFIX_ENV_NAME],
    8085
    buildId: process.env.NEXT_BUILD_ID,
    81-
    isFetch,
    86+
    cacheType,
    8287
    });
    8388
    }
    8489
    }

    packages/cloudflare/src/api/overrides/incremental-cache/regional-cache.ts

    Lines changed: 31 additions & 23 deletions
    Original file line numberDiff line numberDiff line change
    @@ -1,5 +1,10 @@
    11
    import { error } from "@opennextjs/aws/adapters/logger.js";
    2-
    import { CacheValue, IncrementalCache, WithLastModified } from "@opennextjs/aws/types/overrides.js";
    2+
    import {
    3+
    CacheEntryType,
    4+
    CacheValue,
    5+
    IncrementalCache,
    6+
    WithLastModified,
    7+
    } from "@opennextjs/aws/types/overrides.js";
    38

    49
    import { getCloudflareContext } from "../../cloudflare-context.js";
    510
    import { debugCache, FALLBACK_BUILD_ID, IncrementalCacheEntry } from "../internal.js";
    @@ -37,8 +42,8 @@ type Options = {
    3742

    3843
    interface PutToCacheInput {
    3944
    key: string;
    40-
    isFetch: boolean | undefined;
    41-
    entry: IncrementalCacheEntry<boolean>;
    45+
    cacheType?: CacheEntryType;
    46+
    entry: IncrementalCacheEntry<CacheEntryType>;
    4247
    }
    4348

    4449
    /**
    @@ -60,13 +65,13 @@ class RegionalCache implements IncrementalCache {
    6065
    this.opts.shouldLazilyUpdateOnCacheHit ??= this.opts.mode === "long-lived";
    6166
    }
    6267

    63-
    async get<IsFetch extends boolean = false>(
    68+
    async get<CacheType extends CacheEntryType = "cache">(
    6469
    key: string,
    65-
    isFetch?: IsFetch
    66-
    ): Promise<WithLastModified<CacheValue<IsFetch>> | null> {
    70+
    cacheType?: CacheType
    71+
    ): Promise<WithLastModified<CacheValue<CacheType>> | null> {
    6772
    try {
    6873
    const cache = await this.getCacheInstance();
    69-
    const urlKey = this.getCacheUrlKey(key, isFetch);
    74+
    const urlKey = this.getCacheUrlKey(key, cacheType);
    7075

    7176
    // Check for a cached entry as this will be faster than the store response.
    7277
    const cachedResponse = await cache.match(urlKey);
    @@ -76,11 +81,11 @@ class RegionalCache implements IncrementalCache {
    7681
    // Re-fetch from the store and update the regional cache in the background
    7782
    if (this.opts.shouldLazilyUpdateOnCacheHit) {
    7883
    getCloudflareContext().ctx.waitUntil(
    79-
    this.store.get(key, isFetch).then(async (rawEntry) => {
    84+
    this.store.get(key, cacheType).then(async (rawEntry) => {
    8085
    const { value, lastModified } = rawEntry ?? {};
    8186

    8287
    if (value && typeof lastModified === "number") {
    83-
    await this.putToCache({ key, isFetch, entry: { value, lastModified } });
    88+
    await this.putToCache({ key, cacheType, entry: { value, lastModified } });
    8489
    }
    8590
    })
    8691
    );
    @@ -89,12 +94,14 @@ class RegionalCache implements IncrementalCache {
    8994
    return cachedResponse.json();
    9095
    }
    9196

    92-
    const rawEntry = await this.store.get(key, isFetch);
    97+
    const rawEntry = await this.store.get(key, cacheType);
    9398
    const { value, lastModified } = rawEntry ?? {};
    9499
    if (!value || typeof lastModified !== "number") return null;
    95100

    96101
    // Update the locale cache after retrieving from the store.
    97-
    getCloudflareContext().ctx.waitUntil(this.putToCache({ key, isFetch, entry: { value, lastModified } }));
    102+
    getCloudflareContext().ctx.waitUntil(
    103+
    this.putToCache({ key, cacheType, entry: { value, lastModified } })
    104+
    );
    98105

    99106
    return { value, lastModified };
    100107
    } catch (e) {
    @@ -103,17 +110,17 @@ class RegionalCache implements IncrementalCache {
    103110
    }
    104111
    }
    105112

    106-
    async set<IsFetch extends boolean = false>(
    113+
    async set<CacheType extends CacheEntryType = "cache">(
    107114
    key: string,
    108-
    value: CacheValue<IsFetch>,
    109-
    isFetch?: IsFetch
    115+
    value: CacheValue<CacheType>,
    116+
    cacheType?: CacheType
    110117
    ): Promise<void> {
    111118
    try {
    112-
    await this.store.set(key, value, isFetch);
    119+
    await this.store.set(key, value, cacheType);
    113120

    114121
    await this.putToCache({
    115122
    key,
    116-
    isFetch,
    123+
    cacheType,
    117124
    entry: {
    118125
    value,
    119126
    // Note: `Date.now()` returns the time of the last IO rather tha 10000 n the actual time.
    @@ -144,15 +151,13 @@ class RegionalCache implements IncrementalCache {
    144151
    return this.localCache;
    145152
    }
    146153

    147-
    protected getCacheUrlKey(key: string, isFetch?: boolean) {
    154+
    protected getCacheUrlKey(key: string, cacheType?: CacheEntryType) {
    148155
    const buildId = process.env.NEXT_BUILD_ID ?? FALLBACK_BUILD_ID;
    149-
    return (
    150-
    "http://cache.local" + `/${buildId}/${key}`.replace(/\/+/g, "/") + `.${isFetch ? "fetch" : "cache"}`
    151-
    );
    156+
    return "http://cache.local" + `/${buildId}/${key}`.replace(/\/+/g, "/") + `.${cacheType ?? "cache"}`;
    152157
    }
    153158

    154-
    protected async putToCache({ key, isFetch, entry }: PutToCacheInput): Promise<void> {
    155-
    const urlKey = this.getCacheUrlKey(key, isFetch);
    159+
    protected async putToCache({ key, cacheType, entry }: PutToCacheInput): Promise<void> {
    160+
    const urlKey = this.getCacheUrlKey(key, cacheType);
    156161
    const cache = await this.getCacheInstance();
    157162

    158163
    const age =
    @@ -209,7 +214,7 @@ export function withRegionalCache(cache: IncrementalCache, opts: Options) {
    209214
    /**
    210215
    * Extract the list of tags from a cache entry.
    211216
    */
    212-
    function getTagsFromCacheEntry(entry: IncrementalCacheEntry<boolean>): string[] | undefined {
    217+
    function getTagsFromCacheEntry(entry: IncrementalCacheEntry<CacheEntryType>): string[] | undefined {
    213218
    if ("tags" in entry.value && entry.value.tags) {
    214219
    return entry.value.tags;
    215220
    }
    @@ -225,4 +230,7 @@ function getTagsFromCacheEntry(entry: IncrementalCacheEntry<boolean>): string[]
    225230
    return rawTags.split(",");
    226231
    }
    227232
    }
    233+
    if ("value" in entry.value) {
    234+
    return entry.value.tags;
    235+
    }
    228236
    }

    0 commit comments

    Comments
     (0)
    0