@alwatr/nanotron-api-server 4.10.0 โ 4.10.1
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/CHANGELOG.md +7 -0
- package/README.md +0 -1
- package/dist/main.cjs +2 -2
- package/dist/main.mjs +2 -2
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [4.10.1](https://github.com/Alwatr/nanotron/compare/v4.10.0...v4.10.1) (2025-09-21)
|
|
7
|
+
|
|
8
|
+
### ๐งน Miscellaneous Chores
|
|
9
|
+
|
|
10
|
+
* add "sideEffects": false to package.json files for better tree-shaking ([2aae07b](https://github.com/Alwatr/nanotron/commit/2aae07b0e1757b6035ea0ca8c1b0eda64a13dfcc))
|
|
11
|
+
* remove empty line before contributing section in README ([59236cc](https://github.com/Alwatr/nanotron/commit/59236cc1a5445c16f124c49651f8a6f89166a16b))
|
|
12
|
+
|
|
6
13
|
## [4.10.0](https://github.com/Alwatr/nanotron/compare/v4.9.4...v4.10.0) (2025-09-21)
|
|
7
14
|
|
|
8
15
|
### ๐ Bug Fixes
|
package/README.md
CHANGED
|
@@ -57,7 +57,6 @@ apiServer.defineRoute({
|
|
|
57
57
|
|
|
58
58
|
The following companies, organizations, and individuals support Nanotron ongoing maintenance and development. Become a Sponsor to get your logo on our README and website.
|
|
59
59
|
|
|
60
|
-
|
|
61
60
|
### Contributing
|
|
62
61
|
|
|
63
62
|
Contributions are welcome! Please read our [contribution guidelines](https://github.com/Alwatr/.github/blob/next/CONTRIBUTING.md) before submitting a pull request.
|
package/dist/main.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** ๐ฆ @alwatr/nanotron-api-server v4.10.
|
|
2
|
-
__dev_mode__: console.debug("๐ฆ @alwatr/nanotron-api-server v4.10.
|
|
1
|
+
/** ๐ฆ @alwatr/nanotron-api-server v4.10.1 */
|
|
2
|
+
__dev_mode__: console.debug("๐ฆ @alwatr/nanotron-api-server v4.10.1");
|
|
3
3
|
"use strict";var __defProp=Object.defineProperty;var __getOwnPropDesc=Object.getOwnPropertyDescriptor;var __getOwnPropNames=Object.getOwnPropertyNames;var __hasOwnProp=Object.prototype.hasOwnProperty;var __export=(target,all)=>{for(var name in all)__defProp(target,name,{get:all[name],enumerable:true})};var __copyProps=(to,from,except,desc)=>{if(from&&typeof from==="object"||typeof from==="function"){for(let key of __getOwnPropNames(from))if(!__hasOwnProp.call(to,key)&&key!==except)__defProp(to,key,{get:()=>from[key],enumerable:!(desc=__getOwnPropDesc(from,key))||desc.enumerable})}return to};var __toCommonJS=mod=>__copyProps(__defProp({},"__esModule",{value:true}),mod);var main_exports={};__export(main_exports,{HttpMethods:()=>HttpMethods,HttpStatusCodes:()=>HttpStatusCodes,HttpStatusMessages:()=>HttpStatusMessages,NanotronApiServer:()=>NanotronApiServer});module.exports=__toCommonJS(main_exports);var import_node_http=require("node:http");var import_logger3=require("@alwatr/logger");var import_logger2=require("@alwatr/logger");var import_logger=require("@alwatr/logger");var HttpMethods={GET:"GET",HEAD:"HEAD",POST:"POST",PUT:"PUT",DELETE:"DELETE",CONNECT:"CONNECT",OPTIONS:"OPTIONS",TRACE:"TRACE",PATCH:"PATCH"};var HttpStatusCodes={Info_100_Continue:100,Info_101_Switching_Protocols:101,Info_102_Processing:102,Info_103_Early_Hints:103,Success_200_OK:200,Success_201_Created:201,Success_202_Accepted:202,Success_203_Non_Authoritative_Information:203,Success_204_No_Content:204,Success_205_Reset_Content:205,Success_206_Partial_Content:206,Success_207_Multi_Status:207,Success_208_Already_Reported:208,Success_226_IM_Used:226,Redirect_300_Multiple_Choices:300,Redirect_301_Moved_Permanently:301,Redirect_302_Found:302,Redirect_303_See_Other:303,Redirect_304_Not_Modified:304,Redirect_305_Use_Proxy:305,Redirect_306_Switch_Proxy:306,Redirect_307_Temporary_Redirect:307,Redirect_308_Permanent_Redirect:308,Error_Client_400_Bad_Request:400,Error_Client_401_Unauthorized:401,Error_Client_402_Payment_Required:402,Error_Client_403_Forbidden:403,Error_Client_404_Not_Found:404,Error_Client_405_Method_Not_Allowed:405,Error_Client_406_Not_Acceptable:406,Error_Client_407_Proxy_Authentication_Required:407,Error_Client_408_Request_Timeout:408,Error_Client_409_Conflict:409,Error_Client_410_Gone:410,Error_Client_411_Length_Required:411,Error_Client_412_Precondition_Failed:412,Error_Client_413_Payload_Too_Large:413,Error_Client_414_URI_Too_Long:414,Error_Client_415_Unsupported_Media_Type:415,Error_Client_416_Range_Not_Satisfiable:416,Error_Client_417_Expectation_Failed:417,Error_Client_421_Misdirected_Request:421,Error_Client_422_Unprocessable_Entity:422,Error_Client_423_Locked:423,Error_Client_424_Failed_Dependency:424,Error_Client_425_Too_Early:425,Error_Client_426_Upgrade_Required:426,Error_Client_428_Precondition_Required:428,Error_Client_429_Too_Many_Requests:429,Error_Client_431_Request_Header_Fields_Too_Large:431,Error_Client_451_Unavailable_For_Legal_Reasons:451,Error_Server_500_Internal_Server_Error:500,Error_Server_501_Not_Implemented:501,Error_Server_502_Bad_Gateway:502,Error_Server_503_Service_Unavailable:503,Error_Server_504_Gateway_Timeout:504,Error_Server_505_HTTP_Version_Not_Supported:505,Error_Server_506_Variant_Also_Negotiates:506,Error_Server_507_Insufficient_Storage:507,Error_Server_508_Loop_Detected:508,Error_Server_510_Not_Extended:510,Error_Server_511_Network_Authentication_Required:511};var HttpStatusMessages={100:"Continue",101:"Switching Protocols",102:"Processing",103:"Early Hints",200:"OK",201:"Created",202:"Accepted",203:"Non-Authoritative Information",204:"No Content",205:"Reset Content",206:"Partial Content",207:"Multi-Status",208:"Already Reported",226:"IM Used",300:"Multiple Choices",301:"Moved Permanently",302:"Found",303:"See Other",304:"Not Modified",305:"Use Proxy",307:"Temporary Redirect",308:"Permanent Redirect",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",409:"Conflict",410:"Gone",411:"Length Required",412:"Precondition Failed",413:"Payload Too Large",414:"URI Too Long",415:"Unsupported Media Type",416:"Range Not Satisfiable",417:"Expectation Failed",418:"I'm a Teapot",421:"Misdirected Request",422:"Unprocessable Entity",423:"Locked",424:"Failed Dependency",425:"Too Early",426:"Upgrade Required",428:"Precondition Required",429:"Too Many Requests",431:"Request Header Fields Too Large",451:"Unavailable For Legal Reasons",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported",506:"Variant Also Negotiates",507:"Insufficient Storage",508:"Loop Detected",509:"Bandwidth Limit Exceeded",510:"Not Extended",511:"Network Authentication Required"};var NanotronServerResponse=class{constructor(nanotronClientRequest,nativeServerResponse){this.hasBeenSent_=false;this.clientRequest=nanotronClientRequest;this.raw_=nativeServerResponse;this.logger_=(0,import_logger.createLogger)(`nt-server-response(${this.clientRequest.remoteAddress})`);this.logger_.logMethodArgs?.("new",this.clientRequest.url.debugId);this.headers={server:"Alwatr Nanotron","content-type":"text/plain charset=UTF-8"};const crossOrigin=this.clientRequest.routeOption?.crossOrigin;if(crossOrigin?.enable===true){this.headers["access-control-allow-origin"]=crossOrigin.origin;this.headers["access-control-allow-methods"]=crossOrigin.methods;this.headers["access-control-allow-headers"]=crossOrigin.headers;this.headers["access-control-max-age"]=crossOrigin.maxAge}}get hasBeenSent(){return this.hasBeenSent_}get statusCode(){return this.raw_.statusCode}set statusCode(value){this.raw_.statusCode=value}applyHeaders_(){this.logger_.logMethodArgs?.("applyHeaders_",this.headers);for(const key in this.headers){this.raw_.setHeader(key,this.headers[key])}}replyErrorResponse(errorResponse){this.logger_.logMethod?.("replyErrorResponse");this.clientRequest.terminatedHandlers=true;this.headers["content-type"]="application/json";let meta="";if(errorResponse.meta!==void 0){const metaType=typeof errorResponse.meta;if(metaType==="string"||metaType==="number"||metaType==="boolean"||errorResponse.meta===null){meta=`,"meta":"${errorResponse.meta}"`}else if(metaType==="object"){meta=`,"meta":${JSON.stringify(errorResponse.meta)}`}}const responseString=`{"ok":false,"errorCode":"${errorResponse.errorCode}","errorMessage":"${errorResponse.errorMessage}"${meta}}`;this.reply(responseString)}replyError(error){this.logger_.logMethodArgs?.("replyError",{error});this.clientRequest.terminatedHandlers=true;let statusCode=this.statusCode;if(statusCode<HttpStatusCodes.Error_Client_400_Bad_Request){this.statusCode=statusCode=500}if(error instanceof Error){this.replyErrorResponse({ok:false,errorCode:error.name==="Error"?"error_"+statusCode:(error.name+"").toLowerCase(),errorMessage:error.message})}else if(typeof error==="string"){this.replyErrorResponse({ok:false,errorCode:"error_"+statusCode,errorMessage:error})}else if(typeof error==="object"&&error!==null){this.replyJson(error)}else{this.replyErrorResponse({ok:false,errorCode:"error_"+statusCode,errorMessage:HttpStatusMessages[statusCode]})}}replyJson(responseJson){this.logger_.logMethodArgs?.("replyJson",{responseJson});let responseString;try{responseString=JSON.stringify(responseJson)}catch(error){this.logger_.error("replyJson","reply_json_stringify_failed",error,this.clientRequest.url.debugId);this.statusCode=HttpStatusCodes.Error_Server_500_Internal_Server_Error;this.replyErrorResponse({ok:false,errorCode:"reply_json_stringify_failed",errorMessage:"Failed to stringify response JSON."});return}this.headers["content-type"]="application/json";this.reply(responseString)}reply(context){this.logger_.logMethodArgs?.("reply",this.clientRequest.url.debugId);if(this.raw_.writableFinished&&this.hasBeenSent_===false){this.logger_.accident("reply","server_response_writable_finished_directly");this.hasBeenSent_=true}if(this.hasBeenSent_){this.logger_.accident("reply","reply_already_sent",{url:this.clientRequest.url.debugId,replySent:this.hasBeenSent_,writableFinished:this.raw_.writableFinished});return}this.hasBeenSent_=true;try{if(typeof context==="string"){context=Buffer.from(context)}this.headers["content-length"]=context.byteLength;this.applyHeaders_();this.raw_.end(context,"binary")}catch(error){this.logger_.error("reply","server_response_error",error,this.clientRequest.url.debugId);this.hasBeenSent_=false}}};var NanotronClientRequest=class{constructor(url,nativeClientRequest,nativeServerResponse,routeOption){this.sharedMeta={};this.raw_=nativeClientRequest;this.url=url;this.routeOption=routeOption;this.remoteAddress=this.getRemoteAddress__();this.logger_=(0,import_logger2.createLogger)(`nt-client-request(${this.remoteAddress})`);this.logger_.logMethodArgs?.("new",url.debugId);this.serverResponse=new NanotronServerResponse(this,nativeServerResponse)}get headers(){return this.raw_.headers}get queryParams(){if(this.queryParams__===void 0){this.queryParams__={};for(const[key,value]of this.url.searchParams.entries()){this.queryParams__[key]=value}}return this.queryParams__}getBodyRaw(){return new Promise((resolve,reject)=>{const method=this.url.method;if(!(method==="POST"||method==="PUT"||method==="PATCH")){this.serverResponse.headers.connection="close";this.serverResponse.statusCode=HttpStatusCodes.Error_Client_405_Method_Not_Allowed;return reject(new Error("body_not_allowed"))}const contentLength=+this.raw_.headers["content-length"];if(Number.isNaN(contentLength)||contentLength===0){this.serverResponse.headers.connection="close";this.serverResponse.statusCode=HttpStatusCodes.Error_Client_411_Length_Required;return reject(new Error("body_length_required"))}if(contentLength>this.routeOption.bodyLimit){this.serverResponse.headers.connection="close";this.serverResponse.statusCode=HttpStatusCodes.Error_Client_413_Payload_Too_Large;return reject(new Error("body_too_large"))}const dataChunks=[];let receivedLength=0;const onData=chunk=>{receivedLength+=chunk.length;dataChunks.push(chunk);if(receivedLength>this.routeOption.bodyLimit){this.raw_.removeListener("data",onData);this.raw_.removeListener("end",onEnd);this.raw_.removeListener("error",onEnd);dataChunks.length=0;this.serverResponse.headers.connection="close";this.serverResponse.statusCode=HttpStatusCodes.Error_Client_413_Payload_Too_Large;return reject(new Error("body_too_large"))}};const onEnd=err=>{this.raw_.removeListener("data",onData);this.raw_.removeListener("end",onEnd);this.raw_.removeListener("error",onEnd);if(err!==void 0){dataChunks.length=0;this.serverResponse.statusCode=HttpStatusCodes.Error_Client_400_Bad_Request;return reject(err)}if(receivedLength!==contentLength){dataChunks.length=0;this.serverResponse.statusCode=HttpStatusCodes.Error_Client_413_Payload_Too_Large;return reject(new Error("body_too_large"))}const body=Buffer.concat(dataChunks);resolve(body)};this.raw_.on("data",onData);this.raw_.on("end",onEnd);this.raw_.on("error",onEnd);this.raw_.resume()})}getRemoteAddress__(){return this.raw_.headers["x-forwarded-for"]?.split(",").pop()?.trim()||this.raw_.socket.remoteAddress||null}};var import_node_url=require("node:url");var NanotronUrl=class _NanotronUrl extends import_node_url.URL{static{this.versionPattern_=new RegExp("^/v[0-9]+/")}constructor(clientRequest,prefix){let url=clientRequest.url??"";if(prefix!=="/"&&url.indexOf(prefix)===0){url=url.slice(prefix.length-1)}url=url.replace(_NanotronUrl.versionPattern_,"/");super(url,"http://hostname/");this.method=(clientRequest.method??"GET").toUpperCase();this.debugId=`[${this.method}]${this.pathname}`}};var NanotronApiServer=class _NanotronApiServer{static{this.defaultConfig_={host:"0.0.0.0",port:80,requestTimeout:1e4,headersTimeout:13e4,keepAliveTimeout:12e4,healthRoute:true,crossOrigin:{enable:false,origin:"*",methods:"*",headers:"*",maxAge:86400},prefix:"/api/",bodyLimit:1048576}}constructor(config){this.config_={..._NanotronApiServer.defaultConfig_,...config};this.logger_=(0,import_logger3.createLogger)("nt-api-server"+(this.config_.port!==80?":"+this.config_.port:""));this.logger_.logMethodArgs?.("new",{config:this.config_});this.handleClientRequest_=this.handleClientRequest_.bind(this);this.handleServerError_=this.handleServerError_.bind(this);this.handleClientError_=this.handleClientError_.bind(this);this.routeHandlerList__={exact:{},startsWith:{}};this.httpServer=(0,import_node_http.createServer)({keepAlive:true,keepAliveInitialDelay:0,noDelay:true},this.handleClientRequest_);this.httpServer.requestTimeout=this.config_.requestTimeout;this.httpServer.keepAliveTimeout=this.config_.keepAliveTimeout;this.httpServer.headersTimeout=this.config_.headersTimeout;this.httpServer.listen(this.config_.port,this.config_.host,()=>{this.logger_.logOther?.(`listening on ${this.config_.host}:${this.config_.port}`)});this.httpServer.on("error",this.handleServerError_);this.httpServer.on("clientError",this.handleClientError_);this.defineCorsRoute_();if(this.config_.healthRoute){this.defineHealthRoute_()}}close(){this.logger_.logMethod?.("close");this.httpServer.close()}getRouteOption_(url){this.logger_.logMethod?.("getRouteOption_");if(Object.hasOwn(this.routeHandlerList__.exact,url.method)&&Object.hasOwn(this.routeHandlerList__.exact[url.method],url.pathname)){return this.routeHandlerList__.exact[url.method][url.pathname]}if(Object.hasOwn(this.routeHandlerList__.startsWith,url.method)){const routeList=this.routeHandlerList__.startsWith[url.method];for(const pathname in routeList){if(url.pathname.indexOf(pathname)===0){return routeList[pathname]}}}this.logger_.incident?.("getRouteOption_","route_not_found",{method:url.method,url:url.pathname});return null}setRouteOption_(option){this.logger_.logMethodArgs?.("setRouteOption_",option);const routeHandlerList=this.routeHandlerList__[option.matchType];routeHandlerList[option.method]??={};if(Object.hasOwn(routeHandlerList[option.method],option.url)){this.logger_.error("defineRoute","route_already_exists",option);throw new Error("route_already_exists")}routeHandlerList[option.method][option.url]=option}defineRoute(option){const option_={matchType:"exact",preHandlers:[],postHandlers:[],bodyLimit:this.config_.bodyLimit,crossOrigin:this.config_.crossOrigin,...option};this.logger_.logMethodArgs?.("defineRoute",option_);this.setRouteOption_(option_)}handleServerError_(error){if(error.code==="EADDRINUSE"){this.logger_.error("handleServerError_","address_in_use",error)}else{this.logger_.error("handleServerError_","http_server_error",error)}}handleClientError_(err,socket){this.logger_.accident("handleClientError_","http_server_client_error",{errCode:err.code,errMessage:err.message});const errorCode=err.code?.toLowerCase()??`error_${HttpStatusCodes.Error_Client_400_Bad_Request}`;const errorMessage=err.message??HttpStatusMessages[HttpStatusCodes.Error_Client_400_Bad_Request];const errorResponse=`{"ok":false,"errorCode":"${errorCode}","errorMessage":"${errorMessage}"}`;const responseHeaders=[`HTTP/1.1 ${HttpStatusCodes.Error_Client_400_Bad_Request} ${HttpStatusMessages[HttpStatusCodes.Error_Client_400_Bad_Request]}`,"content-type: application/json",`content-length: ${Buffer.byteLength(errorResponse)}`,"\r\n"].join("\r\n");socket.end(responseHeaders+errorResponse)}async handleClientRequest_(nativeClientRequest,nativeServerResponse){this.logger_.logMethod?.("handleClientRequest_");if(nativeClientRequest.url===void 0){this.logger_.accident("handleClientRequest_","http_server_url_undefined");return}const url=new NanotronUrl(nativeClientRequest,this.config_.prefix);const routeOption=this.getRouteOption_(url);const connection=new NanotronClientRequest(url,nativeClientRequest,nativeServerResponse,routeOption);if(routeOption===null){connection.serverResponse.statusCode=HttpStatusCodes.Error_Client_404_Not_Found;connection.serverResponse.replyError();return}try{for(const handler of routeOption.preHandlers){await handler.call(connection,connection,connection.serverResponse,connection.sharedMeta);if(connection.terminatedHandlers===true)return}await routeOption.handler.call(connection,connection,connection.serverResponse,connection.sharedMeta);for(const handler of routeOption.postHandlers){if(connection.terminatedHandlers===true)return;await handler.call(connection,connection,connection.serverResponse,connection.sharedMeta)}}catch(error){this.logger_.error("handleClientRequest_","route_handler_error",error,url.debugId);if(connection.serverResponse.statusCode<HttpStatusCodes.Error_Client_400_Bad_Request){connection.serverResponse.statusCode=HttpStatusCodes.Error_Server_500_Internal_Server_Error}connection.serverResponse.replyError(error)}}defineHealthRoute_(){this.logger_.logMethod?.("defineHealthRoute_");this.defineRoute({method:"GET",url:"/health",handler:function(){const res=this.serverResponse.raw_;res.statusCode=HttpStatusCodes.Success_200_OK;res.setHeader("server","Alwatr Nanotron");res.setHeader("content-type","application/json");res.end('{"ok":true}')}})}defineCorsRoute_(){this.logger_.logMethod?.("defineCorsRoute_");const crossOrigin=this.config_.crossOrigin;if(crossOrigin?.enable!==true)return;this.defineRoute({method:"OPTIONS",matchType:"startsWith",url:"/",handler:function(){const res=this.serverResponse.raw_;res.writeHead(HttpStatusCodes.Success_204_No_Content,{"access-control-allow-origin":crossOrigin.origin,"access-control-allow-methods":crossOrigin.methods,"access-control-allow-headers":crossOrigin.headers,"access-control-max-age":crossOrigin.maxAge+"","content-length":0});res.end()}})}};0&&(module.exports={HttpMethods,HttpStatusCodes,HttpStatusMessages,NanotronApiServer});
|
|
4
4
|
//# sourceMappingURL=main.cjs.map
|
package/dist/main.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/** ๐ฆ @alwatr/nanotron-api-server v4.10.
|
|
2
|
-
__dev_mode__: console.debug("๐ฆ @alwatr/nanotron-api-server v4.10.
|
|
1
|
+
/** ๐ฆ @alwatr/nanotron-api-server v4.10.1 */
|
|
2
|
+
__dev_mode__: console.debug("๐ฆ @alwatr/nanotron-api-server v4.10.1");
|
|
3
3
|
import{createServer}from"node:http";import{createLogger as createLogger3}from"@alwatr/logger";import{createLogger as createLogger2}from"@alwatr/logger";import{createLogger}from"@alwatr/logger";var HttpMethods={GET:"GET",HEAD:"HEAD",POST:"POST",PUT:"PUT",DELETE:"DELETE",CONNECT:"CONNECT",OPTIONS:"OPTIONS",TRACE:"TRACE",PATCH:"PATCH"};var HttpStatusCodes={Info_100_Continue:100,Info_101_Switching_Protocols:101,Info_102_Processing:102,Info_103_Early_Hints:103,Success_200_OK:200,Success_201_Created:201,Success_202_Accepted:202,Success_203_Non_Authoritative_Information:203,Success_204_No_Content:204,Success_205_Reset_Content:205,Success_206_Partial_Content:206,Success_207_Multi_Status:207,Success_208_Already_Reported:208,Success_226_IM_Used:226,Redirect_300_Multiple_Choices:300,Redirect_301_Moved_Permanently:301,Redirect_302_Found:302,Redirect_303_See_Other:303,Redirect_304_Not_Modified:304,Redirect_305_Use_Proxy:305,Redirect_306_Switch_Proxy:306,Redirect_307_Temporary_Redirect:307,Redirect_308_Permanent_Redirect:308,Error_Client_400_Bad_Request:400,Error_Client_401_Unauthorized:401,Error_Client_402_Payment_Required:402,Error_Client_403_Forbidden:403,Error_Client_404_Not_Found:404,Error_Client_405_Method_Not_Allowed:405,Error_Client_406_Not_Acceptable:406,Error_Client_407_Proxy_Authentication_Required:407,Error_Client_408_Request_Timeout:408,Error_Client_409_Conflict:409,Error_Client_410_Gone:410,Error_Client_411_Length_Required:411,Error_Client_412_Precondition_Failed:412,Error_Client_413_Payload_Too_Large:413,Error_Client_414_URI_Too_Long:414,Error_Client_415_Unsupported_Media_Type:415,Error_Client_416_Range_Not_Satisfiable:416,Error_Client_417_Expectation_Failed:417,Error_Client_421_Misdirected_Request:421,Error_Client_422_Unprocessable_Entity:422,Error_Client_423_Locked:423,Error_Client_424_Failed_Dependency:424,Error_Client_425_Too_Early:425,Error_Client_426_Upgrade_Required:426,Error_Client_428_Precondition_Required:428,Error_Client_429_Too_Many_Requests:429,Error_Client_431_Request_Header_Fields_Too_Large:431,Error_Client_451_Unavailable_For_Legal_Reasons:451,Error_Server_500_Internal_Server_Error:500,Error_Server_501_Not_Implemented:501,Error_Server_502_Bad_Gateway:502,Error_Server_503_Service_Unavailable:503,Error_Server_504_Gateway_Timeout:504,Error_Server_505_HTTP_Version_Not_Supported:505,Error_Server_506_Variant_Also_Negotiates:506,Error_Server_507_Insufficient_Storage:507,Error_Server_508_Loop_Detected:508,Error_Server_510_Not_Extended:510,Error_Server_511_Network_Authentication_Required:511};var HttpStatusMessages={100:"Continue",101:"Switching Protocols",102:"Processing",103:"Early Hints",200:"OK",201:"Created",202:"Accepted",203:"Non-Authoritative Information",204:"No Content",205:"Reset Content",206:"Partial Content",207:"Multi-Status",208:"Already Reported",226:"IM Used",300:"Multiple Choices",301:"Moved Permanently",302:"Found",303:"See Other",304:"Not Modified",305:"Use Proxy",307:"Temporary Redirect",308:"Permanent Redirect",400:"Bad Request",401:"Unauthorized",402:"Payment Required",403:"Forbidden",404:"Not Found",405:"Method Not Allowed",406:"Not Acceptable",407:"Proxy Authentication Required",408:"Request Timeout",409:"Conflict",410:"Gone",411:"Length Required",412:"Precondition Failed",413:"Payload Too Large",414:"URI Too Long",415:"Unsupported Media Type",416:"Range Not Satisfiable",417:"Expectation Failed",418:"I'm a Teapot",421:"Misdirected Request",422:"Unprocessable Entity",423:"Locked",424:"Failed Dependency",425:"Too Early",426:"Upgrade Required",428:"Precondition Required",429:"Too Many Requests",431:"Request Header Fields Too Large",451:"Unavailable For Legal Reasons",500:"Internal Server Error",501:"Not Implemented",502:"Bad Gateway",503:"Service Unavailable",504:"Gateway Timeout",505:"HTTP Version Not Supported",506:"Variant Also Negotiates",507:"Insufficient Storage",508:"Loop Detected",509:"Bandwidth Limit Exceeded",510:"Not Extended",511:"Network Authentication Required"};var NanotronServerResponse=class{constructor(nanotronClientRequest,nativeServerResponse){this.hasBeenSent_=false;this.clientRequest=nanotronClientRequest;this.raw_=nativeServerResponse;this.logger_=createLogger(`nt-server-response(${this.clientRequest.remoteAddress})`);this.logger_.logMethodArgs?.("new",this.clientRequest.url.debugId);this.headers={server:"Alwatr Nanotron","content-type":"text/plain charset=UTF-8"};const crossOrigin=this.clientRequest.routeOption?.crossOrigin;if(crossOrigin?.enable===true){this.headers["access-control-allow-origin"]=crossOrigin.origin;this.headers["access-control-allow-methods"]=crossOrigin.methods;this.headers["access-control-allow-headers"]=crossOrigin.headers;this.headers["access-control-max-age"]=crossOrigin.maxAge}}get hasBeenSent(){return this.hasBeenSent_}get statusCode(){return this.raw_.statusCode}set statusCode(value){this.raw_.statusCode=value}applyHeaders_(){this.logger_.logMethodArgs?.("applyHeaders_",this.headers);for(const key in this.headers){this.raw_.setHeader(key,this.headers[key])}}replyErrorResponse(errorResponse){this.logger_.logMethod?.("replyErrorResponse");this.clientRequest.terminatedHandlers=true;this.headers["content-type"]="application/json";let meta="";if(errorResponse.meta!==void 0){const metaType=typeof errorResponse.meta;if(metaType==="string"||metaType==="number"||metaType==="boolean"||errorResponse.meta===null){meta=`,"meta":"${errorResponse.meta}"`}else if(metaType==="object"){meta=`,"meta":${JSON.stringify(errorResponse.meta)}`}}const responseString=`{"ok":false,"errorCode":"${errorResponse.errorCode}","errorMessage":"${errorResponse.errorMessage}"${meta}}`;this.reply(responseString)}replyError(error){this.logger_.logMethodArgs?.("replyError",{error});this.clientRequest.terminatedHandlers=true;let statusCode=this.statusCode;if(statusCode<HttpStatusCodes.Error_Client_400_Bad_Request){this.statusCode=statusCode=500}if(error instanceof Error){this.replyErrorResponse({ok:false,errorCode:error.name==="Error"?"error_"+statusCode:(error.name+"").toLowerCase(),errorMessage:error.message})}else if(typeof error==="string"){this.replyErrorResponse({ok:false,errorCode:"error_"+statusCode,errorMessage:error})}else if(typeof error==="object"&&error!==null){this.replyJson(error)}else{this.replyErrorResponse({ok:false,errorCode:"error_"+statusCode,errorMessage:HttpStatusMessages[statusCode]})}}replyJson(responseJson){this.logger_.logMethodArgs?.("replyJson",{responseJson});let responseString;try{responseString=JSON.stringify(responseJson)}catch(error){this.logger_.error("replyJson","reply_json_stringify_failed",error,this.clientRequest.url.debugId);this.statusCode=HttpStatusCodes.Error_Server_500_Internal_Server_Error;this.replyErrorResponse({ok:false,errorCode:"reply_json_stringify_failed",errorMessage:"Failed to stringify response JSON."});return}this.headers["content-type"]="application/json";this.reply(responseString)}reply(context){this.logger_.logMethodArgs?.("reply",this.clientRequest.url.debugId);if(this.raw_.writableFinished&&this.hasBeenSent_===false){this.logger_.accident("reply","server_response_writable_finished_directly");this.hasBeenSent_=true}if(this.hasBeenSent_){this.logger_.accident("reply","reply_already_sent",{url:this.clientRequest.url.debugId,replySent:this.hasBeenSent_,writableFinished:this.raw_.writableFinished});return}this.hasBeenSent_=true;try{if(typeof context==="string"){context=Buffer.from(context)}this.headers["content-length"]=context.byteLength;this.applyHeaders_();this.raw_.end(context,"binary")}catch(error){this.logger_.error("reply","server_response_error",error,this.clientRequest.url.debugId);this.hasBeenSent_=false}}};var NanotronClientRequest=class{constructor(url,nativeClientRequest,nativeServerResponse,routeOption){this.sharedMeta={};this.raw_=nativeClientRequest;this.url=url;this.routeOption=routeOption;this.remoteAddress=this.getRemoteAddress__();this.logger_=createLogger2(`nt-client-request(${this.remoteAddress})`);this.logger_.logMethodArgs?.("new",url.debugId);this.serverResponse=new NanotronServerResponse(this,nativeServerResponse)}get headers(){return this.raw_.headers}get queryParams(){if(this.queryParams__===void 0){this.queryParams__={};for(const[key,value]of this.url.searchParams.entries()){this.queryParams__[key]=value}}return this.queryParams__}getBodyRaw(){return new Promise((resolve,reject)=>{const method=this.url.method;if(!(method==="POST"||method==="PUT"||method==="PATCH")){this.serverResponse.headers.connection="close";this.serverResponse.statusCode=HttpStatusCodes.Error_Client_405_Method_Not_Allowed;return reject(new Error("body_not_allowed"))}const contentLength=+this.raw_.headers["content-length"];if(Number.isNaN(contentLength)||contentLength===0){this.serverResponse.headers.connection="close";this.serverResponse.statusCode=HttpStatusCodes.Error_Client_411_Length_Required;return reject(new Error("body_length_required"))}if(contentLength>this.routeOption.bodyLimit){this.serverResponse.headers.connection="close";this.serverResponse.statusCode=HttpStatusCodes.Error_Client_413_Payload_Too_Large;return reject(new Error("body_too_large"))}const dataChunks=[];let receivedLength=0;const onData=chunk=>{receivedLength+=chunk.length;dataChunks.push(chunk);if(receivedLength>this.routeOption.bodyLimit){this.raw_.removeListener("data",onData);this.raw_.removeListener("end",onEnd);this.raw_.removeListener("error",onEnd);dataChunks.length=0;this.serverResponse.headers.connection="close";this.serverResponse.statusCode=HttpStatusCodes.Error_Client_413_Payload_Too_Large;return reject(new Error("body_too_large"))}};const onEnd=err=>{this.raw_.removeListener("data",onData);this.raw_.removeListener("end",onEnd);this.raw_.removeListener("error",onEnd);if(err!==void 0){dataChunks.length=0;this.serverResponse.statusCode=HttpStatusCodes.Error_Client_400_Bad_Request;return reject(err)}if(receivedLength!==contentLength){dataChunks.length=0;this.serverResponse.statusCode=HttpStatusCodes.Error_Client_413_Payload_Too_Large;return reject(new Error("body_too_large"))}const body=Buffer.concat(dataChunks);resolve(body)};this.raw_.on("data",onData);this.raw_.on("end",onEnd);this.raw_.on("error",onEnd);this.raw_.resume()})}getRemoteAddress__(){return this.raw_.headers["x-forwarded-for"]?.split(",").pop()?.trim()||this.raw_.socket.remoteAddress||null}};import{URL}from"node:url";var NanotronUrl=class _NanotronUrl extends URL{static{this.versionPattern_=new RegExp("^/v[0-9]+/")}constructor(clientRequest,prefix){let url=clientRequest.url??"";if(prefix!=="/"&&url.indexOf(prefix)===0){url=url.slice(prefix.length-1)}url=url.replace(_NanotronUrl.versionPattern_,"/");super(url,"http://hostname/");this.method=(clientRequest.method??"GET").toUpperCase();this.debugId=`[${this.method}]${this.pathname}`}};var NanotronApiServer=class _NanotronApiServer{static{this.defaultConfig_={host:"0.0.0.0",port:80,requestTimeout:1e4,headersTimeout:13e4,keepAliveTimeout:12e4,healthRoute:true,crossOrigin:{enable:false,origin:"*",methods:"*",headers:"*",maxAge:86400},prefix:"/api/",bodyLimit:1048576}}constructor(config){this.config_={..._NanotronApiServer.defaultConfig_,...config};this.logger_=createLogger3("nt-api-server"+(this.config_.port!==80?":"+this.config_.port:""));this.logger_.logMethodArgs?.("new",{config:this.config_});this.handleClientRequest_=this.handleClientRequest_.bind(this);this.handleServerError_=this.handleServerError_.bind(this);this.handleClientError_=this.handleClientError_.bind(this);this.routeHandlerList__={exact:{},startsWith:{}};this.httpServer=createServer({keepAlive:true,keepAliveInitialDelay:0,noDelay:true},this.handleClientRequest_);this.httpServer.requestTimeout=this.config_.requestTimeout;this.httpServer.keepAliveTimeout=this.config_.keepAliveTimeout;this.httpServer.headersTimeout=this.config_.headersTimeout;this.httpServer.listen(this.config_.port,this.config_.host,()=>{this.logger_.logOther?.(`listening on ${this.config_.host}:${this.config_.port}`)});this.httpServer.on("error",this.handleServerError_);this.httpServer.on("clientError",this.handleClientError_);this.defineCorsRoute_();if(this.config_.healthRoute){this.defineHealthRoute_()}}close(){this.logger_.logMethod?.("close");this.httpServer.close()}getRouteOption_(url){this.logger_.logMethod?.("getRouteOption_");if(Object.hasOwn(this.routeHandlerList__.exact,url.method)&&Object.hasOwn(this.routeHandlerList__.exact[url.method],url.pathname)){return this.routeHandlerList__.exact[url.method][url.pathname]}if(Object.hasOwn(this.routeHandlerList__.startsWith,url.method)){const routeList=this.routeHandlerList__.startsWith[url.method];for(const pathname in routeList){if(url.pathname.indexOf(pathname)===0){return routeList[pathname]}}}this.logger_.incident?.("getRouteOption_","route_not_found",{method:url.method,url:url.pathname});return null}setRouteOption_(option){this.logger_.logMethodArgs?.("setRouteOption_",option);const routeHandlerList=this.routeHandlerList__[option.matchType];routeHandlerList[option.method]??={};if(Object.hasOwn(routeHandlerList[option.method],option.url)){this.logger_.error("defineRoute","route_already_exists",option);throw new Error("route_already_exists")}routeHandlerList[option.method][option.url]=option}defineRoute(option){const option_={matchType:"exact",preHandlers:[],postHandlers:[],bodyLimit:this.config_.bodyLimit,crossOrigin:this.config_.crossOrigin,...option};this.logger_.logMethodArgs?.("defineRoute",option_);this.setRouteOption_(option_)}handleServerError_(error){if(error.code==="EADDRINUSE"){this.logger_.error("handleServerError_","address_in_use",error)}else{this.logger_.error("handleServerError_","http_server_error",error)}}handleClientError_(err,socket){this.logger_.accident("handleClientError_","http_server_client_error",{errCode:err.code,errMessage:err.message});const errorCode=err.code?.toLowerCase()??`error_${HttpStatusCodes.Error_Client_400_Bad_Request}`;const errorMessage=err.message??HttpStatusMessages[HttpStatusCodes.Error_Client_400_Bad_Request];const errorResponse=`{"ok":false,"errorCode":"${errorCode}","errorMessage":"${errorMessage}"}`;const responseHeaders=[`HTTP/1.1 ${HttpStatusCodes.Error_Client_400_Bad_Request} ${HttpStatusMessages[HttpStatusCodes.Error_Client_400_Bad_Request]}`,"content-type: application/json",`content-length: ${Buffer.byteLength(errorResponse)}`,"\r\n"].join("\r\n");socket.end(responseHeaders+errorResponse)}async handleClientRequest_(nativeClientRequest,nativeServerResponse){this.logger_.logMethod?.("handleClientRequest_");if(nativeClientRequest.url===void 0){this.logger_.accident("handleClientRequest_","http_server_url_undefined");return}const url=new NanotronUrl(nativeClientRequest,this.config_.prefix);const routeOption=this.getRouteOption_(url);const connection=new NanotronClientRequest(url,nativeClientRequest,nativeServerResponse,routeOption);if(routeOption===null){connection.serverResponse.statusCode=HttpStatusCodes.Error_Client_404_Not_Found;connection.serverResponse.replyError();return}try{for(const handler of routeOption.preHandlers){await handler.call(connection,connection,connection.serverResponse,connection.sharedMeta);if(connection.terminatedHandlers===true)return}await routeOption.handler.call(connection,connection,connection.serverResponse,connection.sharedMeta);for(const handler of routeOption.postHandlers){if(connection.terminatedHandlers===true)return;await handler.call(connection,connection,connection.serverResponse,connection.sharedMeta)}}catch(error){this.logger_.error("handleClientRequest_","route_handler_error",error,url.debugId);if(connection.serverResponse.statusCode<HttpStatusCodes.Error_Client_400_Bad_Request){connection.serverResponse.statusCode=HttpStatusCodes.Error_Server_500_Internal_Server_Error}connection.serverResponse.replyError(error)}}defineHealthRoute_(){this.logger_.logMethod?.("defineHealthRoute_");this.defineRoute({method:"GET",url:"/health",handler:function(){const res=this.serverResponse.raw_;res.statusCode=HttpStatusCodes.Success_200_OK;res.setHeader("server","Alwatr Nanotron");res.setHeader("content-type","application/json");res.end('{"ok":true}')}})}defineCorsRoute_(){this.logger_.logMethod?.("defineCorsRoute_");const crossOrigin=this.config_.crossOrigin;if(crossOrigin?.enable!==true)return;this.defineRoute({method:"OPTIONS",matchType:"startsWith",url:"/",handler:function(){const res=this.serverResponse.raw_;res.writeHead(HttpStatusCodes.Success_204_No_Content,{"access-control-allow-origin":crossOrigin.origin,"access-control-allow-methods":crossOrigin.methods,"access-control-allow-headers":crossOrigin.headers,"access-control-max-age":crossOrigin.maxAge+"","content-length":0});res.end()}})}};export{HttpMethods,HttpStatusCodes,HttpStatusMessages,NanotronApiServer};
|
|
4
4
|
//# sourceMappingURL=main.mjs.map
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alwatr/nanotron-api-server",
|
|
3
3
|
"description": "Nanotron: Your Lightweight, High-Performance Micro/Nano Service Framework. Nanotron is designed for building blazingly fast and efficient microservices and APIs. Its minimalist approach and focus on performance make it ideal for resource-constrained environments and scenarios where every millisecond counts.",
|
|
4
|
-
"version": "4.10.
|
|
4
|
+
"version": "4.10.1",
|
|
5
5
|
"author": "S. Ali Mihandoost <ali.mihandoost@gmail.com>",
|
|
6
6
|
"bugs": "https://github.com/Alwatr/nanotron/issues",
|
|
7
7
|
"dependencies": {
|
|
@@ -64,7 +64,8 @@
|
|
|
64
64
|
"watch:es": "yarn run build:es --watch",
|
|
65
65
|
"watch:ts": "yarn run build:ts --watch --preserveWatchOutput"
|
|
66
66
|
},
|
|
67
|
+
"sideEffects": false,
|
|
67
68
|
"type": "module",
|
|
68
69
|
"types": "./dist/main.d.ts",
|
|
69
|
-
"gitHead": "
|
|
70
|
+
"gitHead": "e077211736b90023d4842a23b252dc5284d0445a"
|
|
70
71
|
}
|