Skip to content

Release 1.0.0-beta.0 #526

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Apr 3, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/bugs/gh-223/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,6 @@
"postcss": "^8.4.49",
"tailwindcss": "^3.4.17",
"typescript": "^5.7.2",
"wrangler": "^3.107.0"
"wrangler": "catalog:"
}
}
4 changes: 2 additions & 2 deletions examples/e2e/app-pages-router/open-next.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
import memoryQueue from "@opennextjs/cloudflare/overrides/queue/memory-queue";

export default defineCloudflareConfig({
incrementalCache: kvIncrementalCache,
incrementalCache: r2IncrementalCache,
queue: memoryQueue,
});
6 changes: 3 additions & 3 deletions examples/e2e/app-pages-router/wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"directory": ".open-next/assets",
"binding": "ASSETS"
},
"kv_namespaces": [
"r2_buckets": [
{
"binding": "NEXT_INC_CACHE_KV",
"id": "<BINDING_ID>"
"binding": "NEXT_INC_CACHE_R2_BUCKET",
"bucket_name": "<BUCKET_NAME>"
}
],
"services": [
Expand Down
7 changes: 3 additions & 4 deletions examples/e2e/app-router/open-next.config.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
import shardedTagCache from "@opennextjs/cloudflare/overrides/tag-cache/do-sharded-tag-cache";
import doQueue from "@opennextjs/cloudflare/overrides/queue/do-queue";

export default defineCloudflareConfig({
incrementalCache: kvIncrementalCache,
incrementalCache: r2IncrementalCache,
// With such a configuration, we could have up to 12 * (8 + 2) = 120 Durable Objects instances
tagCache: shardedTagCache({
baseShardSize: 12,
enableShardReplication: true,
shardReplicationOptions: {
shardReplication: {
numberOfSoftReplicas: 8,
numberOfHardReplicas: 2,
},
Expand Down
10 changes: 5 additions & 5 deletions examples/e2e/app-router/wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"bindings": [
{
"name": "NEXT_CACHE_DO_QUEUE",
"class_name": "DurableObjectQueueHandler"
"class_name": "DOQueueHandler"
},
{
"name": "NEXT_TAG_CACHE_DO_SHARDED",
Expand All @@ -23,13 +23,13 @@
"migrations": [
{
"tag": "v1",
"new_sqlite_classes": ["DurableObjectQueueHandler", "DOShardedTagCache"]
"new_sqlite_classes": ["DOQueueHandler", "DOShardedTagCache"]
}
],
"kv_namespaces": [
"r2_buckets": [
{
"binding": "NEXT_INC_CACHE_KV",
"id": "<BINDING_ID>"
"binding": "NEXT_INC_CACHE_R2_BUCKET",
"bucket_name": "<BUCKET_NAME>"
}
],
"services": [
Expand Down
4 changes: 2 additions & 2 deletions examples/e2e/pages-router/open-next.config.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import kvIncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/kv-incremental-cache";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
import memoryQueue from "@opennextjs/cloudflare/overrides/queue/memory-queue";

export default defineCloudflareConfig({
incrementalCache: kvIncrementalCache,
incrementalCache: r2IncrementalCache,
queue: memoryQueue,
});
6 changes: 3 additions & 3 deletions examples/e2e/pages-router/wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
"directory": ".open-next/assets",
"binding": "ASSETS"
},
"kv_namespaces": [
"r2_buckets": [
{
"binding": "NEXT_INC_CACHE_KV",
"id": "<BINDING_ID>"
"binding": "NEXT_INC_CACHE_R2_BUCKET",
"bucket_name": "<BUCKET_NAME>"
}
],
"services": [
Expand Down
4 changes: 2 additions & 2 deletions examples/overrides/r2-incremental-cache/open-next.config.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { defineCloudflareConfig } from "@opennextjs/cloudflare";
import d1TagCache from "@opennextjs/cloudflare/overrides/tag-cache/d1-tag-cache";
import d1NextTagCache from "@opennextjs/cloudflare/overrides/tag-cache/d1-next-tag-cache";
import memoryQueue from "@opennextjs/cloudflare/overrides/queue/memory-queue";
import r2IncrementalCache from "@opennextjs/cloudflare/overrides/incremental-cache/r2-incremental-cache";
import { withRegionalCache } from "@opennextjs/cloudflare/overrides/incremental-cache/regional-cache";
Expand All @@ -9,6 +9,6 @@ export default defineCloudflareConfig({
mode: "long-lived",
shouldLazilyUpdateOnCacheHit: true,
}),
tagCache: d1TagCache,
tagCache: d1NextTagCache,
queue: memoryQueue,
});
3 changes: 1 addition & 2 deletions examples/overrides/r2-incremental-cache/wrangler.jsonc
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@
"r2_buckets": [
{
"binding": "NEXT_INC_CACHE_R2_BUCKET",
"bucket_name": "NEXT_INC_CACHE_R2_BUCKET",
"preview_bucket_name": "NEXT_INC_CACHE_R2_BUCKET"
"bucket_name": "NEXT_INC_CACHE_R2_BUCKET"
}
]
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "opennextjs-cloudflare",
"version": "0.0.0.0",
"version": "0.0.0",
"private": true,
"devDependencies": {
"@changesets/changelog-github": "^0.5.0",
Expand Down
17 changes: 17 additions & 0 deletions packages/cloudflare/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
# @opennextjs/cloudflare

## 1.0.0-beta.0

### Minor Changes

- [#526](https://github.com/opennextjs/opennextjs-cloudflare/pull/526) [`8b40268`](https://github.com/opennextjs/opennextjs-cloudflare/commit/8b40268a328f43ee7dfc8fc68bcf14badc0650ca) Thanks [@vicb](https://github.com/vicb)! - Prepare for release 1.0.0-beta.0

Bump `@opennextjs/aws` to 3.5.4

BREAKING CHANGES

- `DurableObjectQueueHandler` renamed to `DOQueueHandler`
- `NEXT_CACHE_DO_QUEUE_MAX_NUM_REVALIDATIONS` renamed to `NEXT_CACHE_DO_QUEUE_MAX_RETRIES`
- `D1TagCache` has been removed, use `D1NextModeTagCache` instead.
- The `enableShardReplication` and `shardReplicationOptions` options passed to `ShardedDOTagCache`
have been folded into `shardReplication`. A value for `shardReplication` must be specified to enable
replications. The value must be an object with the number of soft and hard replicas.

## 0.6.6

### Patch Changes
Expand Down
6 changes: 3 additions & 3 deletions packages/cloudflare/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@opennextjs/cloudflare",
"description": "Cloudflare builder for next apps",
"version": "0.6.6",
"version": "1.0.0-beta.0",
"type": "module",
"scripts": {
"clean": "rimraf dist",
Expand Down Expand Up @@ -37,7 +37,7 @@
],
"repository": {
"type": "git",
"url": "https://github.com/opennextjs/opennextjs-cloudflare.git",
"url": "git+https://github.com/opennextjs/opennextjs-cloudflare.git",
"directory": "packages/cloudflare"
},
"keywords": [
Expand All @@ -53,7 +53,7 @@
"homepage": "https://github.com/opennextjs/opennextjs-cloudflare",
"dependencies": {
"@dotenvx/dotenvx": "catalog:",
"@opennextjs/aws": "https://pkg.pr.new/@opennextjs/aws@802",
"@opennextjs/aws": "3.5.4",
"enquirer": "^2.4.1",
"glob": "catalog:"
},
Expand Down
6 changes: 3 additions & 3 deletions packages/cloudflare/src/api/cloudflare-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import type { Context, RunningCodeOptions } from "node:vm";

import type { GetPlatformProxyOptions } from "wrangler";

import type { DurableObjectQueueHandler } from "./durable-objects/queue";
import type { DOQueueHandler } from "./durable-objects/queue";
import { DOShardedTagCache } from "./durable-objects/sharded-tag-cache";

declare global {
Expand Down Expand Up @@ -35,7 +35,7 @@ declare global {
NEXT_TAG_CACHE_DO_SHARDED_DLQ?: Queue;

// Durable Object namespace to use for the durable object queue
NEXT_CACHE_DO_QUEUE?: DurableObjectNamespace<DurableObjectQueueHandler>;
NEXT_CACHE_DO_QUEUE?: DurableObjectNamespace<DOQueueHandler>;

// Below are the optional environment variables to configure the durable object queue
// The max number of revalidations that can be processed by the durable worker at the same time
Expand All @@ -46,7 +46,7 @@ declare global {
// If it fails again it will exponentially back off until it reaches the max retry interval
NEXT_CACHE_DO_QUEUE_RETRY_INTERVAL_MS?: string;
// The maximum number of attempts that can be made to revalidate a path
NEXT_CACHE_DO_QUEUE_MAX_NUM_REVALIDATIONS?: string;
NEXT_CACHE_DO_QUEUE_MAX_RETRIES?: string;
// Disable SQLite for the durable object queue handler
// This can be safely used if you don't use an eventually consistent incremental cache (i.e. R2 without the regional cache for example)
NEXT_CACHE_DO_QUEUE_DISABLE_SQLITE?: string;
Expand Down
6 changes: 3 additions & 3 deletions packages/cloudflare/src/api/durable-objects/queue.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { describe, expect, it, vi } from "vitest";

import { DurableObjectQueueHandler } from "./queue";
import { DOQueueHandler } from "./queue";

vi.mock("cloudflare:workers", () => ({
DurableObject: class {
Expand Down Expand Up @@ -36,7 +36,7 @@ const createDurableObjectQueue = ({
},
};
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return new DurableObjectQueueHandler(mockState as any, {
return new DOQueueHandler(mockState as any, {
WORKER_SELF_REFERENCE: {
fetch: vi.fn().mockReturnValue(
new Promise<Response>((res) =>
Expand Down Expand Up @@ -198,7 +198,7 @@ describe("DurableObjectQueue", () => {
});

describe("addAlarm", () => {
const getStorage = (queue: DurableObjectQueueHandler): DurableObjectStorage => {
const getStorage = (queue: DOQueueHandler): DurableObjectStorage => {
// @ts-expect-error - ctx is a protected field
return queue.ctx.storage;
};
Expand Down
17 changes: 8 additions & 9 deletions packages/cloudflare/src/api/durable-objects/queue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@ import { DurableObject } from "cloudflare:workers";
const DEFAULT_MAX_REVALIDATION = 5;
const DEFAULT_REVALIDATION_TIMEOUT_MS = 10_000;
const DEFAULT_RETRY_INTERVAL_MS = 2_000;
const DEFAULT_MAX_NUM_REVALIDATIONS = 6;
const DEFAULT_MAX_RETRIES = 6;

interface FailedState {
msg: QueueMessage;
retryCount: number;
nextAlarmMs: number;
}

export class DurableObjectQueueHandler extends DurableObject<CloudflareEnv> {
export class DOQueueHandler extends DurableObject<CloudflareEnv> {
// Ongoing revalidations are deduped by the deduplication id
// Since this is running in waitUntil, we expect the durable object state to persist this during the duration of the revalidation
// TODO: handle incremental cache with only eventual consistency (i.e. KV or R2/D1 with the optional cache layer on top)
Expand All @@ -35,7 +35,7 @@ export class DurableObjectQueueHandler extends DurableObject<CloudflareEnv> {
readonly maxRevalidations: number;
readonly revalidationTimeout: number;
readonly revalidationRetryInterval: number;
readonly maxRevalidationAttempts: number;
readonly maxRetries: number;
readonly disableSQLite: boolean;

constructor(ctx: DurableObjectState, env: CloudflareEnv) {
Expand All @@ -57,9 +57,9 @@ export class DurableObjectQueueHandler extends DurableObject<CloudflareEnv> {
? parseInt(env.NEXT_CACHE_DO_QUEUE_RETRY_INTERVAL_MS)
: DEFAULT_RETRY_INTERVAL_MS;

this.maxRevalidationAttempts = env.NEXT_CACHE_DO_QUEUE_MAX_NUM_REVALIDATIONS
? parseInt(env.NEXT_CACHE_DO_QUEUE_MAX_NUM_REVALIDATIONS)
: DEFAULT_MAX_NUM_REVALIDATIONS;
this.maxRetries = env.NEXT_CACHE_DO_QUEUE_MAX_RETRIES
? parseInt(env.NEXT_CACHE_DO_QUEUE_MAX_RETRIES)
: DEFAULT_MAX_RETRIES;

this.disableSQLite = env.NEXT_CACHE_DO_QUEUE_DISABLE_SQLITE === "true";

Expand Down Expand Up @@ -199,10 +199,9 @@ export class DurableObjectQueueHandler extends DurableObject<CloudflareEnv> {
let updatedFailedState: FailedState;

if (existingFailedState) {
if (existingFailedState.retryCount >= this.maxRevalidationAttempts) {
// We give up after 6 retries and log the error
if (existingFailedState.retryCount >= this.maxRetries) {
error(
`The revalidation for ${msg.MessageBody.host}${msg.MessageBody.url} has failed after 6 retries. It will not be tried again, but subsequent ISR requests will retry.`
`The revalidation for ${msg.MessageBody.host}${msg.MessageBody.url} has failed after ${this.maxRetries} retries. It will not be tried again, but subsequent ISR requests will retry.`
);
this.routeInFailedState.delete(msg.MessageDeduplicationId);
return;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@ export const CACHE_ASSET_DIR = "cdn-cgi/_next_cache";

export const STATUS_DELETED = 1;

export const NAME = "cf-kv-incremental-cache";

/**
* Open Next cache based on cloudflare KV and Assets.
*
* Note: The class is instantiated outside of the request context.
* The cloudflare context and process.env are not initialized yet
* when the constructor is called.
*/
class Cache implements IncrementalCache {
readonly name = "cloudflare-kv";
class KVIncrementalCache implements IncrementalCache {
readonly name = NAME;

async get<IsFetch extends boolean = false>(
key: string,
Expand Down Expand Up @@ -158,4 +160,4 @@ class Cache implements IncrementalCache {
}
}

export default new Cache();
export default new KVIncrementalCache();
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { IgnorableError } from "@opennextjs/aws/utils/error.js";

import { getCloudflareContext } from "../../cloudflare-context.js";

export const NAME = "cf-r2-incremental-cache";

/**
* An instance of the Incremental Cache that uses an R2 bucket (`NEXT_INC_CACHE_R2_BUCKET`) as it's
* underlying data store.
Expand All @@ -12,7 +14,7 @@ import { getCloudflareContext } from "../../cloudflare-context.js";
* environment variable, and defaults to `incremental-cache`.
*/
class R2IncrementalCache implements IncrementalCache {
readonly name = "r2-incremental-cache";
readonly name = NAME;

async get<IsFetch extends boolean = false>(
key: string,
Expand Down
Loading