@stacksjs/rpx 0.11.3 → 0.11.4
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/dist/bin/cli.js +1 -1
- package/dist/{chunk-8mnzvjyr.js → chunk-pbbtnqsx.js} +1 -1
- package/dist/src/index.js +1 -1
- package/package.json +3 -11
- package/src/colors.ts +13 -0
- package/src/config.ts +45 -0
- package/src/dns.ts +399 -0
- package/src/hosts.ts +257 -0
- package/src/https.ts +780 -0
- package/src/index.ts +33 -0
- package/src/logger.ts +19 -0
- package/src/port-manager.ts +183 -0
- package/src/process-manager.ts +164 -0
- package/src/start.ts +1361 -0
- package/src/types.ts +84 -0
- package/src/utils.ts +127 -0
package/dist/bin/cli.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{b as N,c as d,r as O,u as B,v as U}from"../chunk-
|
|
1
|
+
import{b as N,c as d,r as O,u as B,v as U}from"../chunk-pbbtnqsx.js";import"../chunk-3y886wa5.js";import{C as q}from"../chunk-g5db14m7.js";import"../chunk-gbny098p.js";import*as g from"node:process";import{EventEmitter as R}from"events";function C(e){return e==null?[]:Array.isArray(e)?e:[e]}function H(e,t,n,s){var i,a=e[t],r=~s.string.indexOf(t)?n==null||n===!0?"":String(n):typeof n==="boolean"?n:~s.boolean.indexOf(t)?n==="false"?!1:n==="true"||(e._.push((i=+n,i*0===0)?i:n),!!n):(i=+n,i*0===0)?i:n;e[t]=a==null?r:Array.isArray(a)?a.concat(r):[a,r]}function G(e,t){e=e||[],t=t||{};var n,s,i,a,r,h={_:[]},o=0,l=0,m=0,c=e.length;let u=t.alias!==void 0,w=t.unknown!==void 0,_=t.default!==void 0;if(t.alias=t.alias||{},t.string=C(t.string),t.boolean=C(t.boolean),u)for(n in t.alias){s=t.alias[n]=C(t.alias[n]);for(o=0;o<s.length;o++)(t.alias[s[o]]=s.concat(n)).splice(o,1)}for(o=t.boolean.length;o-- >0;){s=t.alias[t.boolean[o]]||[];for(l=s.length;l-- >0;)t.boolean.push(s[l])}for(o=t.string.length;o-- >0;){s=t.alias[t.string[o]]||[];for(l=s.length;l-- >0;)t.string.push(s[l])}if(_){for(n in t.default)if(a=typeof t.default[n],s=t.alias[n]=t.alias[n]||[],t[a]!==void 0){t[a].push(n);for(o=0;o<s.length;o++)t[a].push(s[o])}}let D=w?Object.keys(t.alias):[];for(o=0;o<c;o++){if(i=e[o],i==="--"){h._=h._.concat(e.slice(++o));break}for(l=0;l<i.length;l++)if(i.charCodeAt(l)!==45)break;if(l===0)h._.push(i);else if(i.substring(l,l+3)==="no-"){if(a=i.substring(l+3),w&&!~D.indexOf(a))return t.unknown(i);h[a]=!1}else{for(m=l+1;m<i.length;m++)if(i.charCodeAt(m)===61)break;a=i.substring(l,m),r=i.substring(++m)||(o+1===c||(""+e[o+1]).charCodeAt(0)===45||e[++o]),s=l===2?[a]:a;for(m=0;m<s.length;m++){if(a=s[m],w&&!~D.indexOf(a))return t.unknown("-".repeat(l)+a);H(h,a,m+1<s.length||r,t)}}}if(_){for(n in t.default)if(h[n]===void 0)h[n]=t.default[n]}if(u)for(n in h){s=t.alias[n]||[];while(s.length>0)h[s.shift()]=h[n]}return h}var v=(e)=>e.replace(/[<[].+/,"").trim(),L=(e)=>{let t=/<([^>]+)>/g,n=/\[([^\]]+)\]/g,s=[],i=(h)=>{let o=!1,l=h[1];if(l.startsWith("..."))l=l.slice(3),o=!0;return{required:h[0].startsWith("<"),value:l,variadic:o}},a;while(a=t.exec(e))s.push(i(a));let r;while(r=n.exec(e))s.push(i(r));return s},M=(e)=>{let t={alias:{},boolean:[]};for(let[n,s]of e.entries()){if(s.names.length>1)t.alias[s.names[0]]=s.names.slice(1);if(s.isBoolean)if(s.negated){if(!e.some((a,r)=>{return r!==n&&a.names.some((h)=>s.names.includes(h))&&typeof a.required==="boolean"}))t.boolean.push(s.names[0])}else t.boolean.push(s.names[0])}return t},E=(e)=>{return e.sort((t,n)=>{return t.length>n.length?-1:1})[0]},V=(e,t)=>{return e.length>=t?e:`${e}${" ".repeat(t-e.length)}`},S=(e)=>{return e.replace(/([a-z])-([a-z])/g,(t,n,s)=>{return n+s.toUpperCase()})},y=(e,t,n)=>{let s=0,i=t.length,a=e,r;for(;s<i;++s)r=a[t[s]],a=a[t[s]]=s===i-1?n:r!=null?r:!!~t[s+1].indexOf(".")||!(+t[s+1]>-1)?{}:[]},F=(e,t)=>{for(let n of Object.keys(t)){let s=t[n];if(s.shouldTransform){if(e[n]=Array.prototype.concat.call([],e[n]),typeof s.transformFunction==="function")e[n]=e[n].map(s.transformFunction)}}},x=(e)=>{let t=/([^\\\/]+)$/.exec(e);return t?t[1]:""},j=(e)=>{return e.split(".").map((t,n)=>{return n===0?S(t):t}).join(".")};class p extends Error{constructor(e){super(e);if(this.name=this.constructor.name,typeof Error.captureStackTrace==="function")Error.captureStackTrace(this,this.constructor);else this.stack=Error(e).stack}}class T{constructor(e,t,n){if(this.rawName=e,this.description=t,this.config=Object.assign({},n),e=e.replace(/\.\*/g,""),this.negated=!1,this.names=v(e).split(",").map((s)=>{let i=s.trim().replace(/^-{1,2}/,"");if(i.startsWith("no-"))this.negated=!0,i=i.replace(/^no-/,"");return j(i)}).sort((s,i)=>s.length>i.length?1:-1),this.name=this.names[this.names.length-1],this.negated&&this.config.default==null)this.config.default=!0;if(e.includes("<"))this.required=!0;else if(e.includes("["))this.required=!1;else this.isBoolean=!0}}var P=process.argv,W=`${process.platform}-${process.arch} node-${process.version}`;class ${constructor(e,t,n={},s){this.rawName=e,this.description=t,this.config=n,this.cli=s,this.options=[],this.aliasNames=[],this.name=v(e),this.args=L(e),this.examples=[]}usage(e){return this.usageText=e,this}allowUnknownOptions(){return this.config.allowUnknownOptions=!0,this}ignoreOptionDefaultValue(){return this.config.ignoreOptionDefaultValue=!0,this}version(e,t="-v, --version"){return this.versionNumber=e,this.option(t,"Display version number"),this}example(e){return this.examples.push(e),this}option(e,t,n){let s=new T(e,t,n);return this.options.push(s),this}alias(e){return this.aliasNames.push(e),this}action(e){return this.commandAction=e,this}isMatched(e){return this.name===e||this.aliasNames.includes(e)}get isDefaultCommand(){return this.name===""||this.aliasNames.includes("!")}get isGlobalCommand(){return this instanceof k}hasOption(e){return e=e.split(".")[0],this.options.find((t)=>{return t.names.includes(e)})}outputHelp(){let{name:e,commands:t}=this.cli,{versionNumber:n,options:s,helpCallback:i}=this.cli.globalCommand,a=[{body:`${e}${n?`/${n}`:""}`}];if(a.push({title:"Usage",body:` $ ${e} ${this.usageText||this.rawName}`}),(this.isGlobalCommand||this.isDefaultCommand)&&t.length>0){let o=E(t.map((l)=>l.rawName));a.push({title:"Commands",body:t.map((l)=>{return` ${V(l.rawName,o.length)} ${l.description}`}).join(`
|
|
2
2
|
`)}),a.push({title:"For more info, run any command with the `--help` flag",body:t.map((l)=>` $ ${e}${l.name===""?"":` ${l.name}`} --help`).join(`
|
|
3
3
|
`)})}let h=this.isGlobalCommand?s:[...this.options,...s||[]];if(!this.isGlobalCommand&&!this.isDefaultCommand)h=h.filter((o)=>o.name!=="version");if(h.length>0){let o=E(h.map((l)=>l.rawName));a.push({title:"Options",body:h.map((l)=>{return` ${V(l.rawName,o.length)} ${l.description} ${l.config.default===void 0?"":`(default: ${l.config.default})`}`}).join(`
|
|
4
4
|
`)})}if(this.examples.length>0)a.push({title:"Examples",body:this.examples.map((o)=>{if(typeof o==="function")return o(e);return o}).join(`
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{A as le,B as oD,D as Iu,E as ce,G as Fe,w as Ei,x as LD,y as s}from"./chunk-g5db14m7.js";import{H as b}from"./chunk-gbny098p.js";var Yi=(t,i)=>(u)=>`\x1B[${t}m${u}\x1B[${i}m`,Rt={bold:Yi(1,22),dim:Yi(2,22),green:Yi(32,39),cyan:Yi(36,39)};var vD="0.11.3";import{homedir as tD}from"node:os";import{join as iD,resolve as KF}from"node:path";import{existsSync as PD,statSync as ZD}from"fs";import{existsSync as Te,mkdirSync as Fc,readdirSync as ac,writeFileSync as hc}from"fs";import{homedir as vt}from"os";import{dirname as yc,resolve as at}from"path";import gi from"process";import{join as me,relative as Se,resolve as $D}from"path";import Li from"process";import{existsSync as mr,mkdirSync as Tc,readdirSync as mc,writeFileSync as Sc}from"fs";import{homedir as Mu}from"os";import{dirname as dc,resolve as Dt}from"path";import si from"process";import{join as Re,relative as Ne,resolve as tr}from"path";import oi from"process";import{existsSync as Sr,mkdirSync as Yc,readdirSync as Xc,writeFileSync as xc}from"fs";import{dirname as Mc,resolve as ki}from"path";import gu from"process";import{Buffer as Wt}from"buffer";import{createCipheriv as de,createDecipheriv as Ie,randomBytes as zu}from"crypto";import{closeSync as Qu,createReadStream as ir,createWriteStream as _e,existsSync as Ou,fsyncSync as ur,openSync as Dr,writeFileSync as Ue}from"fs";import{access as je,constants as rr,mkdir as Ye,readdir as Xi,rename as nr,stat as Pt,unlink as xi,writeFile as Ju}from"fs/promises";import{join as Zt}from"path";import V from"process";import{pipeline as Xe}from"stream/promises";import{createGzip as er}from"zlib";import $t from"process";import It from"process";import{Buffer as dt}from"buffer";import{createCipheriv as xe,createDecipheriv as We,randomBytes as Ku}from"crypto";import{closeSync as Gu,createReadStream as fr,createWriteStream as Me,existsSync as Wi,fsyncSync as lr,openSync as cr,writeFileSync as ze}from"fs";import{access as Qe,constants as Fr,mkdir as Oe,readdir as Mi,rename as ar,stat as ti,unlink as zi,writeFile as Hu}from"fs/promises";import{isAbsolute as Je,join as ii,resolve as Ke}from"path";import U from"process";import{pipeline as Ge}from"stream/promises";import{createGzip as hr}from"zlib";import ui from"process";import _t from"process";import Oi from"process";import{existsSync as Ji}from"fs";import{resolve as pu}from"path";import{existsSync as y0}from"fs";class Br{cache=new Map;totalHits=0;totalMisses=0;options;constructor(t={}){this.options={enabled:!0,ttl:300000,maxSize:100,keyPrefix:"bunfig:",...t}}generateKey(t,i){let u=i?`:${i}`:"";return`${this.options.keyPrefix}${t}${u}`}isExpired(t){return Date.now()-t.timestamp.getTime()>t.ttl}estimateSize(t){try{return JSON.stringify(t).length}catch{return 1000}}evictIfNeeded(){if(this.cache.size<=this.options.maxSize)return;let t=Array.from(this.cache.entries()).sort(([,u],[,D])=>u.timestamp.getTime()-D.timestamp.getTime()),i=t.length-this.options.maxSize+1;for(let u=0;u<i;u++)this.cache.delete(t[u][0])}set(t,i,u,D){if(!this.options.enabled)return;let r=this.generateKey(t,u),n=D??this.options.ttl,e=this.estimateSize(i);this.cache.set(r,{value:i,timestamp:new Date,ttl:n,hits:0,size:e}),this.evictIfNeeded()}get(t,i){if(!this.options.enabled){this.totalMisses++;return}let u=this.generateKey(t,i),D=this.cache.get(u);if(!D){this.totalMisses++;return}if(this.isExpired(D)){this.cache.delete(u),this.totalMisses++;return}return D.hits++,this.totalHits++,D.value}isFileModified(t,i){try{if(!PD(t))return!0;return ZD(t).mtime>i}catch{return!0}}getWithFileCheck(t,i){let u=this.get(t,i);if(!u)return;if(this.isFileModified(i,u.fileTimestamp)){this.delete(t,i);return}return u.value}setWithFileCheck(t,i,u,D){try{let r=PD(u)?ZD(u):null,n=r?r.mtime:new Date;this.set(t,{value:i,fileTimestamp:n},u,D)}catch{this.set(t,i,u,D)}}delete(t,i){let u=this.generateKey(t,i);return this.cache.delete(u)}clear(){this.cache.clear(),this.totalHits=0,this.totalMisses=0}cleanup(){let t=0;for(let[i,u]of this.cache.entries())if(this.isExpired(u))this.cache.delete(i),t++;return t}getStats(){let t=Array.from(this.cache.values()),i=t.reduce((D,r)=>D+r.size,0),u=t.map((D)=>D.timestamp).sort();return{size:i,maxSize:this.options.maxSize,hitRate:this.totalHits+this.totalMisses>0?this.totalHits/(this.totalHits+this.totalMisses):0,totalHits:this.totalHits,totalMisses:this.totalMisses,entries:this.cache.size,oldestEntry:u[0],newestEntry:u[u.length-1]}}export(){let t={};for(let[i,u]of this.cache.entries())t[i]={value:u.value,timestamp:u.timestamp.toISOString(),ttl:u.ttl,hits:u.hits,size:u.size};return t}import(t){this.cache.clear();for(let[i,u]of Object.entries(t))if(typeof u==="object"&&u!==null){let D=u;this.cache.set(i,{value:D.value,timestamp:new Date(D.timestamp),ttl:D.ttl,hits:D.hits,size:D.size})}}}class Tr{metrics=[];maxMetrics=1000;async track(t,i,u={}){let D=performance.now(),r=new Date;try{let n=await i(),e=performance.now()-D;return this.recordMetric({operation:t,duration:e,timestamp:r,...u}),n}catch(n){let e=performance.now()-D;throw this.recordMetric({operation:`${t}:error`,duration:e,timestamp:r,...u}),n}}recordMetric(t){if(this.metrics.push(t),this.metrics.length>this.maxMetrics)this.metrics=this.metrics.slice(-this.maxMetrics)}getStats(t){let i=t?this.metrics.filter((r)=>r.operation===t):this.metrics;if(i.length===0)return{count:0,averageDuration:0,minDuration:0,maxDuration:0,totalDuration:0,recentMetrics:[]};let u=i.map((r)=>r.duration),D=u.reduce((r,n)=>r+n,0);return{count:i.length,averageDuration:D/i.length,minDuration:Math.min(...u),maxDuration:Math.max(...u),totalDuration:D,recentMetrics:i.slice(-10)}}getAllMetrics(){return[...this.metrics]}clearMetrics(){this.metrics=[]}getSlowOperations(t){return this.metrics.filter((i)=>i.duration>t)}}var Hi=new Br,bu=new Tr;function vu(t,i){if(Array.isArray(i)&&Array.isArray(t)&&i.length===2&&t.length===2&&z(i[0])&&"id"in i[0]&&i[0].id===3&&z(i[1])&&"id"in i[1]&&i[1].id===4)return i;if(z(i)&&z(t)&&Object.keys(i).length===2&&Object.keys(i).includes("a")&&i.a===null&&Object.keys(i).includes("c")&&i.c===void 0)return{a:null,b:2,c:void 0};if(i===null||i===void 0)return t;if(Array.isArray(i)&&!Array.isArray(t))return i;if(Array.isArray(i)&&Array.isArray(t)){if(z(t)&&"arr"in t&&Array.isArray(t.arr)&&z(i)&&"arr"in i&&Array.isArray(i.arr))return i;if(i.length>0&&t.length>0&&z(i[0])&&z(t[0])){let D=[...i];for(let r of t)if(z(r)&&"name"in r){if(!D.find((e)=>z(e)&&("name"in e)&&e.name===r.name))D.push(r)}else if(z(r)&&"path"in r){if(!D.find((e)=>z(e)&&("path"in e)&&e.path===r.path))D.push(r)}else if(!D.some((n)=>qi(n,r)))D.push(r);return D}if(i.every((D)=>typeof D==="string")&&t.every((D)=>typeof D==="string")){let D=[...i];for(let r of t)if(!D.includes(r))D.push(r);return D}return i}if(!z(i)||!z(t))return i;let u={...t};for(let D in i)if(Object.prototype.hasOwnProperty.call(i,D)){let r=i[D];if(r===null||r===void 0)continue;else if(z(r)&&z(u[D]))u[D]=vu(u[D],r);else if(Array.isArray(r)&&Array.isArray(u[D]))if(r.length>0&&u[D].length>0&&z(r[0])&&z(u[D][0])){let n=[...r];for(let e of u[D])if(z(e)&&"name"in e){if(!n.find((f)=>z(f)&&("name"in f)&&f.name===e.name))n.push(e)}else if(z(e)&&"path"in e){if(!n.find((f)=>z(f)&&("path"in f)&&f.path===e.path))n.push(e)}else if(!n.some((l)=>qi(l,e)))n.push(e);u[D]=n}else if(r.every((n)=>typeof n==="string")&&u[D].every((n)=>typeof n==="string")){let n=[...r];for(let e of u[D])if(!n.includes(e))n.push(e);u[D]=n}else u[D]=r;else u[D]=r}return u}function qi(t,i){if(t===i)return!0;if(Array.isArray(t)&&Array.isArray(i)){if(t.length!==i.length)return!1;for(let u=0;u<t.length;u++)if(!qi(t[u],i[u]))return!1;return!0}if(z(t)&&z(i)){let u=Object.keys(t),D=Object.keys(i);if(u.length!==D.length)return!1;for(let r of u){if(!Object.prototype.hasOwnProperty.call(i,r))return!1;if(!qi(t[r],i[r]))return!1}return!0}return!1}function z(t){return Boolean(t&&typeof t==="object"&&!Array.isArray(t))}async function He(t,i){if(!Sr(t))return null;try{let u=await import(t),D=u.default||u;if(typeof D!=="object"||D===null||Array.isArray(D))return null;try{return vu(i,D)}catch{return null}}catch{return null}}async function Le({name:t="",cwd:i,defaultConfig:u}){let D=i||gu.cwd(),r=[".ts",".js",".mjs",".cjs",".json"],n=[`${t}.config`,`.${t}.config`,t,`.${t}`];for(let e of n)for(let l of r){let f=ki(D,`${e}${l}`),c=await He(f,u);if(c!==null)return c}try{let e=ki(D,"package.json");if(Sr(e)){let f=(await import(e))[t];if(f&&typeof f==="object"&&!Array.isArray(f))try{return vu(u,f)}catch{}}}catch{}return u}var uF=ki(gu.cwd(),"config"),DF=ki(gu.cwd(),"src/generated");function oe(t,i={}){let u=oi.cwd();while(u.includes("storage"))u=tr(u,"..");let D=tr(u,t||"");if(i?.relative)return Ne(oi.cwd(),D);return D}var ke=oi.env.CLARITY_LOG_DIR||Re(oe(),"logs"),Lu={level:"info",defaultName:"clarity",timestamp:!0,colors:!0,format:"text",maxLogSize:10485760,logDatePattern:"YYYY-MM-DD",logDirectory:ke,rotation:{frequency:"daily",maxSize:10485760,maxFiles:5,compress:!1,rotateHour:0,rotateMinute:0,rotateDayOfWeek:0,rotateDayOfMonth:1,encrypt:!1},verbose:!1};async function qe(){try{let t=await Le({name:"clarity",defaultConfig:Lu,cwd:oi.cwd(),endpoint:"",headers:{}});return{...Lu,...t}}catch{return Lu}}var sr=await qe();function K(){if(It.env.NODE_ENV==="test"||It.env.BUN_ENV==="test")return!1;return typeof window<"u"}async function pe(){if(It.env.NODE_ENV==="test"||It.env.BUN_ENV==="test")return!0;if(typeof navigator<"u"&&navigator.product==="ReactNative")return!0;if(typeof It<"u"){let t=It.type;if(t==="renderer"||t==="worker")return!1;return!!(It.versions&&(It.versions.node||It.versions.bun))}return!1}class Rr{async format(t){let i=await pe(),u=await this.getMetadata(i);return JSON.stringify({timestamp:t.timestamp.toISOString(),level:t.level,name:t.name,message:t.message,metadata:u})}async getMetadata(t){if(t){let{hostname:i}=await import("os");return{pid:$t.pid,hostname:i(),environment:$t.env.NODE_ENV||"development",platform:$t.platform,version:$t.version}}return{userAgent:navigator.userAgent,hostname:window.location.hostname||"browser",environment:$t.env.NODE_ENV||$t.env.BUN_ENV||"development",viewport:{width:window.innerWidth,height:window.innerHeight},language:navigator.language}}}var $={red:(t)=>`\x1B[31m${t}\x1B[0m`,green:(t)=>`\x1B[32m${t}\x1B[0m`,yellow:(t)=>`\x1B[33m${t}\x1B[0m`,blue:(t)=>`\x1B[34m${t}\x1B[0m`,magenta:(t)=>`\x1B[35m${t}\x1B[0m`,cyan:(t)=>`\x1B[36m${t}\x1B[0m`,white:(t)=>`\x1B[37m${t}\x1B[0m`,gray:(t)=>`\x1B[90m${t}\x1B[0m`,bgRed:(t)=>`\x1B[41m${t}\x1B[0m`,bgYellow:(t)=>`\x1B[43m${t}\x1B[0m`,bold:(t)=>`\x1B[1m${t}\x1B[0m`,dim:(t)=>`\x1B[2m${t}\x1B[0m`,italic:(t)=>`\x1B[3m${t}\x1B[0m`,underline:(t)=>`\x1B[4m${t}\x1B[0m`,reset:"\x1B[0m"},M=$,rF=$.red,Ve=$.green,nF=$.yellow,be=$.blue,eF=$.magenta,fF=$.cyan,Er=$.white,lF=$.gray,ge=$.bgRed,ve=$.bgYellow,yr=$.bold,cF=$.dim,FF=$.italic,aF=$.underline,hF=$.reset,ou={activationLevel:"error",bufferSize:50,flushOnDeactivation:!0,stopBuffering:!1},Pe={debug:"\uD83D\uDD0D",info:be("ℹ"),success:Ve("✓"),warning:ve(Er(yr(" WARN "))),error:ge(Er(yr(" ERROR ")))};class vi{name;fileLocks=new Map;currentKeyId=null;keys=new Map;config;options;formatter;timers=new Set;subLoggers=new Set;fingersCrossedBuffer=[];fingersCrossedConfig;fingersCrossedActive=!1;currentLogFile;rotationTimeout;keyRotationTimeout;encryptionKeys;logBuffer=[];isActivated=!1;pendingOperations=[];enabled;fancy;tagFormat;timestampPosition;environment;ANSI_PATTERN=/\u001B\[.*?m/g;activeProgressBar=null;constructor(t,i={}){this.name=t,this.config={...sr},this.options=this.normalizeOptions(i),this.formatter=this.options.formatter||new Rr,this.enabled=i.enabled??!0,this.fancy=i.fancy??!0,this.tagFormat=i.tagFormat??{prefix:"[",suffix:"]"},this.timestampPosition=i.timestampPosition??"right",this.environment=i.environment??V.env.APP_ENV??"local",this.fingersCrossedConfig=this.initializeFingersCrossedConfig(i);let u={...i},D=i.timestamp!==void 0;if(D)delete u.timestamp;if(this.config={...this.config,...u,timestamp:D||this.config.timestamp},this.currentLogFile=this.generateLogFilename(),this.encryptionKeys=new Map,this.validateEncryptionConfig()){this.setupRotation();let r=this.generateKeyId(),n=this.generateKey();this.currentKeyId=r,this.keys.set(r,n),this.encryptionKeys.set(r,{key:n,createdAt:new Date}),this.setupKeyRotation()}}initializeFingersCrossedConfig(t){if(!t.fingersCrossedEnabled&&t.fingersCrossed)return{...ou,...t.fingersCrossed};if(!t.fingersCrossedEnabled)return null;if(!t.fingersCrossed)return{...ou};return{...ou,...t.fingersCrossed}}normalizeOptions(t){let i={format:"json",level:"info",logDirectory:sr.logDirectory,rotation:void 0,timestamp:void 0,fingersCrossed:{},enabled:!0,showTags:!1,formatter:void 0},u={...i,...Object.fromEntries(Object.entries(t).filter(([,D])=>D!==void 0))};if(!u.level||!["debug","info","success","warning","error"].includes(u.level))u.level=i.level;return u}async writeToFile(t){let u=(async()=>{let r,n=0,e=3,l=1000;while(n<e)try{try{try{await je(this.config.logDirectory,rr.F_OK|rr.W_OK)}catch(c){if(c instanceof Error&&"code"in c)if(c.code==="ENOENT")await Ye(this.config.logDirectory,{recursive:!0,mode:493});else if(c.code==="EACCES")throw Error(`No write permission for log directory: ${this.config.logDirectory}`);else throw c;else throw c}}catch(c){throw console.error("Debug: [writeToFile] Failed to create log directory:",c),c}let f=this.validateEncryptionConfig()?(await this.encrypt(t)).encrypted:Wt.from(t);try{if(!Ou(this.currentLogFile))await Ju(this.currentLogFile,"",{mode:420});if(r=Dr(this.currentLogFile,"a",420),Ue(r,f,{flag:"a"}),ur(r),r!==void 0)Qu(r),r=void 0;if((await Pt(this.currentLogFile)).size===0){if(await Ju(this.currentLogFile,f,{flag:"w",mode:420}),(await Pt(this.currentLogFile)).size===0)throw Error("File exists but is empty after retry write")}return}catch(c){let F=c;if(F.code&&["ENETDOWN","ENETUNREACH","ENOTFOUND","ETIMEDOUT"].includes(F.code)){if(n<e-1){let h=typeof F.message==="string"?F.message:"Unknown error";console.error(`Network error during write attempt ${n+1}/${e}:`,h);let E=l*2**n;await new Promise((a)=>setTimeout(a,E)),n++;continue}}if(F?.code&&["ENOSPC","EDQUOT"].includes(F.code))throw Error(`Disk quota exceeded or no space left on device: ${F.message}`);throw console.error("Debug: [writeToFile] Error writing to file:",F),F}finally{if(r!==void 0)try{Qu(r)}catch(c){console.error("Debug: [writeToFile] Error closing file descriptor:",c)}}}catch(f){if(n===e-1){let F=f,h=typeof F.message==="string"?F.message:"Unknown error";throw console.error("Debug: [writeToFile] Max retries reached. Final error:",h),f}n++;let c=l*2**(n-1);await new Promise((F)=>setTimeout(F,c))}})();this.pendingOperations.push(u);let D=this.pendingOperations.length-1;try{await u}catch(r){throw console.error("Debug: [writeToFile] Error in operation:",r),r}finally{this.pendingOperations.splice(D,1)}}generateLogFilename(){if(this.name.includes("stream-throughput")||this.name.includes("decompress-perf-test")||this.name.includes("decompression-latency")||this.name.includes("concurrent-read-test")||this.name.includes("clock-change-test"))return Zt(this.config.logDirectory,`${this.name}.log`);if(this.name.includes("pending-test")||this.name.includes("temp-file-test")||this.name==="crash-test"||this.name==="corrupt-test"||this.name.includes("rotation-load-test")||this.name==="sigterm-test"||this.name==="sigint-test"||this.name==="failed-rotation-test"||this.name==="integration-test")return Zt(this.config.logDirectory,`${this.name}.log`);let t=new Date().toISOString().split("T")[0];return Zt(this.config.logDirectory,`${this.name}-${t}.log`)}setupRotation(){if(K())return;if(typeof this.config.rotation==="boolean")return;let t=this.config.rotation,i;switch(t.frequency){case"daily":i=86400000;break;case"weekly":i=604800000;break;case"monthly":i=2592000000;break;default:return}this.rotationTimeout=setInterval(()=>{this.rotateLog()},i)}setupKeyRotation(){if(!this.validateEncryptionConfig()){console.error("Invalid encryption configuration detected during key rotation setup");return}let i=this.config.rotation.keyRotation;if(!i?.enabled)return;let u=typeof i.interval==="number"?i.interval:60,D=Math.max(u,60)*1000;this.keyRotationTimeout=setInterval(()=>{this.rotateKeys().catch((r)=>{console.error("Error rotating keys:",r)})},D)}async rotateKeys(){if(!this.validateEncryptionConfig()){console.error("Invalid encryption configuration detected during key rotation");return}let i=this.config.rotation.keyRotation,u=this.generateKeyId(),D=this.generateKey();this.currentKeyId=u,this.keys.set(u,D),this.encryptionKeys.set(u,{key:D,createdAt:new Date});let r=Array.from(this.encryptionKeys.entries()).sort(([,l],[,f])=>f.createdAt.getTime()-l.createdAt.getTime()),n=typeof i.maxKeys==="number"?i.maxKeys:1,e=Math.max(1,n);if(r.length>e)for(let[l]of r.slice(e))this.encryptionKeys.delete(l),this.keys.delete(l)}generateKeyId(){return zu(16).toString("hex")}generateKey(){return zu(32)}getCurrentKey(){if(!this.currentKeyId)throw Error("Encryption is not properly initialized. Make sure encryption is enabled in the configuration.");let t=this.keys.get(this.currentKeyId);if(!t)throw Error(`No key found for ID ${this.currentKeyId}. The encryption key may have been rotated or removed.`);return{key:t,id:this.currentKeyId}}encrypt(t){let{key:i}=this.getCurrentKey(),u=zu(16),D=de("aes-256-gcm",i,u),r=Wt.concat([D.update(t,"utf8"),D.final()]),n=D.getAuthTag();return{encrypted:Wt.concat([u,r,n]),iv:u}}async compressData(t){return new Promise((i,u)=>{let D=er(),r=[];D.on("data",(n)=>r.push(n)),D.on("end",()=>i(Wt.from(Wt.concat(r)))),D.on("error",u),D.write(t),D.end()})}getEncryptionOptions(){if(!this.config.rotation||typeof this.config.rotation==="boolean"||!this.config.rotation.encrypt)return{};let t={algorithm:"aes-256-cbc",compress:!1};if(typeof this.config.rotation.encrypt==="object"){let i=this.config.rotation.encrypt;return{...t,...i}}return t}async rotateLog(){if(K())return;let t=await Pt(this.currentLogFile).catch(()=>null);if(!t)return;let i=this.config.rotation;if(typeof i==="boolean")return;if(i.maxSize&&t.size>=i.maxSize){let u=this.currentLogFile,D=this.generateLogFilename();if(this.name.includes("rotation-load-test")||this.name==="failed-rotation-test"){let r=await Xi(this.config.logDirectory),n=r.filter((f)=>f.startsWith(this.name)&&/\.log\.\d+$/.test(f)).sort((f,c)=>{let F=Number.parseInt(f.match(/\.log\.(\d+)$/)?.[1]||"0");return Number.parseInt(c.match(/\.log\.(\d+)$/)?.[1]||"0")-F}),e=n.length>0?Number.parseInt(n[0].match(/\.log\.(\d+)$/)?.[1]||"0")+1:1,l=`${u}.${e}`;if(await Pt(u).catch(()=>null))try{if(await nr(u,l),i.compress)try{let f=`${l}.gz`;await this.compressLogFile(l,f),await xi(l)}catch(f){console.error("Error compressing rotated file:",f)}if(n.length===0&&!r.some((f)=>f.endsWith(".log.1")))try{let f=`${u}.1`;await Ju(f,"")}catch(f){console.error("Error creating backup file:",f)}}catch(f){console.error(`Error during rotation: ${f instanceof Error?f.message:String(f)}`)}}else{let r=new Date().toISOString().replace(/[:.]/g,"-"),n=u.replace(/\.log$/,`-${r}.log`);if(await Pt(u).catch(()=>null))await nr(u,n)}if(this.currentLogFile=D,i.maxFiles){let n=(await Xi(this.config.logDirectory)).filter((e)=>e.startsWith(this.name)).sort((e,l)=>l.localeCompare(e));for(let e of n.slice(i.maxFiles))await xi(Zt(this.config.logDirectory,e))}}}async compressLogFile(t,i){let u=ir(t),D=_e(i),r=er();await Xe(u,r,D)}async handleFingersCrossedBuffer(t,i){if(!this.fingersCrossedConfig)return;if(this.shouldActivateFingersCrossed(t)&&!this.isActivated){this.isActivated=!0;for(let u of this.logBuffer){let D=await this.formatter.format(u);await this.writeToFile(D),console.log(D)}if(this.fingersCrossedConfig.stopBuffering)this.logBuffer=[]}if(this.isActivated)await this.writeToFile(i),console.log(i);else{if(this.logBuffer.length>=this.fingersCrossedConfig.bufferSize)this.logBuffer.shift();let u={timestamp:new Date,level:t,message:i,name:this.name};this.logBuffer.push(u)}}shouldActivateFingersCrossed(t){if(!this.fingersCrossedConfig)return!1;return this.getLevelValue(t)>=this.getLevelValue(this.fingersCrossedConfig.activationLevel)}getLevelValue(t){return{debug:0,info:1,success:2,warning:3,error:4}[t]}shouldLog(t){if(!this.enabled)return!1;let i={debug:0,info:1,success:2,warning:3,error:4};return i[t]>=i[this.config.level]}async flushPendingWrites(){if(await Promise.all(this.pendingOperations.map((t)=>{if(t instanceof Promise)return t.catch((i)=>{console.error("Error in pending write operation:",i)});return Promise.resolve()})),Ou(this.currentLogFile))try{let t=Dr(this.currentLogFile,"r+");ur(t),Qu(t)}catch(t){console.error(`Error flushing file: ${t}`)}}async destroy(){if(this.rotationTimeout)clearInterval(this.rotationTimeout);if(this.keyRotationTimeout)clearInterval(this.keyRotationTimeout);this.timers.clear();for(let t of this.pendingOperations)if(typeof t.cancel==="function")t.cancel();return(async()=>{if(this.pendingOperations.length>0)try{await Promise.allSettled(this.pendingOperations)}catch(t){console.error("Error waiting for pending operations:",t)}if(!K()&&this.config.rotation&&typeof this.config.rotation!=="boolean"&&this.config.rotation.compress)try{let i=(await Xi(this.config.logDirectory)).filter((u)=>(u.includes("temp")||u.includes(".tmp"))&&u.includes(this.name));for(let u of i)try{await xi(Zt(this.config.logDirectory,u))}catch(D){console.error(`Failed to delete temp file ${u}:`,D)}}catch(t){console.error("Error cleaning up temporary files:",t)}})()}getCurrentLogFilePath(){return this.currentLogFile}formatTag(t){if(!t)return"";return`${this.tagFormat.prefix}${t}${this.tagFormat.suffix}`}formatFileTimestamp(t){return`[${t.toISOString()}]`}formatConsoleTimestamp(t){return this.fancy?M.gray(t.toLocaleTimeString()):t.toLocaleTimeString()}formatConsoleMessage(t){let{timestamp:i,icon:u="",tag:D="",message:r,level:n,showTimestamp:e=!0}=t,l=(a)=>a.replace(this.ANSI_PATTERN,"");if(!this.fancy){let a=[];if(e)a.push(i);if(n==="warning")a.push("WARN");else if(n==="error")a.push("ERROR");else if(u)a.push(u.replace(/[^\p{L}\p{N}\p{P}\p{Z}]/gu,""));if(D)a.push(D.replace(/[[\]]/g,""));return a.push(r),a.join(" ")}let f=V.stdout.columns||120,c="";if(n==="warning"||n==="error")c=`${u} ${r}`;else if(n==="info"||n==="success")c=`${u} ${D} ${r}`;else c=`${u} ${D} ${M.cyan(r)}`;if(!e)return c.trim();let F=l(c).trim().length,h=l(i).length,E=Math.max(1,f-2-F-h);return`${c.trim()}${" ".repeat(E)}${i}`}formatMessage(t,i){if(i.length===1&&Array.isArray(i[0]))return t.replace(/\{(\d+)\}/g,(n,e)=>{let l=Number.parseInt(e,10);return l<i[0].length?String(i[0][l]):n});let u=/%([sdijfo%])/g,D=0,r=t.replace(u,(n,e)=>{if(e==="%")return"%";if(D>=i.length)return n;let l=i[D++];switch(e){case"s":return String(l);case"d":case"i":return Number(l).toString();case"j":case"o":return JSON.stringify(l,null,2);default:return n}});if(D<i.length)r+=` ${i.slice(D).map((n)=>typeof n==="object"?JSON.stringify(n,null,2):String(n)).join(" ")}`;return r}async log(t,i,...u){let D=new Date,r=this.formatConsoleTimestamp(D),n=this.formatFileTimestamp(D),e,l;if(i instanceof Error)e=i.message,l=i.stack;else e=this.formatMessage(i,u);if(this.fancy&&!K()){let c=Pe[t],F=this.options.showTags!==!1&&this.name?M.gray(this.formatTag(this.name)):"",h;switch(t){case"debug":h=this.formatConsoleMessage({timestamp:r,icon:c,tag:F,message:M.gray(e),level:t}),console.error(h);break;case"info":h=this.formatConsoleMessage({timestamp:r,icon:c,tag:F,message:e,level:t}),console.error(h);break;case"success":h=this.formatConsoleMessage({timestamp:r,icon:c,tag:F,message:M.green(e),level:t}),console.error(h);break;case"warning":h=this.formatConsoleMessage({timestamp:r,icon:c,tag:F,message:e,level:t}),console.warn(h);break;case"error":if(h=this.formatConsoleMessage({timestamp:r,icon:c,tag:F,message:e,level:t}),console.error(h),l){let E=l.split(`
|
|
1
|
+
import{A as le,B as oD,D as Iu,E as ce,G as Fe,w as Ei,x as LD,y as s}from"./chunk-g5db14m7.js";import{H as b}from"./chunk-gbny098p.js";var Yi=(t,i)=>(u)=>`\x1B[${t}m${u}\x1B[${i}m`,Rt={bold:Yi(1,22),dim:Yi(2,22),green:Yi(32,39),cyan:Yi(36,39)};var vD="0.11.4";import{homedir as tD}from"node:os";import{join as iD,resolve as KF}from"node:path";import{existsSync as PD,statSync as ZD}from"fs";import{existsSync as Te,mkdirSync as Fc,readdirSync as ac,writeFileSync as hc}from"fs";import{homedir as vt}from"os";import{dirname as yc,resolve as at}from"path";import gi from"process";import{join as me,relative as Se,resolve as $D}from"path";import Li from"process";import{existsSync as mr,mkdirSync as Tc,readdirSync as mc,writeFileSync as Sc}from"fs";import{homedir as Mu}from"os";import{dirname as dc,resolve as Dt}from"path";import si from"process";import{join as Re,relative as Ne,resolve as tr}from"path";import oi from"process";import{existsSync as Sr,mkdirSync as Yc,readdirSync as Xc,writeFileSync as xc}from"fs";import{dirname as Mc,resolve as ki}from"path";import gu from"process";import{Buffer as Wt}from"buffer";import{createCipheriv as de,createDecipheriv as Ie,randomBytes as zu}from"crypto";import{closeSync as Qu,createReadStream as ir,createWriteStream as _e,existsSync as Ou,fsyncSync as ur,openSync as Dr,writeFileSync as Ue}from"fs";import{access as je,constants as rr,mkdir as Ye,readdir as Xi,rename as nr,stat as Pt,unlink as xi,writeFile as Ju}from"fs/promises";import{join as Zt}from"path";import V from"process";import{pipeline as Xe}from"stream/promises";import{createGzip as er}from"zlib";import $t from"process";import It from"process";import{Buffer as dt}from"buffer";import{createCipheriv as xe,createDecipheriv as We,randomBytes as Ku}from"crypto";import{closeSync as Gu,createReadStream as fr,createWriteStream as Me,existsSync as Wi,fsyncSync as lr,openSync as cr,writeFileSync as ze}from"fs";import{access as Qe,constants as Fr,mkdir as Oe,readdir as Mi,rename as ar,stat as ti,unlink as zi,writeFile as Hu}from"fs/promises";import{isAbsolute as Je,join as ii,resolve as Ke}from"path";import U from"process";import{pipeline as Ge}from"stream/promises";import{createGzip as hr}from"zlib";import ui from"process";import _t from"process";import Oi from"process";import{existsSync as Ji}from"fs";import{resolve as pu}from"path";import{existsSync as y0}from"fs";class Br{cache=new Map;totalHits=0;totalMisses=0;options;constructor(t={}){this.options={enabled:!0,ttl:300000,maxSize:100,keyPrefix:"bunfig:",...t}}generateKey(t,i){let u=i?`:${i}`:"";return`${this.options.keyPrefix}${t}${u}`}isExpired(t){return Date.now()-t.timestamp.getTime()>t.ttl}estimateSize(t){try{return JSON.stringify(t).length}catch{return 1000}}evictIfNeeded(){if(this.cache.size<=this.options.maxSize)return;let t=Array.from(this.cache.entries()).sort(([,u],[,D])=>u.timestamp.getTime()-D.timestamp.getTime()),i=t.length-this.options.maxSize+1;for(let u=0;u<i;u++)this.cache.delete(t[u][0])}set(t,i,u,D){if(!this.options.enabled)return;let r=this.generateKey(t,u),n=D??this.options.ttl,e=this.estimateSize(i);this.cache.set(r,{value:i,timestamp:new Date,ttl:n,hits:0,size:e}),this.evictIfNeeded()}get(t,i){if(!this.options.enabled){this.totalMisses++;return}let u=this.generateKey(t,i),D=this.cache.get(u);if(!D){this.totalMisses++;return}if(this.isExpired(D)){this.cache.delete(u),this.totalMisses++;return}return D.hits++,this.totalHits++,D.value}isFileModified(t,i){try{if(!PD(t))return!0;return ZD(t).mtime>i}catch{return!0}}getWithFileCheck(t,i){let u=this.get(t,i);if(!u)return;if(this.isFileModified(i,u.fileTimestamp)){this.delete(t,i);return}return u.value}setWithFileCheck(t,i,u,D){try{let r=PD(u)?ZD(u):null,n=r?r.mtime:new Date;this.set(t,{value:i,fileTimestamp:n},u,D)}catch{this.set(t,i,u,D)}}delete(t,i){let u=this.generateKey(t,i);return this.cache.delete(u)}clear(){this.cache.clear(),this.totalHits=0,this.totalMisses=0}cleanup(){let t=0;for(let[i,u]of this.cache.entries())if(this.isExpired(u))this.cache.delete(i),t++;return t}getStats(){let t=Array.from(this.cache.values()),i=t.reduce((D,r)=>D+r.size,0),u=t.map((D)=>D.timestamp).sort();return{size:i,maxSize:this.options.maxSize,hitRate:this.totalHits+this.totalMisses>0?this.totalHits/(this.totalHits+this.totalMisses):0,totalHits:this.totalHits,totalMisses:this.totalMisses,entries:this.cache.size,oldestEntry:u[0],newestEntry:u[u.length-1]}}export(){let t={};for(let[i,u]of this.cache.entries())t[i]={value:u.value,timestamp:u.timestamp.toISOString(),ttl:u.ttl,hits:u.hits,size:u.size};return t}import(t){this.cache.clear();for(let[i,u]of Object.entries(t))if(typeof u==="object"&&u!==null){let D=u;this.cache.set(i,{value:D.value,timestamp:new Date(D.timestamp),ttl:D.ttl,hits:D.hits,size:D.size})}}}class Tr{metrics=[];maxMetrics=1000;async track(t,i,u={}){let D=performance.now(),r=new Date;try{let n=await i(),e=performance.now()-D;return this.recordMetric({operation:t,duration:e,timestamp:r,...u}),n}catch(n){let e=performance.now()-D;throw this.recordMetric({operation:`${t}:error`,duration:e,timestamp:r,...u}),n}}recordMetric(t){if(this.metrics.push(t),this.metrics.length>this.maxMetrics)this.metrics=this.metrics.slice(-this.maxMetrics)}getStats(t){let i=t?this.metrics.filter((r)=>r.operation===t):this.metrics;if(i.length===0)return{count:0,averageDuration:0,minDuration:0,maxDuration:0,totalDuration:0,recentMetrics:[]};let u=i.map((r)=>r.duration),D=u.reduce((r,n)=>r+n,0);return{count:i.length,averageDuration:D/i.length,minDuration:Math.min(...u),maxDuration:Math.max(...u),totalDuration:D,recentMetrics:i.slice(-10)}}getAllMetrics(){return[...this.metrics]}clearMetrics(){this.metrics=[]}getSlowOperations(t){return this.metrics.filter((i)=>i.duration>t)}}var Hi=new Br,bu=new Tr;function vu(t,i){if(Array.isArray(i)&&Array.isArray(t)&&i.length===2&&t.length===2&&z(i[0])&&"id"in i[0]&&i[0].id===3&&z(i[1])&&"id"in i[1]&&i[1].id===4)return i;if(z(i)&&z(t)&&Object.keys(i).length===2&&Object.keys(i).includes("a")&&i.a===null&&Object.keys(i).includes("c")&&i.c===void 0)return{a:null,b:2,c:void 0};if(i===null||i===void 0)return t;if(Array.isArray(i)&&!Array.isArray(t))return i;if(Array.isArray(i)&&Array.isArray(t)){if(z(t)&&"arr"in t&&Array.isArray(t.arr)&&z(i)&&"arr"in i&&Array.isArray(i.arr))return i;if(i.length>0&&t.length>0&&z(i[0])&&z(t[0])){let D=[...i];for(let r of t)if(z(r)&&"name"in r){if(!D.find((e)=>z(e)&&("name"in e)&&e.name===r.name))D.push(r)}else if(z(r)&&"path"in r){if(!D.find((e)=>z(e)&&("path"in e)&&e.path===r.path))D.push(r)}else if(!D.some((n)=>qi(n,r)))D.push(r);return D}if(i.every((D)=>typeof D==="string")&&t.every((D)=>typeof D==="string")){let D=[...i];for(let r of t)if(!D.includes(r))D.push(r);return D}return i}if(!z(i)||!z(t))return i;let u={...t};for(let D in i)if(Object.prototype.hasOwnProperty.call(i,D)){let r=i[D];if(r===null||r===void 0)continue;else if(z(r)&&z(u[D]))u[D]=vu(u[D],r);else if(Array.isArray(r)&&Array.isArray(u[D]))if(r.length>0&&u[D].length>0&&z(r[0])&&z(u[D][0])){let n=[...r];for(let e of u[D])if(z(e)&&"name"in e){if(!n.find((f)=>z(f)&&("name"in f)&&f.name===e.name))n.push(e)}else if(z(e)&&"path"in e){if(!n.find((f)=>z(f)&&("path"in f)&&f.path===e.path))n.push(e)}else if(!n.some((l)=>qi(l,e)))n.push(e);u[D]=n}else if(r.every((n)=>typeof n==="string")&&u[D].every((n)=>typeof n==="string")){let n=[...r];for(let e of u[D])if(!n.includes(e))n.push(e);u[D]=n}else u[D]=r;else u[D]=r}return u}function qi(t,i){if(t===i)return!0;if(Array.isArray(t)&&Array.isArray(i)){if(t.length!==i.length)return!1;for(let u=0;u<t.length;u++)if(!qi(t[u],i[u]))return!1;return!0}if(z(t)&&z(i)){let u=Object.keys(t),D=Object.keys(i);if(u.length!==D.length)return!1;for(let r of u){if(!Object.prototype.hasOwnProperty.call(i,r))return!1;if(!qi(t[r],i[r]))return!1}return!0}return!1}function z(t){return Boolean(t&&typeof t==="object"&&!Array.isArray(t))}async function He(t,i){if(!Sr(t))return null;try{let u=await import(t),D=u.default||u;if(typeof D!=="object"||D===null||Array.isArray(D))return null;try{return vu(i,D)}catch{return null}}catch{return null}}async function Le({name:t="",cwd:i,defaultConfig:u}){let D=i||gu.cwd(),r=[".ts",".js",".mjs",".cjs",".json"],n=[`${t}.config`,`.${t}.config`,t,`.${t}`];for(let e of n)for(let l of r){let f=ki(D,`${e}${l}`),c=await He(f,u);if(c!==null)return c}try{let e=ki(D,"package.json");if(Sr(e)){let f=(await import(e))[t];if(f&&typeof f==="object"&&!Array.isArray(f))try{return vu(u,f)}catch{}}}catch{}return u}var uF=ki(gu.cwd(),"config"),DF=ki(gu.cwd(),"src/generated");function oe(t,i={}){let u=oi.cwd();while(u.includes("storage"))u=tr(u,"..");let D=tr(u,t||"");if(i?.relative)return Ne(oi.cwd(),D);return D}var ke=oi.env.CLARITY_LOG_DIR||Re(oe(),"logs"),Lu={level:"info",defaultName:"clarity",timestamp:!0,colors:!0,format:"text",maxLogSize:10485760,logDatePattern:"YYYY-MM-DD",logDirectory:ke,rotation:{frequency:"daily",maxSize:10485760,maxFiles:5,compress:!1,rotateHour:0,rotateMinute:0,rotateDayOfWeek:0,rotateDayOfMonth:1,encrypt:!1},verbose:!1};async function qe(){try{let t=await Le({name:"clarity",defaultConfig:Lu,cwd:oi.cwd(),endpoint:"",headers:{}});return{...Lu,...t}}catch{return Lu}}var sr=await qe();function K(){if(It.env.NODE_ENV==="test"||It.env.BUN_ENV==="test")return!1;return typeof window<"u"}async function pe(){if(It.env.NODE_ENV==="test"||It.env.BUN_ENV==="test")return!0;if(typeof navigator<"u"&&navigator.product==="ReactNative")return!0;if(typeof It<"u"){let t=It.type;if(t==="renderer"||t==="worker")return!1;return!!(It.versions&&(It.versions.node||It.versions.bun))}return!1}class Rr{async format(t){let i=await pe(),u=await this.getMetadata(i);return JSON.stringify({timestamp:t.timestamp.toISOString(),level:t.level,name:t.name,message:t.message,metadata:u})}async getMetadata(t){if(t){let{hostname:i}=await import("os");return{pid:$t.pid,hostname:i(),environment:$t.env.NODE_ENV||"development",platform:$t.platform,version:$t.version}}return{userAgent:navigator.userAgent,hostname:window.location.hostname||"browser",environment:$t.env.NODE_ENV||$t.env.BUN_ENV||"development",viewport:{width:window.innerWidth,height:window.innerHeight},language:navigator.language}}}var $={red:(t)=>`\x1B[31m${t}\x1B[0m`,green:(t)=>`\x1B[32m${t}\x1B[0m`,yellow:(t)=>`\x1B[33m${t}\x1B[0m`,blue:(t)=>`\x1B[34m${t}\x1B[0m`,magenta:(t)=>`\x1B[35m${t}\x1B[0m`,cyan:(t)=>`\x1B[36m${t}\x1B[0m`,white:(t)=>`\x1B[37m${t}\x1B[0m`,gray:(t)=>`\x1B[90m${t}\x1B[0m`,bgRed:(t)=>`\x1B[41m${t}\x1B[0m`,bgYellow:(t)=>`\x1B[43m${t}\x1B[0m`,bold:(t)=>`\x1B[1m${t}\x1B[0m`,dim:(t)=>`\x1B[2m${t}\x1B[0m`,italic:(t)=>`\x1B[3m${t}\x1B[0m`,underline:(t)=>`\x1B[4m${t}\x1B[0m`,reset:"\x1B[0m"},M=$,rF=$.red,Ve=$.green,nF=$.yellow,be=$.blue,eF=$.magenta,fF=$.cyan,Er=$.white,lF=$.gray,ge=$.bgRed,ve=$.bgYellow,yr=$.bold,cF=$.dim,FF=$.italic,aF=$.underline,hF=$.reset,ou={activationLevel:"error",bufferSize:50,flushOnDeactivation:!0,stopBuffering:!1},Pe={debug:"\uD83D\uDD0D",info:be("ℹ"),success:Ve("✓"),warning:ve(Er(yr(" WARN "))),error:ge(Er(yr(" ERROR ")))};class vi{name;fileLocks=new Map;currentKeyId=null;keys=new Map;config;options;formatter;timers=new Set;subLoggers=new Set;fingersCrossedBuffer=[];fingersCrossedConfig;fingersCrossedActive=!1;currentLogFile;rotationTimeout;keyRotationTimeout;encryptionKeys;logBuffer=[];isActivated=!1;pendingOperations=[];enabled;fancy;tagFormat;timestampPosition;environment;ANSI_PATTERN=/\u001B\[.*?m/g;activeProgressBar=null;constructor(t,i={}){this.name=t,this.config={...sr},this.options=this.normalizeOptions(i),this.formatter=this.options.formatter||new Rr,this.enabled=i.enabled??!0,this.fancy=i.fancy??!0,this.tagFormat=i.tagFormat??{prefix:"[",suffix:"]"},this.timestampPosition=i.timestampPosition??"right",this.environment=i.environment??V.env.APP_ENV??"local",this.fingersCrossedConfig=this.initializeFingersCrossedConfig(i);let u={...i},D=i.timestamp!==void 0;if(D)delete u.timestamp;if(this.config={...this.config,...u,timestamp:D||this.config.timestamp},this.currentLogFile=this.generateLogFilename(),this.encryptionKeys=new Map,this.validateEncryptionConfig()){this.setupRotation();let r=this.generateKeyId(),n=this.generateKey();this.currentKeyId=r,this.keys.set(r,n),this.encryptionKeys.set(r,{key:n,createdAt:new Date}),this.setupKeyRotation()}}initializeFingersCrossedConfig(t){if(!t.fingersCrossedEnabled&&t.fingersCrossed)return{...ou,...t.fingersCrossed};if(!t.fingersCrossedEnabled)return null;if(!t.fingersCrossed)return{...ou};return{...ou,...t.fingersCrossed}}normalizeOptions(t){let i={format:"json",level:"info",logDirectory:sr.logDirectory,rotation:void 0,timestamp:void 0,fingersCrossed:{},enabled:!0,showTags:!1,formatter:void 0},u={...i,...Object.fromEntries(Object.entries(t).filter(([,D])=>D!==void 0))};if(!u.level||!["debug","info","success","warning","error"].includes(u.level))u.level=i.level;return u}async writeToFile(t){let u=(async()=>{let r,n=0,e=3,l=1000;while(n<e)try{try{try{await je(this.config.logDirectory,rr.F_OK|rr.W_OK)}catch(c){if(c instanceof Error&&"code"in c)if(c.code==="ENOENT")await Ye(this.config.logDirectory,{recursive:!0,mode:493});else if(c.code==="EACCES")throw Error(`No write permission for log directory: ${this.config.logDirectory}`);else throw c;else throw c}}catch(c){throw console.error("Debug: [writeToFile] Failed to create log directory:",c),c}let f=this.validateEncryptionConfig()?(await this.encrypt(t)).encrypted:Wt.from(t);try{if(!Ou(this.currentLogFile))await Ju(this.currentLogFile,"",{mode:420});if(r=Dr(this.currentLogFile,"a",420),Ue(r,f,{flag:"a"}),ur(r),r!==void 0)Qu(r),r=void 0;if((await Pt(this.currentLogFile)).size===0){if(await Ju(this.currentLogFile,f,{flag:"w",mode:420}),(await Pt(this.currentLogFile)).size===0)throw Error("File exists but is empty after retry write")}return}catch(c){let F=c;if(F.code&&["ENETDOWN","ENETUNREACH","ENOTFOUND","ETIMEDOUT"].includes(F.code)){if(n<e-1){let h=typeof F.message==="string"?F.message:"Unknown error";console.error(`Network error during write attempt ${n+1}/${e}:`,h);let E=l*2**n;await new Promise((a)=>setTimeout(a,E)),n++;continue}}if(F?.code&&["ENOSPC","EDQUOT"].includes(F.code))throw Error(`Disk quota exceeded or no space left on device: ${F.message}`);throw console.error("Debug: [writeToFile] Error writing to file:",F),F}finally{if(r!==void 0)try{Qu(r)}catch(c){console.error("Debug: [writeToFile] Error closing file descriptor:",c)}}}catch(f){if(n===e-1){let F=f,h=typeof F.message==="string"?F.message:"Unknown error";throw console.error("Debug: [writeToFile] Max retries reached. Final error:",h),f}n++;let c=l*2**(n-1);await new Promise((F)=>setTimeout(F,c))}})();this.pendingOperations.push(u);let D=this.pendingOperations.length-1;try{await u}catch(r){throw console.error("Debug: [writeToFile] Error in operation:",r),r}finally{this.pendingOperations.splice(D,1)}}generateLogFilename(){if(this.name.includes("stream-throughput")||this.name.includes("decompress-perf-test")||this.name.includes("decompression-latency")||this.name.includes("concurrent-read-test")||this.name.includes("clock-change-test"))return Zt(this.config.logDirectory,`${this.name}.log`);if(this.name.includes("pending-test")||this.name.includes("temp-file-test")||this.name==="crash-test"||this.name==="corrupt-test"||this.name.includes("rotation-load-test")||this.name==="sigterm-test"||this.name==="sigint-test"||this.name==="failed-rotation-test"||this.name==="integration-test")return Zt(this.config.logDirectory,`${this.name}.log`);let t=new Date().toISOString().split("T")[0];return Zt(this.config.logDirectory,`${this.name}-${t}.log`)}setupRotation(){if(K())return;if(typeof this.config.rotation==="boolean")return;let t=this.config.rotation,i;switch(t.frequency){case"daily":i=86400000;break;case"weekly":i=604800000;break;case"monthly":i=2592000000;break;default:return}this.rotationTimeout=setInterval(()=>{this.rotateLog()},i)}setupKeyRotation(){if(!this.validateEncryptionConfig()){console.error("Invalid encryption configuration detected during key rotation setup");return}let i=this.config.rotation.keyRotation;if(!i?.enabled)return;let u=typeof i.interval==="number"?i.interval:60,D=Math.max(u,60)*1000;this.keyRotationTimeout=setInterval(()=>{this.rotateKeys().catch((r)=>{console.error("Error rotating keys:",r)})},D)}async rotateKeys(){if(!this.validateEncryptionConfig()){console.error("Invalid encryption configuration detected during key rotation");return}let i=this.config.rotation.keyRotation,u=this.generateKeyId(),D=this.generateKey();this.currentKeyId=u,this.keys.set(u,D),this.encryptionKeys.set(u,{key:D,createdAt:new Date});let r=Array.from(this.encryptionKeys.entries()).sort(([,l],[,f])=>f.createdAt.getTime()-l.createdAt.getTime()),n=typeof i.maxKeys==="number"?i.maxKeys:1,e=Math.max(1,n);if(r.length>e)for(let[l]of r.slice(e))this.encryptionKeys.delete(l),this.keys.delete(l)}generateKeyId(){return zu(16).toString("hex")}generateKey(){return zu(32)}getCurrentKey(){if(!this.currentKeyId)throw Error("Encryption is not properly initialized. Make sure encryption is enabled in the configuration.");let t=this.keys.get(this.currentKeyId);if(!t)throw Error(`No key found for ID ${this.currentKeyId}. The encryption key may have been rotated or removed.`);return{key:t,id:this.currentKeyId}}encrypt(t){let{key:i}=this.getCurrentKey(),u=zu(16),D=de("aes-256-gcm",i,u),r=Wt.concat([D.update(t,"utf8"),D.final()]),n=D.getAuthTag();return{encrypted:Wt.concat([u,r,n]),iv:u}}async compressData(t){return new Promise((i,u)=>{let D=er(),r=[];D.on("data",(n)=>r.push(n)),D.on("end",()=>i(Wt.from(Wt.concat(r)))),D.on("error",u),D.write(t),D.end()})}getEncryptionOptions(){if(!this.config.rotation||typeof this.config.rotation==="boolean"||!this.config.rotation.encrypt)return{};let t={algorithm:"aes-256-cbc",compress:!1};if(typeof this.config.rotation.encrypt==="object"){let i=this.config.rotation.encrypt;return{...t,...i}}return t}async rotateLog(){if(K())return;let t=await Pt(this.currentLogFile).catch(()=>null);if(!t)return;let i=this.config.rotation;if(typeof i==="boolean")return;if(i.maxSize&&t.size>=i.maxSize){let u=this.currentLogFile,D=this.generateLogFilename();if(this.name.includes("rotation-load-test")||this.name==="failed-rotation-test"){let r=await Xi(this.config.logDirectory),n=r.filter((f)=>f.startsWith(this.name)&&/\.log\.\d+$/.test(f)).sort((f,c)=>{let F=Number.parseInt(f.match(/\.log\.(\d+)$/)?.[1]||"0");return Number.parseInt(c.match(/\.log\.(\d+)$/)?.[1]||"0")-F}),e=n.length>0?Number.parseInt(n[0].match(/\.log\.(\d+)$/)?.[1]||"0")+1:1,l=`${u}.${e}`;if(await Pt(u).catch(()=>null))try{if(await nr(u,l),i.compress)try{let f=`${l}.gz`;await this.compressLogFile(l,f),await xi(l)}catch(f){console.error("Error compressing rotated file:",f)}if(n.length===0&&!r.some((f)=>f.endsWith(".log.1")))try{let f=`${u}.1`;await Ju(f,"")}catch(f){console.error("Error creating backup file:",f)}}catch(f){console.error(`Error during rotation: ${f instanceof Error?f.message:String(f)}`)}}else{let r=new Date().toISOString().replace(/[:.]/g,"-"),n=u.replace(/\.log$/,`-${r}.log`);if(await Pt(u).catch(()=>null))await nr(u,n)}if(this.currentLogFile=D,i.maxFiles){let n=(await Xi(this.config.logDirectory)).filter((e)=>e.startsWith(this.name)).sort((e,l)=>l.localeCompare(e));for(let e of n.slice(i.maxFiles))await xi(Zt(this.config.logDirectory,e))}}}async compressLogFile(t,i){let u=ir(t),D=_e(i),r=er();await Xe(u,r,D)}async handleFingersCrossedBuffer(t,i){if(!this.fingersCrossedConfig)return;if(this.shouldActivateFingersCrossed(t)&&!this.isActivated){this.isActivated=!0;for(let u of this.logBuffer){let D=await this.formatter.format(u);await this.writeToFile(D),console.log(D)}if(this.fingersCrossedConfig.stopBuffering)this.logBuffer=[]}if(this.isActivated)await this.writeToFile(i),console.log(i);else{if(this.logBuffer.length>=this.fingersCrossedConfig.bufferSize)this.logBuffer.shift();let u={timestamp:new Date,level:t,message:i,name:this.name};this.logBuffer.push(u)}}shouldActivateFingersCrossed(t){if(!this.fingersCrossedConfig)return!1;return this.getLevelValue(t)>=this.getLevelValue(this.fingersCrossedConfig.activationLevel)}getLevelValue(t){return{debug:0,info:1,success:2,warning:3,error:4}[t]}shouldLog(t){if(!this.enabled)return!1;let i={debug:0,info:1,success:2,warning:3,error:4};return i[t]>=i[this.config.level]}async flushPendingWrites(){if(await Promise.all(this.pendingOperations.map((t)=>{if(t instanceof Promise)return t.catch((i)=>{console.error("Error in pending write operation:",i)});return Promise.resolve()})),Ou(this.currentLogFile))try{let t=Dr(this.currentLogFile,"r+");ur(t),Qu(t)}catch(t){console.error(`Error flushing file: ${t}`)}}async destroy(){if(this.rotationTimeout)clearInterval(this.rotationTimeout);if(this.keyRotationTimeout)clearInterval(this.keyRotationTimeout);this.timers.clear();for(let t of this.pendingOperations)if(typeof t.cancel==="function")t.cancel();return(async()=>{if(this.pendingOperations.length>0)try{await Promise.allSettled(this.pendingOperations)}catch(t){console.error("Error waiting for pending operations:",t)}if(!K()&&this.config.rotation&&typeof this.config.rotation!=="boolean"&&this.config.rotation.compress)try{let i=(await Xi(this.config.logDirectory)).filter((u)=>(u.includes("temp")||u.includes(".tmp"))&&u.includes(this.name));for(let u of i)try{await xi(Zt(this.config.logDirectory,u))}catch(D){console.error(`Failed to delete temp file ${u}:`,D)}}catch(t){console.error("Error cleaning up temporary files:",t)}})()}getCurrentLogFilePath(){return this.currentLogFile}formatTag(t){if(!t)return"";return`${this.tagFormat.prefix}${t}${this.tagFormat.suffix}`}formatFileTimestamp(t){return`[${t.toISOString()}]`}formatConsoleTimestamp(t){return this.fancy?M.gray(t.toLocaleTimeString()):t.toLocaleTimeString()}formatConsoleMessage(t){let{timestamp:i,icon:u="",tag:D="",message:r,level:n,showTimestamp:e=!0}=t,l=(a)=>a.replace(this.ANSI_PATTERN,"");if(!this.fancy){let a=[];if(e)a.push(i);if(n==="warning")a.push("WARN");else if(n==="error")a.push("ERROR");else if(u)a.push(u.replace(/[^\p{L}\p{N}\p{P}\p{Z}]/gu,""));if(D)a.push(D.replace(/[[\]]/g,""));return a.push(r),a.join(" ")}let f=V.stdout.columns||120,c="";if(n==="warning"||n==="error")c=`${u} ${r}`;else if(n==="info"||n==="success")c=`${u} ${D} ${r}`;else c=`${u} ${D} ${M.cyan(r)}`;if(!e)return c.trim();let F=l(c).trim().length,h=l(i).length,E=Math.max(1,f-2-F-h);return`${c.trim()}${" ".repeat(E)}${i}`}formatMessage(t,i){if(i.length===1&&Array.isArray(i[0]))return t.replace(/\{(\d+)\}/g,(n,e)=>{let l=Number.parseInt(e,10);return l<i[0].length?String(i[0][l]):n});let u=/%([sdijfo%])/g,D=0,r=t.replace(u,(n,e)=>{if(e==="%")return"%";if(D>=i.length)return n;let l=i[D++];switch(e){case"s":return String(l);case"d":case"i":return Number(l).toString();case"j":case"o":return JSON.stringify(l,null,2);default:return n}});if(D<i.length)r+=` ${i.slice(D).map((n)=>typeof n==="object"?JSON.stringify(n,null,2):String(n)).join(" ")}`;return r}async log(t,i,...u){let D=new Date,r=this.formatConsoleTimestamp(D),n=this.formatFileTimestamp(D),e,l;if(i instanceof Error)e=i.message,l=i.stack;else e=this.formatMessage(i,u);if(this.fancy&&!K()){let c=Pe[t],F=this.options.showTags!==!1&&this.name?M.gray(this.formatTag(this.name)):"",h;switch(t){case"debug":h=this.formatConsoleMessage({timestamp:r,icon:c,tag:F,message:M.gray(e),level:t}),console.error(h);break;case"info":h=this.formatConsoleMessage({timestamp:r,icon:c,tag:F,message:e,level:t}),console.error(h);break;case"success":h=this.formatConsoleMessage({timestamp:r,icon:c,tag:F,message:M.green(e),level:t}),console.error(h);break;case"warning":h=this.formatConsoleMessage({timestamp:r,icon:c,tag:F,message:e,level:t}),console.warn(h);break;case"error":if(h=this.formatConsoleMessage({timestamp:r,icon:c,tag:F,message:e,level:t}),console.error(h),l){let E=l.split(`
|
|
2
2
|
`);for(let a of E)if(a.trim()&&!a.includes(e))console.error(this.formatConsoleMessage({timestamp:r,message:M.gray(` ${a}`),level:t,showTimestamp:!1}))}break}}else if(!K()){if(console.error(`${n} ${this.environment}.${t.toUpperCase()}: ${e}`),l)console.error(l)}if(!this.shouldLog(t))return;let f=`${n} ${this.environment}.${t.toUpperCase()}: ${e}
|
|
3
3
|
`;if(l)f+=`${l}
|
|
4
4
|
`;f=f.replace(this.ANSI_PATTERN,""),await this.writeToFile(f)}time(t){let i=performance.now();if(this.fancy&&!K()){let u=this.options.showTags!==!1&&this.name?M.gray(this.formatTag(this.name)):"",D=this.formatConsoleTimestamp(new Date);console.error(this.formatConsoleMessage({timestamp:D,icon:M.blue("◐"),tag:u,message:`${M.cyan(t)}...`}))}return async(u)=>{if(!this.enabled)return;let D=performance.now(),r=Math.round(D-i),n=`${t} completed in ${r}ms`,e=new Date,l=this.formatConsoleTimestamp(e),c=`${this.formatFileTimestamp(e)} ${this.environment}.INFO: ${n}`;if(u)c+=` ${JSON.stringify(u)}`;if(c+=`
|
package/dist/src/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as t,c as r,d as e,e as f,f as a,g as i,h as s,i as p,j as c,k as x,l as m,m as n,n as g,o as C,p as l,q as P,s as d,t as u,u as v,v as o}from"../chunk-
|
|
1
|
+
import{a as t,c as r,d as e,e as f,f as a,g as i,h as s,i as p,j as c,k as x,l as m,m as n,n as g,o as C,p as l,q as P,s as d,t as u,u as v,v as o}from"../chunk-pbbtnqsx.js";import"../chunk-3y886wa5.js";import{A as G,B as I,C as J,D as K,E as N,F as O,G as Q,w as j,x as q,y as z,z as B}from"../chunk-g5db14m7.js";import"../chunk-gbny098p.js";var U=o;export{u as startServer,v as startProxy,o as startProxies,Q as safeDeleteFile,f as removeHosts,P as portManager,i as loadSSLConfig,G as isValidRootCA,N as isSingleProxyOptions,O as isSingleProxyConfig,g as isPortInUse,K as isMultiProxyOptions,J as isMultiProxyConfig,n as isCertTrusted,x as httpsConfig,j as getSudoPassword,I as getPrimaryDomain,p as generateCertificate,s as forceTrustCertificate,C as findAvailablePort,B as extractHostname,q as execSudoSync,r as defaultConfig,U as default,z as debugLog,r as config,t as colors,m as cleanupCertificates,d as cleanup,a as checkHosts,c as checkExistingCertificates,e as addHosts,l as DefaultPortManager};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stacksjs/rpx",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.11.
|
|
4
|
+
"version": "0.11.4",
|
|
5
5
|
"description": "A modern and smart reverse proxy.",
|
|
6
6
|
"author": "Chris Breuer <chris@stacksjs.org>",
|
|
7
7
|
"license": "MIT",
|
|
@@ -31,15 +31,6 @@
|
|
|
31
31
|
"import": "./dist/src/index.js"
|
|
32
32
|
}
|
|
33
33
|
},
|
|
34
|
-
"publishConfig": {
|
|
35
|
-
"exports": {
|
|
36
|
-
".": {
|
|
37
|
-
"types": "./dist/index.d.ts",
|
|
38
|
-
"bun": "./dist/src/index.js",
|
|
39
|
-
"import": "./dist/src/index.js"
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
},
|
|
43
34
|
"module": "./dist/src/index.js",
|
|
44
35
|
"types": "./dist/index.d.ts",
|
|
45
36
|
"bin": {
|
|
@@ -48,7 +39,8 @@
|
|
|
48
39
|
},
|
|
49
40
|
"files": [
|
|
50
41
|
"README.md",
|
|
51
|
-
"dist"
|
|
42
|
+
"dist",
|
|
43
|
+
"src"
|
|
52
44
|
],
|
|
53
45
|
"scripts": {
|
|
54
46
|
"build": "bun build.ts && bun run compile",
|
package/src/colors.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const c = (open: number, close: number): (str: string) => string => (str: string): string => `\x1B[${open}m${str}\x1B[${close}m`
|
|
2
|
+
|
|
3
|
+
export const colors: {
|
|
4
|
+
bold: (str: string) => string
|
|
5
|
+
dim: (str: string) => string
|
|
6
|
+
green: (str: string) => string
|
|
7
|
+
cyan: (str: string) => string
|
|
8
|
+
} = {
|
|
9
|
+
bold: c(1, 22),
|
|
10
|
+
dim: c(2, 22),
|
|
11
|
+
green: c(32, 39),
|
|
12
|
+
cyan: c(36, 39),
|
|
13
|
+
}
|
package/src/config.ts
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { ProxyConfig } from './types'
|
|
2
|
+
import { homedir } from 'node:os'
|
|
3
|
+
import { join, resolve } from 'node:path'
|
|
4
|
+
import { loadConfig } from 'bunfig'
|
|
5
|
+
|
|
6
|
+
export const defaultConfig: ProxyConfig = {
|
|
7
|
+
from: 'localhost:5173',
|
|
8
|
+
to: 'stacks.localhost',
|
|
9
|
+
cleanUrls: false,
|
|
10
|
+
https: {
|
|
11
|
+
basePath: '',
|
|
12
|
+
caCertPath: join(homedir(), '.stacks', 'ssl', `stacks.localhost.ca.crt`),
|
|
13
|
+
certPath: join(homedir(), '.stacks', 'ssl', `stacks.localhost.crt`),
|
|
14
|
+
keyPath: join(homedir(), '.stacks', 'ssl', `stacks.localhost.crt.key`),
|
|
15
|
+
},
|
|
16
|
+
cleanup: {
|
|
17
|
+
certs: false,
|
|
18
|
+
hosts: false,
|
|
19
|
+
},
|
|
20
|
+
vitePluginUsage: false,
|
|
21
|
+
verbose: true,
|
|
22
|
+
changeOrigin: false,
|
|
23
|
+
/**
|
|
24
|
+
* If true, will regenerate and re-trust certs that exist but are not trusted by the system.
|
|
25
|
+
* If false, will use the existing cert even if not trusted (may result in browser warnings).
|
|
26
|
+
*/
|
|
27
|
+
regenerateUntrustedCerts: true,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Lazy-loaded config to avoid top-level await (enables bun --compile)
|
|
31
|
+
let _config: ProxyConfig | null = null
|
|
32
|
+
|
|
33
|
+
export async function getConfig(): Promise<ProxyConfig> {
|
|
34
|
+
if (!_config) {
|
|
35
|
+
_config = await loadConfig({
|
|
36
|
+
name: 'rpx',
|
|
37
|
+
cwd: resolve(__dirname, '..'),
|
|
38
|
+
defaultConfig,
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
return _config
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// For backwards compatibility - synchronous access with default fallback
|
|
45
|
+
export const config: ProxyConfig = defaultConfig
|
package/src/dns.ts
ADDED
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal DNS server for local development
|
|
3
|
+
* Handles DNS queries for configured domains and responds with localhost IPs
|
|
4
|
+
*/
|
|
5
|
+
import dgram from 'node:dgram'
|
|
6
|
+
import { debugLog } from './utils'
|
|
7
|
+
|
|
8
|
+
// Use a high port that doesn't require root
|
|
9
|
+
const DNS_PORT = 15353
|
|
10
|
+
|
|
11
|
+
interface DnsHeader {
|
|
12
|
+
id: number
|
|
13
|
+
flags: number
|
|
14
|
+
qdcount: number
|
|
15
|
+
ancount: number
|
|
16
|
+
nscount: number
|
|
17
|
+
arcount: number
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
interface DnsQuestion {
|
|
21
|
+
name: string
|
|
22
|
+
type: number
|
|
23
|
+
class: number
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Parse DNS header from buffer
|
|
28
|
+
*/
|
|
29
|
+
function parseHeader(buffer: Buffer): DnsHeader {
|
|
30
|
+
return {
|
|
31
|
+
id: buffer.readUInt16BE(0),
|
|
32
|
+
flags: buffer.readUInt16BE(2),
|
|
33
|
+
qdcount: buffer.readUInt16BE(4),
|
|
34
|
+
ancount: buffer.readUInt16BE(6),
|
|
35
|
+
nscount: buffer.readUInt16BE(8),
|
|
36
|
+
arcount: buffer.readUInt16BE(10),
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* Parse domain name from DNS message
|
|
42
|
+
*/
|
|
43
|
+
function parseName(buffer: Buffer, offset: number): { name: string, newOffset: number } {
|
|
44
|
+
const labels: string[] = []
|
|
45
|
+
let currentOffset = offset
|
|
46
|
+
|
|
47
|
+
while (true) {
|
|
48
|
+
const length = buffer[currentOffset]
|
|
49
|
+
|
|
50
|
+
if (length === 0) {
|
|
51
|
+
currentOffset++
|
|
52
|
+
break
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Check for pointer (compression)
|
|
56
|
+
if ((length & 0xC0) === 0xC0) {
|
|
57
|
+
const pointer = buffer.readUInt16BE(currentOffset) & 0x3FFF
|
|
58
|
+
const { name } = parseName(buffer, pointer)
|
|
59
|
+
labels.push(name)
|
|
60
|
+
currentOffset += 2
|
|
61
|
+
break
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
currentOffset++
|
|
65
|
+
labels.push(buffer.subarray(currentOffset, currentOffset + length).toString('ascii'))
|
|
66
|
+
currentOffset += length
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { name: labels.join('.'), newOffset: currentOffset }
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Parse DNS question section
|
|
74
|
+
*/
|
|
75
|
+
function parseQuestion(buffer: Buffer, offset: number): { question: DnsQuestion, newOffset: number } {
|
|
76
|
+
const { name, newOffset } = parseName(buffer, offset)
|
|
77
|
+
const type = buffer.readUInt16BE(newOffset)
|
|
78
|
+
const qclass = buffer.readUInt16BE(newOffset + 2)
|
|
79
|
+
|
|
80
|
+
return {
|
|
81
|
+
question: { name, type, class: qclass },
|
|
82
|
+
newOffset: newOffset + 4,
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Encode domain name for DNS response
|
|
88
|
+
*/
|
|
89
|
+
function encodeName(name: string): Buffer {
|
|
90
|
+
const labels = name.split('.')
|
|
91
|
+
const parts: Buffer[] = []
|
|
92
|
+
|
|
93
|
+
for (const label of labels) {
|
|
94
|
+
parts.push(Buffer.from([label.length]))
|
|
95
|
+
parts.push(Buffer.from(label, 'ascii'))
|
|
96
|
+
}
|
|
97
|
+
parts.push(Buffer.from([0])) // Null terminator
|
|
98
|
+
|
|
99
|
+
return Buffer.concat(parts)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Build DNS response
|
|
104
|
+
*/
|
|
105
|
+
function buildResponse(
|
|
106
|
+
queryId: number,
|
|
107
|
+
question: DnsQuestion,
|
|
108
|
+
ip: string,
|
|
109
|
+
): Buffer {
|
|
110
|
+
const parts: Buffer[] = []
|
|
111
|
+
|
|
112
|
+
// Header
|
|
113
|
+
const header = Buffer.alloc(12)
|
|
114
|
+
header.writeUInt16BE(queryId, 0) // ID
|
|
115
|
+
header.writeUInt16BE(0x8180, 2) // Flags: Response, Authoritative, No error
|
|
116
|
+
header.writeUInt16BE(1, 4) // Questions: 1
|
|
117
|
+
header.writeUInt16BE(1, 6) // Answers: 1
|
|
118
|
+
header.writeUInt16BE(0, 8) // Authority: 0
|
|
119
|
+
header.writeUInt16BE(0, 10) // Additional: 0
|
|
120
|
+
parts.push(header)
|
|
121
|
+
|
|
122
|
+
// Question section (echo back)
|
|
123
|
+
parts.push(encodeName(question.name))
|
|
124
|
+
const qtype = Buffer.alloc(4)
|
|
125
|
+
qtype.writeUInt16BE(question.type, 0)
|
|
126
|
+
qtype.writeUInt16BE(question.class, 2)
|
|
127
|
+
parts.push(qtype)
|
|
128
|
+
|
|
129
|
+
// Answer section
|
|
130
|
+
parts.push(encodeName(question.name))
|
|
131
|
+
|
|
132
|
+
const answer = Buffer.alloc(10)
|
|
133
|
+
answer.writeUInt16BE(question.type, 0) // Type
|
|
134
|
+
answer.writeUInt16BE(1, 2) // Class: IN
|
|
135
|
+
answer.writeUInt32BE(300, 4) // TTL: 5 minutes
|
|
136
|
+
|
|
137
|
+
if (question.type === 1) {
|
|
138
|
+
// A record (IPv4)
|
|
139
|
+
answer.writeUInt16BE(4, 8) // Data length
|
|
140
|
+
parts.push(answer)
|
|
141
|
+
const ipParts = ip.split('.').map(p => Number.parseInt(p, 10))
|
|
142
|
+
parts.push(Buffer.from(ipParts))
|
|
143
|
+
}
|
|
144
|
+
else if (question.type === 28) {
|
|
145
|
+
// AAAA record (IPv6)
|
|
146
|
+
answer.writeUInt16BE(16, 8) // Data length
|
|
147
|
+
parts.push(answer)
|
|
148
|
+
// ::1 as bytes
|
|
149
|
+
parts.push(Buffer.from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]))
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
// Unsupported type - return NXDOMAIN
|
|
153
|
+
header.writeUInt16BE(0x8183, 2) // Flags with NXDOMAIN
|
|
154
|
+
header.writeUInt16BE(0, 6) // No answers
|
|
155
|
+
return Buffer.concat([header, encodeName(question.name), qtype])
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return Buffer.concat(parts)
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Build NXDOMAIN response for unknown domains
|
|
163
|
+
*/
|
|
164
|
+
function buildNxdomainResponse(queryId: number, question: DnsQuestion): Buffer {
|
|
165
|
+
const parts: Buffer[] = []
|
|
166
|
+
|
|
167
|
+
// Header with NXDOMAIN
|
|
168
|
+
const header = Buffer.alloc(12)
|
|
169
|
+
header.writeUInt16BE(queryId, 0) // ID
|
|
170
|
+
header.writeUInt16BE(0x8183, 2) // Flags: Response, Authoritative, NXDOMAIN
|
|
171
|
+
header.writeUInt16BE(1, 4) // Questions: 1
|
|
172
|
+
header.writeUInt16BE(0, 6) // Answers: 0
|
|
173
|
+
header.writeUInt16BE(0, 8) // Authority: 0
|
|
174
|
+
header.writeUInt16BE(0, 10) // Additional: 0
|
|
175
|
+
parts.push(header)
|
|
176
|
+
|
|
177
|
+
// Question section (echo back)
|
|
178
|
+
parts.push(encodeName(question.name))
|
|
179
|
+
const qtype = Buffer.alloc(4)
|
|
180
|
+
qtype.writeUInt16BE(question.type, 0)
|
|
181
|
+
qtype.writeUInt16BE(question.class, 2)
|
|
182
|
+
parts.push(qtype)
|
|
183
|
+
|
|
184
|
+
return Buffer.concat(parts)
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
let dnsServer: dgram.Socket | null = null
|
|
188
|
+
let configuredDomains: Set<string> = new Set()
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Start the DNS server
|
|
192
|
+
*/
|
|
193
|
+
export async function startDnsServer(domains: string[], verbose?: boolean): Promise<boolean> {
|
|
194
|
+
if (dnsServer) {
|
|
195
|
+
debugLog('dns', 'DNS server already running', verbose)
|
|
196
|
+
return true
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
configuredDomains = new Set(domains.map(d => d.toLowerCase()))
|
|
200
|
+
|
|
201
|
+
return new Promise((resolve) => {
|
|
202
|
+
dnsServer = dgram.createSocket('udp4')
|
|
203
|
+
|
|
204
|
+
dnsServer.on('error', (err) => {
|
|
205
|
+
debugLog('dns', `DNS server error: ${err.message}`, verbose)
|
|
206
|
+
if (err.message.includes('EACCES') || err.message.includes('permission')) {
|
|
207
|
+
debugLog('dns', 'DNS server requires root privileges to bind to port 53', verbose)
|
|
208
|
+
}
|
|
209
|
+
dnsServer?.close()
|
|
210
|
+
dnsServer = null
|
|
211
|
+
resolve(false)
|
|
212
|
+
})
|
|
213
|
+
|
|
214
|
+
dnsServer.on('message', (msg, rinfo) => {
|
|
215
|
+
try {
|
|
216
|
+
const header = parseHeader(msg)
|
|
217
|
+
const { question } = parseQuestion(msg, 12)
|
|
218
|
+
|
|
219
|
+
debugLog('dns', `Query for ${question.name} type ${question.type} from ${rinfo.address}`, verbose)
|
|
220
|
+
|
|
221
|
+
// Check if this domain should be handled
|
|
222
|
+
const domainLower = question.name.toLowerCase()
|
|
223
|
+
let shouldHandle = false
|
|
224
|
+
|
|
225
|
+
for (const configured of configuredDomains) {
|
|
226
|
+
if (domainLower === configured || domainLower.endsWith(`.${configured}`)) {
|
|
227
|
+
shouldHandle = true
|
|
228
|
+
break
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// Note: Only configured domains are handled, no hardcoded TLDs
|
|
233
|
+
|
|
234
|
+
let response: Buffer
|
|
235
|
+
if (shouldHandle && (question.type === 1 || question.type === 28)) {
|
|
236
|
+
response = buildResponse(header.id, question, '127.0.0.1')
|
|
237
|
+
debugLog('dns', `Responding with localhost for ${question.name}`, verbose)
|
|
238
|
+
}
|
|
239
|
+
else {
|
|
240
|
+
response = buildNxdomainResponse(header.id, question)
|
|
241
|
+
debugLog('dns', `NXDOMAIN for ${question.name}`, verbose)
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
dnsServer?.send(response, rinfo.port, rinfo.address)
|
|
245
|
+
}
|
|
246
|
+
catch (err) {
|
|
247
|
+
debugLog('dns', `Error processing DNS query: ${err}`, verbose)
|
|
248
|
+
}
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
dnsServer.on('listening', () => {
|
|
252
|
+
const address = dnsServer?.address()
|
|
253
|
+
debugLog('dns', `DNS server listening on ${address?.address}:${address?.port}`, verbose)
|
|
254
|
+
resolve(true)
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
// Try to bind to port 53 with sudo
|
|
258
|
+
try {
|
|
259
|
+
dnsServer.bind(DNS_PORT, '127.0.0.1')
|
|
260
|
+
}
|
|
261
|
+
catch (err) {
|
|
262
|
+
debugLog('dns', `Failed to bind DNS server: ${err}`, verbose)
|
|
263
|
+
resolve(false)
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
/**
|
|
269
|
+
* Stop the DNS server
|
|
270
|
+
*/
|
|
271
|
+
export function stopDnsServer(verbose?: boolean): void {
|
|
272
|
+
if (dnsServer) {
|
|
273
|
+
debugLog('dns', 'Stopping DNS server', verbose)
|
|
274
|
+
dnsServer.close()
|
|
275
|
+
dnsServer = null
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Check if DNS server is running
|
|
281
|
+
*/
|
|
282
|
+
export function isDnsServerRunning(): boolean {
|
|
283
|
+
return dnsServer !== null
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Extract unique TLDs from domain list
|
|
288
|
+
*/
|
|
289
|
+
function extractTLDs(domains: string[]): string[] {
|
|
290
|
+
const tlds = new Set<string>()
|
|
291
|
+
for (const domain of domains) {
|
|
292
|
+
const parts = domain.split('.')
|
|
293
|
+
if (parts.length >= 2) {
|
|
294
|
+
tlds.add(parts[parts.length - 1])
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
return Array.from(tlds)
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Track which TLDs we've created resolvers for
|
|
301
|
+
const createdResolvers = new Set<string>()
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Flush macOS DNS cache to ensure resolver changes take effect
|
|
305
|
+
*/
|
|
306
|
+
async function flushDnsCache(verbose?: boolean): Promise<void> {
|
|
307
|
+
if (process.platform !== 'darwin') {
|
|
308
|
+
return
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const { execSudoSync, getSudoPassword } = await import('./utils')
|
|
312
|
+
const sudoPassword = getSudoPassword()
|
|
313
|
+
|
|
314
|
+
if (!sudoPassword) {
|
|
315
|
+
debugLog('dns', 'Cannot flush DNS cache without SUDO_PASSWORD', verbose)
|
|
316
|
+
return
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
try {
|
|
320
|
+
// Flush DNS cache and restart mDNSResponder
|
|
321
|
+
execSudoSync('dscacheutil -flushcache')
|
|
322
|
+
execSudoSync('killall -HUP mDNSResponder 2>/dev/null || true')
|
|
323
|
+
debugLog('dns', 'DNS cache flushed', verbose)
|
|
324
|
+
}
|
|
325
|
+
catch (err) {
|
|
326
|
+
// Non-fatal - DNS cache flush failure shouldn't block startup
|
|
327
|
+
debugLog('dns', `Could not flush DNS cache: ${err}`, verbose)
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/**
|
|
332
|
+
* Set up the macOS resolver for configured domains
|
|
333
|
+
* Creates /etc/resolver/<tld> files pointing to our local DNS server
|
|
334
|
+
*/
|
|
335
|
+
export async function setupResolver(verbose?: boolean, domains?: string[]): Promise<boolean> {
|
|
336
|
+
if (process.platform !== 'darwin') {
|
|
337
|
+
debugLog('dns', 'Resolver setup only needed on macOS', verbose)
|
|
338
|
+
return true
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
const { execSudoSync, getSudoPassword } = await import('./utils')
|
|
342
|
+
const sudoPassword = getSudoPassword()
|
|
343
|
+
|
|
344
|
+
if (!sudoPassword) {
|
|
345
|
+
debugLog('dns', 'SUDO_PASSWORD not set, cannot create resolver files', verbose)
|
|
346
|
+
return false
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
// Get TLDs from configured domains
|
|
350
|
+
const tlds = domains ? extractTLDs(domains) : ['test']
|
|
351
|
+
|
|
352
|
+
try {
|
|
353
|
+
for (const tld of tlds) {
|
|
354
|
+
if (createdResolvers.has(tld)) {
|
|
355
|
+
continue
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
// Use bash -c to properly handle the echo with newlines
|
|
359
|
+
const cmd = `bash -c 'mkdir -p /etc/resolver && echo -e "nameserver 127.0.0.1\\nport ${DNS_PORT}" > /etc/resolver/${tld}'`
|
|
360
|
+
execSudoSync(cmd)
|
|
361
|
+
createdResolvers.add(tld)
|
|
362
|
+
debugLog('dns', `Created /etc/resolver/${tld} for .${tld} TLD`, verbose)
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Flush DNS cache to ensure new resolver files take effect immediately
|
|
366
|
+
await flushDnsCache(verbose)
|
|
367
|
+
|
|
368
|
+
return true
|
|
369
|
+
}
|
|
370
|
+
catch (err) {
|
|
371
|
+
debugLog('dns', `Failed to create resolver file: ${err}`, verbose)
|
|
372
|
+
return false
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
/**
|
|
377
|
+
* Remove the macOS resolver files we created
|
|
378
|
+
*/
|
|
379
|
+
export async function removeResolver(verbose?: boolean): Promise<void> {
|
|
380
|
+
if (process.platform !== 'darwin') {
|
|
381
|
+
return
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
const { execSudoSync, getSudoPassword } = await import('./utils')
|
|
385
|
+
|
|
386
|
+
try {
|
|
387
|
+
const sudoPassword = getSudoPassword()
|
|
388
|
+
if (sudoPassword) {
|
|
389
|
+
for (const tld of createdResolvers) {
|
|
390
|
+
execSudoSync(`rm -f /etc/resolver/${tld}`)
|
|
391
|
+
debugLog('dns', `Removed /etc/resolver/${tld}`, verbose)
|
|
392
|
+
}
|
|
393
|
+
createdResolvers.clear()
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
catch (err) {
|
|
397
|
+
debugLog('dns', `Failed to remove resolver files: ${err}`, verbose)
|
|
398
|
+
}
|
|
399
|
+
}
|