@edgeone/opennextjs-pages 0.0.6 → 0.0.7

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.
@@ -191,6 +191,16 @@ var copyNextDependencies = async (ctx) => {
191
191
  );
192
192
  }
193
193
  await Promise.all(promises);
194
+ const packageJsonPath = join(ctx.serverHandlerDir, "package.json");
195
+ if (existsSync(packageJsonPath)) {
196
+ try {
197
+ const packageJsonContent = JSON.parse(await readFile(packageJsonPath, "utf-8"));
198
+ packageJsonContent.type = "module";
199
+ await writeFile(packageJsonPath, JSON.stringify(packageJsonContent, null, 2));
200
+ } catch (error) {
201
+ console.warn("Warning: Failed to update package.json with ES module type:", error);
202
+ }
203
+ }
194
204
  const serverHandlerRequire = createRequire(posixJoin(ctx.serverHandlerDir, ":internal:"));
195
205
  if (ctx.nextVersion) {
196
206
  await patchNextModules(ctx, ctx.nextVersion, serverHandlerRequire.resolve);
@@ -98,25 +98,20 @@ var getHandlerFile = async (ctx) => {
98
98
  const templateVariables = {
99
99
  "{{useRegionalBlobs}}": ctx.useRegionalBlobs.toString()
100
100
  };
101
- let runtime_shim = "";
102
- const getRuntimeShim = ctx.getRuntimeShim;
103
- if (getRuntimeShim) {
104
- runtime_shim = getRuntimeShim();
105
- }
106
101
  if (ctx.relativeAppDir.length !== 0) {
107
102
  const template2 = await readFile(join(templatesDir, "handler-monorepo.tmpl.js"), "utf-8");
108
103
  console.log("ctx.lambdaWorkingDirectory", ctx.lambdaWorkingDirectory);
109
104
  console.log("ctx.nextServerHandler", ctx.nextServerHandler);
110
105
  templateVariables["{{cwd}}"] = posixJoin(ctx.lambdaWorkingDirectory);
111
106
  templateVariables["{{nextServerHandler}}"] = posixJoin(ctx.nextServerHandler);
112
- return applyTemplateVariables(runtime_shim + template2, templateVariables);
107
+ return applyTemplateVariables(template2, templateVariables);
113
108
  }
114
109
  const template = await readFile(join(templatesDir, "handler.tmpl.js"), "utf-8");
115
- return applyTemplateVariables(runtime_shim + template, templateVariables);
110
+ return applyTemplateVariables(template, templateVariables);
116
111
  };
117
112
  var writeHandlerFile = async (ctx) => {
118
113
  const handler = await getHandlerFile(ctx);
119
- await writeFile(join(ctx.serverHandlerRootDir, `index.mjs`), handler);
114
+ await writeFile(join(ctx.serverHandlerRootDir, `handler.js`), handler);
120
115
  };
121
116
  var clearStaleServerHandlers = async (ctx) => {
122
117
  await rm(ctx.serverFunctionsDir, { recursive: true, force: true });
@@ -97,27 +97,17 @@ var createRouteMeta = async (ctx) => {
97
97
  path: path2,
98
98
  ...config
99
99
  }));
100
- const edgeOneDir = path.join(process.cwd(), ".edgeone");
101
- if (!fs.existsSync(edgeOneDir)) {
102
- fs.mkdirSync(edgeOneDir, { recursive: true });
100
+ const serverHandlerDir = ctx.serverHandlerDir;
101
+ if (!fs.existsSync(serverHandlerDir)) {
102
+ fs.mkdirSync(serverHandlerDir, { recursive: true });
103
103
  }
104
- const metaFilePath = path.join(edgeOneDir, "meta.json");
105
- let existingMetaData = {};
106
- if (fs.existsSync(metaFilePath)) {
107
- try {
108
- const existingContent = fs.readFileSync(metaFilePath, "utf-8");
109
- existingMetaData = JSON.parse(existingContent);
110
- } catch (error) {
111
- console.warn("Failed to parse existing meta.json:", error);
112
- }
113
- }
114
- const mergedMetaData = {
115
- ...existingMetaData,
104
+ const metaFilePath = path.join(serverHandlerDir, "meta.json");
105
+ const metaData = {
116
106
  nextRoutes: routesArray
117
107
  };
118
108
  fs.writeFileSync(
119
109
  metaFilePath,
120
- JSON.stringify(mergedMetaData, null, 2),
110
+ JSON.stringify(metaData, null, 2),
121
111
  "utf-8"
122
112
  );
123
113
  };
@@ -1,4 +1,3 @@
1
- import { createServer } from 'http';
2
1
  import {
3
2
  createRequestContext,
4
3
  runWithRequestContext,
@@ -6,151 +5,19 @@ import {
6
5
  import { getTracer } from './{{cwd}}/.edgeone/dist/run/handlers/tracer.cjs'
7
6
  import * as serverHandler from './{{cwd}}/.edgeone/dist/run/handlers/server.js'
8
7
 
9
-
10
8
  process.chdir('./{{cwd}}')
11
9
 
12
10
  // Set feature flag for regional blobs
13
11
  process.env.USE_REGIONAL_BLOBS = '{{useRegionalBlobs}}'
14
12
 
15
-
16
- async function handleResponse(res, response, passHeaders = {}) {
17
- const startTime = Date.now();
18
-
19
- // 没有响应 - 404 拦截
20
- if (!response) {
21
- const requestId = passHeaders['functions-request-id'] || '';
22
- res.writeHead(404, {
23
- 'Functions-Request-Id': requestId,
24
- 'eo-pages-inner-scf-status': '404',
25
- 'eo-pages-inner-status-intercept': 'true'
26
- });
27
- res.end(JSON.stringify({
28
- error: "Not Found",
29
- message: "The requested path does not exist"
30
- }));
31
- const endTime = Date.now();
32
- console.log(`Pages response status: 404`);
33
- return;
34
- }
35
-
36
- try {
37
- if (response instanceof Response) {
38
- const requestId = passHeaders['functions-request-id'] || '';
39
- const responseStatus = response.status;
40
-
41
- const headers = Object.fromEntries(response.headers);
42
- Object.assign(headers, passHeaders);
43
-
44
- // 添加状态码区分的 headers
45
- headers['Functions-Request-Id'] = requestId;
46
-
47
- // 如果 Response 中已经设置了,使用它的值;否则使用 responseStatus
48
- if (!headers['eo-pages-inner-scf-status']) {
49
- headers['eo-pages-inner-scf-status'] = String(responseStatus);
50
- }
51
-
52
- // 如果 Response 中已经设置了,使用它的值;否则默认为 false
53
- if (!headers['eo-pages-inner-status-intercept']) {
54
- headers['eo-pages-inner-status-intercept'] = 'false';
55
- }
56
-
57
- if (response.headers.get('eop-client-geo')) {
58
- // 删除 eop-client-geo 头部
59
- response.headers.delete('eop-client-geo');
60
- }
61
- // 处理 set-cookie 头部
62
- if (response.headers.has('set-cookie')) {
63
- const cookieArr = response.headers.getSetCookie();
64
-
65
- headers['set-cookie'] = cookieArr;
66
- }
67
- // 检查是否是流式响应
68
- const isStream = response.body && (
69
- response.headers.get('content-type')?.includes('text/event-stream') ||
70
- response.headers.get('transfer-encoding')?.includes('chunked') ||
71
- response.body instanceof ReadableStream ||
72
- typeof response.body.pipe === 'function' ||
73
- response.headers.get('x-content-type-stream') === 'true'
74
- );
75
-
76
- if (isStream) {
77
- // 设置流式响应所需的头部
78
- const streamHeaders = {
79
- ...headers
80
- };
81
-
82
- if (response.headers.get('content-type')?.includes('text/event-stream')) {
83
- streamHeaders['Content-Type'] = 'text/event-stream';
84
- }
85
-
86
- res.writeHead(response.status, streamHeaders);
87
-
88
- if (typeof response.body.pipe === 'function') {
89
- response.body.pipe(res);
90
- } else {
91
- const reader = response.body.getReader();
92
- try {
93
- while (true) {
94
- const { done, value } = await reader.read();
95
- if (done) break;
96
-
97
- if (value instanceof Uint8Array || Buffer.isBuffer(value)) {
98
- res.write(value);
99
- } else {
100
- const chunk = new TextDecoder().decode(value);
101
- res.write(chunk);
102
- }
103
- }
104
- } finally {
105
- reader.releaseLock();
106
- res.end();
107
- }
108
- }
109
- } else {
110
- // 普通响应
111
- res.writeHead(response.status, headers);
112
- const body = await response.text();
113
- res.end(body);
114
- }
115
- } else {
116
- // 非 Response 对象,直接返回 JSON
117
- const requestId = passHeaders['functions-request-id'] || '';
118
- res.writeHead(200, {
119
- 'Content-Type': 'application/json',
120
- 'Functions-Request-Id': requestId,
121
- 'eo-pages-inner-scf-status': '200',
122
- 'eo-pages-inner-status-intercept': 'false'
123
- });
124
- res.end(JSON.stringify(response));
125
- }
126
- } catch (error) {
127
- // 用户函数内部错误 内部502 - 拦截
128
- const requestId = passHeaders['functions-request-id'] || '';
129
- res.writeHead(502, {
130
- 'Functions-Request-Id': requestId,
131
- 'eo-pages-inner-scf-status': '502',
132
- 'eo-pages-inner-status-intercept': 'true'
133
- });
134
- res.end(JSON.stringify({
135
- error: "Internal Server Error",
136
- message: error.message
137
- }));
138
- } finally {
139
- const endTime = Date.now();
140
- console.log(`Pages response status: ${response?.status || 'unknown'}`);
141
- }
142
- }
143
-
144
-
145
13
  let cachedHandler
146
- export default async function eoHandler (req, context) {
14
+ export default async function handler(req, context = {}) {
147
15
  const requestContext = createRequestContext(req, context)
148
16
  const tracer = getTracer()
149
17
 
150
18
  const handlerResponse = await runWithRequestContext(requestContext, () => {
151
19
  return tracer.withActiveSpan('Next.js Server Handler', async (span) => {
152
20
  if (!cachedHandler) {
153
- // const { default: handler } = await import('{{nextServerHandler}}')
154
21
  cachedHandler = serverHandler.default
155
22
  }
156
23
  const response = await cachedHandler(req, context, span, requestContext)
@@ -158,117 +25,14 @@ export default async function eoHandler (req, context) {
158
25
  })
159
26
  })
160
27
 
28
+ if (requestContext.serverTiming) {
29
+ handlerResponse.headers.set('server-timing', requestContext.serverTiming);
30
+ }
31
+
161
32
  return handlerResponse
162
33
  }
163
34
 
164
-
165
35
  export const config = {
166
36
  path: '/*',
167
37
  preferStatic: true,
168
- };
169
-
170
- const port = 9000;
171
-
172
- // 实时流转换函数
173
- function createReadableStreamFromRequest(req) {
174
- return new ReadableStream({
175
- start(controller) {
176
- req.on('data', chunk => {
177
- // 将Buffer转换为Uint8Array
178
- const uint8Array = new Uint8Array(chunk);
179
- controller.enqueue(uint8Array);
180
- });
181
-
182
- req.on('end', () => {
183
- controller.close();
184
- });
185
-
186
- req.on('error', error => {
187
- controller.error(error);
188
- });
189
- },
190
-
191
- cancel() {
192
- // 清理资源
193
- req.destroy();
194
- }
195
- });
196
- }
197
-
198
- const server = createServer(async (req, res) => {
199
- try {
200
- const requestStartTime = Date.now();
201
-
202
- // 构造 handler 需要的 req 对象(可根据需要扩展)
203
- // 用 eo-pages-host 替换 host
204
- const originalHost = req.headers['eo-pages-host'] || req.headers['host'];
205
- const handlerReq = {
206
- ...req,
207
- headers: {
208
- ...req.headers,
209
- 'accept-encoding': 'identity',
210
- 'host': originalHost,
211
- },
212
- method: req.method,
213
- url: req.url,
214
- };
215
-
216
- // 读取 body(如果有)
217
- // let body = [];
218
- // req.on('data', chunk => body.push(chunk));
219
- // await new Promise(resolve => req.on('end', resolve));
220
- // if (body.length > 0) {
221
- // handlerReq.body = Buffer.concat(body);
222
- // }
223
-
224
- handlerReq.body = createReadableStreamFromRequest(req);
225
-
226
- const response = await eoHandler(handlerReq, {});
227
-
228
- // response.headers.set('functions-request-id', req.headers['x-scf-request-id'] || '');
229
-
230
- const requestEndTime = Date.now();
231
- const url = new URL(req.url, `http://${req.headers.host}`);
232
- let pathname = url.pathname;
233
-
234
- if (pathname !== '/' && pathname.endsWith('/')) {
235
- pathname = pathname.slice(0, -1);
236
- }
237
-
238
- let fullPath = '';
239
- if (req.headers.host === 'localhost:9000') {
240
- fullPath = pathname;
241
- } else {
242
- const host = req.headers['eo-pages-host'];
243
- const xForwardedProto = req.headers['x-forwarded-proto'];
244
-
245
- fullPath = (xForwardedProto || 'https') + '://' + host + req.url;
246
-
247
- if (fullPath.endsWith('?')) {
248
- fullPath = fullPath.slice(0, -1);
249
- }
250
- }
251
-
252
- console.log(`Pages request path: ${fullPath}`);
253
-
254
- await handleResponse(res, response, {
255
- 'functions-request-id': req.headers['x-scf-request-id'] || ''
256
- });
257
- return;
258
- } catch (error) {
259
- console.log(`Pages response status: 502`);
260
- // 用户函数内部错误 内部502 - 拦截
261
- const requestId = req.headers['x-scf-request-id'] || '';
262
- res.statusCode = 502;
263
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
264
- res.setHeader('Functions-Request-Id', requestId);
265
- res.setHeader('eo-pages-inner-scf-status', '502');
266
- res.setHeader('eo-pages-inner-status-intercept', 'true');
267
- res.end('<html><body><h1>Error</h1><p>'+error.message+'</p></body></html>');
268
- }
269
- });
270
-
271
- server.listen(port, () => {
272
- console.log('Server is running on http://localhost:9000');
273
- });
274
-
38
+ };
@@ -1,5 +1,4 @@
1
1
 
2
- import { createServer } from 'http';
3
2
  import {
4
3
  createRequestContext,
5
4
  runWithRequestContext,
@@ -7,141 +6,8 @@ import {
7
6
  import serverHandler from './.edgeone/dist/run/handlers/server.js';
8
7
  import { getTracer } from './.edgeone/dist/run/handlers/tracer.cjs';
9
8
 
10
-
11
- async function handleResponse(res, response, passHeaders = {}) {
12
- const startTime = Date.now();
13
-
14
- // 没有响应 - 404 拦截
15
- if (!response) {
16
- const requestId = passHeaders['functions-request-id'] || '';
17
- res.writeHead(404, {
18
- 'Functions-Request-Id': requestId,
19
- 'eo-pages-inner-scf-status': '404',
20
- 'eo-pages-inner-status-intercept': 'true'
21
- });
22
- res.end(JSON.stringify({
23
- error: "Not Found",
24
- message: "The requested path does not exist"
25
- }));
26
- const endTime = Date.now();
27
- console.log(`Pages response status: 404`);
28
- return;
29
- }
30
-
31
- try {
32
- if (response instanceof Response) {
33
- const requestId = passHeaders['functions-request-id'] || '';
34
- const responseStatus = response.status;
35
-
36
- const headers = Object.fromEntries(response.headers);
37
- Object.assign(headers, passHeaders);
38
-
39
- // 添加状态码区分的 headers
40
- headers['Functions-Request-Id'] = requestId;
41
-
42
- // 如果 Response 中已经设置了,使用它的值;否则使用 responseStatus
43
- if (!headers['eo-pages-inner-scf-status']) {
44
- headers['eo-pages-inner-scf-status'] = String(responseStatus);
45
- }
46
-
47
- // 如果 Response 中已经设置了,使用它的值;否则默认为 false
48
- if (!headers['eo-pages-inner-status-intercept']) {
49
- headers['eo-pages-inner-status-intercept'] = 'false';
50
- }
51
-
52
- // 删除内部 header
53
- if (response.headers.get('eop-client-geo')) {
54
- response.headers.delete('eop-client-geo');
55
- }
56
- // 处理 set-cookie 头部
57
- if (response.headers.has('set-cookie')) {
58
- const cookieArr = response.headers.getSetCookie();
59
- headers['set-cookie'] = cookieArr;
60
- }
61
-
62
- // 检查是否是流式响应
63
- const isStream = response.body && (
64
- response.headers.get('content-type')?.includes('text/event-stream') ||
65
- response.headers.get('transfer-encoding')?.includes('chunked') ||
66
- response.body instanceof ReadableStream ||
67
- typeof response.body.pipe === 'function' ||
68
- response.headers.get('x-content-type-stream') === 'true'
69
- );
70
-
71
- if (isStream) {
72
- // 设置流式响应所需的头部
73
- const streamHeaders = {
74
- ...headers
75
- };
76
-
77
- if (response.headers.get('content-type')?.includes('text/event-stream')) {
78
- streamHeaders['Content-Type'] = 'text/event-stream';
79
- }
80
-
81
- res.writeHead(response.status, streamHeaders);
82
-
83
- if (typeof response.body.pipe === 'function') {
84
- response.body.pipe(res);
85
- } else {
86
- const reader = response.body.getReader();
87
- try {
88
- while (true) {
89
- const { done, value } = await reader.read();
90
- if (done) break;
91
-
92
- if (value instanceof Uint8Array || Buffer.isBuffer(value)) {
93
- res.write(value);
94
- } else {
95
- const chunk = new TextDecoder().decode(value);
96
- res.write(chunk);
97
- }
98
- }
99
- } finally {
100
- reader.releaseLock();
101
- // scf可能会立即冻结环境上下文,导致后续日志无法输出,通过延时来确保日志输出
102
- setTimeout(() => {
103
- res.end();
104
- }, 1);
105
- }
106
- }
107
- } else {
108
- // 普通响应
109
- res.writeHead(response.status, headers);
110
- const body = await response.text();
111
- res.end(body);
112
- }
113
- } else {
114
- // 非 Response 对象,直接返回 JSON
115
- const requestId = passHeaders['functions-request-id'] || '';
116
- res.writeHead(200, {
117
- 'Content-Type': 'application/json',
118
- 'Functions-Request-Id': requestId,
119
- 'eo-pages-inner-scf-status': '200',
120
- 'eo-pages-inner-status-intercept': 'false'
121
- });
122
- res.end(JSON.stringify(response));
123
- }
124
- } catch (error) {
125
- // 用户函数内部错误 内部502 - 拦截
126
- const requestId = passHeaders['functions-request-id'] || '';
127
- res.writeHead(502, {
128
- 'Functions-Request-Id': requestId,
129
- 'eo-pages-inner-scf-status': '502',
130
- 'eo-pages-inner-status-intercept': 'true'
131
- });
132
- res.end(JSON.stringify({
133
- error: "Internal Server Error",
134
- message: error.message
135
- }));
136
- } finally {
137
- const endTime = Date.now();
138
- console.log(`Pages response status: ${response?.status || 'unknown'}`);
139
- }
140
- }
141
-
142
-
143
9
  process.env.USE_REGIONAL_BLOBS = 'true';
144
- export default async function handler(req, context) {
10
+ export default async function handler(req, context = {}) {
145
11
  const requestContext = createRequestContext(req, context);
146
12
  const tracer = getTracer();
147
13
 
@@ -162,115 +28,4 @@ export default async function handler(req, context) {
162
28
  export const config = {
163
29
  path: '/*',
164
30
  preferStatic: true,
165
- };
166
-
167
- const port = 9000;
168
-
169
- // 实时流转换函数
170
- function createReadableStreamFromRequest(req) {
171
- return new ReadableStream({
172
- start(controller) {
173
- req.on('data', chunk => {
174
- // 将Buffer转换为Uint8Array
175
- const uint8Array = new Uint8Array(chunk);
176
- controller.enqueue(uint8Array);
177
- });
178
-
179
- req.on('end', () => {
180
- controller.close();
181
- });
182
-
183
- req.on('error', error => {
184
- controller.error(error);
185
- });
186
- },
187
-
188
- cancel() {
189
- // 清理资源
190
- req.destroy();
191
- }
192
- });
193
- }
194
-
195
- const server = createServer(async (req, res) => {
196
- try {
197
- const requestStartTime = Date.now();
198
-
199
- // 构造 handler 需要的 req 对象(可根据需要扩展)
200
- // 用 eo-pages-host 替换 host
201
- const originalHost = req.headers['eo-pages-host'] || req.headers['host'];
202
- const handlerReq = {
203
- ...req,
204
- headers: {
205
- ...req.headers,
206
- 'accept-encoding': 'identity',
207
- 'host': originalHost,
208
- },
209
- method: req.method,
210
- url: req.url,
211
- };
212
-
213
-
214
-
215
- // 读取 body(如果有)
216
- // let body = [];
217
- // req.on('data', chunk => body.push(chunk));
218
- // await new Promise(resolve => req.on('end', resolve));
219
- // if (body.length > 0) {
220
- // handlerReq.body = Buffer.concat(body);
221
- // }
222
-
223
- handlerReq.body = createReadableStreamFromRequest(req);
224
-
225
- const response = await handler(handlerReq, {});
226
-
227
- // 不要在这里设置 functions-request-id,避免重复
228
- // response.headers.set('functions-request-id', req.headers['x-scf-request-id'] || '');
229
- // const requestEndTime = Date.now();
230
-
231
- // 解析请求路径
232
- const url = new URL(req.url, `http://${req.headers.host}`);
233
- let pathname = url.pathname;
234
-
235
- if (pathname !== '/' && pathname.endsWith('/')) {
236
- pathname = pathname.slice(0, -1);
237
- }
238
-
239
- let fullPath = '';
240
- if (req.headers.host === 'localhost:9000') {
241
- fullPath = pathname;
242
- } else {
243
- const host = req.headers['eo-pages-host'];
244
- const xForwardedProto = req.headers['x-forwarded-proto'];
245
-
246
- fullPath = (xForwardedProto || 'https') + '://' + host + req.url;
247
-
248
- if (fullPath.endsWith('?')) {
249
- fullPath = fullPath.slice(0, -1);
250
- }
251
- }
252
-
253
- console.log(`Pages request path: ${fullPath}`);
254
-
255
- // console.log(`Request processing time: ${requestEndTime - requestStartTime}ms`);
256
- await handleResponse(res, response, {
257
- 'functions-request-id': req.headers['x-scf-request-id'] || ''
258
- });
259
- return;
260
- } catch (error) {
261
- console.log(`Pages response status: 502`);
262
- // 用户函数内部错误 内部502 - 拦截
263
- const requestId = req.headers['x-scf-request-id'] || '';
264
- res.statusCode = 502;
265
- res.setHeader('Content-Type', 'text/html; charset=utf-8');
266
- res.setHeader('Functions-Request-Id', requestId);
267
- res.setHeader('eo-pages-inner-scf-status', '502');
268
- res.setHeader('eo-pages-inner-status-intercept', 'true');
269
- res.end('<html><body><h1>Error</h1><p>'+error.message+'</p></body></html>');
270
- }
271
- });
272
-
273
- server.listen(port, () => {
274
- console.log('Server is running on http://localhost:9000');
275
- });
276
-
31
+ };
package/dist/index.js CHANGED
@@ -35,9 +35,9 @@ var onBuild = async (options) => {
35
35
  // copyStaticAssets(ctx),
36
36
  copyStaticContent(ctx),
37
37
  copyPrerenderedContent(ctx),
38
- createServerHandler(ctx)
38
+ createServerHandler(ctx),
39
+ createRouteMeta(ctx)
39
40
  ]);
40
- createRouteMeta(ctx);
41
41
  };
42
42
  var onPostBuild = async (options) => {
43
43
  console.log("onPostBuild");
@@ -28,7 +28,7 @@ module.exports = __toCommonJS(tags_handler_exports);
28
28
 
29
29
  // package.json
30
30
  var name = "@edgeone/opennextjs-pages";
31
- var version = "0.0.6";
31
+ var version = "0.0.7";
32
32
 
33
33
  // src/run/handlers/tags-handler.cts
34
34
  var import_request_context = require("./request-context.cjs");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@edgeone/opennextjs-pages",
3
- "version": "0.0.6",
3
+ "version": "0.0.7",
4
4
  "description": "",
5
5
  "main": "./dist/index.js",
6
6
  "type": "module",