@open-editor/server
Advanced tools
+75
-12
| import connect from 'connect'; | ||
| /** | ||
| * 服务器核心配置选项 | ||
| * | ||
| * @remarks | ||
| * 本配置定义了服务器启动的基础参数,支持 HTTP/HTTPS 双协议模式, | ||
| * 证书配置遵循 TLS 标准规范,适用于本地开发和生产环境 | ||
| */ | ||
| interface Options { | ||
| /** | ||
| * source rootDir path | ||
| * 项目源码根目录路径 | ||
| * | ||
| * @default process.cwd() | ||
| * @default `process.cwd()` 进程当前工作目录 | ||
| * | ||
| * @securityNote 需确保该路径具备可读权限 | ||
| */ | ||
| rootDir?: string; | ||
| /** | ||
| * enable https | ||
| * HTTPS 安全传输层配置 | ||
| * | ||
| * @see https://nodejs.org/api/tls.html#tls_tls_createsecurecontext_options | ||
| * @see [TLS Context Options](https://nodejs.org/api/tls.html#tlscreatesecurecontextoptions) | ||
| * | ||
| * @example | ||
| * { | ||
| * key: '/path/to/private.key', | ||
| * cert: '/path/to/certificate.pem' | ||
| * } | ||
| */ | ||
| https?: { | ||
| /** | ||
| * PEM 格式的 SSL 私钥文件路径 | ||
| * | ||
| * @fileMustExist 文件必须存在且可读 | ||
| */ | ||
| key: string; | ||
| /** | ||
| * PEM 格式的 SSL 证书文件路径 | ||
| * | ||
| * @fileMustExist 文件必须存在且可读 | ||
| */ | ||
| cert: string; | ||
| }; | ||
| /** | ||
| * custom openEditor handler | ||
| * 自定义编辑器打开处理器 | ||
| * | ||
| * @default 'launch-editor' | ||
| * @default 使用内置的 `launch-editor` 实现 | ||
| * | ||
| * @param file - 需要打开的目标文件路径 | ||
| */ | ||
| onOpenEditor?(file: string): void; | ||
| onOpenEditor?(file: string, errorCallback: (errorMessage: string) => void): void; | ||
| } | ||
| /** | ||
| * 创建并启动应用服务器 | ||
| * | ||
| * @param options - 服务器配置参数集 | ||
| * | ||
| * @returns 返回包含实际监听端口的 Promise | ||
| * | ||
| * @technicalProcess | ||
| * 1. 初始化应用实例 | ||
| * 2. 根据配置创建 HTTP/HTTPS 服务器 | ||
| * 3. 动态分配可用端口并启动监听 | ||
| * | ||
| * @example | ||
| * ```typescript | ||
| * setupServer({ | ||
| * https: { | ||
| * key: 'key.pem', | ||
| * cert: 'cert.pem' | ||
| * } | ||
| * }).then(port => { | ||
| * console.log(`Server running on port ${port}`); | ||
| * }); | ||
| * ``` | ||
| */ | ||
| declare function setupServer(options?: Options): Promise<number>; | ||
@@ -30,16 +81,28 @@ | ||
| /** | ||
| * source rootDir path | ||
| * 项目根目录路径 | ||
| * | ||
| * @default process.cwd() | ||
| * | ||
| * @remarks | ||
| * 用于解析文件相对路径的基础目录 | ||
| */ | ||
| rootDir?: string; | ||
| /** | ||
| * custom openEditor handler | ||
| * 自定义编辑器打开处理器 | ||
| * | ||
| * @default 'launch-editor' | ||
| * @remarks | ||
| * 默认使用 launch-editor 库实现 | ||
| * 可通过此参数覆盖默认行为 | ||
| */ | ||
| onOpenEditor?(file: string): void; | ||
| onOpenEditor?(file: string, errorCallback: (errorMessage: string) => void): void; | ||
| } | ||
| declare function openEditorMiddleware(options: OpenEditorMiddlewareOptions): connect.NextHandleFunction; | ||
| /** | ||
| * 创建编辑器中间件 | ||
| * | ||
| * @param options - 中间件配置选项 | ||
| * | ||
| * @returns connect 中间件处理函数 | ||
| */ | ||
| declare function openEditorMiddleware(options?: OpenEditorMiddlewareOptions): connect.NextHandleFunction; | ||
| export { OpenEditorMiddlewareOptions, Options, openEditorMiddleware, setupServer }; |
+1
-1
@@ -1,1 +0,1 @@ | ||
| "use strict";var http=require("node:http"),https=require("node:https"),node_fs=require("node:fs"),connect=require("connect"),corsMiddleware=require("cors"),shared=require("@open-editor/shared"),node_path=require("node:path"),node_url=require("node:url"),openEditor=require("launch-editor");function openEditorMiddleware(options){const{rootDir=process.cwd(),onOpenEditor=openEditor}=options;return(req,res)=>{var _a;const{query}=node_url.parse((_a=req.url)!=null?_a:"/",!0),{f:file="",l:line=1,c:column=1}=query,filename=node_path.resolve(rootDir,decodeURIComponent(file));if(!node_fs.existsSync(filename)){res.statusCode=404,res.end(sendMessage(`file '${filename}' not found`));return}if(!node_fs.statSync(filename).isFile()){res.statusCode=500,res.end(sendMessage(`'${filename}' is not a valid file`));return}req.headers.referer&&onOpenEditor(`${filename}:${line}:${column}`),res.setHeader("Content-Type","application/javascript;charset=UTF-8"),res.end(node_fs.readFileSync(filename,"utf-8"))}}function sendMessage(msg){return`[@open-editor/server] ${msg}.`}function createApp(options){const{rootDir,onOpenEditor}=options,app=connect();return app.use(corsMiddleware({methods:"GET"})),app.use(shared.ServerApis.OPEN_EDITOR,openEditorMiddleware({rootDir,onOpenEditor})),app}function setupServer(options={}){const{rootDir,https:httpsOpts}=options,app=createApp({rootDir}),httpServer=httpsOpts?https.createServer({key:node_fs.readFileSync(httpsOpts.key),cert:node_fs.readFileSync(httpsOpts.cert)},app):http.createServer(app);return startServer(httpServer)}function startServer(server){return new Promise((resolve,reject)=>{server.on("error",reject),server.listen(void 0,()=>{const address=server.address();if(!address){server.close(),reject(Error("@open-editor/server: start fail."));return}const port=typeof address=="string"?+address.match(/:(\d+)$/)[1]:address.port;resolve(port)})})}exports.openEditorMiddleware=openEditorMiddleware,exports.setupServer=setupServer; | ||
| "use strict";var http=require("node:http"),https=require("node:https"),node_fs=require("node:fs"),connect=require("connect"),corsMiddleware=require("cors"),shared=require("@open-editor/shared"),node_path=require("node:path"),node_url=require("node:url"),openEditor=require("launch-editor"),net=require("node:net");const DEFAULE_OPEN_DDITOR=(file,errorCallback)=>{openEditor(file,(_,errorMessage)=>errorCallback(errorMessage))};function openEditorMiddleware(options={}){const{rootDir=process.cwd(),onOpenEditor=DEFAULE_OPEN_DDITOR}=options;return(req,res)=>{var _a;try{const{query}=node_url.parse((_a=req.url)!=null?_a:"/",!0),{f:file="unknown",l:line="1",c:column="1"}=query;if(!file){sendErrorResponse(res,400,"\u7F3A\u5C11\u6587\u4EF6\u8DEF\u5F84\u53C2\u6570");return}const filename=node_path.resolve(rootDir,decodeURIComponent(file));if(!validateFile(filename,res))return;req.headers.referer&&onOpenEditor(`${filename}:${line}:${column}`,errorMessage=>{throw new Error(errorMessage||"\u53EF\u80FD\u539F\u56E0\u6709\u7F16\u8F91\u5668\u672A\u542F\u52A8/\u7F16\u8F91\u5668\u672A\u54CD\u5E94")}),sendFileContent(res,filename)}catch(error){const errorMessage=error instanceof Error?error.message:"\u672A\u77E5\u9519\u8BEF";sendErrorResponse(res,500,`\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF: ${errorMessage}`)}}}function validateFile(filename,res){return node_fs.existsSync(filename)?node_fs.statSync(filename).isFile()?!0:(sendErrorResponse(res,400,`'${filename}' \u4E0D\u662F\u6709\u6548\u6587\u4EF6`),!1):(sendErrorResponse(res,404,`\u6587\u4EF6 '${filename}' \u4E0D\u5B58\u5728`),!1)}function sendFileContent(res,filename){res.setHeader("Content-Type","application/javascript;charset=UTF-8"),res.end(node_fs.readFileSync(filename,"utf-8"))}function sendErrorResponse(res,code,message){res.statusCode=code,res.setHeader("Content-Type","text/plain;charset=UTF-8"),res.end(`[@open-editor/server] ${message}`)}function createApp(options){const{rootDir,onOpenEditor}=options,app=connect();return app.use(corsMiddleware({methods:"GET"})),app.use(shared.ServerApis.OPEN_EDITOR,openEditorMiddleware({rootDir,onOpenEditor})),app}var __async=(__this,__arguments,generator)=>new Promise((resolve,reject)=>{var fulfilled=value=>{try{step(generator.next(value))}catch(e){reject(e)}},rejected=value=>{try{step(generator.throw(value))}catch(e){reject(e)}},step=x=>x.done?resolve(x.value):Promise.resolve(x.value).then(fulfilled,rejected);step((generator=generator.apply(__this,__arguments)).next())});const MIN_PORT_NUMBER=3e3,MAX_PORT_NUMBER=9e3;function getAvailablePort(){return __async(this,arguments,function*({concurrency=5,retries=10}={}){for(let i=0;i<retries;i++){const promises=Array.from({length:concurrency},generatePort).map(port=>checkPortNumber(port).then(available=>available?port:null)),result=yield Promise.race([...promises,new Promise(resolve=>{setTimeout(()=>resolve(null),100)})]);if(result)return result}throw new Error(`\u7AEF\u53E3\u63A2\u6D4B\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7CFB\u7EDF\u8D44\u6E90\u3002\u5C1D\u8BD5\u6B21\u6570\uFF1A${retries}`)})}function checkPortNumber(port){return new Promise(resolve=>{const server=net.createServer();server.unref(),server.on("error",()=>{resolve(!1)}),server.listen(port,()=>{server.close(()=>{resolve(!0)})})})}function generatePort(){return Math.floor(Math.random()*(MAX_PORT_NUMBER-MIN_PORT_NUMBER)+MIN_PORT_NUMBER)}function setupServer(options={}){const{rootDir,https:httpsConfig}=options,app=createApp({rootDir}),server=createHttpServer(app,httpsConfig);return startServer(server)}function createHttpServer(app,httpsConfig){if(!httpsConfig)return http.createServer(app);const sslOptions={key:node_fs.readFileSync(httpsConfig.key),cert:node_fs.readFileSync(httpsConfig.cert)};return https.createServer(sslOptions,app)}function startServer(server){return new Promise((resolve,reject)=>{getAvailablePort().then(port=>{server.listen(port).once("listening",()=>resolve(port)).once("error",reject)}).catch(reject)})}exports.openEditorMiddleware=openEditorMiddleware,exports.setupServer=setupServer; |
+1
-1
@@ -1,1 +0,1 @@ | ||
| import http from"node:http";import https from"node:https";import{existsSync,statSync,readFileSync}from"node:fs";import connect from"connect";import corsMiddleware from"cors";import{ServerApis}from"@open-editor/shared";import{resolve}from"node:path";import{parse}from"node:url";import openEditor from"launch-editor";function openEditorMiddleware(options){const{rootDir=process.cwd(),onOpenEditor=openEditor}=options;return(req,res)=>{var _a;const{query}=parse((_a=req.url)!=null?_a:"/",!0),{f:file="",l:line=1,c:column=1}=query,filename=resolve(rootDir,decodeURIComponent(file));if(!existsSync(filename)){res.statusCode=404,res.end(sendMessage(`file '${filename}' not found`));return}if(!statSync(filename).isFile()){res.statusCode=500,res.end(sendMessage(`'${filename}' is not a valid file`));return}req.headers.referer&&onOpenEditor(`${filename}:${line}:${column}`),res.setHeader("Content-Type","application/javascript;charset=UTF-8"),res.end(readFileSync(filename,"utf-8"))}}function sendMessage(msg){return`[@open-editor/server] ${msg}.`}function createApp(options){const{rootDir,onOpenEditor}=options,app=connect();return app.use(corsMiddleware({methods:"GET"})),app.use(ServerApis.OPEN_EDITOR,openEditorMiddleware({rootDir,onOpenEditor})),app}function setupServer(options={}){const{rootDir,https:httpsOpts}=options,app=createApp({rootDir}),httpServer=httpsOpts?https.createServer({key:readFileSync(httpsOpts.key),cert:readFileSync(httpsOpts.cert)},app):http.createServer(app);return startServer(httpServer)}function startServer(server){return new Promise((resolve2,reject)=>{server.on("error",reject),server.listen(void 0,()=>{const address=server.address();if(!address){server.close(),reject(Error("@open-editor/server: start fail."));return}const port=typeof address=="string"?+address.match(/:(\d+)$/)[1]:address.port;resolve2(port)})})}export{openEditorMiddleware,setupServer}; | ||
| import http from"node:http";import https from"node:https";import{existsSync,statSync,readFileSync}from"node:fs";import connect from"connect";import corsMiddleware from"cors";import{ServerApis}from"@open-editor/shared";import{resolve}from"node:path";import{parse}from"node:url";import openEditor from"launch-editor";import net from"node:net";const DEFAULE_OPEN_DDITOR=(file,errorCallback)=>{openEditor(file,(_,errorMessage)=>errorCallback(errorMessage))};function openEditorMiddleware(options={}){const{rootDir=process.cwd(),onOpenEditor=DEFAULE_OPEN_DDITOR}=options;return(req,res)=>{var _a;try{const{query}=parse((_a=req.url)!=null?_a:"/",!0),{f:file="unknown",l:line="1",c:column="1"}=query;if(!file){sendErrorResponse(res,400,"\u7F3A\u5C11\u6587\u4EF6\u8DEF\u5F84\u53C2\u6570");return}const filename=resolve(rootDir,decodeURIComponent(file));if(!validateFile(filename,res))return;req.headers.referer&&onOpenEditor(`${filename}:${line}:${column}`,errorMessage=>{throw new Error(errorMessage||"\u53EF\u80FD\u539F\u56E0\u6709\u7F16\u8F91\u5668\u672A\u542F\u52A8/\u7F16\u8F91\u5668\u672A\u54CD\u5E94")}),sendFileContent(res,filename)}catch(error){const errorMessage=error instanceof Error?error.message:"\u672A\u77E5\u9519\u8BEF";sendErrorResponse(res,500,`\u670D\u52A1\u5668\u5185\u90E8\u9519\u8BEF: ${errorMessage}`)}}}function validateFile(filename,res){return existsSync(filename)?statSync(filename).isFile()?!0:(sendErrorResponse(res,400,`'${filename}' \u4E0D\u662F\u6709\u6548\u6587\u4EF6`),!1):(sendErrorResponse(res,404,`\u6587\u4EF6 '${filename}' \u4E0D\u5B58\u5728`),!1)}function sendFileContent(res,filename){res.setHeader("Content-Type","application/javascript;charset=UTF-8"),res.end(readFileSync(filename,"utf-8"))}function sendErrorResponse(res,code,message){res.statusCode=code,res.setHeader("Content-Type","text/plain;charset=UTF-8"),res.end(`[@open-editor/server] ${message}`)}function createApp(options){const{rootDir,onOpenEditor}=options,app=connect();return app.use(corsMiddleware({methods:"GET"})),app.use(ServerApis.OPEN_EDITOR,openEditorMiddleware({rootDir,onOpenEditor})),app}var __async=(__this,__arguments,generator)=>new Promise((resolve2,reject)=>{var fulfilled=value=>{try{step(generator.next(value))}catch(e){reject(e)}},rejected=value=>{try{step(generator.throw(value))}catch(e){reject(e)}},step=x=>x.done?resolve2(x.value):Promise.resolve(x.value).then(fulfilled,rejected);step((generator=generator.apply(__this,__arguments)).next())});const MIN_PORT_NUMBER=3e3,MAX_PORT_NUMBER=9e3;function getAvailablePort(){return __async(this,arguments,function*({concurrency=5,retries=10}={}){for(let i=0;i<retries;i++){const promises=Array.from({length:concurrency},generatePort).map(port=>checkPortNumber(port).then(available=>available?port:null)),result=yield Promise.race([...promises,new Promise(resolve2=>{setTimeout(()=>resolve2(null),100)})]);if(result)return result}throw new Error(`\u7AEF\u53E3\u63A2\u6D4B\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7CFB\u7EDF\u8D44\u6E90\u3002\u5C1D\u8BD5\u6B21\u6570\uFF1A${retries}`)})}function checkPortNumber(port){return new Promise(resolve2=>{const server=net.createServer();server.unref(),server.on("error",()=>{resolve2(!1)}),server.listen(port,()=>{server.close(()=>{resolve2(!0)})})})}function generatePort(){return Math.floor(Math.random()*(MAX_PORT_NUMBER-MIN_PORT_NUMBER)+MIN_PORT_NUMBER)}function setupServer(options={}){const{rootDir,https:httpsConfig}=options,app=createApp({rootDir}),server=createHttpServer(app,httpsConfig);return startServer(server)}function createHttpServer(app,httpsConfig){if(!httpsConfig)return http.createServer(app);const sslOptions={key:readFileSync(httpsConfig.key),cert:readFileSync(httpsConfig.cert)};return https.createServer(sslOptions,app)}function startServer(server){return new Promise((resolve2,reject)=>{getAvailablePort().then(port=>{server.listen(port).once("listening",()=>resolve2(port)).once("error",reject)}).catch(reject)})}export{openEditorMiddleware,setupServer}; |
+3
-3
| { | ||
| "name": "@open-editor/server", | ||
| "version": "0.9.3", | ||
| "version": "0.9.4", | ||
| "description": "internal utils shared across @open-editor packages", | ||
@@ -28,3 +28,3 @@ "main": "./dist/index.js", | ||
| }, | ||
| "homepage": "https://github.com/zjxxxxxxxxx/open-editor/tree/main/packages/server#readme", | ||
| "homepage": "https://github.com/zjxxxxxxxxx/open-editor#readme", | ||
| "dependencies": { | ||
@@ -34,3 +34,3 @@ "connect": "^3.7.0", | ||
| "launch-editor": "^2.6.0", | ||
| "@open-editor/shared": "0.9.3" | ||
| "@open-editor/shared": "0.9.4" | ||
| }, | ||
@@ -37,0 +37,0 @@ "devDependencies": { |
AI-detected potential code anomaly
Supply chain riskAI has identified unusual behaviors that may pose a security risk.
Found 1 instance in 1 package
12966
83.03%136
138.6%1
Infinity%+ Added
- Removed
Updated