@opennextjs/cloudflare 1.0.3 → 1.0.4
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/dist/api/config.d.ts
CHANGED
|
@@ -46,6 +46,13 @@ interface OpenNextConfig extends AwsOpenNextConfig {
|
|
|
46
46
|
* @default true
|
|
47
47
|
*/
|
|
48
48
|
useWorkerdCondition?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Disable throwing an error when the config validation fails.
|
|
51
|
+
* This is useful for overriding some of the default provided by cloudflare.
|
|
52
|
+
* **USE AT YOUR OWN RISK**
|
|
53
|
+
* @default false
|
|
54
|
+
*/
|
|
55
|
+
dangerousDisableConfigValidation?: boolean;
|
|
49
56
|
};
|
|
50
57
|
}
|
|
51
58
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { debug, error } from "@opennextjs/aws/adapters/logger.js";
|
|
1
|
+
import { debug, error, warn } from "@opennextjs/aws/adapters/logger.js";
|
|
2
2
|
import { FatalError, IgnorableError, isOpenNextError, RecoverableError, } from "@opennextjs/aws/utils/error.js";
|
|
3
3
|
import { DurableObject } from "cloudflare:workers";
|
|
4
4
|
const DEFAULT_MAX_REVALIDATION = 5;
|
|
@@ -47,6 +47,9 @@ export class DOQueueHandler extends DurableObject {
|
|
|
47
47
|
debug(`Durable object initialized`);
|
|
48
48
|
}
|
|
49
49
|
async revalidate(msg) {
|
|
50
|
+
if (this.ongoingRevalidations.size > 2 * this.maxRevalidations) {
|
|
51
|
+
warn(`Your durable object has 2 times the maximum number of revalidations (${this.maxRevalidations}) in progress. If this happens often, you should consider increasing the NEXT_CACHE_DO_QUEUE_MAX_REVALIDATION or the number of durable objects with the MAX_REVALIDATE_CONCURRENCY env var.`);
|
|
52
|
+
}
|
|
50
53
|
// If there is already an ongoing revalidation, we don't need to revalidate again
|
|
51
54
|
if (this.ongoingRevalidations.has(msg.MessageDeduplicationId))
|
|
52
55
|
return;
|
|
@@ -59,19 +62,18 @@ export class DOQueueHandler extends DurableObject {
|
|
|
59
62
|
return;
|
|
60
63
|
if (this.ongoingRevalidations.size >= this.maxRevalidations) {
|
|
61
64
|
debug(`The maximum number of revalidations (${this.maxRevalidations}) is reached. Blocking until one of the revalidations finishes.`);
|
|
62
|
-
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
65
|
+
// TODO: need more investigation
|
|
66
|
+
// We don't use `blockConcurrencyWhile` here because it block the whole durable object for 30 seconds
|
|
67
|
+
// if we exceed the max revalidations too fast
|
|
68
|
+
while (this.ongoingRevalidations.size >= this.maxRevalidations) {
|
|
69
|
+
const ongoingRevalidations = this.ongoingRevalidations.values();
|
|
67
70
|
debug(`Waiting for one of the revalidations to finish`);
|
|
68
71
|
await Promise.race(ongoingRevalidations);
|
|
69
|
-
}
|
|
72
|
+
}
|
|
70
73
|
}
|
|
71
74
|
const revalidationPromise = this.executeRevalidation(msg);
|
|
72
75
|
// We store the promise to dedupe the revalidation
|
|
73
76
|
this.ongoingRevalidations.set(msg.MessageDeduplicationId, revalidationPromise);
|
|
74
|
-
// TODO: check if the object stays up during waitUntil so that the internal state is maintained
|
|
75
77
|
this.ctx.waitUntil(revalidationPromise);
|
|
76
78
|
}
|
|
77
79
|
async executeRevalidation(msg) {
|
|
@@ -86,6 +88,7 @@ export class DOQueueHandler extends DurableObject {
|
|
|
86
88
|
"x-prerender-revalidate": process.env.__NEXT_PREVIEW_MODE_ID,
|
|
87
89
|
"x-isr": "1",
|
|
88
90
|
},
|
|
91
|
+
// This one is kind of problematic, it will always show the wall time of the revalidation to `this.revalidationTimeout`
|
|
89
92
|
signal: AbortSignal.timeout(this.revalidationTimeout),
|
|
90
93
|
});
|
|
91
94
|
// Now we need to handle errors from the fetch
|
|
@@ -202,6 +205,7 @@ export class DOQueueHandler extends DurableObject {
|
|
|
202
205
|
// We create the sync table to handle eventually consistent incremental cache
|
|
203
206
|
this.sql.exec("CREATE TABLE IF NOT EXISTS sync (id TEXT PRIMARY KEY, lastSuccess INTEGER, buildId TEXT)");
|
|
204
207
|
// Before doing anything else, we clear the DB for any potential old data
|
|
208
|
+
// TODO: extract this to a function so that it could be called by the user at another time than init
|
|
205
209
|
this.sql.exec("DELETE FROM failed_state WHERE buildId != ?", process.env.__NEXT_BUILD_ID);
|
|
206
210
|
this.sql.exec("DELETE FROM sync WHERE buildId != ?", process.env.__NEXT_BUILD_ID);
|
|
207
211
|
const failedStateCursor = this.sql.exec("SELECT * FROM failed_state");
|
|
@@ -82,9 +82,6 @@ describe("DurableObjectQueue", () => {
|
|
|
82
82
|
expect(queue.ongoingRevalidations.size).toBe(queue.maxRevalidations);
|
|
83
83
|
expect(queue.ongoingRevalidations.has("id6")).toBe(false);
|
|
84
84
|
expect(Array.from(queue.ongoingRevalidations.keys())).toEqual(["id", "id2", "id3", "id4", "id5"]);
|
|
85
|
-
// BlockConcurrencyWhile is called twice here, first time during creation of the object and second time when we try to revalidate
|
|
86
|
-
// @ts-expect-error
|
|
87
|
-
expect(queue.ctx.blockConcurrencyWhile).toHaveBeenCalledTimes(2);
|
|
88
85
|
// Here we await the blocked request to ensure it's resolved
|
|
89
86
|
await blockedReq;
|
|
90
87
|
// We then need to await for the actual revalidation to finish
|
|
@@ -28,7 +28,7 @@ export function ensureCloudflareConfig(config) {
|
|
|
28
28
|
logger.warn("The direct mode queue is not recommended for use in production.");
|
|
29
29
|
}
|
|
30
30
|
if (Object.values(requirements).some((satisfied) => !satisfied)) {
|
|
31
|
-
|
|
31
|
+
const errorMessage = "The `open-next.config.ts` should have a default export like this:\n\n" +
|
|
32
32
|
`{
|
|
33
33
|
default: {
|
|
34
34
|
override: {
|
|
@@ -52,6 +52,11 @@ export function ensureCloudflareConfig(config) {
|
|
|
52
52
|
queue: "dummy" | "direct" | function,
|
|
53
53
|
},
|
|
54
54
|
},
|
|
55
|
-
}\n\n`.replace(/^ {8}/gm, "")
|
|
55
|
+
}\n\n`.replace(/^ {8}/gm, "");
|
|
56
|
+
if (config.cloudflare?.dangerousDisableConfigValidation) {
|
|
57
|
+
logger.warn(errorMessage);
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
throw new Error(errorMessage);
|
|
56
61
|
}
|
|
57
62
|
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@opennextjs/cloudflare",
|
|
3
3
|
"description": "Cloudflare builder for next apps",
|
|
4
|
-
"version": "1.0.
|
|
4
|
+
"version": "1.0.4",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
7
7
|
"opennextjs-cloudflare": "dist/cli/index.js"
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"homepage": "https://github.com/opennextjs/opennextjs-cloudflare",
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@dotenvx/dotenvx": "1.31.0",
|
|
46
|
-
"@opennextjs/aws": "^3.6.
|
|
46
|
+
"@opennextjs/aws": "^3.6.2",
|
|
47
47
|
"enquirer": "^2.4.1",
|
|
48
48
|
"glob": "^11.0.0",
|
|
49
49
|
"ts-tqdm": "^0.8.6"
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"@tsconfig/strictest": "^2.0.5",
|
|
55
55
|
"@types/mock-fs": "^4.13.4",
|
|
56
56
|
"@types/node": "^22.2.0",
|
|
57
|
-
"esbuild": "^0.
|
|
57
|
+
"esbuild": "^0.25.4",
|
|
58
58
|
"eslint": "^9.11.1",
|
|
59
59
|
"eslint-plugin-import": "^2.31.0",
|
|
60
60
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|