@opennextjs/cloudflare 0.0.0-88fe982 → 0.0.0-953d0b1

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.
@@ -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<any> {
20
+ async function readFile(path: string, options: unknown): Promise<unknown> {
21
21
  console.log(
22
22
  "readFile",
23
23
  { path, options }
@@ -1,55 +1,76 @@
1
- import Stream from "node:stream";
2
- import type { NextConfig } from "next";
3
- import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node";
4
- import { MockedResponse } from "next/dist/server/lib/mock-request";
5
1
  import NextNodeServer, { NodeRequestHandler } from "next/dist/server/next-server";
2
+ import { NodeNextRequest, NodeNextResponse } from "next/dist/server/base-http/node";
3
+ import { AsyncLocalStorage } from "node:async_hooks";
4
+ import { type CloudflareContext } from "../../api";
6
5
  import type { IncomingMessage } from "node:http";
6
+ import { MockedResponse } from "next/dist/server/lib/mock-request";
7
+ import type { NextConfig } from "next";
8
+ import Stream from "node:stream";
7
9
 
8
10
  const NON_BODY_RESPONSES = new Set([101, 204, 205, 304]);
9
11
 
12
+ const cloudflareContextALS = new AsyncLocalStorage<CloudflareContext>();
13
+
14
+ // Note: this symbol needs to be kept in sync with the one defined in `src/api/get-cloudflare-context.ts`
15
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
16
+ (globalThis as any)[Symbol.for("__cloudflare-context__")] = new Proxy(
17
+ {},
18
+ {
19
+ ownKeys: () => Reflect.ownKeys(cloudflareContextALS.getStore()!),
20
+ getOwnPropertyDescriptor: (_, ...args) =>
21
+ Reflect.getOwnPropertyDescriptor(cloudflareContextALS.getStore()!, ...args),
22
+ get: (_, property) => Reflect.get(cloudflareContextALS.getStore()!, property),
23
+ set: (_, property, value) => Reflect.set(cloudflareContextALS.getStore()!, property, value),
24
+ }
25
+ );
26
+
10
27
  // Injected at build time
11
28
  const nextConfig: NextConfig = JSON.parse(process.env.__NEXT_PRIVATE_STANDALONE_CONFIG ?? "{}");
12
29
 
13
30
  let requestHandler: NodeRequestHandler | null = null;
14
31
 
15
32
  export default {
16
- async fetch(request: Request, env: any, ctx: any) {
17
- if (requestHandler == null) {
18
- globalThis.process.env = { ...globalThis.process.env, ...env };
19
- requestHandler = new NextNodeServer({
20
- conf: { ...nextConfig, env },
21
- customServer: false,
22
- dev: false,
23
- dir: "",
24
- minimalMode: false,
25
- }).getRequestHandler();
26
- }
27
-
28
- const url = new URL(request.url);
29
-
30
- if (url.pathname === "/_next/image") {
31
- let imageUrl =
32
- url.searchParams.get("url") ?? "https://developers.cloudflare.com/_astro/logo.BU9hiExz.svg";
33
- if (imageUrl.startsWith("/")) {
34
- return env.ASSETS.fetch(new URL(imageUrl, request.url));
33
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
34
+ async fetch(request: Request & { cf: IncomingRequestCfProperties }, env: any, ctx: any) {
35
+ return cloudflareContextALS.run({ env, ctx, cf: request.cf }, async () => {
36
+ if (requestHandler == null) {
37
+ globalThis.process.env = { ...globalThis.process.env, ...env };
38
+ requestHandler = new NextNodeServer({
39
+ conf: { ...nextConfig, env },
40
+ customServer: false,
41
+ dev: false,
42
+ dir: "",
43
+ minimalMode: false,
44
+ }).getRequestHandler();
45
+ }
46
+
47
+ const url = new URL(request.url);
48
+
49
+ if (url.pathname === "/_next/image") {
50
+ const imageUrl =
51
+ url.searchParams.get("url") ?? "https://developers.cloudflare.com/_astro/logo.BU9hiExz.svg";
52
+ if (imageUrl.startsWith("/")) {
53
+ return env.ASSETS.fetch(new URL(imageUrl, request.url));
54
+ }
55
+ // @ts-ignore
56
+ return fetch(imageUrl, { cf: { cacheEverything: true } } as unknown);
35
57
  }
36
- return fetch(imageUrl, { cf: { cacheEverything: true } } as any);
37
- }
38
58
 
39
- const { req, res, webResponse } = getWrappedStreams(request, ctx);
59
+ const { req, res, webResponse } = getWrappedStreams(request, ctx);
40
60
 
41
- ctx.waitUntil(requestHandler(new NodeNextRequest(req), new NodeNextResponse(res)));
61
+ ctx.waitUntil(requestHandler(new NodeNextRequest(req), new NodeNextResponse(res)));
42
62
 
43
- return await webResponse();
63
+ return await webResponse();
64
+ });
44
65
  },
45
66
  };
46
67
 
47
- function getWrappedStreams(request: Request, ctx: any) {
68
+ function getWrappedStreams(request: Request, ctx: ExecutionContext) {
48
69
  const url = new URL(request.url);
49
70
 
50
- const req = (
51
- request.body ? Stream.Readable.fromWeb(request.body as any) : Stream.Readable.from([])
52
- ) as IncomingMessage;
71
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
72
+ const reqBody = request.body && Stream.Readable.fromWeb(request.body as any);
73
+ const req = (reqBody ?? Stream.Readable.from([])) as IncomingMessage;
53
74
  req.httpVersion = "1.0";
54
75
  req.httpVersionMajor = 1;
55
76
  req.httpVersionMinor = 0;
@@ -76,7 +97,7 @@ function getWrappedStreams(request: Request, ctx: any) {
76
97
 
77
98
  const res = new MockedResponse({
78
99
  resWriter: (chunk) => {
79
- resBodyWriter.write(typeof chunk === "string" ? Buffer.from(chunk) : chunk).catch((err: any) => {
100
+ resBodyWriter.write(typeof chunk === "string" ? Buffer.from(chunk) : chunk).catch((err) => {
80
101
  if (
81
102
  err.message.includes("WritableStream has been closed") ||
82
103
  err.message.includes("Network connection lost")
@@ -92,6 +113,7 @@ function getWrappedStreams(request: Request, ctx: any) {
92
113
  });
93
114
 
94
115
  // It's implemented as a no-op, but really it should mark the headers as done
116
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
95
117
  res.flushHeaders = () => (res as any).headPromiseResolve();
96
118
 
97
119
  // Only allow statusCode to be modified if not sent
@@ -102,7 +124,6 @@ function getWrappedStreams(request: Request, ctx: any) {
102
124
  },
103
125
  set: function (val) {
104
126
  if (this.finished || this.headersSent) {
105
- console.error("headers already sent");
106
127
  return;
107
128
  }
108
129
  statusCode = val;
@@ -110,6 +131,7 @@ function getWrappedStreams(request: Request, ctx: any) {
110
131
  });
111
132
 
112
133
  // Make sure the writer is eventually closed
134
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
113
135
  ctx.waitUntil((res as any).hasStreamed.finally(() => resBodyWriter.close().catch(() => {})));
114
136
 
115
137
  return {
@@ -121,6 +143,7 @@ function getWrappedStreams(request: Request, ctx: any) {
121
143
  res.setHeader("content-encoding", "identity");
122
144
  return new Response(NON_BODY_RESPONSES.has(res.statusCode) ? null : readable, {
123
145
  status: res.statusCode,
146
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
124
147
  headers: (res as any).headers,
125
148
  });
126
149
  },
package/package.json CHANGED
@@ -1,16 +1,24 @@
1
1
  {
2
2
  "name": "@opennextjs/cloudflare",
3
3
  "description": "Cloudflare builder for next apps",
4
- "version": "0.0.0-88fe982",
5
- "bin": "dist/index.mjs",
4
+ "version": "0.0.0-953d0b1",
5
+ "bin": "dist/cli/index.mjs",
6
+ "main": "./dist/api/index.mjs",
7
+ "types": "./dist/api/index.d.mts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/api/index.mjs",
11
+ "types": "./dist/api/index.d.mts"
12
+ }
13
+ },
6
14
  "files": [
7
15
  "README.md",
8
16
  "dist"
9
17
  ],
10
18
  "repository": {
11
19
  "type": "git",
12
- "url": "https://github.com/flarelabs-net/poc-next.git",
13
- "directory": "builder"
20
+ "url": "https://github.com/opennextjs/opennextjs-cloudflare.git",
21
+ "directory": "packages/cloudflare"
14
22
  },
15
23
  "keywords": [
16
24
  "cloudflare",
@@ -19,23 +27,35 @@
19
27
  ],
20
28
  "license": "MIT",
21
29
  "bugs": {
22
- "url": "https://github.com/flarelabs-net/poc-next/issues"
30
+ "url": "https://github.com/opennextjs/opennextjs-cloudflare/issues"
23
31
  },
24
- "homepage": "https://github.com/flarelabs-net/poc-next",
32
+ "homepage": "https://github.com/opennextjs/opennextjs-cloudflare",
25
33
  "devDependencies": {
34
+ "@cloudflare/workers-types": "^4.20240925.0",
35
+ "@eslint/js": "^9.11.1",
26
36
  "@types/node": "^22.2.0",
27
37
  "esbuild": "^0.23.0",
38
+ "eslint": "^9.11.1",
39
+ "eslint-plugin-unicorn": "^55.0.0",
28
40
  "glob": "^11.0.0",
41
+ "globals": "^15.9.0",
42
+ "next": "14.2.11",
29
43
  "tsup": "^8.2.4",
30
44
  "typescript": "^5.5.4",
45
+ "typescript-eslint": "^8.7.0",
31
46
  "vitest": "^2.1.1"
32
47
  },
33
48
  "dependencies": {
34
49
  "ts-morph": "^23.0.0"
35
50
  },
51
+ "peerDependencies": {
52
+ "wrangler": "^3.78.10"
53
+ },
36
54
  "scripts": {
37
55
  "build": "tsup",
38
56
  "build:watch": "tsup --watch src",
57
+ "lint:check": "eslint",
58
+ "lint:fix": "eslint --fix",
39
59
  "test": "vitest --run",
40
60
  "test:watch": "vitest"
41
61
  }
File without changes