@opennextjs/cloudflare 0.0.0-e62af72 → 0.0.3
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/README.md +53 -8
- package/dist/api/get-cloudflare-context.d.mts +1 -1
- package/dist/cli/cache-handler/index.mjs +20 -0
- package/dist/cli/chunk-F7LECSR5.mjs +160 -0
- package/dist/cli/index.mjs +493 -332
- package/dist/cli/templates/shims/node-fs.ts +1 -1
- package/dist/cli/templates/worker.ts +28 -17
- package/package.json +13 -3
- package/dist/cli/cache-handler.mjs +0 -48
- package/dist/cli/chunk-UJCSKKID.mjs +0 -30
|
@@ -17,7 +17,7 @@ function existsSync(path: string) {
|
|
|
17
17
|
return FILES.has(path);
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
async function readFile(path: string, options: unknown): Promise<
|
|
20
|
+
async function readFile(path: string, options: unknown): Promise<unknown> {
|
|
21
21
|
console.log(
|
|
22
22
|
"readFile",
|
|
23
23
|
{ path, options }
|
|
@@ -1,17 +1,19 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import Stream from "node:stream";
|
|
3
|
-
import type { NextConfig } from "next";
|
|
1
|
+
import type { ExportedHandler, Fetcher } from "@cloudflare/workers-types";
|
|
4
2
|
import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node";
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
3
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
4
|
+
import type { CloudflareContext } from "../../api";
|
|
7
5
|
import type { IncomingMessage } from "node:http";
|
|
8
|
-
import {
|
|
6
|
+
import { MockedResponse } from "next/dist/server/lib/mock-request";
|
|
7
|
+
import type { NextConfig } from "next";
|
|
8
|
+
import type { NodeRequestHandler } from "next/dist/server/next-server";
|
|
9
|
+
import Stream from "node:stream";
|
|
9
10
|
|
|
10
11
|
const NON_BODY_RESPONSES = new Set([101, 204, 205, 304]);
|
|
11
12
|
|
|
12
13
|
const cloudflareContextALS = new AsyncLocalStorage<CloudflareContext>();
|
|
13
14
|
|
|
14
15
|
// Note: this symbol needs to be kept in sync with the one defined in `src/api/get-cloudflare-context.ts`
|
|
16
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
15
17
|
(globalThis as any)[Symbol.for("__cloudflare-context__")] = new Proxy(
|
|
16
18
|
{},
|
|
17
19
|
{
|
|
@@ -29,12 +31,18 @@ const nextConfig: NextConfig = JSON.parse(process.env.__NEXT_PRIVATE_STANDALONE_
|
|
|
29
31
|
let requestHandler: NodeRequestHandler | null = null;
|
|
30
32
|
|
|
31
33
|
export default {
|
|
32
|
-
async fetch(request
|
|
34
|
+
async fetch(request, env, ctx) {
|
|
33
35
|
return cloudflareContextALS.run({ env, ctx, cf: request.cf }, async () => {
|
|
34
36
|
if (requestHandler == null) {
|
|
35
37
|
globalThis.process.env = { ...globalThis.process.env, ...env };
|
|
38
|
+
// Note: "next/dist/server/next-server" is a cjs module so we have to `require` it not to confuse esbuild
|
|
39
|
+
// (since esbuild can run in projects with different module resolutions)
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
41
|
+
const NextNodeServer = require("next/dist/server/next-server")
|
|
42
|
+
.default as typeof import("next/dist/server/next-server").default;
|
|
43
|
+
|
|
36
44
|
requestHandler = new NextNodeServer({
|
|
37
|
-
conf:
|
|
45
|
+
conf: nextConfig,
|
|
38
46
|
customServer: false,
|
|
39
47
|
dev: false,
|
|
40
48
|
dir: "",
|
|
@@ -45,29 +53,29 @@ export default {
|
|
|
45
53
|
const url = new URL(request.url);
|
|
46
54
|
|
|
47
55
|
if (url.pathname === "/_next/image") {
|
|
48
|
-
|
|
56
|
+
const imageUrl =
|
|
49
57
|
url.searchParams.get("url") ?? "https://developers.cloudflare.com/_astro/logo.BU9hiExz.svg";
|
|
50
58
|
if (imageUrl.startsWith("/")) {
|
|
51
59
|
return env.ASSETS.fetch(new URL(imageUrl, request.url));
|
|
52
60
|
}
|
|
53
|
-
return fetch(imageUrl, { cf: { cacheEverything: true } }
|
|
61
|
+
return fetch(imageUrl, { cf: { cacheEverything: true } });
|
|
54
62
|
}
|
|
55
63
|
|
|
56
64
|
const { req, res, webResponse } = getWrappedStreams(request, ctx);
|
|
57
65
|
|
|
58
|
-
ctx.waitUntil(requestHandler(new NodeNextRequest(req), new NodeNextResponse(res)));
|
|
66
|
+
ctx.waitUntil(Promise.resolve(requestHandler(new NodeNextRequest(req), new NodeNextResponse(res))));
|
|
59
67
|
|
|
60
68
|
return await webResponse();
|
|
61
69
|
});
|
|
62
70
|
},
|
|
63
|
-
}
|
|
71
|
+
} as ExportedHandler<{ ASSETS: Fetcher }>;
|
|
64
72
|
|
|
65
|
-
function getWrappedStreams(request: Request, ctx:
|
|
73
|
+
function getWrappedStreams(request: Request, ctx: ExecutionContext) {
|
|
66
74
|
const url = new URL(request.url);
|
|
67
75
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
) as IncomingMessage;
|
|
76
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
77
|
+
const reqBody = request.body && Stream.Readable.fromWeb(request.body as any);
|
|
78
|
+
const req = (reqBody ?? Stream.Readable.from([])) as IncomingMessage;
|
|
71
79
|
req.httpVersion = "1.0";
|
|
72
80
|
req.httpVersionMajor = 1;
|
|
73
81
|
req.httpVersionMinor = 0;
|
|
@@ -94,7 +102,7 @@ function getWrappedStreams(request: Request, ctx: any) {
|
|
|
94
102
|
|
|
95
103
|
const res = new MockedResponse({
|
|
96
104
|
resWriter: (chunk) => {
|
|
97
|
-
resBodyWriter.write(typeof chunk === "string" ? Buffer.from(chunk) : chunk).catch((err
|
|
105
|
+
resBodyWriter.write(typeof chunk === "string" ? Buffer.from(chunk) : chunk).catch((err) => {
|
|
98
106
|
if (
|
|
99
107
|
err.message.includes("WritableStream has been closed") ||
|
|
100
108
|
err.message.includes("Network connection lost")
|
|
@@ -110,6 +118,7 @@ function getWrappedStreams(request: Request, ctx: any) {
|
|
|
110
118
|
});
|
|
111
119
|
|
|
112
120
|
// It's implemented as a no-op, but really it should mark the headers as done
|
|
121
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
113
122
|
res.flushHeaders = () => (res as any).headPromiseResolve();
|
|
114
123
|
|
|
115
124
|
// Only allow statusCode to be modified if not sent
|
|
@@ -127,6 +136,7 @@ function getWrappedStreams(request: Request, ctx: any) {
|
|
|
127
136
|
});
|
|
128
137
|
|
|
129
138
|
// Make sure the writer is eventually closed
|
|
139
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
130
140
|
ctx.waitUntil((res as any).hasStreamed.finally(() => resBodyWriter.close().catch(() => {})));
|
|
131
141
|
|
|
132
142
|
return {
|
|
@@ -138,6 +148,7 @@ function getWrappedStreams(request: Request, ctx: any) {
|
|
|
138
148
|
res.setHeader("content-encoding", "identity");
|
|
139
149
|
return new Response(NON_BODY_RESPONSES.has(res.statusCode) ? null : readable, {
|
|
140
150
|
status: res.statusCode,
|
|
151
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
141
152
|
headers: (res as any).headers,
|
|
142
153
|
});
|
|
143
154
|
},
|
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": "0.0.
|
|
4
|
+
"version": "0.0.3",
|
|
5
5
|
"bin": "dist/cli/index.mjs",
|
|
6
6
|
"main": "./dist/api/index.mjs",
|
|
7
7
|
"types": "./dist/api/index.d.mts",
|
|
@@ -31,24 +31,34 @@
|
|
|
31
31
|
},
|
|
32
32
|
"homepage": "https://github.com/opennextjs/opennextjs-cloudflare",
|
|
33
33
|
"devDependencies": {
|
|
34
|
-
"@cloudflare/workers-types": "^4.
|
|
34
|
+
"@cloudflare/workers-types": "^4.20240925.0",
|
|
35
|
+
"@eslint/js": "^9.11.1",
|
|
36
|
+
"@tsconfig/strictest": "^2.0.5",
|
|
35
37
|
"@types/node": "^22.2.0",
|
|
36
38
|
"esbuild": "^0.23.0",
|
|
39
|
+
"eslint": "^9.11.1",
|
|
40
|
+
"eslint-plugin-unicorn": "^55.0.0",
|
|
37
41
|
"glob": "^11.0.0",
|
|
42
|
+
"globals": "^15.9.0",
|
|
38
43
|
"next": "14.2.11",
|
|
44
|
+
"package-manager-detector": "^0.2.0",
|
|
39
45
|
"tsup": "^8.2.4",
|
|
40
46
|
"typescript": "^5.5.4",
|
|
47
|
+
"typescript-eslint": "^8.7.0",
|
|
41
48
|
"vitest": "^2.1.1"
|
|
42
49
|
},
|
|
43
50
|
"dependencies": {
|
|
44
51
|
"ts-morph": "^23.0.0"
|
|
45
52
|
},
|
|
46
53
|
"peerDependencies": {
|
|
47
|
-
"wrangler": "^3.78.
|
|
54
|
+
"wrangler": "^3.78.10"
|
|
48
55
|
},
|
|
49
56
|
"scripts": {
|
|
50
57
|
"build": "tsup",
|
|
51
58
|
"build:watch": "tsup --watch src",
|
|
59
|
+
"lint:check": "eslint",
|
|
60
|
+
"lint:fix": "eslint --fix",
|
|
61
|
+
"ts:check": "tsc --noEmit",
|
|
52
62
|
"test": "vitest --run",
|
|
53
63
|
"test:watch": "vitest"
|
|
54
64
|
}
|
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
import "./chunk-UJCSKKID.mjs";
|
|
2
|
-
|
|
3
|
-
// src/cli/cache-handler.ts
|
|
4
|
-
var CfWorkersKvCacheHandler = class _CfWorkersKvCacheHandler {
|
|
5
|
-
constructor(ctx) {
|
|
6
|
-
this.ctx = ctx;
|
|
7
|
-
}
|
|
8
|
-
static maybeKVNamespace = void 0;
|
|
9
|
-
async get(key) {
|
|
10
|
-
if (_CfWorkersKvCacheHandler.maybeKVNamespace === void 0) {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
console.log(`[Cf] Getting cache[${key}]`);
|
|
14
|
-
try {
|
|
15
|
-
return await _CfWorkersKvCacheHandler.maybeKVNamespace.get(key, "json") ?? null;
|
|
16
|
-
} catch (e) {
|
|
17
|
-
console.error(`Failed to get value for key = ${key}: ${e}`);
|
|
18
|
-
return null;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
async set(key, entry, ctx) {
|
|
22
|
-
if (_CfWorkersKvCacheHandler.maybeKVNamespace === void 0) {
|
|
23
|
-
return;
|
|
24
|
-
}
|
|
25
|
-
console.log(`[Cf] Setting cache[${key}]`);
|
|
26
|
-
try {
|
|
27
|
-
const data = {
|
|
28
|
-
lastModified: Date.now(),
|
|
29
|
-
value: entry
|
|
30
|
-
};
|
|
31
|
-
await _CfWorkersKvCacheHandler.maybeKVNamespace.put(key, JSON.stringify(data));
|
|
32
|
-
} catch (e) {
|
|
33
|
-
console.error(`Failed to set value for key = ${key}: ${e}`);
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
async revalidateTag(tags) {
|
|
37
|
-
if (_CfWorkersKvCacheHandler.maybeKVNamespace === void 0) {
|
|
38
|
-
return;
|
|
39
|
-
}
|
|
40
|
-
tags = [tags].flat();
|
|
41
|
-
console.log(`[Cf] revalidateTag ${JSON.stringify(tags)}}`);
|
|
42
|
-
}
|
|
43
|
-
resetRequestCache() {
|
|
44
|
-
}
|
|
45
|
-
};
|
|
46
|
-
export {
|
|
47
|
-
CfWorkersKvCacheHandler as default
|
|
48
|
-
};
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
var __create = Object.create;
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __getProtoOf = Object.getPrototypeOf;
|
|
6
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
-
var __commonJS = (cb, mod) => function __require() {
|
|
8
|
-
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
19
|
-
// If the importer is in node compatibility mode or this is not an ESM
|
|
20
|
-
// file that has been converted to a CommonJS file using a Babel-
|
|
21
|
-
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
22
|
-
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
23
|
-
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
24
|
-
mod
|
|
25
|
-
));
|
|
26
|
-
|
|
27
|
-
export {
|
|
28
|
-
__commonJS,
|
|
29
|
-
__toESM
|
|
30
|
-
};
|