localdeck 1.6.2 → 1.7.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.
@@ -0,0 +1,135 @@
1
+ import{createRequire as $2}from"node:module";var i4=Object.create;var{getPrototypeOf:c4,defineProperty:Y1,getOwnPropertyNames:n4}=Object;var a4=Object.prototype.hasOwnProperty;function o4($){return this[$]}var s4,t4,O0=($,Z,Q)=>{var X=$!=null&&typeof $==="object";if(X){var G=Z?s4??=new WeakMap:t4??=new WeakMap,J=G.get($);if(J)return J}Q=$!=null?i4(c4($)):{};let V=Z||!$||!$.__esModule?Y1(Q,"default",{value:$,enumerable:!0}):Q;for(let z of n4($))if(!a4.call(V,z))Y1(V,z,{get:o4.bind($,z),enumerable:!0});if(X)G.set($,V);return V};var d=($,Z)=>()=>(Z||$((Z={exports:{}}).exports,Z),Z.exports);var r4=($)=>$;function e4($,Z){this[$]=r4.bind(null,Z)}var r6=($,Z)=>{for(var Q in Z)Y1($,Q,{get:Z[Q],enumerable:!0,configurable:!0,set:e4.bind(Z,Q)})};var y=$2(import.meta.url);var G0=d((ZZ,K8)=>{var V8=["nodebuffer","arraybuffer","fragments"],Y8=typeof Blob<"u";if(Y8)V8.push("blob");K8.exports={BINARY_TYPES:V8,CLOSE_TIMEOUT:30000,EMPTY_BUFFER:Buffer.alloc(0),GUID:"258EAFA5-E914-47DA-95CA-C5AB0DC85B11",hasBlob:Y8,kForOnEventAttribute:Symbol("kIsForOnEventAttribute"),kListener:Symbol("kListener"),kStatusCode:Symbol("status-code"),kWebSocket:Symbol("websocket"),NOOP:()=>{}}});var a0=d((QZ,R$)=>{var{EMPTY_BUFFER:Z2}=G0(),K1=Buffer[Symbol.species];function Q2($,Z){if($.length===0)return Z2;if($.length===1)return $[0];let Q=Buffer.allocUnsafe(Z),X=0;for(let G=0;G<$.length;G++){let J=$[G];Q.set(J,X),X+=J.length}if(X<Z)return new K1(Q.buffer,Q.byteOffset,X);return Q}function z8($,Z,Q,X,G){for(let J=0;J<G;J++)Q[X+J]=$[J]^Z[J&3]}function N8($,Z){for(let Q=0;Q<$.length;Q++)$[Q]^=Z[Q&3]}function X2($){if($.length===$.buffer.byteLength)return $.buffer;return $.buffer.slice($.byteOffset,$.byteOffset+$.length)}function z1($){if(z1.readOnly=!0,Buffer.isBuffer($))return $;let Z;if($ instanceof ArrayBuffer)Z=new K1($);else if(ArrayBuffer.isView($))Z=new K1($.buffer,$.byteOffset,$.byteLength);else Z=Buffer.from($),z1.readOnly=!1;return Z}R$.exports={concat:Q2,mask:z8,toArrayBuffer:X2,toBuffer:z1,unmask:N8};if(!process.env.WS_NO_BUFFER_UTIL)try{let $=(()=>{throw new Error("Cannot require module "+"bufferutil");})();R$.exports.mask=function(Z,Q,X,G,J){if(J<48)z8(Z,Q,X,G,J);else $.mask(Z,Q,X,G,J)},R$.exports.unmask=function(Z,Q){if(Z.length<32)N8(Z,Q);else $.unmask(Z,Q)}}catch($){}});var W8=d((XZ,O8)=>{var U8=Symbol("kDone"),N1=Symbol("kRun");class D8{constructor($){this[U8]=()=>{this.pending--,this[N1]()},this.concurrency=$||1/0,this.jobs=[],this.pending=0}add($){this.jobs.push($),this[N1]()}[N1](){if(this.pending===this.concurrency)return;if(this.jobs.length){let $=this.jobs.shift();this.pending++,$(this[U8])}}}O8.exports=D8});var f0=d((GZ,L8)=>{var o0=y("zlib"),C8=a0(),G2=W8(),{kStatusCode:B8}=G0(),J2=Buffer[Symbol.species],V2=Buffer.from([0,0,255,255]),M$=Symbol("permessage-deflate"),J0=Symbol("total-length"),h0=Symbol("callback"),W0=Symbol("buffers"),g0=Symbol("error"),F$;class _8{constructor($){if(this._options=$||{},this._threshold=this._options.threshold!==void 0?this._options.threshold:1024,this._maxPayload=this._options.maxPayload|0,this._isServer=!!this._options.isServer,this._deflate=null,this._inflate=null,this.params=null,!F$){let Z=this._options.concurrencyLimit!==void 0?this._options.concurrencyLimit:10;F$=new G2(Z)}}static get extensionName(){return"permessage-deflate"}offer(){let $={};if(this._options.serverNoContextTakeover)$.server_no_context_takeover=!0;if(this._options.clientNoContextTakeover)$.client_no_context_takeover=!0;if(this._options.serverMaxWindowBits)$.server_max_window_bits=this._options.serverMaxWindowBits;if(this._options.clientMaxWindowBits)$.client_max_window_bits=this._options.clientMaxWindowBits;else if(this._options.clientMaxWindowBits==null)$.client_max_window_bits=!0;return $}accept($){return $=this.normalizeParams($),this.params=this._isServer?this.acceptAsServer($):this.acceptAsClient($),this.params}cleanup(){if(this._inflate)this._inflate.close(),this._inflate=null;if(this._deflate){let $=this._deflate[h0];if(this._deflate.close(),this._deflate=null,$)$(Error("The deflate stream was closed while data was being processed"))}}acceptAsServer($){let Z=this._options,Q=$.find((X)=>{if(Z.serverNoContextTakeover===!1&&X.server_no_context_takeover||X.server_max_window_bits&&(Z.serverMaxWindowBits===!1||typeof Z.serverMaxWindowBits==="number"&&Z.serverMaxWindowBits>X.server_max_window_bits)||typeof Z.clientMaxWindowBits==="number"&&(typeof X.client_max_window_bits==="number"?Z.clientMaxWindowBits>X.client_max_window_bits:!X.client_max_window_bits))return!1;return!0});if(!Q)throw Error("None of the extension offers can be accepted");if(Z.serverNoContextTakeover)Q.server_no_context_takeover=!0;if(Z.clientNoContextTakeover)Q.client_no_context_takeover=!0;if(typeof Z.serverMaxWindowBits==="number")Q.server_max_window_bits=Z.serverMaxWindowBits;if(typeof Z.clientMaxWindowBits==="number")Q.client_max_window_bits=Z.clientMaxWindowBits;else if(Q.client_max_window_bits===!0||Z.clientMaxWindowBits===!1)delete Q.client_max_window_bits;return Q}acceptAsClient($){let Z=$[0];if(this._options.clientNoContextTakeover===!1&&Z.client_no_context_takeover)throw Error('Unexpected parameter "client_no_context_takeover"');if(!Z.client_max_window_bits){if(typeof this._options.clientMaxWindowBits==="number")Z.client_max_window_bits=this._options.clientMaxWindowBits}else if(this._options.clientMaxWindowBits===!1||typeof this._options.clientMaxWindowBits==="number"&&Z.client_max_window_bits>this._options.clientMaxWindowBits)throw Error('Unexpected or invalid parameter "client_max_window_bits"');return Z}normalizeParams($){return $.forEach((Z)=>{Object.keys(Z).forEach((Q)=>{let X=Z[Q];if(X.length>1)throw Error(`Parameter "${Q}" must have only a single value`);if(X=X[0],Q==="client_max_window_bits"){if(X!==!0){let G=+X;if(!Number.isInteger(G)||G<8||G>15)throw TypeError(`Invalid value for parameter "${Q}": ${X}`);X=G}else if(!this._isServer)throw TypeError(`Invalid value for parameter "${Q}": ${X}`)}else if(Q==="server_max_window_bits"){let G=+X;if(!Number.isInteger(G)||G<8||G>15)throw TypeError(`Invalid value for parameter "${Q}": ${X}`);X=G}else if(Q==="client_no_context_takeover"||Q==="server_no_context_takeover"){if(X!==!0)throw TypeError(`Invalid value for parameter "${Q}": ${X}`)}else throw Error(`Unknown parameter "${Q}"`);Z[Q]=X})}),$}decompress($,Z,Q){F$.add((X)=>{this._decompress($,Z,(G,J)=>{X(),Q(G,J)})})}compress($,Z,Q){F$.add((X)=>{this._compress($,Z,(G,J)=>{X(),Q(G,J)})})}_decompress($,Z,Q){let X=this._isServer?"client":"server";if(!this._inflate){let G=`${X}_max_window_bits`,J=typeof this.params[G]!=="number"?o0.Z_DEFAULT_WINDOWBITS:this.params[G];this._inflate=o0.createInflateRaw({...this._options.zlibInflateOptions,windowBits:J}),this._inflate[M$]=this,this._inflate[J0]=0,this._inflate[W0]=[],this._inflate.on("error",K2),this._inflate.on("data",H8)}if(this._inflate[h0]=Q,this._inflate.write($),Z)this._inflate.write(V2);this._inflate.flush(()=>{let G=this._inflate[g0];if(G){this._inflate.close(),this._inflate=null,Q(G);return}let J=C8.concat(this._inflate[W0],this._inflate[J0]);if(this._inflate._readableState.endEmitted)this._inflate.close(),this._inflate=null;else if(this._inflate[J0]=0,this._inflate[W0]=[],Z&&this.params[`${X}_no_context_takeover`])this._inflate.reset();Q(null,J)})}_compress($,Z,Q){let X=this._isServer?"server":"client";if(!this._deflate){let G=`${X}_max_window_bits`,J=typeof this.params[G]!=="number"?o0.Z_DEFAULT_WINDOWBITS:this.params[G];this._deflate=o0.createDeflateRaw({...this._options.zlibDeflateOptions,windowBits:J}),this._deflate[J0]=0,this._deflate[W0]=[],this._deflate.on("data",Y2)}this._deflate[h0]=Q,this._deflate.write($),this._deflate.flush(o0.Z_SYNC_FLUSH,()=>{if(!this._deflate)return;let G=C8.concat(this._deflate[W0],this._deflate[J0]);if(Z)G=new J2(G.buffer,G.byteOffset,G.length-4);if(this._deflate[h0]=null,this._deflate[J0]=0,this._deflate[W0]=[],Z&&this.params[`${X}_no_context_takeover`])this._deflate.reset();Q(null,G)})}}L8.exports=_8;function Y2($){this[W0].push($),this[J0]+=$.length}function H8($){if(this[J0]+=$.length,this[M$]._maxPayload<1||this[J0]<=this[M$]._maxPayload){this[W0].push($);return}this[g0]=RangeError("Max payload size exceeded"),this[g0].code="WS_ERR_UNSUPPORTED_MESSAGE_LENGTH",this[g0][B8]=1009,this.removeListener("data",H8),this.reset()}function K2($){if(this[M$]._inflate=null,this[g0]){this[h0](this[g0]);return}$[B8]=1007,this[h0]($)}});var b0=d((JZ,x$)=>{var{isUtf8:T8}=y("buffer"),{hasBlob:z2}=G0(),N2=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,1,1,0,0,1,1,0,1,1,0,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,0,1,0];function U2($){return $>=1000&&$<=1014&&$!==1004&&$!==1005&&$!==1006||$>=3000&&$<=4999}function U1($){let Z=$.length,Q=0;while(Q<Z)if(($[Q]&128)===0)Q++;else if(($[Q]&224)===192){if(Q+1===Z||($[Q+1]&192)!==128||($[Q]&254)===192)return!1;Q+=2}else if(($[Q]&240)===224){if(Q+2>=Z||($[Q+1]&192)!==128||($[Q+2]&192)!==128||$[Q]===224&&($[Q+1]&224)===128||$[Q]===237&&($[Q+1]&224)===160)return!1;Q+=3}else if(($[Q]&248)===240){if(Q+3>=Z||($[Q+1]&192)!==128||($[Q+2]&192)!==128||($[Q+3]&192)!==128||$[Q]===240&&($[Q+1]&240)===128||$[Q]===244&&$[Q+1]>143||$[Q]>244)return!1;Q+=4}else return!1;return!0}function D2($){return z2&&typeof $==="object"&&typeof $.arrayBuffer==="function"&&typeof $.type==="string"&&typeof $.stream==="function"&&($[Symbol.toStringTag]==="Blob"||$[Symbol.toStringTag]==="File")}x$.exports={isBlob:D2,isValidStatusCode:U2,isValidUTF8:U1,tokenChars:N2};if(T8)x$.exports.isValidUTF8=function($){return $.length<24?U1($):T8($)};else if(!process.env.WS_NO_UTF_8_VALIDATE)try{let $=(()=>{throw new Error("Cannot require module "+"utf-8-validate");})();x$.exports.isValidUTF8=function(Z){return Z.length<32?U1(Z):$(Z)}}catch($){}});var O1=d((VZ,x8)=>{var{Writable:O2}=y("stream"),A8=f0(),{BINARY_TYPES:W2,EMPTY_BUFFER:R8,kStatusCode:C2,kWebSocket:B2}=G0(),{concat:D1,toArrayBuffer:_2,unmask:H2}=a0(),{isValidStatusCode:L2,isValidUTF8:F8}=b0(),P$=Buffer[Symbol.species];class M8 extends O2{constructor($={}){super();this._allowSynchronousEvents=$.allowSynchronousEvents!==void 0?$.allowSynchronousEvents:!0,this._binaryType=$.binaryType||W2[0],this._extensions=$.extensions||{},this._isServer=!!$.isServer,this._maxBufferedChunks=$.maxBufferedChunks|0,this._maxFragments=$.maxFragments|0,this._maxPayload=$.maxPayload|0,this._skipUTF8Validation=!!$.skipUTF8Validation,this[B2]=void 0,this._bufferedBytes=0,this._buffers=[],this._compressed=!1,this._payloadLength=0,this._mask=void 0,this._fragmented=0,this._masked=!1,this._fin=!1,this._opcode=0,this._totalPayloadLength=0,this._messageLength=0,this._numFragments=0,this._fragments=[],this._errored=!1,this._loop=!1,this._state=0}_write($,Z,Q){if(this._opcode===8&&this._state==0)return Q();if(this._maxBufferedChunks>0&&this._buffers.length>=this._maxBufferedChunks){Q(this.createError(RangeError,"Too many buffered chunks",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS"));return}this._bufferedBytes+=$.length,this._buffers.push($),this.startLoop(Q)}consume($){if(this._bufferedBytes-=$,$===this._buffers[0].length)return this._buffers.shift();if($<this._buffers[0].length){let Q=this._buffers[0];return this._buffers[0]=new P$(Q.buffer,Q.byteOffset+$,Q.length-$),new P$(Q.buffer,Q.byteOffset,$)}let Z=Buffer.allocUnsafe($);do{let Q=this._buffers[0],X=Z.length-$;if($>=Q.length)Z.set(this._buffers.shift(),X);else Z.set(new Uint8Array(Q.buffer,Q.byteOffset,$),X),this._buffers[0]=new P$(Q.buffer,Q.byteOffset+$,Q.length-$);$-=Q.length}while($>0);return Z}startLoop($){this._loop=!0;do switch(this._state){case 0:this.getInfo($);break;case 1:this.getPayloadLength16($);break;case 2:this.getPayloadLength64($);break;case 3:this.getMask();break;case 4:this.getData($);break;case 5:case 6:this._loop=!1;return}while(this._loop);if(!this._errored)$()}getInfo($){if(this._bufferedBytes<2){this._loop=!1;return}let Z=this.consume(2);if((Z[0]&48)!==0){let X=this.createError(RangeError,"RSV2 and RSV3 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_2_3");$(X);return}let Q=(Z[0]&64)===64;if(Q&&!this._extensions[A8.extensionName]){let X=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");$(X);return}if(this._fin=(Z[0]&128)===128,this._opcode=Z[0]&15,this._payloadLength=Z[1]&127,this._opcode===0){if(Q){let X=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");$(X);return}if(!this._fragmented){let X=this.createError(RangeError,"invalid opcode 0",!0,1002,"WS_ERR_INVALID_OPCODE");$(X);return}this._opcode=this._fragmented}else if(this._opcode===1||this._opcode===2){if(this._fragmented){let X=this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");$(X);return}this._compressed=Q}else if(this._opcode>7&&this._opcode<11){if(!this._fin){let X=this.createError(RangeError,"FIN must be set",!0,1002,"WS_ERR_EXPECTED_FIN");$(X);return}if(Q){let X=this.createError(RangeError,"RSV1 must be clear",!0,1002,"WS_ERR_UNEXPECTED_RSV_1");$(X);return}if(this._payloadLength>125||this._opcode===8&&this._payloadLength===1){let X=this.createError(RangeError,`invalid payload length ${this._payloadLength}`,!0,1002,"WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH");$(X);return}}else{let X=this.createError(RangeError,`invalid opcode ${this._opcode}`,!0,1002,"WS_ERR_INVALID_OPCODE");$(X);return}if(!this._fin&&!this._fragmented)this._fragmented=this._opcode;if(this._masked=(Z[1]&128)===128,this._isServer){if(!this._masked){let X=this.createError(RangeError,"MASK must be set",!0,1002,"WS_ERR_EXPECTED_MASK");$(X);return}}else if(this._masked){let X=this.createError(RangeError,"MASK must be clear",!0,1002,"WS_ERR_UNEXPECTED_MASK");$(X);return}if(this._payloadLength===126)this._state=1;else if(this._payloadLength===127)this._state=2;else this.haveLength($)}getPayloadLength16($){if(this._bufferedBytes<2){this._loop=!1;return}this._payloadLength=this.consume(2).readUInt16BE(0),this.haveLength($)}getPayloadLength64($){if(this._bufferedBytes<8){this._loop=!1;return}let Z=this.consume(8),Q=Z.readUInt32BE(0);if(Q>Math.pow(2,21)-1){let X=this.createError(RangeError,"Unsupported WebSocket frame: payload length > 2^53 - 1",!1,1009,"WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH");$(X);return}this._payloadLength=Q*Math.pow(2,32)+Z.readUInt32BE(4),this.haveLength($)}haveLength($){if(this._payloadLength&&this._opcode<8){if(this._totalPayloadLength+=this._payloadLength,this._totalPayloadLength>this._maxPayload&&this._maxPayload>0){let Z=this.createError(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");$(Z);return}}if(this._masked)this._state=3;else this._state=4}getMask(){if(this._bufferedBytes<4){this._loop=!1;return}this._mask=this.consume(4),this._state=4}getData($){let Z=R8;if(this._payloadLength){if(this._bufferedBytes<this._payloadLength){this._loop=!1;return}if(Z=this.consume(this._payloadLength),this._masked&&(this._mask[0]|this._mask[1]|this._mask[2]|this._mask[3])!==0)H2(Z,this._mask)}if(this._opcode>7){this.controlMessage(Z,$);return}if(this._maxFragments>0&&++this._numFragments>this._maxFragments){let Q=this.createError(RangeError,"Too many message fragments",!1,1008,"WS_ERR_TOO_MANY_BUFFERED_PARTS");$(Q);return}if(this._compressed){this._state=5,this.decompress(Z,$);return}if(Z.length)this._messageLength=this._totalPayloadLength,this._fragments.push(Z);this.dataMessage($)}decompress($,Z){this._extensions[A8.extensionName].decompress($,this._fin,(X,G)=>{if(X)return Z(X);if(G.length){if(this._messageLength+=G.length,this._messageLength>this._maxPayload&&this._maxPayload>0){let J=this.createError(RangeError,"Max payload size exceeded",!1,1009,"WS_ERR_UNSUPPORTED_MESSAGE_LENGTH");Z(J);return}this._fragments.push(G)}if(this.dataMessage(Z),this._state===0)this.startLoop(Z)})}dataMessage($){if(!this._fin){this._state=0;return}let Z=this._messageLength,Q=this._fragments;if(this._totalPayloadLength=0,this._messageLength=0,this._fragmented=0,this._numFragments=0,this._fragments=[],this._opcode===2){let X;if(this._binaryType==="nodebuffer")X=D1(Q,Z);else if(this._binaryType==="arraybuffer")X=_2(D1(Q,Z));else if(this._binaryType==="blob")X=new Blob(Q);else X=Q;if(this._allowSynchronousEvents)this.emit("message",X,!0),this._state=0;else this._state=6,setImmediate(()=>{this.emit("message",X,!0),this._state=0,this.startLoop($)})}else{let X=D1(Q,Z);if(!this._skipUTF8Validation&&!F8(X)){let G=this.createError(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");$(G);return}if(this._state===5||this._allowSynchronousEvents)this.emit("message",X,!1),this._state=0;else this._state=6,setImmediate(()=>{this.emit("message",X,!1),this._state=0,this.startLoop($)})}}controlMessage($,Z){if(this._opcode===8){if($.length===0)this._loop=!1,this.emit("conclude",1005,R8),this.end();else{let Q=$.readUInt16BE(0);if(!L2(Q)){let G=this.createError(RangeError,`invalid status code ${Q}`,!0,1002,"WS_ERR_INVALID_CLOSE_CODE");Z(G);return}let X=new P$($.buffer,$.byteOffset+2,$.length-2);if(!this._skipUTF8Validation&&!F8(X)){let G=this.createError(Error,"invalid UTF-8 sequence",!0,1007,"WS_ERR_INVALID_UTF8");Z(G);return}this._loop=!1,this.emit("conclude",Q,X),this.end()}this._state=0;return}if(this._allowSynchronousEvents)this.emit(this._opcode===9?"ping":"pong",$),this._state=0;else this._state=6,setImmediate(()=>{this.emit(this._opcode===9?"ping":"pong",$),this._state=0,this.startLoop(Z)})}createError($,Z,Q,X,G){this._loop=!1,this._errored=!0;let J=new $(Q?`Invalid WebSocket frame: ${Z}`:Z);return Error.captureStackTrace(J,this.createError),J.code=G,J[C2]=X,J}}x8.exports=M8});var C1=d((KZ,S8)=>{var{Duplex:YZ}=y("stream"),{randomFillSync:T2}=y("crypto"),{types:{isUint8Array:A2}}=y("util"),P8=f0(),{EMPTY_BUFFER:R2,kWebSocket:F2,NOOP:M2}=G0(),{isBlob:y0,isValidStatusCode:x2}=b0(),{mask:I8,toBuffer:R0}=a0(),a=Symbol("kByteLength"),P2=Buffer.alloc(4),F0,v0=8192,t=0,I2=1,S2=2;class C0{constructor($,Z,Q){if(this._extensions=Z||{},Q)this._generateMask=Q,this._maskBuffer=Buffer.alloc(4);this._socket=$,this._firstFragment=!0,this._compress=!1,this._bufferedBytes=0,this._queue=[],this._state=t,this.onerror=M2,this[F2]=void 0}static frame($,Z){let Q,X=!1,G=2,J=!1;if(Z.mask){if(Q=Z.maskBuffer||P2,Z.generateMask)Z.generateMask(Q);else{if(v0===8192){if(F0===void 0)F0=Buffer.alloc(8192);T2(F0,0,8192),v0=0}Q[0]=F0[v0++],Q[1]=F0[v0++],Q[2]=F0[v0++],Q[3]=F0[v0++]}J=(Q[0]|Q[1]|Q[2]|Q[3])===0,G=6}let V;if(typeof $==="string")if((!Z.mask||J)&&Z[a]!==void 0)V=Z[a];else $=Buffer.from($),V=$.length;else V=$.length,X=Z.mask&&Z.readOnly&&!J;let z=V;if(V>=65536)G+=8,z=127;else if(V>125)G+=2,z=126;let Y=Buffer.allocUnsafe(X?V+G:G);if(Y[0]=Z.fin?Z.opcode|128:Z.opcode,Z.rsv1)Y[0]|=64;if(Y[1]=z,z===126)Y.writeUInt16BE(V,2);else if(z===127)Y[2]=Y[3]=0,Y.writeUIntBE(V,4,6);if(!Z.mask)return[Y,$];if(Y[1]|=128,Y[G-4]=Q[0],Y[G-3]=Q[1],Y[G-2]=Q[2],Y[G-1]=Q[3],J)return[Y,$];if(X)return I8($,Q,Y,G,V),[Y];return I8($,Q,$,0,V),[Y,$]}close($,Z,Q,X){let G;if($===void 0)G=R2;else if(typeof $!=="number"||!x2($))throw TypeError("First argument must be a valid error code number");else if(Z===void 0||!Z.length)G=Buffer.allocUnsafe(2),G.writeUInt16BE($,0);else{let V=Buffer.byteLength(Z);if(V>123)throw RangeError("The message must not be greater than 123 bytes");if(G=Buffer.allocUnsafe(2+V),G.writeUInt16BE($,0),typeof Z==="string")G.write(Z,2);else if(A2(Z))G.set(Z,2);else throw TypeError("Second argument must be a string or a Uint8Array")}let J={[a]:G.length,fin:!0,generateMask:this._generateMask,mask:Q,maskBuffer:this._maskBuffer,opcode:8,readOnly:!1,rsv1:!1};if(this._state!==t)this.enqueue([this.dispatch,G,!1,J,X]);else this.sendFrame(C0.frame(G,J),X)}ping($,Z,Q){let X,G;if(typeof $==="string")X=Buffer.byteLength($),G=!1;else if(y0($))X=$.size,G=!1;else $=R0($),X=$.length,G=R0.readOnly;if(X>125)throw RangeError("The data size must not be greater than 125 bytes");let J={[a]:X,fin:!0,generateMask:this._generateMask,mask:Z,maskBuffer:this._maskBuffer,opcode:9,readOnly:G,rsv1:!1};if(y0($))if(this._state!==t)this.enqueue([this.getBlobData,$,!1,J,Q]);else this.getBlobData($,!1,J,Q);else if(this._state!==t)this.enqueue([this.dispatch,$,!1,J,Q]);else this.sendFrame(C0.frame($,J),Q)}pong($,Z,Q){let X,G;if(typeof $==="string")X=Buffer.byteLength($),G=!1;else if(y0($))X=$.size,G=!1;else $=R0($),X=$.length,G=R0.readOnly;if(X>125)throw RangeError("The data size must not be greater than 125 bytes");let J={[a]:X,fin:!0,generateMask:this._generateMask,mask:Z,maskBuffer:this._maskBuffer,opcode:10,readOnly:G,rsv1:!1};if(y0($))if(this._state!==t)this.enqueue([this.getBlobData,$,!1,J,Q]);else this.getBlobData($,!1,J,Q);else if(this._state!==t)this.enqueue([this.dispatch,$,!1,J,Q]);else this.sendFrame(C0.frame($,J),Q)}send($,Z,Q){let X=this._extensions[P8.extensionName],G=Z.binary?2:1,J=Z.compress,V,z;if(typeof $==="string")V=Buffer.byteLength($),z=!1;else if(y0($))V=$.size,z=!1;else $=R0($),V=$.length,z=R0.readOnly;if(this._firstFragment){if(this._firstFragment=!1,J&&X&&X.params[X._isServer?"server_no_context_takeover":"client_no_context_takeover"])J=V>=X._threshold;this._compress=J}else J=!1,G=0;if(Z.fin)this._firstFragment=!0;let Y={[a]:V,fin:Z.fin,generateMask:this._generateMask,mask:Z.mask,maskBuffer:this._maskBuffer,opcode:G,readOnly:z,rsv1:J};if(y0($))if(this._state!==t)this.enqueue([this.getBlobData,$,this._compress,Y,Q]);else this.getBlobData($,this._compress,Y,Q);else if(this._state!==t)this.enqueue([this.dispatch,$,this._compress,Y,Q]);else this.dispatch($,this._compress,Y,Q)}getBlobData($,Z,Q,X){this._bufferedBytes+=Q[a],this._state=S2,$.arrayBuffer().then((G)=>{if(this._socket.destroyed){let V=Error("The socket was closed while the blob was being read");process.nextTick(W1,this,V,X);return}this._bufferedBytes-=Q[a];let J=R0(G);if(!Z)this._state=t,this.sendFrame(C0.frame(J,Q),X),this.dequeue();else this.dispatch(J,Z,Q,X)}).catch((G)=>{process.nextTick(q2,this,G,X)})}dispatch($,Z,Q,X){if(!Z){this.sendFrame(C0.frame($,Q),X);return}let G=this._extensions[P8.extensionName];this._bufferedBytes+=Q[a],this._state=I2,G.compress($,Q.fin,(J,V)=>{if(this._socket.destroyed){let z=Error("The socket was closed while data was being compressed");W1(this,z,X);return}this._bufferedBytes-=Q[a],this._state=t,Q.readOnly=!1,this.sendFrame(C0.frame(V,Q),X),this.dequeue()})}dequeue(){while(this._state===t&&this._queue.length){let $=this._queue.shift();this._bufferedBytes-=$[3][a],Reflect.apply($[0],this,$.slice(1))}}enqueue($){this._bufferedBytes+=$[3][a],this._queue.push($)}sendFrame($,Z){if($.length===2)this._socket.cork(),this._socket.write($[0]),this._socket.write($[1],Z),this._socket.uncork();else this._socket.write($[0],Z)}}S8.exports=C0;function W1($,Z,Q){if(typeof Q==="function")Q(Z);for(let X=0;X<$._queue.length;X++){let G=$._queue[X],J=G[G.length-1];if(typeof J==="function")J(Z)}}function q2($,Z,Q){W1($,Z,Q),$.onerror(Z)}});var y8=d((zZ,b8)=>{var{kForOnEventAttribute:s0,kListener:B1}=G0(),q8=Symbol("kCode"),E8=Symbol("kData"),w8=Symbol("kError"),j8=Symbol("kMessage"),h8=Symbol("kReason"),k0=Symbol("kTarget"),g8=Symbol("kType"),f8=Symbol("kWasClean");class B0{constructor($){this[k0]=null,this[g8]=$}get target(){return this[k0]}get type(){return this[g8]}}Object.defineProperty(B0.prototype,"target",{enumerable:!0});Object.defineProperty(B0.prototype,"type",{enumerable:!0});class u0 extends B0{constructor($,Z={}){super($);this[q8]=Z.code===void 0?0:Z.code,this[h8]=Z.reason===void 0?"":Z.reason,this[f8]=Z.wasClean===void 0?!1:Z.wasClean}get code(){return this[q8]}get reason(){return this[h8]}get wasClean(){return this[f8]}}Object.defineProperty(u0.prototype,"code",{enumerable:!0});Object.defineProperty(u0.prototype,"reason",{enumerable:!0});Object.defineProperty(u0.prototype,"wasClean",{enumerable:!0});class t0 extends B0{constructor($,Z={}){super($);this[w8]=Z.error===void 0?null:Z.error,this[j8]=Z.message===void 0?"":Z.message}get error(){return this[w8]}get message(){return this[j8]}}Object.defineProperty(t0.prototype,"error",{enumerable:!0});Object.defineProperty(t0.prototype,"message",{enumerable:!0});class S$ extends B0{constructor($,Z={}){super($);this[E8]=Z.data===void 0?null:Z.data}get data(){return this[E8]}}Object.defineProperty(S$.prototype,"data",{enumerable:!0});var E2={addEventListener($,Z,Q={}){for(let G of this.listeners($))if(!Q[s0]&&G[B1]===Z&&!G[s0])return;let X;if($==="message")X=function(J,V){let z=new S$("message",{data:V?J:J.toString()});z[k0]=this,I$(Z,this,z)};else if($==="close")X=function(J,V){let z=new u0("close",{code:J,reason:V.toString(),wasClean:this._closeFrameReceived&&this._closeFrameSent});z[k0]=this,I$(Z,this,z)};else if($==="error")X=function(J){let V=new t0("error",{error:J,message:J.message});V[k0]=this,I$(Z,this,V)};else if($==="open")X=function(){let J=new B0("open");J[k0]=this,I$(Z,this,J)};else return;if(X[s0]=!!Q[s0],X[B1]=Z,Q.once)this.once($,X);else this.on($,X)},removeEventListener($,Z){for(let Q of this.listeners($))if(Q[B1]===Z&&!Q[s0]){this.removeListener($,Q);break}}};b8.exports={CloseEvent:u0,ErrorEvent:t0,Event:B0,EventTarget:E2,MessageEvent:S$};function I$($,Z,Q){if(typeof $==="object"&&$.handleEvent)$.handleEvent.call($,Q);else $.call(Z,Q)}});var q$=d((NZ,v8)=>{var{tokenChars:r0}=b0();function Z0($,Z,Q){if($[Z]===void 0)$[Z]=[Q];else $[Z].push(Q)}function w2($){let Z=Object.create(null),Q=Object.create(null),X=!1,G=!1,J=!1,V,z,Y=-1,K=-1,N=-1,U=0;for(;U<$.length;U++)if(K=$.charCodeAt(U),V===void 0)if(N===-1&&r0[K]===1){if(Y===-1)Y=U}else if(U!==0&&(K===32||K===9)){if(N===-1&&Y!==-1)N=U}else if(K===59||K===44){if(Y===-1)throw SyntaxError(`Unexpected character at index ${U}`);if(N===-1)N=U;let C=$.slice(Y,N);if(K===44)Z0(Z,C,Q),Q=Object.create(null);else V=C;Y=N=-1}else throw SyntaxError(`Unexpected character at index ${U}`);else if(z===void 0)if(N===-1&&r0[K]===1){if(Y===-1)Y=U}else if(K===32||K===9){if(N===-1&&Y!==-1)N=U}else if(K===59||K===44){if(Y===-1)throw SyntaxError(`Unexpected character at index ${U}`);if(N===-1)N=U;if(Z0(Q,$.slice(Y,N),!0),K===44)Z0(Z,V,Q),Q=Object.create(null),V=void 0;Y=N=-1}else if(K===61&&Y!==-1&&N===-1)z=$.slice(Y,U),Y=N=-1;else throw SyntaxError(`Unexpected character at index ${U}`);else if(G){if(r0[K]!==1)throw SyntaxError(`Unexpected character at index ${U}`);if(Y===-1)Y=U;else if(!X)X=!0;G=!1}else if(J)if(r0[K]===1){if(Y===-1)Y=U}else if(K===34&&Y!==-1)J=!1,N=U;else if(K===92)G=!0;else throw SyntaxError(`Unexpected character at index ${U}`);else if(K===34&&$.charCodeAt(U-1)===61)J=!0;else if(N===-1&&r0[K]===1){if(Y===-1)Y=U}else if(Y!==-1&&(K===32||K===9)){if(N===-1)N=U}else if(K===59||K===44){if(Y===-1)throw SyntaxError(`Unexpected character at index ${U}`);if(N===-1)N=U;let C=$.slice(Y,N);if(X)C=C.replace(/\\/g,""),X=!1;if(Z0(Q,z,C),K===44)Z0(Z,V,Q),Q=Object.create(null),V=void 0;z=void 0,Y=N=-1}else throw SyntaxError(`Unexpected character at index ${U}`);if(Y===-1||J||K===32||K===9)throw SyntaxError("Unexpected end of input");if(N===-1)N=U;let W=$.slice(Y,N);if(V===void 0)Z0(Z,W,Q);else{if(z===void 0)Z0(Q,W,!0);else if(X)Z0(Q,z,W.replace(/\\/g,""));else Z0(Q,z,W);Z0(Z,V,Q)}return Z}function j2($){return Object.keys($).map((Z)=>{let Q=$[Z];if(!Array.isArray(Q))Q=[Q];return Q.map((X)=>{return[Z].concat(Object.keys(X).map((G)=>{let J=X[G];if(!Array.isArray(J))J=[J];return J.map((V)=>V===!0?G:`${G}=${V}`).join("; ")})).join("; ")}).join(", ")}).join(", ")}v8.exports={format:j2,parse:w2}});var h$=d((OZ,s8)=>{var h2=y("events"),g2=y("https"),f2=y("http"),m8=y("net"),b2=y("tls"),{randomBytes:y2,createHash:v2}=y("crypto"),{Duplex:UZ,Readable:DZ}=y("stream"),{URL:_1}=y("url"),_0=f0(),k2=O1(),u2=C1(),{isBlob:m2}=b0(),{BINARY_TYPES:k8,CLOSE_TIMEOUT:l2,EMPTY_BUFFER:E$,GUID:p2,kForOnEventAttribute:H1,kListener:d2,kStatusCode:i2,kWebSocket:v,NOOP:l8}=G0(),{EventTarget:{addEventListener:c2,removeEventListener:n2}}=y8(),{format:a2,parse:o2}=q$(),{toBuffer:s2}=a0(),p8=Symbol("kAborted"),L1=[8,13],V0=["CONNECTING","OPEN","CLOSING","CLOSED"],t2=/^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;class P extends h2{constructor($,Z,Q){super();if(this._binaryType=k8[0],this._closeCode=1006,this._closeFrameReceived=!1,this._closeFrameSent=!1,this._closeMessage=E$,this._closeTimer=null,this._errorEmitted=!1,this._extensions={},this._paused=!1,this._protocol="",this._readyState=P.CONNECTING,this._receiver=null,this._sender=null,this._socket=null,$!==null){if(this._bufferedAmount=0,this._isServer=!1,this._redirects=0,Z===void 0)Z=[];else if(!Array.isArray(Z))if(typeof Z==="object"&&Z!==null)Q=Z,Z=[];else Z=[Z];d8(this,$,Z,Q)}else this._autoPong=Q.autoPong,this._closeTimeout=Q.closeTimeout,this._isServer=!0}get binaryType(){return this._binaryType}set binaryType($){if(!k8.includes($))return;if(this._binaryType=$,this._receiver)this._receiver._binaryType=$}get bufferedAmount(){if(!this._socket)return this._bufferedAmount;return this._socket._writableState.length+this._sender._bufferedBytes}get extensions(){return Object.keys(this._extensions).join()}get isPaused(){return this._paused}get onclose(){return null}get onerror(){return null}get onopen(){return null}get onmessage(){return null}get protocol(){return this._protocol}get readyState(){return this._readyState}get url(){return this._url}setSocket($,Z,Q){let X=new k2({allowSynchronousEvents:Q.allowSynchronousEvents,binaryType:this.binaryType,extensions:this._extensions,isServer:this._isServer,maxBufferedChunks:Q.maxBufferedChunks,maxFragments:Q.maxFragments,maxPayload:Q.maxPayload,skipUTF8Validation:Q.skipUTF8Validation}),G=new u2($,this._extensions,Q.generateMask);if(this._receiver=X,this._sender=G,this._socket=$,X[v]=this,G[v]=this,$[v]=this,X.on("conclude",$3),X.on("drain",Z3),X.on("error",Q3),X.on("message",X3),X.on("ping",G3),X.on("pong",J3),G.onerror=V3,$.setTimeout)$.setTimeout(0);if($.setNoDelay)$.setNoDelay();if(Z.length>0)$.unshift(Z);$.on("close",n8),$.on("data",j$),$.on("end",a8),$.on("error",o8),this._readyState=P.OPEN,this.emit("open")}emitClose(){if(!this._socket){this._readyState=P.CLOSED,this.emit("close",this._closeCode,this._closeMessage);return}if(this._extensions[_0.extensionName])this._extensions[_0.extensionName].cleanup();this._receiver.removeAllListeners(),this._readyState=P.CLOSED,this.emit("close",this._closeCode,this._closeMessage)}close($,Z){if(this.readyState===P.CLOSED)return;if(this.readyState===P.CONNECTING){i(this,this._req,"WebSocket was closed before the connection was established");return}if(this.readyState===P.CLOSING){if(this._closeFrameSent&&(this._closeFrameReceived||this._receiver._writableState.errorEmitted))this._socket.end();return}this._readyState=P.CLOSING,this._sender.close($,Z,!this._isServer,(Q)=>{if(Q)return;if(this._closeFrameSent=!0,this._closeFrameReceived||this._receiver._writableState.errorEmitted)this._socket.end()}),c8(this)}pause(){if(this.readyState===P.CONNECTING||this.readyState===P.CLOSED)return;this._paused=!0,this._socket.pause()}ping($,Z,Q){if(this.readyState===P.CONNECTING)throw Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof $==="function")Q=$,$=Z=void 0;else if(typeof Z==="function")Q=Z,Z=void 0;if(typeof $==="number")$=$.toString();if(this.readyState!==P.OPEN){T1(this,$,Q);return}if(Z===void 0)Z=!this._isServer;this._sender.ping($||E$,Z,Q)}pong($,Z,Q){if(this.readyState===P.CONNECTING)throw Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof $==="function")Q=$,$=Z=void 0;else if(typeof Z==="function")Q=Z,Z=void 0;if(typeof $==="number")$=$.toString();if(this.readyState!==P.OPEN){T1(this,$,Q);return}if(Z===void 0)Z=!this._isServer;this._sender.pong($||E$,Z,Q)}resume(){if(this.readyState===P.CONNECTING||this.readyState===P.CLOSED)return;if(this._paused=!1,!this._receiver._writableState.needDrain)this._socket.resume()}send($,Z,Q){if(this.readyState===P.CONNECTING)throw Error("WebSocket is not open: readyState 0 (CONNECTING)");if(typeof Z==="function")Q=Z,Z={};if(typeof $==="number")$=$.toString();if(this.readyState!==P.OPEN){T1(this,$,Q);return}let X={binary:typeof $!=="string",mask:!this._isServer,compress:!0,fin:!0,...Z};if(!this._extensions[_0.extensionName])X.compress=!1;this._sender.send($||E$,X,Q)}terminate(){if(this.readyState===P.CLOSED)return;if(this.readyState===P.CONNECTING){i(this,this._req,"WebSocket was closed before the connection was established");return}if(this._socket)this._readyState=P.CLOSING,this._socket.destroy()}}Object.defineProperty(P,"CONNECTING",{enumerable:!0,value:V0.indexOf("CONNECTING")});Object.defineProperty(P.prototype,"CONNECTING",{enumerable:!0,value:V0.indexOf("CONNECTING")});Object.defineProperty(P,"OPEN",{enumerable:!0,value:V0.indexOf("OPEN")});Object.defineProperty(P.prototype,"OPEN",{enumerable:!0,value:V0.indexOf("OPEN")});Object.defineProperty(P,"CLOSING",{enumerable:!0,value:V0.indexOf("CLOSING")});Object.defineProperty(P.prototype,"CLOSING",{enumerable:!0,value:V0.indexOf("CLOSING")});Object.defineProperty(P,"CLOSED",{enumerable:!0,value:V0.indexOf("CLOSED")});Object.defineProperty(P.prototype,"CLOSED",{enumerable:!0,value:V0.indexOf("CLOSED")});["binaryType","bufferedAmount","extensions","isPaused","protocol","readyState","url"].forEach(($)=>{Object.defineProperty(P.prototype,$,{enumerable:!0})});["open","error","close","message"].forEach(($)=>{Object.defineProperty(P.prototype,`on${$}`,{enumerable:!0,get(){for(let Z of this.listeners($))if(Z[H1])return Z[d2];return null},set(Z){for(let Q of this.listeners($))if(Q[H1]){this.removeListener($,Q);break}if(typeof Z!=="function")return;this.addEventListener($,Z,{[H1]:!0})}})});P.prototype.addEventListener=c2;P.prototype.removeEventListener=n2;s8.exports=P;function d8($,Z,Q,X){let G={allowSynchronousEvents:!0,autoPong:!0,closeTimeout:l2,protocolVersion:L1[1],maxBufferedChunks:262144,maxFragments:16384,maxPayload:104857600,skipUTF8Validation:!1,perMessageDeflate:!0,followRedirects:!1,maxRedirects:10,...X,socketPath:void 0,hostname:void 0,protocol:void 0,timeout:void 0,method:"GET",host:void 0,path:void 0,port:void 0};if($._autoPong=G.autoPong,$._closeTimeout=G.closeTimeout,!L1.includes(G.protocolVersion))throw RangeError(`Unsupported protocol version: ${G.protocolVersion} (supported versions: ${L1.join(", ")})`);let J;if(Z instanceof _1)J=Z;else try{J=new _1(Z)}catch{throw SyntaxError(`Invalid URL: ${Z}`)}if(J.protocol==="http:")J.protocol="ws:";else if(J.protocol==="https:")J.protocol="wss:";$._url=J.href;let V=J.protocol==="wss:",z=J.protocol==="ws+unix:",Y;if(J.protocol!=="ws:"&&!V&&!z)Y=`The URL's protocol must be one of "ws:", "wss:", "http:", "https:", or "ws+unix:"`;else if(z&&!J.pathname)Y="The URL's pathname is empty";else if(J.hash)Y="The URL contains a fragment identifier";if(Y){let O=SyntaxError(Y);if($._redirects===0)throw O;else{w$($,O);return}}let K=V?443:80,N=y2(16).toString("base64"),U=V?g2.request:f2.request,W=new Set,C;if(G.createConnection=G.createConnection||(V?e2:r2),G.defaultPort=G.defaultPort||K,G.port=J.port||K,G.host=J.hostname.startsWith("[")?J.hostname.slice(1,-1):J.hostname,G.headers={...G.headers,"Sec-WebSocket-Version":G.protocolVersion,"Sec-WebSocket-Key":N,Connection:"Upgrade",Upgrade:"websocket"},G.path=J.pathname+J.search,G.timeout=G.handshakeTimeout,G.perMessageDeflate)C=new _0({...G.perMessageDeflate,isServer:!1,maxPayload:G.maxPayload}),G.headers["Sec-WebSocket-Extensions"]=a2({[_0.extensionName]:C.offer()});if(Q.length){for(let O of Q){if(typeof O!=="string"||!t2.test(O)||W.has(O))throw SyntaxError("An invalid or duplicated subprotocol was specified");W.add(O)}G.headers["Sec-WebSocket-Protocol"]=Q.join(",")}if(G.origin)if(G.protocolVersion<13)G.headers["Sec-WebSocket-Origin"]=G.origin;else G.headers.Origin=G.origin;if(J.username||J.password)G.auth=`${J.username}:${J.password}`;if(z){let O=G.path.split(":");G.socketPath=O[0],G.path=O[1]}let D;if(G.followRedirects){if($._redirects===0){$._originalIpc=z,$._originalSecure=V,$._originalHostOrSocketPath=z?G.socketPath:J.host;let O=X&&X.headers;if(X={...X,headers:{}},O)for(let[B,L]of Object.entries(O))X.headers[B.toLowerCase()]=L}else if($.listenerCount("redirect")===0){let O=z?$._originalIpc?G.socketPath===$._originalHostOrSocketPath:!1:$._originalIpc?!1:J.host===$._originalHostOrSocketPath;if(!O||$._originalSecure&&!V){if(delete G.headers.authorization,delete G.headers.cookie,!O)delete G.headers.host;G.auth=void 0}}if(G.auth&&!X.headers.authorization)X.headers.authorization="Basic "+Buffer.from(G.auth).toString("base64");if(D=$._req=U(G),$._redirects)$.emit("redirect",$.url,D)}else D=$._req=U(G);if(G.timeout)D.on("timeout",()=>{i($,D,"Opening handshake has timed out")});if(D.on("error",(O)=>{if(D===null||D[p8])return;D=$._req=null,w$($,O)}),D.on("response",(O)=>{let B=O.headers.location,L=O.statusCode;if(B&&G.followRedirects&&L>=300&&L<400){if(++$._redirects>G.maxRedirects){i($,D,"Maximum redirects exceeded");return}D.abort();let _;try{_=new _1(B,Z)}catch(H){let T=SyntaxError(`Invalid URL: ${B}`);w$($,T);return}d8($,_,Q,X)}else if(!$.emit("unexpected-response",D,O))i($,D,`Unexpected server response: ${O.statusCode}`)}),D.on("upgrade",(O,B,L)=>{if($.emit("upgrade",O),$.readyState!==P.CONNECTING)return;D=$._req=null;let _=O.headers.upgrade;if(_===void 0||_.toLowerCase()!=="websocket"){i($,B,"Invalid Upgrade header");return}let H=v2("sha1").update(N+p2).digest("base64");if(O.headers["sec-websocket-accept"]!==H){i($,B,"Invalid Sec-WebSocket-Accept header");return}let T=O.headers["sec-websocket-protocol"],A;if(T!==void 0){if(!W.size)A="Server sent a subprotocol but none was requested";else if(!W.has(T))A="Server sent an invalid subprotocol"}else if(W.size)A="Server sent no subprotocol";if(A){i($,B,A);return}if(T)$._protocol=T;let R=O.headers["sec-websocket-extensions"];if(R!==void 0){if(!C){i($,B,"Server sent a Sec-WebSocket-Extensions header but no extension was requested");return}let M;try{M=o2(R)}catch(F){i($,B,"Invalid Sec-WebSocket-Extensions header");return}let E=Object.keys(M);if(E.length!==1||E[0]!==_0.extensionName){i($,B,"Server indicated an extension that was not requested");return}try{C.accept(M[_0.extensionName])}catch(F){i($,B,"Invalid Sec-WebSocket-Extensions header");return}$._extensions[_0.extensionName]=C}$.setSocket(B,L,{allowSynchronousEvents:G.allowSynchronousEvents,generateMask:G.generateMask,maxBufferedChunks:G.maxBufferedChunks,maxFragments:G.maxFragments,maxPayload:G.maxPayload,skipUTF8Validation:G.skipUTF8Validation})}),G.finishRequest)G.finishRequest(D,$);else D.end()}function w$($,Z){$._readyState=P.CLOSING,$._errorEmitted=!0,$.emit("error",Z),$.emitClose()}function r2($){return $.path=$.socketPath,m8.connect($)}function e2($){if($.path=void 0,!$.servername&&$.servername!=="")$.servername=m8.isIP($.host)?"":$.host;return b2.connect($)}function i($,Z,Q){$._readyState=P.CLOSING;let X=Error(Q);if(Error.captureStackTrace(X,i),Z.setHeader){if(Z[p8]=!0,Z.abort(),Z.socket&&!Z.socket.destroyed)Z.socket.destroy();process.nextTick(w$,$,X)}else Z.destroy(X),Z.once("error",$.emit.bind($,"error")),Z.once("close",$.emitClose.bind($))}function T1($,Z,Q){if(Z){let X=m2(Z)?Z.size:s2(Z).length;if($._socket)$._sender._bufferedBytes+=X;else $._bufferedAmount+=X}if(Q){let X=Error(`WebSocket is not open: readyState ${$.readyState} (${V0[$.readyState]})`);process.nextTick(Q,X)}}function $3($,Z){let Q=this[v];if(Q._closeFrameReceived=!0,Q._closeMessage=Z,Q._closeCode=$,Q._socket[v]===void 0)return;if(Q._socket.removeListener("data",j$),process.nextTick(i8,Q._socket),$===1005)Q.close();else Q.close($,Z)}function Z3(){let $=this[v];if(!$.isPaused)$._socket.resume()}function Q3($){let Z=this[v];if(Z._socket[v]!==void 0)Z._socket.removeListener("data",j$),process.nextTick(i8,Z._socket),Z.close($[i2]);if(!Z._errorEmitted)Z._errorEmitted=!0,Z.emit("error",$)}function u8(){this[v].emitClose()}function X3($,Z){this[v].emit("message",$,Z)}function G3($){let Z=this[v];if(Z._autoPong)Z.pong($,!this._isServer,l8);Z.emit("ping",$)}function J3($){this[v].emit("pong",$)}function i8($){$.resume()}function V3($){let Z=this[v];if(Z.readyState===P.CLOSED)return;if(Z.readyState===P.OPEN)Z._readyState=P.CLOSING,c8(Z);if(this._socket.end(),!Z._errorEmitted)Z._errorEmitted=!0,Z.emit("error",$)}function c8($){$._closeTimer=setTimeout($._socket.destroy.bind($._socket),$._closeTimeout)}function n8(){let $=this[v];if(this.removeListener("close",n8),this.removeListener("data",j$),this.removeListener("end",a8),$._readyState=P.CLOSING,!this._readableState.endEmitted&&!$._closeFrameReceived&&!$._receiver._writableState.errorEmitted&&this._readableState.length!==0){let Z=this.read(this._readableState.length);$._receiver.write(Z)}if($._receiver.end(),this[v]=void 0,clearTimeout($._closeTimer),$._receiver._writableState.finished||$._receiver._writableState.errorEmitted)$.emitClose();else $._receiver.on("error",u8),$._receiver.on("finish",u8)}function j$($){if(!this[v]._receiver.write($))this.pause()}function a8(){let $=this[v];$._readyState=P.CLOSING,$._receiver.end(),this.end()}function o8(){let $=this[v];if(this.removeListener("error",o8),this.on("error",l8),$)$._readyState=P.CLOSING,this.destroy()}});var $5=d((CZ,e8)=>{var WZ=h$(),{Duplex:Y3}=y("stream");function t8($){$.emit("close")}function K3(){if(!this.destroyed&&this._writableState.finished)this.destroy()}function r8($){if(this.removeListener("error",r8),this.destroy(),this.listenerCount("error")===0)this.emit("error",$)}function z3($,Z){let Q=!0,X=new Y3({...Z,autoDestroy:!1,emitClose:!1,objectMode:!1,writableObjectMode:!1});return $.on("message",function(J,V){let z=!V&&X._readableState.objectMode?J.toString():J;if(!X.push(z))$.pause()}),$.once("error",function(J){if(X.destroyed)return;Q=!1,X.destroy(J)}),$.once("close",function(){if(X.destroyed)return;X.push(null)}),X._destroy=function(G,J){if($.readyState===$.CLOSED){J(G),process.nextTick(t8,X);return}let V=!1;if($.once("error",function(Y){V=!0,J(Y)}),$.once("close",function(){if(!V)J(G);process.nextTick(t8,X)}),Q)$.terminate()},X._final=function(G){if($.readyState===$.CONNECTING){$.once("open",function(){X._final(G)});return}if($._socket===null)return;if($._socket._writableState.finished){if(G(),X._readableState.endEmitted)X.destroy()}else $._socket.once("finish",function(){G()}),$.close()},X._read=function(){if($.isPaused)$.resume()},X._write=function(G,J,V){if($.readyState===$.CONNECTING){$.once("open",function(){X._write(G,J,V)});return}$.send(G,V)},X.on("end",K3),X.on("error",r8),X}e8.exports=z3});var A1=d((BZ,Z5)=>{var{tokenChars:N3}=b0();function U3($){let Z=new Set,Q=-1,X=-1,G=0;for(G;G<$.length;G++){let V=$.charCodeAt(G);if(X===-1&&N3[V]===1){if(Q===-1)Q=G}else if(G!==0&&(V===32||V===9)){if(X===-1&&Q!==-1)X=G}else if(V===44){if(Q===-1)throw SyntaxError(`Unexpected character at index ${G}`);if(X===-1)X=G;let z=$.slice(Q,X);if(Z.has(z))throw SyntaxError(`The "${z}" subprotocol is duplicated`);Z.add(z),Q=X=-1}else throw SyntaxError(`Unexpected character at index ${G}`)}if(Q===-1||X!==-1)throw SyntaxError("Unexpected end of input");let J=$.slice(Q,G);if(Z.has(J))throw SyntaxError(`The "${J}" subprotocol is duplicated`);return Z.add(J),Z}Z5.exports={parse:U3}});var V5=d((HZ,J5)=>{var D3=y("events"),g$=y("http"),{Duplex:_Z}=y("stream"),{createHash:O3}=y("crypto"),Q5=q$(),M0=f0(),W3=A1(),C3=h$(),{CLOSE_TIMEOUT:B3,GUID:_3,kWebSocket:H3}=G0(),L3=/^[+/0-9A-Za-z]{22}==$/;class G5 extends D3{constructor($,Z){super();if($={allowSynchronousEvents:!0,autoPong:!0,maxBufferedChunks:262144,maxFragments:16384,maxPayload:104857600,skipUTF8Validation:!1,perMessageDeflate:!1,handleProtocols:null,clientTracking:!0,closeTimeout:B3,verifyClient:null,noServer:!1,backlog:null,server:null,host:null,path:null,port:null,WebSocket:C3,...$},$.port==null&&!$.server&&!$.noServer||$.port!=null&&($.server||$.noServer)||$.server&&$.noServer)throw TypeError('One and only one of the "port", "server", or "noServer" options must be specified');if($.port!=null)this._server=g$.createServer((Q,X)=>{let G=g$.STATUS_CODES[426];X.writeHead(426,{"Content-Length":G.length,"Content-Type":"text/plain"}),X.end(G)}),this._server.listen($.port,$.host,$.backlog,Z);else if($.server)this._server=$.server;if(this._server){let Q=this.emit.bind(this,"connection");this._removeListeners=T3(this._server,{listening:this.emit.bind(this,"listening"),error:this.emit.bind(this,"error"),upgrade:(X,G,J)=>{this.handleUpgrade(X,G,J,Q)}})}if($.perMessageDeflate===!0)$.perMessageDeflate={};if($.clientTracking)this.clients=new Set,this._shouldEmitClose=!1;this.options=$,this._state=0}address(){if(this.options.noServer)throw Error('The server is operating in "noServer" mode');if(!this._server)return null;return this._server.address()}close($){if(this._state===2){if($)this.once("close",()=>{$(Error("The server is not running"))});process.nextTick(e0,this);return}if($)this.once("close",$);if(this._state===1)return;if(this._state=1,this.options.noServer||this.options.server){if(this._server)this._removeListeners(),this._removeListeners=this._server=null;if(this.clients)if(!this.clients.size)process.nextTick(e0,this);else this._shouldEmitClose=!0;else process.nextTick(e0,this)}else{let Z=this._server;this._removeListeners(),this._removeListeners=this._server=null,Z.close(()=>{e0(this)})}}shouldHandle($){if(this.options.path){let Z=$.url.indexOf("?");if((Z!==-1?$.url.slice(0,Z):$.url)!==this.options.path)return!1}return!0}handleUpgrade($,Z,Q,X){Z.on("error",X5);let G=$.headers["sec-websocket-key"],J=$.headers.upgrade,V=+$.headers["sec-websocket-version"];if($.method!=="GET"){x0(this,$,Z,405,"Invalid HTTP method");return}if(J===void 0||J.toLowerCase()!=="websocket"){x0(this,$,Z,400,"Invalid Upgrade header");return}if(G===void 0||!L3.test(G)){x0(this,$,Z,400,"Missing or invalid Sec-WebSocket-Key header");return}if(V!==13&&V!==8){x0(this,$,Z,400,"Missing or invalid Sec-WebSocket-Version header",{"Sec-WebSocket-Version":"13, 8"});return}if(!this.shouldHandle($)){$$(Z,400);return}let z=$.headers["sec-websocket-protocol"],Y=new Set;if(z!==void 0)try{Y=W3.parse(z)}catch(U){x0(this,$,Z,400,"Invalid Sec-WebSocket-Protocol header");return}let K=$.headers["sec-websocket-extensions"],N={};if(this.options.perMessageDeflate&&K!==void 0){let U=new M0({...this.options.perMessageDeflate,isServer:!0,maxPayload:this.options.maxPayload});try{let W=Q5.parse(K);if(W[M0.extensionName])U.accept(W[M0.extensionName]),N[M0.extensionName]=U}catch(W){x0(this,$,Z,400,"Invalid or unacceptable Sec-WebSocket-Extensions header");return}}if(this.options.verifyClient){let U={origin:$.headers[`${V===8?"sec-websocket-origin":"origin"}`],secure:!!($.socket.authorized||$.socket.encrypted),req:$};if(this.options.verifyClient.length===2){this.options.verifyClient(U,(W,C,D,O)=>{if(!W)return $$(Z,C||401,D,O);this.completeUpgrade(N,G,Y,$,Z,Q,X)});return}if(!this.options.verifyClient(U))return $$(Z,401)}this.completeUpgrade(N,G,Y,$,Z,Q,X)}completeUpgrade($,Z,Q,X,G,J,V){if(!G.readable||!G.writable)return G.destroy();if(G[H3])throw Error("server.handleUpgrade() was called more than once with the same socket, possibly due to a misconfiguration");if(this._state>0)return $$(G,503);let Y=["HTTP/1.1 101 Switching Protocols","Upgrade: websocket","Connection: Upgrade",`Sec-WebSocket-Accept: ${O3("sha1").update(Z+_3).digest("base64")}`],K=new this.options.WebSocket(null,void 0,this.options);if(Q.size){let N=this.options.handleProtocols?this.options.handleProtocols(Q,X):Q.values().next().value;if(N)Y.push(`Sec-WebSocket-Protocol: ${N}`),K._protocol=N}if($[M0.extensionName]){let N=$[M0.extensionName].params,U=Q5.format({[M0.extensionName]:[N]});Y.push(`Sec-WebSocket-Extensions: ${U}`),K._extensions=$}if(this.emit("headers",Y,X),G.write(Y.concat(`\r
2
+ `).join(`\r
3
+ `)),G.removeListener("error",X5),K.setSocket(G,J,{allowSynchronousEvents:this.options.allowSynchronousEvents,maxBufferedChunks:this.options.maxBufferedChunks,maxFragments:this.options.maxFragments,maxPayload:this.options.maxPayload,skipUTF8Validation:this.options.skipUTF8Validation}),this.clients)this.clients.add(K),K.on("close",()=>{if(this.clients.delete(K),this._shouldEmitClose&&!this.clients.size)process.nextTick(e0,this)});V(K,X)}}J5.exports=G5;function T3($,Z){for(let Q of Object.keys(Z))$.on(Q,Z[Q]);return function(){for(let X of Object.keys(Z))$.removeListener(X,Z[X])}}function e0($){$._state=2,$.emit("close")}function X5(){this.destroy()}function $$($,Z,Q,X){Q=Q||g$.STATUS_CODES[Z],X={Connection:"close","Content-Type":"text/html","Content-Length":Buffer.byteLength(Q),...X},$.once("finish",$.destroy),$.end(`HTTP/1.1 ${Z} ${g$.STATUS_CODES[Z]}\r
4
+ `+Object.keys(X).map((G)=>`${G}: ${X[G]}`).join(`\r
5
+ `)+`\r
6
+ \r
7
+ `+Q)}function x0($,Z,Q,X,G,J){if($.listenerCount("wsClientError")){let V=Error(G);Error.captureStackTrace(V,x0),$.emit("wsClientError",V,Q,Z)}else $$(Q,X,G,J)}});var A3=O0($5(),1),R3=O0(q$(),1),F3=O0(f0(),1),M3=O0(O1(),1),x3=O0(C1(),1),P3=O0(A1(),1),Z$=O0(h$(),1),f$=O0(V5(),1);var TZ=Z$.default;import I3 from"node:os";import H0 from"node:path";import Y0 from"node:fs";var o=process.env.LOCALDECK_HOME??H0.join(I3.homedir(),".localdeck"),R1=H0.join(o,"logs"),b$=H0.join(o,"daemon.json"),m0=H0.join(o,"ports.json"),Q$=H0.join(o,"projects.json"),X$=H0.join(o,"daemon.log"),G$=Number(process.env.LOCALDECK_PORT??7777);function J$($=process.getuid?.(),Z=process.env){if($===0&&Z.SUDO_UID&&Z.SUDO_UID!=="0")throw Error("Do not run the LocalDeck runtime with sudo. Run localdeck --update or localdeck daemon start without sudo. The updater requests administrator access only for npm when needed.")}function y$(){Y0.mkdirSync(R1,{recursive:!0})}function r($,Z){try{return JSON.parse(Y0.readFileSync($,"utf8"))}catch{return Z}}function s($,Z){Y0.mkdirSync(H0.dirname($),{recursive:!0});let Q=`${$}.${process.pid}.tmp`;Y0.writeFileSync(Q,JSON.stringify(Z,null,2)),Y0.renameSync(Q,$)}function K0($,Z){Y0.mkdirSync(H0.dirname($),{recursive:!0});let Q=`${$}.${process.pid}.tmp`;Y0.writeFileSync(Q,JSON.stringify(Z,null,2),{mode:384}),Y0.chmodSync(Q,384),Y0.renameSync(Q,$)}import{createHash as S3}from"node:crypto";import c from"node:fs";import S from"node:path";var v$=60000,k$=400,K5=[".localdeck",".localdeck.json","localdeck.json"];function z5($=process.cwd()){let Z=S.resolve($);for(;;){for(let X of K5){let G=S.join(Z,X);if(c.existsSync(G)&&c.statSync(G).isFile())return G}let Q=S.dirname(Z);if(Q===Z)return;Z=Q}}function q3($=process.cwd()){let Z=z5($);return Z?L0(Z):void 0}function L0($){let Z=P1($),Q=U5(Z,$),{profiles:X,legacyProfiles:G}=C5(Z,Q,$),J;if(Z&&typeof Z==="object"&&!Array.isArray(Z)&&(Array.isArray(Z.commands)||Array.isArray(Z.services))){let V=Z.nickname;if(V!==void 0){if(typeof V!=="string"||!/^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/i.test(V)||V.toLowerCase()==="standalone")throw Error(`${S.basename($)}: nickname must be 1–63 letters, numbers or interior hyphens; standalone is reserved`);J=V.toLowerCase()}}return{file:$,dir:S.dirname($),commands:Q,...X?{profiles:X}:{},...G?{legacyProfiles:G}:{},...J?{nickname:J}:{}}}function N5($,Z){let Q=P1($);L0($);let X;if(Q&&typeof Q==="object"&&!Array.isArray(Q)&&(Array.isArray(Q.commands)||Array.isArray(Q.services)))X=Q;else if(Array.isArray(Q))X={commands:Q};else X={commands:Object.entries(Q).map(([V,z])=>typeof z==="string"?{name:V,run:z}:{...z,name:V})};if(Z)X.nickname=Z;else delete X.nickname;let G=`${$}.${process.pid}.tmp`,J=c.statSync($).mode&511;try{c.writeFileSync(G,`${JSON.stringify(X,null,2)}
8
+ `,{mode:J}),c.chmodSync(G,J),c.renameSync(G,$)}catch(V){throw c.rmSync(G,{force:!0}),V}}function M1($,Z,Q){if(!Q||typeof Q!=="object"||Array.isArray(Q))throw Error("settings must be an object");let X=Q,G=Object.keys(X);if(!G.length||G.some((C)=>!["port","upstream","after","ready"].includes(C)))throw Error("Only port, upstream, after and ready can be edited here");if("after"in X&&(!Array.isArray(X.after)||!X.after.every((C)=>typeof C==="string")))throw Error("after must be an array of service names");if("ready"in X){let C=X.ready;if(!C||typeof C!=="object"||Array.isArray(C))throw Error("ready must be a TCP or HTTP check");let D=C;if(!["tcp","http"].includes(D.type)||Object.keys(D).some((O)=>!["type","path","status","timeoutMs","intervalMs"].includes(O)))throw Error("Only TCP and HTTP readiness checks can be edited here")}let J=P1($),V=Z.toLowerCase(),z=!1,Y=(C)=>{for(let[D,O]of Object.entries(X))if(O===null||D==="after"&&Array.isArray(O)&&!O.length)delete C[D];else C[D]=O;z=!0},K=(C)=>{if(!C||typeof C!=="object"||Array.isArray(C))return;let D=C,O=D.name??D.command??D.id;if(typeof O==="string"&&O.toLowerCase()===V)Y(D)};if(Array.isArray(J))J.forEach(K);else if(J&&typeof J==="object"){let C=J;if(Array.isArray(C.commands))C.commands.forEach(K);else if(Array.isArray(C.services))C.services.forEach(K);else{let D=Object.keys(C).find((O)=>O.toLowerCase()===V);if(D){if(typeof C[D]==="string")C[D]={run:C[D]};if(C[D]&&typeof C[D]==="object"&&!Array.isArray(C[D]))Y(C[D])}}}if(!z)throw Error(`${S.basename($)}: no service named "${Z}"`);let N=U5(J,$);C5(J,N,$);let U=`${$}.${process.pid}.tmp`,W=c.statSync($).mode&511;try{c.writeFileSync(U,`${JSON.stringify(J,null,2)}
9
+ `,{mode:W}),c.chmodSync(U,W),c.renameSync(U,$)}catch(C){throw c.rmSync(U,{force:!0}),C}return N}function x1($,Z,Q){return M1($,Z,{after:Q.map((X)=>X.toLowerCase())})}function P1($){try{return JSON.parse(c.readFileSync($,"utf8"))}catch(Z){throw Error(`${S.basename($)} is not valid JSON: ${Z.message}`)}}function U5($,Z){let Q;if(Array.isArray($))Q=$;else if($&&typeof $==="object"&&Array.isArray($.commands)){if("services"in $)throw Error(`${S.basename(Z)}: use commands or services, not both`);Q=$.commands}else if($&&typeof $==="object"&&Array.isArray($.services))Q=$.services;else if($&&typeof $==="object")Q=Object.entries($).map(([G,J])=>typeof J==="string"?{name:G,run:J}:{name:G,...J});else throw Error(`${S.basename(Z)}: expected an array of commands`);let X=[];for(let[G,J]of Q.entries()){if(!J||typeof J!=="object"||Array.isArray(J))throw Error(`${S.basename(Z)}: entry ${G} must be an object`);let V=J,z=V.name??V.command??V.id,Y=V.run??V.value??V.cmd??V.exec;if(typeof z!=="string"||typeof Y!=="string")throw Error(`${S.basename(Z)}: entry ${G} needs string "name" and "run" fields`);let K=z.toLowerCase();if(!/^[a-z0-9][a-z0-9_-]{0,40}$/.test(K))throw Error(`${S.basename(Z)}: entry ${G} has invalid name "${z}"`);if(!Y.trim())throw Error(`${S.basename(Z)}: entry ${G} "run" must not be empty`);if(V.cwd!==void 0&&typeof V.cwd!=="string")throw Error(`${S.basename(Z)}: entry ${G} "cwd" must be a string`);let N=X.findIndex((O)=>O.name===K);if(N!==-1)throw Error(`${S.basename(Z)}: entries ${N} and ${G} both define "${K}"`);let U=[].concat(V.after??[]).map((O)=>{if(typeof O!=="string"||!O.trim())throw Error(`${S.basename(Z)}: entry ${G} "after" must be a service name or array of service names`);return O.toLowerCase()}),W=V.serviceType;if(W!==void 0&&!["http","postgres","redis","compose"].includes(W))throw Error(`${S.basename(Z)}: entry ${G} serviceType must be http, postgres, redis, or compose`);if(W&&W!=="http"&&(V.upstream==null||V.port!=null))throw Error(`${S.basename(Z)}: database services need an explicit upstream (published port) and must not set an HTTP proxy port`);let C=V.env===void 0?void 0:D5(V.env,Z),D=V.secrets===void 0?void 0:O5(V.secrets,C,Z);X.push({name:K,run:Y,...V.port===void 0||V.port===null?{}:{port:Y5(V.port,"port",Z,G)},...V.upstream===void 0||V.upstream===null?{}:{upstream:Y5(V.upstream,"upstream",Z,G)},tags:[].concat(V.tag??V.tags??[]).map(String),...V.cwd===void 0?{}:{cwd:V.cwd},after:[...new Set(U)],ready:W5(V.ready??(W==="postgres"||W==="redis"?W:void 0),Z,G),...W?{serviceType:W}:{},...C?{env:C}:{},...D?{secrets:D}:{}})}return w3(X,Z),X}function D5($,Z){if(!$||typeof $!=="object"||Array.isArray($))throw Error(`${S.basename(Z)}: env must be an object of strings`);let Q={};for(let[X,G]of Object.entries($)){if(!/^[A-Za-z_][A-Za-z0-9_]*$/.test(X)||typeof G!=="string"||G.includes("\x00"))throw Error(`${S.basename(Z)}: env must contain valid variable names and string values`);if(X==="PORT"||X.startsWith("LOCALDECK_"))throw Error(`${S.basename(Z)}: ${X} is reserved by LocalDeck`);Object.defineProperty(Q,X,{value:G,enumerable:!0,writable:!0,configurable:!0})}return Q}function O5($,Z,Q){if(!Array.isArray($)||!$.every((G)=>typeof G==="string"&&/^[A-Za-z_][A-Za-z0-9_]*$/.test(G)))throw Error(`${S.basename(Q)}: secrets must contain valid environment names`);let X=[];for(let G of $){if(G==="PORT"||G.startsWith("LOCALDECK_"))throw Error(`${S.basename(Q)}: ${G} is reserved by LocalDeck`);if(Z&&Object.prototype.hasOwnProperty.call(Z,G))throw Error(`${S.basename(Q)}: ${G} cannot be both a secret and env setting`);if(X.includes(G))throw Error(`${S.basename(Q)}: duplicate secret ${G}`);X.push(G)}return X}function W5($,Z,Q){if($==="postgres"||$==="redis")return{type:"command",run:$==="postgres"?"pg_isready -h 127.0.0.1 -p {upstream}":"redis-cli -h 127.0.0.1 -p {upstream} ping",...$==="redis"?{expectedOutput:"PONG"}:{},timeoutMs:v$,intervalMs:k$};if($===void 0||$===null||$==="tcp")return{type:"tcp",timeoutMs:v$,intervalMs:k$};if(typeof $==="string"){if(!$.startsWith("/"))throw Error(`${S.basename(Z)}: entry ${Q} ready must be "tcp", an HTTP path, or an object`);return{type:"http",path:$,timeoutMs:v$,intervalMs:k$}}if(!$||typeof $!=="object"||Array.isArray($))throw Error(`${S.basename(Z)}: entry ${Q} ready must be "tcp", an HTTP path, or an object`);let X=$;if(X.type==="compose"){if(typeof X.service!=="string"||!/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/.test(X.service)||!["postgres","redis"].includes(X.engine))throw Error(`${S.basename(Z)}: compose readiness requires a valid service name and engine postgres or redis`);return W5({...X,type:"command",run:`docker compose exec -T ${X.service} ${X.engine==="postgres"?"pg_isready":"redis-cli ping"}`,...X.engine==="redis"?{expectedOutput:"PONG"}:{}},Z,Q)}let G=X.type??(X.path!==void 0?"http":X.run!==void 0?"command":"tcp");if(G!=="tcp"&&G!=="http"&&G!=="command")throw Error(`${S.basename(Z)}: entry ${Q} ready.type must be tcp, http, or command`);let J=F1(X.timeoutMs,v$,100,600000,"ready.timeoutMs",Z,Q),V=F1(X.intervalMs,k$,50,60000,"ready.intervalMs",Z,Q);if(G==="tcp")return{type:G,timeoutMs:J,intervalMs:V};if(G==="http"){if(typeof X.path!=="string"||!X.path.startsWith("/"))throw Error(`${S.basename(Z)}: entry ${Q} ready.path must start with "/"`);let z=X.status===void 0?void 0:F1(X.status,200,100,599,"ready.status",Z,Q);return{type:G,path:X.path,...z===void 0?{}:{status:z},timeoutMs:J,intervalMs:V}}if(typeof X.run!=="string"||!X.run.trim())throw Error(`${S.basename(Z)}: entry ${Q} ready.run must not be empty`);if(X.expectedOutput!==void 0&&(typeof X.expectedOutput!=="string"||X.expectedOutput.length>4000))throw Error(`${S.basename(Z)}: expectedOutput must be a string of at most 4000 characters`);return{type:G,run:X.run,...X.expectedOutput===void 0?{}:{expectedOutput:X.expectedOutput},timeoutMs:J,intervalMs:V}}var E3=["run","cwd","env","secrets"];function C5($,Z,Q){if(!$||typeof $!=="object"||Array.isArray($)||!Array.isArray($.services)&&!Array.isArray($.commands))return{};let X=$.profiles;if(X===void 0)return{};let G=S.basename(Q);if(!X||typeof X!=="object"||Array.isArray(X))throw Error(`${G}: profiles must map names to profile objects`);let J=Object.entries(X);if(!J.length)return{};for(let[K]of J)if(!/^[a-z0-9][a-z0-9_-]{0,40}$/.test(K))throw Error(`${G}: invalid profile name "${K}"`);let V=J.filter(([,K])=>Array.isArray(K));if(V.length&&V.length!==J.length)throw Error(`${G}: profiles cannot mix service lists and profile objects; move service lists to tags`);let z=new Map(Z.map((K)=>[K.name,K]));if(V.length){let K=Object.create(null);for(let[N,U]of V){if(!U.length||!U.every((W)=>typeof W==="string"&&z.has(W.toLowerCase())))throw Error(`${G}: profile ${N} must contain existing service names`);K[N]=[...new Set(U.map((W)=>W.toLowerCase()))];for(let W of K[N]){let C=z.get(W);if(!C.tags.includes(N))C.tags.push(N)}}return{legacyProfiles:K}}let Y=[];for(let[K,N]of J){if(!N||typeof N!=="object")throw Error(`${G}: profile ${K} must be an object`);let U=N,W=Object.keys(U).find((O)=>O!=="description"&&O!=="services");if(W)throw Error(`${G}: profile ${K} has unknown field "${W}"; use "description" and "services"`);if(U.description!==void 0&&(typeof U.description!=="string"||U.description.length>200))throw Error(`${G}: profile ${K} description must be a string of at most 200 characters`);let C=U.services??{};if(!C||typeof C!=="object"||Array.isArray(C))throw Error(`${G}: profile ${K} services must map service names to overrides`);let D=Object.create(null);for(let[O,B]of Object.entries(C)){let L=O.toLowerCase(),_=z.get(L);if(!_)throw Error(`${G}: profile ${K} changes unknown service "${O}"`);if(!B||typeof B!=="object"||Array.isArray(B))throw Error(`${G}: profile ${K} override for ${L} must be an object`);let H=B,T=Object.keys(H).find((E)=>!E3.includes(E));if(T)throw Error(`${G}: profile ${K} cannot change ${L}.${T}; profiles can change run, cwd, env and secrets`);if(H.run!==void 0&&(typeof H.run!=="string"||!H.run.trim()))throw Error(`${G}: profile ${K} ${L}.run must be a non-empty string`);if(H.cwd!==void 0&&typeof H.cwd!=="string")throw Error(`${G}: profile ${K} ${L}.cwd must be a string`);let A=H.env===void 0?void 0:D5(H.env,Q),R=H.secrets===void 0?void 0:O5(H.secrets,A,Q),M={...H.run===void 0?{}:{run:H.run},...H.cwd===void 0?{}:{cwd:H.cwd},...A?{env:A}:{},...R?{secrets:R}:{}};_5(B5(_,M).command,`profile ${K}`,Q),D[L]=M}Y.push({name:K,...U.description?{description:U.description}:{},services:D})}return{profiles:Y}}function B5($,Z){let Q=Z.env?{...$.env,...Z.env}:$.env,X=Z.secrets?[...new Set([...$.secrets??[],...Z.secrets])]:$.secrets;return{command:{...$,...Z.run===void 0?{}:{run:Z.run},...Z.cwd===void 0?{}:{cwd:Z.cwd},...Q?{env:Q}:{},...X?{secrets:X}:{}}}}function _5($,Z,Q){let X=$.secrets?.find((G)=>$.env&&Object.prototype.hasOwnProperty.call($.env,G));if(X)throw Error(`${S.basename(Q)}: ${Z} makes ${X} both a secret and env setting for ${$.name}`)}function I1($,Z=[]){let Q=new Set(Z),X=($.profiles??[]).filter((Y)=>Q.has(Y.name)),G=Object.create(null),J=new Map,V=$.commands.map((Y)=>{let K={run:"base",cwd:"base",env:Object.fromEntries(Object.keys(Y.env??{}).map((U)=>[U,"base"])),secrets:Object.fromEntries((Y.secrets??[]).map((U)=>[U,"base"]))},N=Y;for(let U of X){let W=U.services[Y.name];if(!W)continue;let C=(D)=>{let O=`${Y.name}\x00${D}`;J.set(O,[...J.get(O)??[],U.name])};if(W.run!==void 0)K.run=U.name,C("run");if(W.cwd!==void 0)K.cwd=U.name,C("cwd");for(let D of Object.keys(W.env??{}))K.env[D]=U.name,C(`env.${D}`);for(let D of W.secrets??[])if(!(D in K.secrets))K.secrets[D]=U.name;N=B5(N,W).command}if(N!==Y)_5(N,`active profiles ${X.map((U)=>U.name).join(" + ")}`,$.file);return G[Y.name]=K,N}),z=[];for(let[Y,K]of J){if(K.length<2)continue;let[N,U]=Y.split("\x00");z.push({service:N,field:U,profiles:K,winner:K[K.length-1]})}return{commands:V,active:X.map((Y)=>Y.name),provenance:G,clashes:z}}function P0($){let Z=Object.entries($.env??{}).sort(([X],[G])=>X<G?-1:X>G?1:0),Q=[...$.secrets??[]].sort();return S3("sha256").update(JSON.stringify([$.run,$.cwd??"",Z,Q])).digest("hex").slice(0,16)}function F1($,Z,Q,X,G,J,V){if($===void 0)return Z;if(!Number.isInteger($)||$<Q||$>X)throw Error(`${S.basename(J)}: entry ${V} ${G} must be an integer between ${Q} and ${X}`);return $}function w3($,Z){let Q=new Set($.map((z)=>z.name));for(let z of $)for(let Y of z.after){if(Y===z.name)throw Error(`${S.basename(Z)}: service "${z.name}" cannot start after itself`);if(!Q.has(Y))throw Error(`${S.basename(Z)}: service "${z.name}" starts after unknown service "${Y}"`)}let X=new Map,G=[],J=new Map($.map((z)=>[z.name,z])),V=(z)=>{if(X.get(z)==="visited")return;if(X.get(z)==="visiting"){let Y=G.indexOf(z);throw Error(`${S.basename(Z)}: dependency cycle: ${[...G.slice(Y),z].join(" -> ")}`)}X.set(z,"visiting"),G.push(z);for(let Y of J.get(z).after)V(Y);G.pop(),X.set(z,"visited")};for(let z of $)V(z.name)}function Y5($,Z,Q,X){if($===void 0||$===null)return;let G=typeof $==="number"?$:typeof $==="string"&&/^\d+$/.test($)?Number($):Number.NaN;if(!Number.isInteger(G)||G<1||G>65535)throw Error(`${S.basename(Q)}: entry ${X} ${Z} must be an integer between 1 and 65535`);return G}function V$($,Z=process.platform,Q=process.env.ComSpec){if(Z==="win32")return[Q??"cmd.exe","/d","/s","/c",$];return[process.env.SHELL||"/bin/sh","-c",$]}import H5 from"node:net";function L5($={}){let Z=$.listenPort??80,Q=$.targetPort??7777;if(!Number.isInteger(Z)||Z<0||Z>65535||!Number.isInteger(Q)||Q<1||Q>65535)return Promise.reject(Error("forward ports must be integers between 1 and 65535"));if(Z!==0&&Z===Q)return Promise.reject(Error("forward listen port and target port must be different"));let X=new Set,G=H5.createServer((J)=>{X.add(J),J.once("close",()=>X.delete(J));let V=H5.connect(Q,"127.0.0.1");X.add(V),V.once("close",()=>X.delete(V)),J.pipe(V),V.pipe(J);let z=()=>{J.destroy(),V.destroy()};J.once("error",z),V.once("error",z),J.once("close",z),V.once("close",z)});return new Promise((J,V)=>{let z=(Y)=>{G.removeAllListeners(),V(Error(Y.code==="EADDRINUSE"?`forwarder could not listen on 127.0.0.1:${Z}: address already in use`:Y.code==="EACCES"||Y.code==="EPERM"?`forwarder cannot listen on port ${Z}: permission denied (choose another port; do not run LocalDeck as root)`:`forwarder failed: ${Y.message}`))};G.once("error",z),G.listen(Z,"127.0.0.1",()=>{G.off("error",z),J({port:G.address().port,close:()=>new Promise((Y)=>{for(let K of X)K.destroy();G.close(()=>Y())})})})})}function u$($,Z){let Q=new Map($.map((Y)=>[Y.name,Y])),X=new Set,G=(Y)=>{if(X.has(Y))return;let K=Q.get(Y.toLowerCase());if(!K)throw Error(`unknown service "${Y}"`);for(let N of K.after)G(N);X.add(K.name)};for(let Y of Z??$.map((K)=>K.name))G(Y);let J=$.filter((Y)=>X.has(Y.name)),V=new Set,z=[];while(J.length){let Y=J.filter((K)=>K.after.every((N)=>V.has(N)));if(!Y.length)throw Error("project dependency graph contains a cycle");z.push(Y);for(let K of Y)V.add(K.name),J.splice(J.indexOf(K),1)}return z}function S1($){return u$($).reverse().flatMap((Z)=>[...Z].reverse())}import X0 from"node:fs";import i6 from"node:crypto";import m4 from"node:path";import n3 from"node:path";import P5 from"node:fs";import I5 from"node:path";import{createHash as k3}from"node:crypto";import{createHash as g3}from"node:crypto";import T0 from"node:fs";import{execFileSync as f3}from"node:child_process";import Q0 from"node:path";import T5 from"node:net";function j3($,Z,Q){return new Promise((X)=>{let G=T5.createServer();G.once("error",(J)=>X(!Q&&J.code!=="EADDRINUSE"&&J.code!=="EACCES"?void 0:!1)),G.listen({port:$,host:Z,exclusive:!0},()=>G.close(()=>X(!0)))})}async function Y$($,Z){for(let Q of Z?[Z]:["127.0.0.1","::1","0.0.0.0","::"])if(await j3($,Q,Q===(Z??"127.0.0.1"))===!1)return!1;return!0}function K$($="127.0.0.1"){return new Promise((Z,Q)=>{let X=T5.createServer();X.once("error",Q),X.listen(0,$,()=>{let{port:G}=X.address();X.close(()=>Z(G))})})}function A5($){let Z=$.lastIndexOf(":");return Z===-1?$:$.slice(Z+1)}function h3($,Z){let Q=r(Z,{});if(Q[$]!==void 0)return Q[$];let X=A5($);return Object.keys(Q).some((J)=>J!==$&&J.includes(":")&&J.endsWith(`:${X}`))?void 0:Q[X]}function R5($,Z,Q=m0){let X=r(Q,{});X[$]=Z,s(Q,X)}function F5($,Z=m0){let Q=r(Z,{}),X=Object.fromEntries(Object.entries(Q).filter(([G])=>!G.startsWith(`${$}:`)));if(Object.keys(X).length!==Object.keys(Q).length)s(Z,X)}async function M5($,Z,Q=4000,X=4999,G=m0){let J=r(G,{}),V=h3($,G);if(V){if(Z.has(V)||!await Y$(V))throw Error(`remembered stable port ${V} for "${$}" is already in use; stop the conflicting listener or explicitly choose a different port`);return V}let z=A5($),Y=J[$]===void 0&&V===J[z],K=new Set(Object.entries(J).filter(([N])=>N!==$&&!(Y&&N===z)).map(([,N])=>N));for(let N=Q;N<=X;N++){if(Z.has(N)||K.has(N))continue;if(await Y$(N))return N}throw Error(`no free port between ${Q} and ${X}`)}class q extends Error{code;constructor($,Z){super(Z);this.code=$}}class l${catalogFile;portsFile;now;projects;constructor({catalogFile:$=Q$,portsFile:Z=m0,now:Q=Date.now}={}){this.catalogFile=$,this.portsFile=Z,this.now=Q,this.projects=this.readCatalog()}remember($,Z=this.now()){let Q=T0.realpathSync($),X=L0(Q),G=x5(Q),J=Q0.basename(Q0.dirname(Q)),V=Q0.dirname(Q),z=this.projects.find((K)=>K.id===G),Y=X.nickname?this.configAlias(G,Q,X.nickname):void 0;if(z){if(z.name=J,z.file=Q,z.directory=V,z.lastUsedAt=Z,z.configNickname=X.nickname,Y){if(z.sharedConfigNickname=!0,!z.nickname)z.nickname=Y}}else this.projects.push({id:G,name:J,slug:this.assignSlug(J,G),file:Q,directory:V,lastUsedAt:Z,...X.nickname?{configNickname:X.nickname}:{},...Y?{nickname:Y,sharedConfigNickname:!0}:{}});return this.persist(),this.toSummary(this.byId(G))}list(){return this.sorted().map(($)=>this.toSummary($))}details($,Z){let Q=this.require($),X;try{X=this.load(Q)}catch(K){return{...Q,available:!1,error:I0(K),commands:[]}}let G=Z??Q.activeProfiles??[],{activeProfiles:J,...V}=Q,z={...V,nickname:this.nickname($),available:!0,...X.legacyProfiles?{legacyProfiles:X.legacyProfiles}:{}},Y=(K)=>X.profiles?.length?{profiles:X.profiles.map((N)=>({name:N.name,...N.description?{description:N.description}:{},services:Object.keys(N.services),active:K.includes(N.name)}))}:{};try{let K=I1(X,G);return{...z,...K.active.length?{activeProfiles:K.active}:{},commands:K.commands,...Y(K.active),...K.clashes.length?{profileClashes:K.clashes}:{},provenance:K.provenance,fingerprints:Object.fromEntries(K.commands.map((N)=>[N.name,P0(N)]))}}catch(K){let N=(X.profiles??[]).map((U)=>U.name).filter((U)=>G.includes(U));return{...z,...N.length?{activeProfiles:N}:{},commands:X.commands,...Y(N),profileError:I0(K)}}}resolve($,Z,Q){let X=this.details($,Q);if(!X.available)throw new q("invalid",X.error);if(X.profileError)throw new q("invalid",X.profileError);let G=X.commands.find((J)=>J.name===Z.toLowerCase());if(!G)throw new q("not_found",`Project ${$} has no service named ${Z}`);return G}forget($,Z){if(this.require($),[...Z].some((Q)=>Q.startsWith(`${$}:`)))throw new q("active","stop its services before forgetting it");this.projects=this.projects.filter((Q)=>Q.id!==$),this.persist(),F5($,this.portsFile)}refresh($){return this.details($)}nickname($){let Z=this.byId($);return Z?.nickname??Z?.configNickname}updateNickname($,Z){let Q=this.require($),X=Z.trim().toLowerCase();if(X&&(!m$(X)||X==="standalone"))throw new q("invalid","Use 1–63 letters, numbers or hyphens, with no leading or trailing hyphen. 'standalone' is reserved.");if(X)this.assertNicknameAvailable($,X);let G=Q.nickname;if(X)Q.nickname=X;else delete Q.nickname;try{this.persist()}catch(J){if(G===void 0)delete Q.nickname;else Q.nickname=G;throw J}return this.details($)}saveConfigNickname($,Z){let Q=this.require($),X=Z.trim().toLowerCase();if(X&&(!m$(X)||X==="standalone"))throw new q("invalid","Use 1–63 letters, numbers or interior hyphens; standalone is reserved.");if(X)this.assertNicknameAvailable($,X);try{N5(Q.file,X)}catch(G){throw new q("invalid",I0(G))}return Q.configNickname=X||void 0,this.updateNickname($,"")}setActiveProfiles($,Z){let Q=this.require($);if(!Array.isArray(Z)||!Z.every((Y)=>typeof Y==="string"))throw new q("invalid","profiles must be an array of profile names");let X;try{X=(this.load(Q).profiles??[]).map((Y)=>Y.name)}catch(Y){throw new q("invalid",I0(Y))}let G=Z.map((Y)=>Y.toLowerCase()),J=G.filter((Y)=>!X.includes(Y));if(J.length)throw new q("invalid",`Unknown profile${J.length>1?"s":""} ${J.join(", ")}. Available profiles: ${X.join(", ")||"(none)"}`);let V=Q.activeProfiles,z=X.filter((Y)=>G.includes(Y));if(z.length)Q.activeProfiles=z;else delete Q.activeProfiles;try{this.persist()}catch(Y){if(V===void 0)delete Q.activeProfiles;else Q.activeProfiles=V;throw Y}return this.details($)}updateDependencies($,Z,Q){let X=this.require($);try{return x1(X.file,Z,Q),this.details($)}catch(G){throw new q("invalid",I0(G))}}updateServiceConfig($,Z,Q){let X=this.require($);try{return M1(X.file,Z,Q),this.details($)}catch(G){throw new q("invalid",I0(G))}}readCatalog(){if(!T0.existsSync(this.catalogFile))return[];try{let $=JSON.parse(T0.readFileSync(this.catalogFile,"utf8"));if(!y3($))throw Error("invalid project catalog");return $.projects}catch{return T0.renameSync(this.catalogFile,this.nextCorruptFile()),[]}}assertNicknameAvailable($,Z){if(this.projects.some((Q)=>Q.id!==$&&(Q.slug===Z||(Q.nickname??Q.configNickname)===Z||!Q.sharedConfigNickname&&Q.configNickname===Z)))throw new q("invalid","That project nickname is already taken. Choose another.")}configAlias($,Z,Q){let X=this.projects.filter((K)=>K.id!==$&&(K.slug===Q||(K.nickname??K.configNickname)===Q||!K.sharedConfigNickname&&K.configNickname===Q));if(!X.length)return;let G=z$(Z);if(!G||X.some((K)=>{let N=z$(K.file);return!N||N.repository!==G.repository||N.relativeFile!==G.relativeFile}))this.assertNicknameAvailable($,Q);let J=this.byId($)?.nickname;if(J)return J;let V=`${Q.slice(0,46)}-${$.slice(0,8)}`,z=V,Y=2;while(this.projects.some((K)=>K.id!==$&&(K.slug===z||(K.nickname??K.configNickname)===z||!K.sharedConfigNickname&&K.configNickname===z)))z=`${V}-${Y++}`;return z}nextCorruptFile(){let $=`${this.catalogFile}.corrupt-${this.now()}`,Z=$,Q=2;while(T0.existsSync(Z))Z=`${$}-${Q++}`;return Z}persist(){s(this.catalogFile,{version:1,projects:this.sortedEntries()})}sorted(){return this.sortedEntries().map(($)=>({...$}))}sortedEntries(){return[...this.projects].sort(($,Z)=>Z.lastUsedAt-$.lastUsedAt)}toSummary($){try{return this.load($),{...$,nickname:this.nickname($.id),available:!0}}catch(Z){return{...$,available:!1,error:I0(Z)}}}load($){if(!T0.existsSync($.file))throw Error(`${$.file} does not exist`);let Z=L0($.file);if(Z.nickname){let Q=this.configAlias($.id,$.file,Z.nickname);if(Q){if($.sharedConfigNickname=!0,!$.nickname)$.nickname=Q}}return $.configNickname=Z.nickname,Z}require($){let Z=this.byId($);if(!Z)throw new q("not_found",`Project ${$} was not found`);return Z}byId($){return this.projects.find((Z)=>Z.id===$)}assignSlug($,Z){let Q=b3($)||"project";if(!this.projects.some((V)=>V.slug===Q||V.nickname===Q||V.configNickname===Q))return Q;let X=Z.slice(0,6),G=`${Q}-${X}`,J=2;while(this.projects.some((V)=>V.slug===G||V.nickname===G||V.configNickname===G))G=`${Q}-${X}-${J++}`;return G}}function x5($){return g3("sha256").update($).digest("hex").slice(0,16)}function b3($){return $.toLowerCase().replace(/[^a-z0-9-]+/g,"-").replace(/^-+|-+$/g,"")}function y3($){if(!$||typeof $!=="object")return!1;let Z=$;return Z.version===1&&Array.isArray(Z.projects)&&Z.projects.every(v3)}function v3($){if(!$||typeof $!=="object")return!1;let Z=$;if(!["id","name","slug","file","directory"].every((V)=>typeof Z[V]==="string"))return!1;let{id:Q,slug:X,file:G,directory:J}=Z;return Q0.isAbsolute(G)&&Q0.normalize(G)===G&&J===Q0.dirname(G)&&/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test(X)&&/^[a-f0-9]{16}$/.test(Q)&&(Z.nickname===void 0||typeof Z.nickname==="string"&&m$(Z.nickname))&&(Z.configNickname===void 0||typeof Z.configNickname==="string"&&m$(Z.configNickname))&&(Z.sharedConfigNickname===void 0||typeof Z.sharedConfigNickname==="boolean")&&(Z.activeProfiles===void 0||Array.isArray(Z.activeProfiles)&&Z.activeProfiles.every((V)=>typeof V==="string"&&/^[a-z0-9][a-z0-9_-]{0,40}$/.test(V)))&&Q===x5(G)&&typeof Z.lastUsedAt==="number"&&Number.isFinite(Z.lastUsedAt)}function m$($){return $.length<=63&&/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/.test($)}function I0($){return $ instanceof Error?$.message:String($)}function S0($,Z){return f3("git",["-C",$,...Z],{encoding:"utf8",timeout:2000,maxBuffer:1048576,stdio:["ignore","pipe","pipe"],env:{...process.env,GIT_TERMINAL_PROMPT:"0",GIT_OPTIONAL_LOCKS:"0"}})}function z$($){try{let Z=Q0.dirname($),Q=T0.realpathSync(S0(Z,["rev-parse","--show-toplevel"]).replace(/\r?\n$/,"")),X=S0(Z,["rev-parse","--git-common-dir"]).replace(/\r?\n$/,""),G=T0.realpathSync(Q0.resolve(Z,X)),J=Q0.relative(Q,$);if(J.startsWith("../")||Q0.isAbsolute(J))return;return{root:Q,repository:G,relativeFile:J}}catch{return}}var q1="Worktrees have separate processes and automatic ports. Databases, Docker resources, secrets, and external services may still be shared by configuration.";function E1($,Z){let Q=$.details(Z),X=z$(Q.file);if(!X)return{environments:[],error:"Git repository metadata is unavailable for this project.",sharedResourceNotice:q1};let G;try{G=S0(X.root,["worktree","list","--porcelain","-z"])}catch{return{environments:[],error:"Unable to list Git worktrees.",sharedResourceNotice:q1}}let J=new Map($.list().map((z)=>[z.file,z])),V=[];for(let z of G.split("\x00\x00")){let Y=z.split("\x00"),K=Y.find((B)=>B.startsWith("worktree "));if(!K)continue;let N=I5.resolve(K.slice(9));try{N=P5.realpathSync(N)}catch{}let U=I5.join(N,X.relativeFile),W=U,C;try{let B=P5.realpathSync(U),L=z$(B);if(!L||L.repository!==X.repository||L.relativeFile!==X.relativeFile||L.root!==N)throw Error("Configuration resolves outside this worktree.");W=B,L0(W)}catch(B){C=B instanceof Error?B.message:String(B)}let D=J.get(W),O=Y.find((B)=>B.startsWith("branch "))?.slice(7).replace(/^refs\/heads\//,"");V.push({id:k3("sha256").update(W).digest("hex").slice(0,16),...D?{projectId:D.id}:{},directory:N,configFile:W,...O?{branch:O}:{},head:Y.find((B)=>B.startsWith("HEAD "))?.slice(5),detached:Y.includes("detached"),available:!C,registered:!!D,current:W===Q.file,...C?{error:C}:{}})}return{environments:V,repository:X.repository,relativeConfig:X.relativeFile,sharedResourceNotice:q1}}function S5($,Z,Q){let G=E1($,Z).environments.find((J)=>J.id===Q);if(!G)throw new q("not_found","This environment is not a discovered worktree of the selected project.");if(!G.available)throw new q("invalid",G.error??"This environment is unavailable.");return $.remember(G.configFile)}import m3 from"node:path";import q5 from"node:fs";import{randomUUID as E5}from"node:crypto";import u3 from"node:http";function p$($,Z,Q={}){if(Z.service!==$.key||!["GET","HEAD"].includes(Z.method))throw Error("Only recorded GET and HEAD requests for this service can be replayed");if($.status!=="running"||!$.upstreamReady||$.serviceType&&$.serviceType!=="http")throw Error("The HTTP service must be running before replay");if(!["127.0.0.1","::1"].includes($.upstreamHost)||!Z.path.startsWith("/")||Z.path.startsWith("//")||/[\r\n\\\x00-\x20\x7f]/.test(Z.path))throw Error("Request path must be a local HTTP path");let X=Q.timeoutMs??5000,G=Q.maxBytes??65536;if(!Number.isInteger(X)||X<1||X>5000||!Number.isInteger(G)||G<1||G>65536)throw Error("Replay limits must be positive integers within 5000 ms and 65536 bytes");return new Promise((J,V)=>{let z=Date.now(),Y=!1,K=0,N=[],U=u3.request({host:$.upstreamHost,port:$.upstreamPort,path:Z.path,method:Z.method,headers:{"x-localdeck-replay":"1"}}),W=setTimeout(()=>{if(!Y)Y=!0,V(Error("Replay timed out"));U.destroy()},X),C=(D,O)=>{if(Y)return;Y=!0,clearTimeout(W),J({status:D,truncated:O,body:Buffer.concat(N).toString("utf8"),durationMs:Date.now()-z})};U.on("response",(D)=>{D.on("data",(O)=>{let B=Math.max(0,G-K);if(N.push(O.subarray(0,B)),K+=O.length,K>G)C(D.statusCode??502,!0),D.destroy(),U.destroy()}),D.on("end",()=>C(D.statusCode??502,!1)),D.on("error",(O)=>U.destroy(O)),D.on("aborted",()=>U.destroy(Error("Replay response was interrupted")))}),U.on("error",(D)=>{if(clearTimeout(W),!Y)Y=!0,V(D)}),U.end()})}var N$=/authorization|cookie|token|secret|password|passwd|api[-_]?key|credential|session|signature/i,d$=($)=>"'"+$.replace(/'/g,"'\\''")+"'";function w5($){return typeof $==="string"&&$.length<=8192&&$.startsWith("/")&&!$.startsWith("//")&&!/[\r\n\\\x00-\x20\x7f#]/.test($)}function q0($,Z){for(let Q of Z.filter(Boolean))$=$.split(Q).join("[REDACTED]");return $}function i$($,Z,Q=[]){if(!w5($.path)||!/^[A-Z]+$/.test($.method))throw Error("Request must have a valid local HTTP path and method");let X=new URL(Z);if(!["http:","https:"].includes(X.protocol)||X.username||X.password)throw Error("Export requires an HTTP base URL without credentials");let G=[],[J,V]=$.path.split(/\?(.*)/s),z=q0(J,Q.flatMap((O)=>[O,encodeURIComponent(O)]));if(z===J&&Q.some((O)=>O&&j5(J).includes(O)))z="/[REDACTED]";if(V!==void 0){let O=!1,B=new URLSearchParams(V),L=new URLSearchParams;for(let[_,H]of[...B]){let T=N$.test(_)?"[REDACTED]":q0(H,Q),A=q0(_,Q);if(L.append(A,T),T!==H||A!==_)O=!0,G.push("Sensitive query values redacted")}z+="?"+(O?L.toString():V)}if(z.split("?")[0]!==J)G.push("Secret in path redacted");let Y=[];for(let[O,B]of $.requestHeaders?.entries??[]){if(!["accept","content-type"].includes(O.toLowerCase())||N$.test(B)||q0(B,Q)!==B||/[\r\n]/.test(B)){G.push(`Header ${N$.test(O)?"credential":"non-representation"} omitted`);continue}Y.push([O,B])}if($.requestHeaders?.truncated)G.push("Header capture incomplete");let K,N=$.requestBody,U=!!N&&(N.bytes>0||N.data.length>0||!N.complete||N.truncated);if(N&&U){let O=Y.find(([B])=>B.toLowerCase()==="content-type")?.[1]??"";if(!N.complete||N.truncated||N.encoding!=="utf8"||N.contentEncoding&&N.contentEncoding!=="identity")G.push("Incomplete, binary or encoded body omitted");else if(/application\/json/i.test(O))try{K=JSON.stringify(JSON.parse(N.data),(B,L)=>N$.test(B)?"[REDACTED]":typeof L==="string"?q0(L,Q):L)}catch{G.push("Invalid JSON body omitted")}else if(/application\/x-www-form-urlencoded/i.test(O)){let B=new URLSearchParams(N.data);for(let[L,_]of[...B])B.set(L,N$.test(L)?"[REDACTED]":q0(_,Q));K=B.toString()}else G.push("Unsupported body format omitted");if(K!==void 0&&K!==N.data)G.push("Body sanitized")}let W={method:$.method,url:X.origin+z,headers:Y,...K===void 0?{}:{body:K}},C=["curl","--globoff","--path-as-is","--request",d$(W.method),"--url",d$(W.url),...Y.flatMap(([O,B])=>["--header",d$(`${O}: ${B}`)]),...K===void 0?[]:["--data-raw",d$(K)]].join(" "),D=["GET","HEAD"].includes($.method)&&!U&&!G.some((O)=>O.includes("query")||O.includes("path"));return{request:W,curl:C,omitted:[...new Set(G)],executable:D}}function j5($){try{return decodeURIComponent($)}catch{return $}}function l3($){try{if(q5.statSync($).size>2000000)return[];let Z=JSON.parse(q5.readFileSync($,"utf8"));if(!Array.isArray(Z))return[];let Q=new Set;return Z.slice(-200).filter((X)=>X&&typeof X.id==="string"&&X.id.length<=100&&typeof X.projectId==="string"&&X.projectId.length<=200&&typeof X.serviceKey==="string"&&X.serviceKey.startsWith(X.projectId+":")&&X.serviceKey.length<=400&&typeof X.name==="string"&&X.name.length<=120&&w5(X.path)&&["GET","HEAD"].includes(X.method)&&Number.isInteger(X.expectedStatus)&&X.expectedStatus>=100&&X.expectedStatus<=599&&Number.isFinite(X.createdAt)&&Array.isArray(X.runs)).filter((X)=>{if(Q.has(X.id))return!1;return Q.add(X.id),!0}).map((X)=>({id:X.id,projectId:X.projectId,serviceKey:X.serviceKey,name:X.name,method:X.method,path:X.path,expectedStatus:X.expectedStatus,createdAt:X.createdAt,runs:X.runs.slice(-20).filter((G,J,V)=>G&&V.findIndex((z)=>z?.id===G.id)===J).filter((G)=>G&&typeof G.id==="string"&&G.id.length<=100&&G.projectId===X.projectId&&G.serviceKey===X.serviceKey&&Number.isFinite(G.ts)&&Number.isFinite(G.durationMs)&&G.durationMs>=0&&G.expectedStatus===X.expectedStatus&&["passed","status-mismatch","transport-error"].includes(G.result)&&(G.actualStatus===void 0||Number.isInteger(G.actualStatus)&&G.actualStatus>=100&&G.actualStatus<=599)&&(G.error===void 0||typeof G.error==="string"&&G.error.length<=500)).map((G)=>({id:G.id,projectId:G.projectId,serviceKey:G.serviceKey,ts:G.ts,expectedStatus:G.expectedStatus,actualStatus:G.actualStatus,durationMs:G.durationMs,result:G.result,error:G.error}))}))}catch{return[]}}class w1{file;items;active=new Set;constructor($={}){this.file=$.file??m3.join(o,"reproductions.json"),this.items=l3(this.file)}list($){return structuredClone(this.items.filter((Z)=>Z.projectId===$))}persist(){let $=[...this.items];while($.length>1&&Buffer.byteLength(JSON.stringify($,null,2))>2000000)$.shift();K0(this.file,$),this.items=$}save($,Z,Q,X=[]){if(!$||$.length>200||Z.service.length>400||!Z.service.startsWith($+":"))throw Error("Request belongs to another project");if(typeof Q.name!=="string"||!Q.name.trim()||Q.name.length>120)throw Error("Check name must contain 1–120 characters");if(!Number.isInteger(Q.expectedStatus)||Q.expectedStatus<100||Q.expectedStatus>599)throw Error("Choose an expected HTTP status from 100 to 599");if(!i$(Z,"http://localhost",X).executable||X.some((V)=>V&&j5(Z.path).includes(V)))throw Error("Checks require an unchanged GET/HEAD path without secret query values or a request body");let G={id:E5(),projectId:$,serviceKey:Z.service,name:q0(Q.name.trim(),X).slice(0,120),method:Z.method,path:Z.path,expectedStatus:Q.expectedStatus,createdAt:Date.now(),runs:[]},J=this.items;this.items=[...this.items,G].slice(-200);try{this.persist()}catch(V){throw this.items=J,V}return structuredClone(G)}async run($,Z,Q){let X=this.items.find((G)=>G.id===Z&&G.projectId===$);if(!X||Q.projectId!==$||Q.key!==X.serviceKey)throw Error("Check not found in the selected service and environment");if(!i$({id:X.id,ts:0,service:X.serviceKey,method:X.method,path:X.path,status:0,bytes:0,durationMs:0,via:"local"},"http://localhost").executable)throw Error("Saved check is invalid");if(this.active.has(Z))throw Error("This check is already running");this.active.add(Z);try{let G=Date.now(),J={id:E5(),projectId:$,serviceKey:Q.key,ts:G,expectedStatus:X.expectedStatus,durationMs:0,result:"transport-error"};try{let z=await p$(Q,{id:X.id,ts:G,service:X.serviceKey,method:X.method,path:X.path,status:0,bytes:0,durationMs:0,via:"local"});J.actualStatus=z.status,J.durationMs=z.durationMs,J.result=z.status===X.expectedStatus?"passed":"status-mismatch"}catch{J.durationMs=Date.now()-G,J.error="Could not complete the request. Check that the local HTTP service is running and ready."}let V=X.runs;X.runs=[...X.runs,J].slice(-20);try{this.persist()}catch(z){throw X.runs=V,z}return structuredClone(J)}finally{this.active.delete(Z)}}delete($,Z){if(this.active.has(Z))throw Error("Wait for the check to finish before deleting it");let Q=this.items;if(this.items=this.items.filter((X)=>!(X.id===Z&&X.projectId===$)),Q.length===this.items.length)return!1;try{this.persist()}catch(X){throw this.items=Q,X}return!0}}import h5 from"node:fs";import p3 from"node:os";import g5 from"node:path";function U$($,Z=[]){let Q=$.replace(/-----BEGIN [^-]*PRIVATE KEY-----[\s\S]*?-----END [^-]*PRIVATE KEY-----/g,"[REDACTED PRIVATE KEY]").replace(/(authorization["']?\s*[:=]\s*["']?)(?:Bearer|Basic)\s+[^\s,"'}]+/gi,"$1[REDACTED]").replace(/((?:set-cookie|cookie)["']?\s*[:=]\s*)[^\r\n]+/gi,"$1[REDACTED]").replace(/(?<![a-z0-9+.-])([a-z][a-z0-9+.-]*:\/\/)([^\s/@]+)@/gi,(G,J,V)=>V.includes(":")?`${J}[REDACTED]@`:G).replace(/(?<![\w-])(?=[\w-]*(?:password|passwd|secret|token|api[_-]?key|credential))([\w-]+["']?\s*[:=]\s*)(?:"[^"\n]*"|'[^'\n]*'|[^\s,;&}\n]+)/gi,"$1[REDACTED]").replace(/((?:--)(?:password|token|secret|api-key)\s+)(?:"[^"]*"|'[^']*'|\S+)/gi,"$1[REDACTED]");for(let G of[...new Set(Z)].filter(Boolean).sort((J,V)=>V.length-J.length))Q=Q.replaceAll(G,"[REDACTED]");let X=p3.homedir();if(X.length>1)Q=Q.replaceAll(X,"<home>");return Q}function f5($,Z){if($==="NODE_ENV"&&/^(development|production|test)$/.test(Z))return!1;if(/^(?:PORT|[A-Z_]+_PORT)$/.test($)&&/^\d{1,5}$/.test(Z)&&Number(Z)>0&&Number(Z)<=65535)return!1;return!0}function c$($){let Z=[];for(let Q of[".env",".env.local",".env.development",".env.development.local"]){let X=g5.join($,Q);try{let G=h5.lstatSync(X);if(!G.isFile()||G.size>65536)continue;let J=h5.readFileSync(X,"utf8");for(let V of J.split(/\r?\n/)){let z=V.match(/^\s*(?:export\s+)?([A-Za-z_][\w]*)\s*=\s*(.*)$/);if(z){let Y=z[2].trim().replace(/^(['"])(.*)\1$/,"$2");if(f5(z[1],Y))Z.push(Y)}}}catch{}}return Z}function b5($,Z,Q,X,G=[]){let J=Object.entries(process.env).filter(([N])=>/password|passwd|secret|token|api[_-]?key|credential/i.test(N)).flatMap(([,N])=>N?[N]:[]),V=new Set([$.directory,...$.commands.map((N)=>g5.resolve($.directory,N.cwd??"."))]),z=[...G,...J,...[...V].flatMap(c$),...$.commands.flatMap((N)=>Object.entries(N.env??{}).filter(([U,W])=>f5(U,W)).map(([,U])=>U))],Y={notice:"Review before sharing. Known secrets are redacted, but application logs may contain other private data.",version:X,project:{name:$.name,available:$.available,error:$.error},configuration:$.commands.map(({env:N,...U})=>({...U,environmentVariables:Object.keys(N??{})})),services:Z.map((N)=>({name:N.name,status:N.status,readiness:N.readinessStatus,message:N.readinessMessage,lastError:N.lastError,serviceType:N.serviceType??"http",port:N.stablePort})),logs:Q.slice(-100).map(({stream:N,line:U,ts:W,service:C})=>({service:C,ts:W,stream:N,line:U.slice(0,2000)}))},K=(N)=>typeof N==="string"?U$(N,z):Array.isArray(N)?N.map(K):N&&typeof N==="object"?Object.fromEntries(Object.entries(N).map(([U,W])=>[U,K(W)])):N;return JSON.stringify(K(Y),null,2)}import j1 from"node:fs";import y5 from"node:path";var d3=/^[a-f0-9]{16}$/,i3=/^[A-Za-z_][A-Za-z0-9_]*$/;class e extends Error{}function n$($){if(!i3.test($)||$==="PORT"||$.startsWith("LOCALDECK_"))throw new e("invalid secret name")}function c3($=o){let Z=y5.join($,"secrets");function Q(K){if(!d3.test(K))throw new e("invalid project ID");return y5.join(Z,`${K}.json`)}function X(K){let N=Q(K),U;try{U=j1.readFileSync(N,"utf8")}catch(D){if(D.code==="ENOENT")return Object.create(null);throw new e("Could not read stored secrets")}let W;try{W=JSON.parse(U)}catch{throw new e("stored secrets are corrupt")}if(!W||typeof W!=="object"||Array.isArray(W))throw new e("stored secrets are corrupt");let C=Object.create(null);for(let[D,O]of Object.entries(W)){if(n$(D),typeof O!=="string"||!O||O.includes("\x00"))throw new e("stored secrets are corrupt");C[D]=O}return C}function G(K,N){let U=Q(K);if(j1.mkdirSync(Z,{recursive:!0,mode:448}),process.platform!=="win32")j1.chmodSync(Z,448);K0(U,N)}function J(K){return Object.keys(X(K)).sort()}function V(K,N,U){if(n$(N),typeof U!=="string"||!U||U.includes("\x00"))throw new e("secret value must be a nonempty string without NUL");let W=X(K);W[N]=U,G(K,W)}function z(K,N){n$(N);let U=X(K);delete U[N],G(K,U)}function Y(K,N){let U=Object.create(null);if(!N.length)return U;let W=X(K);for(let C of N){if(n$(C),!Object.prototype.hasOwnProperty.call(W,C))throw new e(`Add ${C} in Project → Secrets.`);U[C]=W[C]}return U}return{listProjectSecrets:J,setProjectSecret:V,deleteProjectSecret:z,resolveProjectSecrets:Y}}var{listProjectSecrets:A0,setProjectSecret:D$,deleteProjectSecret:O$,resolveProjectSecrets:z0}=c3();var v5=new WeakMap;function a3($){let Z=$.reproductions??v5.get($);if(!Z)Z=new w1,v5.set($,Z);return Z}function a$($,Z){let Q=$.projects.details(Z),X=($.listProjectSecrets??A0)(Z);return[$.controlToken,...Object.values(($.resolveProjectSecrets??z0)(Z,X)),...Object.entries(process.env).flatMap(([G,J])=>/secret|token|password|credential|api[_-]?key/i.test(G)&&J?[J]:[]),...c$(Q.directory),...Q.commands.flatMap((G)=>[...Object.values(G.env??{}),...c$(n3.resolve(Q.directory,G.cwd??"."))])]}async function o$($,Z){let Q=await n($);if(!Q||typeof Q!=="object"||Array.isArray(Q)||Object.keys(Q).some((X)=>!Z.includes(X)))throw new I(400,"Unexpected request fields");return Q}async function k5($,Z,Q,X,G){let J=$.method??"GET",V=X[0]==="projects"&&X.length>=3&&["activity","baselines","checks","environments"].includes(X[2]),z=X[0]==="services"&&X.length===3&&X[2]==="reproduction";if(!V&&!z)return!1;let Y=(K,N)=>{return Z.setHeader("cache-control","no-store"),x(Z,K,N),!0};try{if(J!=="GET")j(G);if(z&&J==="GET"){let D=X[1],O=D.split(":")[0];if(!G.projects.details(O).commands.some((T)=>`${O}:${T.name}`===D)&&!G.registry.get(D))throw new I(404,"Unknown service");let L=G.store.requests(D,5000).find((T)=>T.id===Q.searchParams.get("requestId"));if(!L)throw new I(404,"Recorded request is no longer available");let _=G.registry.get(D);if(!_)throw new I(422,"Start this service before exporting so its current local address is available");let H=`http://localhost:${_.stablePort}`;return Y(200,i$(L,H,a$(G,O)))}if(!V)return Y(405,{error:"Method not allowed"});let K=X[1],N=X[2],U=G.projects.details(K),W=[...new Set([...U.commands.map((D)=>`${K}:${D.name}`),...G.registry.list(K).filter((D)=>D.projectId===K).map((D)=>D.key)])],C=(D)=>{let O=D===void 0?W:D;if(!Array.isArray(O)||!O.length||O.length>100||O.some((B)=>typeof B!=="string"||!W.includes(B)))throw new I(422,"Select 1–100 configured or registered services in this project");return[...new Set(O)]};if(N==="activity"&&X.length===3&&J==="GET"){let D=Q.searchParams.get("services");if(!W.length&&!D)return Y(200,{items:[],coverage:{partial:!1,reasons:[]}});let O={limit:Q.searchParams.has("limit")?Number(Q.searchParams.get("limit")):100,filter:Q.searchParams.get("filter")??"all",query:Q.searchParams.get("query")??void 0,cursor:Q.searchParams.get("cursor")??void 0,eventId:Q.searchParams.get("eventId")??void 0};return Y(200,G.store.activity.timeline(K,C(D===null?void 0:D.split(",")),O))}if(N==="activity"&&X.length===5&&X[4]==="evidence"&&J==="GET"){let D=G.store.activity.timeline(K,C(void 0),{eventId:X[3],limit:1}).items[0];if(!D)throw new I(404,"This event has expired or was cleared");let O=D.kind==="request"?G.store.requests(D.service,5000).find((L)=>L.id===D.id):void 0,B=D.kind==="log"?G.store.logs(D.service,2000).find((L)=>L.id===D.id):void 0;return Y(200,{event:D,request:O,log:B,service:G.registry.get(D.service)})}if(N==="baselines"){if(X.length===3&&J==="GET")return Y(200,{items:G.store.activity.markers(K)});if(X.length===3&&J==="POST"){let D=await o$($,["services","label"]);if(j(G),D.label!==void 0&&typeof D.label!=="string")throw new I(422,"Baseline label must be text");let O;try{O={head:S0(U.directory,["rev-parse","HEAD"]).trim()};try{O.branch=S0(U.directory,["symbolic-ref","--short","HEAD"]).trim()}catch{}}catch{}return Y(201,G.store.activity.mark(K,C(D.services),{label:D.label,git:O,secrets:a$(G,K)}))}if(X.length===4&&J==="GET")return Y(200,G.store.activity.compare(K,X[3],Date.now(),a$(G,K)))}if(N==="environments"){if(X.length===3&&J==="GET"){let D=E1(G.projects,K);return Y(200,{...D,environments:D.environments.map((O)=>({...O,runningCount:O.projectId?G.registry.list(O.projectId).filter((B)=>B.projectId===O.projectId&&B.status!=="stopped").length:0}))})}if(X.length===5&&X[4]==="register"&&J==="POST")return await o$($,[]),j(G),Y(201,S5(G.projects,K,X[3]))}if(N==="checks"){let D=a3(G);if(X.length===3&&J==="GET")return Y(200,{items:D.list(K)});if(X.length===3&&J==="POST"){let B=await o$($,["requestId","serviceKey","name","expectedStatus"]);j(G);let[L]=C([B.serviceKey]);if(typeof B.requestId!=="string")throw new I(422,"A recorded request ID is required");let _=G.store.requests(L,5000).find((H)=>H.id===B.requestId);if(!_)throw new I(404,"Recorded request is no longer available");return Y(201,D.save(K,_,{name:B.name,expectedStatus:B.expectedStatus},a$(G,K)))}let O=D.list(K).find((B)=>B.id===X[3]);if(!O)throw new I(404,"Check not found in this project");if(X.length===4&&J==="DELETE")return Y(200,{ok:D.delete(K,O.id)});if(X.length===5&&X[4]==="run"&&J==="POST"){await o$($,[]),j(G);let B=G.registry.get(O.serviceKey);if(!B||B.status!=="running"||!B.upstreamReady)throw new I(422,"Start the check’s HTTP service and wait for readiness before running it");return Y(200,await D.run(K,O.id,B))}}return Y(404,{error:"Unknown debugging endpoint"})}catch(K){if(K instanceof I)throw K;return Y(422,{error:K instanceof Error?K.message:"Debugging operation failed"})}}import y7 from"node:http";import{timingSafeEqual as v7,randomBytes as k7,randomUUID as u7}from"node:crypto";import V7 from"node:fs";import Y7 from"node:http";import K7 from"node:path";import{execFile as o3}from"node:child_process";import{promisify as s3}from"node:util";var t3=s3(o3);function r3($,Z=!1){if(!Number.isInteger($)||$<1||$>65535||$===80)throw Error("Invalid forwarding target port.");return String.raw`$ErrorActionPreference = 'Stop'
10
+ $ownerPath = 'HKLM:\SOFTWARE\LocalDeck\Port80'
11
+ $rulePath = 'HKLM:\SYSTEM\CurrentControlSet\Services\PortProxy\v4tov4\tcp'
12
+ $ruleName = '127.0.0.1/80'
13
+ $marker = 'LocalDeck loopback portproxy v1'
14
+ $netsh = Join-Path $env:SystemRoot 'System32\netsh.exe'
15
+ $owner = Get-ItemProperty -LiteralPath $ownerPath -ErrorAction SilentlyContinue
16
+ $rule = if (Test-Path -LiteralPath $rulePath) { (Get-Item -LiteralPath $rulePath).GetValue($ruleName) } else { $null }
17
+ $owned = $owner -and $owner.Marker -eq $marker -and $owner.TargetPort -match '^\d+$' -and [int]$owner.TargetPort -ge 1 -and [int]$owner.TargetPort -le 65535 -and [int]$owner.TargetPort -ne 80
18
+ if ($owner -and !$owned) { throw 'Refusing to change an unrecognized LocalDeck ownership record.' }
19
+ if ($rule -and (!$owned -or $rule -ne ('127.0.0.1/' + $owner.TargetPort))) { throw 'Port 80 has an unmanaged forwarding rule. It was left unchanged.' }
20
+ ${Z?String.raw`if ($rule) {
21
+ & $netsh interface portproxy delete v4tov4 listenaddress=127.0.0.1 listenport=80 protocol=tcp | Out-Null
22
+ if ($LASTEXITCODE -ne 0) { throw 'Could not remove the LocalDeck forwarding rule.' }
23
+ }
24
+ if ($owned) { Remove-Item -LiteralPath $ownerPath }
25
+ `:String.raw`if (!$rule) {
26
+ $listeners = @(Get-NetTCPConnection -ErrorAction Stop | Where-Object { $_.State -eq 'Listen' -and $_.LocalPort -eq 80 -and $_.LocalAddress -in @('127.0.0.1','0.0.0.0','::','::1') })
27
+ if ($listeners.Count) { throw 'Port 80 is already in use. The existing listener was left unchanged.' }
28
+ }
29
+ $helper = Get-Service iphlpsvc
30
+ if ($helper.StartType -eq 'Disabled') { throw 'Windows IP Helper is disabled. Enable it through your system administrator to use port forwarding.' }
31
+ if ($helper.Status -ne 'Running') { Start-Service iphlpsvc }
32
+ $oldRule = $rule
33
+ $oldPort = if ($owned) { $owner.TargetPort } else { $null }
34
+ try {
35
+ New-Item -Path $ownerPath -Force | Out-Null
36
+ New-ItemProperty -LiteralPath $ownerPath -Name Marker -Value $marker -PropertyType String -Force | Out-Null
37
+ New-ItemProperty -LiteralPath $ownerPath -Name TargetPort -Value '${$}' -PropertyType String -Force | Out-Null
38
+ & $netsh interface portproxy add v4tov4 listenaddress=127.0.0.1 listenport=80 connectaddress=127.0.0.1 connectport=${$} protocol=tcp | Out-Null
39
+ if ($LASTEXITCODE -ne 0) { throw 'Windows could not install the forwarding rule.' }
40
+ $installed = (Get-Item -LiteralPath $rulePath).GetValue($ruleName)
41
+ if ($installed -ne '127.0.0.1/${$}') { throw 'The installed forwarding rule did not match the requested destination.' }
42
+ } catch {
43
+ if ($oldRule) {
44
+ & $netsh interface portproxy add v4tov4 listenaddress=127.0.0.1 listenport=80 connectaddress=127.0.0.1 "connectport=$oldPort" protocol=tcp | Out-Null
45
+ if ($LASTEXITCODE -eq 0) { Set-ItemProperty -LiteralPath $ownerPath -Name TargetPort -Value $oldPort }
46
+ } else {
47
+ & $netsh interface portproxy delete v4tov4 listenaddress=127.0.0.1 listenport=80 protocol=tcp | Out-Null
48
+ if ($LASTEXITCODE -eq 0) { Remove-Item -LiteralPath $ownerPath }
49
+ }
50
+ throw
51
+ }
52
+ `}`}function e3($,Z=!1){let Q=`try {
53
+ ${r3($,Z)}
54
+ exit 0
55
+ } catch { Write-Error $_ -ErrorAction Continue; exit 1 }`;return`$ErrorActionPreference = 'Stop'; $exe = Join-Path $env:SystemRoot 'System32\\WindowsPowerShell\\v1.0\\powershell.exe'; $child = Start-Process -FilePath $exe -Verb RunAs -ArgumentList '-NoLogo -NoProfile -NonInteractive -EncodedCommand ${Buffer.from(Q,"utf16le").toString("base64")}' -PassThru -Wait; if ($child.ExitCode -ne 0) { throw 'Windows administrator setup failed.' }`}async function u5($,Z=!1){let Q=e3($,Z);try{await t3("powershell.exe",["-NoLogo","-NoProfile","-NonInteractive","-Command",Q],{windowsHide:!0,timeout:120000,maxBuffer:8192})}catch{throw Error("Windows administrator setup was cancelled or failed. Port 80 may be occupied or reserved, or IP Helper may be disabled. Existing port-number links still work; retry from Settings.")}}import{execFile as $7}from"node:child_process";import Z7 from"node:os";import{promisify as Q7}from"node:util";var X7=Q7($7),s$="dev.localdeck.port80",h1=`/Library/LaunchDaemons/${s$}.plist`,$0=h1,m5="LocalDeck managed loopback relay v1";function G7($,Z){if(!/^[a-zA-Z_][a-zA-Z0-9_.-]*$/.test($)||$==="root")throw Error("Forwarding must run as a regular macOS user.");if(!Number.isInteger(Z)||Z<1||Z>65535||Z===80)throw Error("Invalid forwarding target port.");return`<?xml version="1.0" encoding="UTF-8"?>
56
+ <!-- ${m5} -->
57
+ <plist version="1.0"><dict>
58
+ <key>Label</key><string>${s$}</string>
59
+ <key>UserName</key><string>${$}</string>
60
+ <key>ProgramArguments</key><array><string>/usr/bin/nc</string><string>127.0.0.1</string><string>${Z}</string></array>
61
+ <key>inetdCompatibility</key><dict><key>Wait</key><false/></dict>
62
+ <key>Sockets</key><dict><key>Listeners</key><dict>
63
+ <key>SockNodeName</key><string>127.0.0.1</string>
64
+ <key>SockServiceName</key><string>80</string>
65
+ <key>SockFamily</key><string>IPv4</string>
66
+ <key>SockType</key><string>stream</string>
67
+ <key>SockProtocol</key><string>TCP</string>
68
+ </dict></dict>
69
+ </dict></plist>`}function J7($,Z,Q=!1){let X=G7($,Z),G=`set -eu
70
+ if [ -L '${$0}' ]; then exit 1; fi
71
+ if [ -e '${$0}' ] && ! /usr/bin/grep -q '${m5}' '${$0}'; then
72
+ echo 'Refusing to replace an unmanaged forwarding service.' >&2; exit 1
73
+ fi`;if(Q)return`${G}
74
+ /bin/launchctl bootout system/${s$} 2>/dev/null || true
75
+ /bin/rm -f '${$0}'`;return`${G}
76
+ relay_file=$(/usr/bin/mktemp /Library/LaunchDaemons/.localdeck-port80.XXXXXX)
77
+ trap '/bin/rm -f "$relay_file" "$relay_file.backup"' EXIT
78
+ /bin/cat > "$relay_file" <<'LOCALDECK_PLIST'
79
+ ${X}
80
+ LOCALDECK_PLIST
81
+ /usr/bin/plutil -lint "$relay_file" >/dev/null
82
+ /usr/sbin/chown root:wheel "$relay_file"
83
+ /bin/chmod 644 "$relay_file"
84
+ if [ -f '${$0}' ]; then /bin/cp -p '${$0}' "$relay_file.backup"; fi
85
+ /bin/launchctl bootout system/${s$} 2>/dev/null || true
86
+ /bin/mv "$relay_file" '${$0}'
87
+ if ! /bin/launchctl bootstrap system '${$0}'; then
88
+ /bin/rm -f '${$0}'
89
+ if [ -f "$relay_file.backup" ]; then
90
+ /bin/mv "$relay_file.backup" '${$0}'
91
+ /bin/launchctl bootstrap system '${$0}' || true
92
+ fi
93
+ exit 1
94
+ fi`}async function l5($,Z=!1){if(process.platform==="win32")return u5($,Z);if(process.platform!=="darwin")throw Error("Automatic administrator setup is available on macOS and Windows.");let Q=J7(Z7.userInfo().username,$,Z);try{await X7("/usr/bin/osascript",["-e",`on run argv
95
+ do shell script (item 1 of argv) with administrator privileges
96
+ end run`,Q],{timeout:120000,maxBuffer:8192})}catch{throw Error("Administrator setup was cancelled or failed. Continuing with working port-number links; retry in Settings whenever you like.")}}class g1{targetPort;identity;port;platform;preferenceFile;configureSystem;systemRelayInstalled;bridge;enabling;closed=!1;constructor($,Z,Q=80,X=process.platform,G=K7.join(o,"forwarder.json"),J=l5,V=()=>V7.existsSync(h1)){this.targetPort=$;this.identity=Z;this.port=Q;this.platform=X;this.preferenceFile=G;this.configureSystem=J;this.systemRelayInstalled=V}async status(){return{ready:await new Promise((Z)=>{let Q=Y7.get({hostname:"127.0.0.1",port:this.port,path:"/api/forwarder/probe",agent:!1},(G)=>{let J="";G.on("data",(V)=>{if(J+=V,J.length>256)Q.destroy()}),G.on("end",()=>Z(G.statusCode===200&&J===this.identity)),G.on("error",()=>Z(!1))}),X=setTimeout(()=>{Q.destroy(),Z(!1)},1500);Q.on("close",()=>clearTimeout(X)),Q.on("error",()=>Z(!1))})&&!this.closed}}enable($={}){if(this.enabling)return this.enabling;return this.enabling=this.start($).finally(()=>{this.enabling=void 0}),this.enabling}async start($){if(this.closed)return{ready:!1,error:"LocalDeck is shutting down."};let Z=this.preferenceFile,Q=r(Z,{});if(Q.removed){if($.automatic)return{ready:!1,error:"Clean URLs are turned off; enable them in the dashboard to use them again."};s(Z,{declined:Q.declined})}if(this.platform==="win32"&&$.install&&this.port===80&&!($.automatic&&r(Z,{}).declined)){if(!this.bridge&&(await this.status()).ready)return{ready:!0};if(this.bridge)await this.bridge.close(),this.bridge=void 0;try{s(Z,{declined:!0}),await this.configureSystem(this.targetPort());let X=!1;for(let G=0;G<20&&!this.closed;G++){if((await this.status()).ready){X=!0;break}await new Promise((J)=>setTimeout(J,250))}if(!X)throw Error("Windows setup completed but forwarding could not be verified. Port-number links remain available; retry in Settings.");return s(Z,{declined:!1}),{ready:!0}}catch(X){return{ready:!1,error:X instanceof Error?X.message:"Windows setup failed."}}}if((await this.status()).ready)return{ready:!0};try{if(this.closed)return{ready:!1,error:"LocalDeck is shutting down."};if(this.bridge??=await L5({listenPort:this.port,targetPort:this.targetPort()}),this.closed)return await this.bridge.close(),this.bridge=void 0,{ready:!1,error:"LocalDeck is shutting down."};if((await this.status()).ready)return{ready:!0};return{ready:!1,error:"Port 80 does not reach this LocalDeck instance. Your existing links are unchanged."}}catch(X){let G=X instanceof Error?X.message:"Could not start port-80 forwarding.",J=this.preferenceFile;if($.install&&this.port===80&&this.platform==="darwin"&&G.includes("permission denied")&&!($.automatic&&r(J,{}).declined))try{s(J,{declined:!0}),await this.configureSystem(this.targetPort());let V=await this.status();if(!V.ready)throw Error("Setup completed but forwarding could not be verified. Your original links are unchanged.");return s(J,{declined:!1}),V}catch(V){return{ready:!1,error:V instanceof Error?V.message:"Administrator setup failed."}}return{ready:!1,error:G}}}async uninstall(){if(this.enabling)return{ready:!1,error:"Wait for the current setup to finish."};try{let $=Boolean(this.bridge);if(this.bridge)await this.bridge.close(),this.bridge=void 0;if(this.platform==="darwin"?this.systemRelayInstalled():this.platform==="win32"&&this.port===80&&!$)await this.configureSystem(this.targetPort(),!0);return s(this.preferenceFile,{declined:!0,removed:!0}),{ready:!1,removed:!0}}catch($){return{ready:!1,error:$ instanceof Error?$.message:"Removal failed."}}}async close(){if(this.closed=!0,await this.enabling,this.bridge)await this.bridge.close(),this.bridge=void 0}}import Z1 from"node:fs";import U0 from"node:path";import{brotliDecompressSync as z7,gunzipSync as N7,inflateSync as U7}from"node:zlib";var D7=16384;class l0{limit;chunks=[];retained=0;bytes=0;tailUsed=0;constructor($=D7){this.limit=$}append($){this.bytes+=$.length;let Z=Math.min($.length,this.limit-this.retained),Q=0;while(Q<Z){let X=this.chunks.at(-1);if(!X||this.tailUsed===X.length)if(X&&X.length<4096){let J=Buffer.allocUnsafe(Math.min(4096,this.limit-this.retained+this.tailUsed,Math.max(X.length*2,Z-Q)));X.copy(J,0,0,this.tailUsed),this.chunks[this.chunks.length-1]=X=J}else X=Buffer.allocUnsafe(Math.min(4096,this.limit-this.retained,Math.max(64,Z-Q))),this.chunks.push(X),this.tailUsed=0;let G=Math.min(Z-Q,X.length-this.tailUsed);$.copy(X,this.tailUsed,Q,Q+G),this.tailUsed+=G,this.retained+=G,Q+=G}}snapshot($,Z){let Q=Buffer.concat(this.chunks.map((z,Y)=>Y===this.chunks.length-1?z.subarray(0,this.tailUsed):z),this.retained),X=Boolean(Z&&Z!=="identity"),G=this.bytes>this.retained;if(X&&$&&!G&&Q.length){let z={gzip:N7,deflate:U7,br:z7}[Z];try{if(z)Q=z(Q,{maxOutputLength:this.limit}),X=!1}catch{}}let J,V="utf8";try{if(X||Q.includes(0))throw Error("binary body");J=new TextDecoder("utf-8",{fatal:!0}).decode(Q)}catch{J=Q.toString("base64"),V="base64"}return{data:J,encoding:V,bytes:this.bytes,truncated:G,complete:$,...X?{contentEncoding:Z}:{}}}}function p0($){let Z=[],Q=0;for(let X=0;X+1<$.length;X+=2){let G=$[X],J=$[X+1];if(Q+=Buffer.byteLength(G)+Buffer.byteLength(J),Q>16384||Z.length>=100)return{entries:Z,truncated:!0};Z.push([G,J])}return{entries:Z,truncated:!1}}import O7 from"node:http";import p5 from"node:net";var W7=new Set(["connection","keep-alive","proxy-authenticate","proxy-authorization","te","trailer","transfer-encoding","upgrade"]);function d5($,Z){let Q={};for(let[G,J]of Object.entries($.headers)){if(W7.has(G)||J===void 0)continue;Q[G]=J}if(Z.via==="share"){let G=p5.isIP(Z.upstreamHost)===6?`[${Z.upstreamHost}]`:Z.upstreamHost;Q.host=`${G}:${Z.upstreamPort}`}let X=$.socket.remoteAddress??"";return Q["x-forwarded-for"]=$.headers["x-forwarded-for"]?`${$.headers["x-forwarded-for"]}, ${X}`:X,Q["x-forwarded-proto"]=Z.via==="share"?"https":"http",Q["x-forwarded-host"]=$.headers.host??"",Q["x-localdeck-service"]=Z.service,Q}function C7($){return`<!doctype html><meta charset="utf-8"><meta http-equiv="refresh" content="2">
97
+ <title>LocalDeck — waiting for ${$.service}</title>
98
+ <style>body{font:15px/1.5 system-ui;margin:0;display:grid;place-items:center;height:100vh;background:#0f1115;color:#e6e8ef}
99
+ .c{max-width:420px;text-align:center}code{background:#1c1f27;padding:2px 6px;border-radius:4px}</style>
100
+ <div class="c"><h1 style="font-weight:600">Waiting for <code>${$.service}</code></h1>
101
+ <p>LocalDeck is holding this port. Nothing is listening on the upstream port <code>${$.upstreamPort}</code> yet.
102
+ This page reloads every 2 seconds.</p></div>`}function d0($,Z,Q,X){let G=Date.now(),J=p0($.rawHeaders),V=new l0,z=new l0,Y=X.responseBodies?.start(Q.service),K=(T)=>{z.append(T),Y?.append(T)},N=!1,U,W,C=0,D=!1,O=(T,A)=>{if(D)return;D=!0,Y?.finish(N,U),X.onRequest({ts:G,service:Q.service,method:$.method??"GET",path:$.url??"/",status:T,durationMs:Date.now()-G,bytes:C,via:Q.via,error:A,requestHeaders:J,responseHeaders:W,requestBody:V.snapshot($.readableEnded,$.headers["content-encoding"]),responseBody:z.snapshot(N,U),responseBodyId:Y?.id})};if(!Q.upstreamReady){W=p0(["content-type","text/html; charset=utf-8","retry-after","2"]),Z.writeHead(503,{"content-type":"text/html; charset=utf-8","retry-after":"2"});let T=C7(Q);K(Buffer.from(T)),N=!0,Z.end(T),O(503,"upstream not ready");return}let B=502,L,_=O7.request({host:Q.upstreamHost,port:Q.upstreamPort,method:$.method,path:$.url,headers:d5($,Q)},(T)=>{if(Z.destroyed){T.destroy();return}L=T,W=p0(T.rawHeaders),U=T.headers["content-encoding"],T.on("end",()=>{N=!0}),B=T.statusCode??502,T.on("error",(R)=>{O(502,`upstream response error: ${R.message}`),Z.destroy()}),T.on("aborted",()=>{O(502,"upstream response aborted"),Z.destroy()});let A={...T.headers};Z.writeHead(T.statusCode??502,T.statusMessage,A),T.on("data",(R)=>{C+=R.length,K(R)}),T.pipe(Z)});_.on("error",(T)=>{if(!Z.headersSent)W=p0(["content-type","text/plain; charset=utf-8"]);if(!Z.headersSent&&!Z.destroyed){Z.writeHead(502,{"content-type":"text/plain; charset=utf-8"});let A=`LocalDeck: upstream ${Q.service} (${Q.upstreamHost}:${Q.upstreamPort}) error: ${T.code??T.message}`;K(Buffer.from(A)),N=!0,Z.end(A)}else Z.destroy();O(502,T.code??T.message)});let H=()=>{O(499,"client disconnected before response completed"),L?.destroy(),_.destroy()};$.on("aborted",H),Z.on("finish",()=>O(B)),Z.on("close",()=>{if(!Z.writableFinished)H()}),$.on("data",(T)=>V.append(T)),$.pipe(_)}function i0($,Z,Q,X,G){let J=Date.now();if(Z.on("error",()=>Z.destroy()),!X.upstreamReady){Z.end(`HTTP/1.1 503 Service Unavailable\r
103
+ Connection: close\r
104
+ \r
105
+ `);return}let V=p5.connect(X.upstreamPort,X.upstreamHost,()=>{let Y=d5($,X);Y.connection="Upgrade",Y.upgrade=$.headers.upgrade;let K=[`${$.method} ${$.url} HTTP/1.1`];for(let[N,U]of Object.entries(Y)){if(U===void 0)continue;for(let W of Array.isArray(U)?U:[String(U)])K.push(`${N}: ${W}`)}if(V.write(K.join(`\r
106
+ `)+`\r
107
+ \r
108
+ `),Q.length)V.write(Q);V.pipe(Z).pipe(V),G.onRequest({ts:J,service:X.service,method:$.method??"GET",path:$.url??"/",status:101,durationMs:Date.now()-J,bytes:0,requestHeaders:p0($.rawHeaders),via:X.via})}),z=()=>{V.destroy(),Z.destroy()};V.on("error",z),Z.on("error",z),Z.on("close",()=>V.destroy()),V.on("close",()=>Z.destroy())}import _7 from"node:http";import{setTimeout as B7}from"node:timers/promises";async function i5($,Z,Q,X={}){let G=X.fetch??fetch;while(!0){Q.throwIfAborted();try{let J=await G(new URL(`/__localdeck/ready/${Z}`,$),{signal:AbortSignal.any([Q,AbortSignal.timeout(3000)]),redirect:"manual",cache:"no-store"}),V=J.status===204&&J.headers.get("x-localdeck-ready")===Z;if(await J.body?.cancel(),V)return}catch{Q.throwIfAborted()}await B7(X.retryMs??1000,void 0,{signal:Q})}}import b1 from"node:crypto";import{spawn as H7}from"node:child_process";class N0 extends Error{}var y1="localdeck_share",L7=/https:\/\/[a-z0-9-]+\.trycloudflare\.com/,T7=65536,A7=1000,R7={"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"};function F7($){return $.replace(/[&<>"']/g,(Z)=>R7[Z])}class o5{now;clients=new Map;all=[];windowMs;perClient;perShare;constructor($=Date.now,Z={}){this.now=$;this.windowMs=Z.windowMs??900000,this.perClient=Z.perClient??10,this.perShare=Z.perShare??100}retryAfterSeconds($){this.prune();let Z=this.clients.get($)??[],Q=Math.max(Z.length>=this.perClient?Z[Z.length-this.perClient]+this.windowMs:0,this.all.length>=this.perShare?this.all[this.all.length-this.perShare]+this.windowMs:0);return Q?Math.max(1,Math.ceil((Q-this.now())/1000)):0}fail($){let Z=this.now();this.all.push(Z),this.clients.set($,[...this.clients.get($)??[],Z])}prune(){let $=this.now()-this.windowMs;this.all=this.all.filter((Z)=>Z>$);for(let[Z,Q]of this.clients){let X=Q.filter((G)=>G>$);if(X.length)this.clients.set(Z,X);else this.clients.delete(Z)}}}function M7($){let Z=$.headers["cf-connecting-ip"];return typeof Z==="string"&&Z||$.socket.remoteAddress||"unknown"}function f1($,Z,Q=0){let X=F7($);return`<!doctype html><meta charset="utf-8"><meta name="viewport" content="width=device-width">
109
+ <title>${X} — LocalDeck</title>
110
+ <style>body{font:15px/1.5 system-ui;margin:0;display:grid;place-items:center;height:100vh;background:#0f1115;color:#e6e8ef}
111
+ form{background:#171a21;padding:28px;border-radius:12px;width:300px}input{width:100%;box-sizing:border-box;padding:10px;border-radius:8px;border:1px solid #2a2e3a;background:#0f1115;color:inherit;margin:8px 0 14px}
112
+ button{width:100%;padding:10px;border:0;border-radius:8px;background:#5b8cff;color:#fff;font-weight:600}.e{color:#ff7b7b;margin:0 0 8px}</style>
113
+ <form method="post" action="/__localdeck/login"><h2 style="margin:0 0 6px;font-weight:600">${X}</h2>
114
+ <p style="margin:0;opacity:.7">Shared with LocalDeck. Enter the password you were given.</p>
115
+ ${Q?`<p class="e">Too many attempts. Try again in ${Math.ceil(Q/60)} min.</p>`:Z?'<p class="e">Wrong password.</p>':""}
116
+ <input type="password" name="password" autofocus placeholder="Password"><button>Open</button></form>`}function x7($){let Z={};for(let Q of($??"").split(";")){let X=Q.indexOf("=");if(X>0)try{Z[Q.slice(0,X).trim()]=decodeURIComponent(Q.slice(X+1).trim())}catch{}}return Z}function c5($){let Z=(X)=>X.split(";").map((G)=>G.trim()).filter((G)=>G&&G.split("=",1)[0]!==y1).join("; ");if(typeof $.headers.cookie==="string"){let X=Z($.headers.cookie);if(X)$.headers.cookie=X;else delete $.headers.cookie}let Q=[];for(let X=0;X+1<$.rawHeaders.length;X+=2){let G=$.rawHeaders[X],J=G.toLowerCase()==="cookie",V=J?Z($.rawHeaders[X+1]):$.rawHeaders[X+1];if(V||!J)Q.push(G,V)}$.rawHeaders.splice(0,$.rawHeaders.length,...Q)}function n5($,Z){let Q=Buffer.from($),X=Buffer.from(Z);return Q.length===X.length&&b1.timingSafeEqual(Q,X)}class v1{registry;store;shares=new Map;startingPasswords=new Map;pendingStarts=new Map;startControllers=new Map;pendingStops=new Map;cleanupTargets=new Map;shuttingDown=!1;shutdownPromise;cleanupAfterMs;verify;constructor($,Z,Q={}){this.registry=$;this.store=Z;this.cleanupAfterMs=Q.cleanupAfterMs??A7,this.verify=Q.verify??i5}get($){return this.shares.get($)?.info}password($){return this.shares.get($)?.password??this.startingPasswords.get($)}async start($,Z,Q={}){if(this.shuttingDown)throw Error("daemon is shutting down");let X=this.registry.get($);if(!X)throw Error(`unknown service "${$}"`);if(!this.registry.target($))throw Error(`service "${X.name}" is not running`);if(Q.exclusive&&(this.shares.has($)||this.pendingStarts.has($)))throw Error("Service is already shared or sharing is starting; stop it before creating a new share");let G=this.shares.get($);if(G)return Promise.resolve(G.info);if(this.cleanupTargets.has($))throw Error(`previous share cleanup for "${X.name}" is incomplete; stop it before retrying`);let J=this.pendingStarts.get($);if(J)return J;if(Z)this.startingPasswords.set($,Z);let V=new AbortController;this.startControllers.set($,V),this.registry.setShareStartup($,{status:"starting",startedAt:Date.now(),protected:Boolean(Z)});let z=this.startNow($,X.name,Z,V.signal);return this.pendingStarts.set($,z),z.then(()=>{if(this.pendingStarts.get($)===z)this.startingPasswords.delete($),this.pendingStarts.delete($),this.startControllers.delete($)},(Y)=>{if(this.pendingStarts.get($)===z)this.registry.setShareStartup($,V.signal.aborted?void 0:{status:"failed",error:W$(Y).message}),this.startingPasswords.delete($),this.pendingStarts.delete($),this.startControllers.delete($)}),z}async startNow($,Z,Q,X){let G=b1.randomBytes(24).toString("base64url"),J=b1.randomBytes(24).toString("base64url"),V=AbortSignal.timeout(120000),z=new AbortController,Y=AbortSignal.any([X,V,z.signal]),K=await K$();X.throwIfAborted();let N=(R)=>!Q||n5(x7(R.headers.cookie)[y1]??"",G),U=new o5,W,C,D=new Promise((R)=>{C=R}),O=_7.createServer((R,M)=>{if(W&&R.headers.host?.toLowerCase()===W)C();if(R.method==="GET"&&R.url===`/__localdeck/ready/${J}`){M.writeHead(204,{"x-localdeck-ready":J,"cache-control":"no-store"}).end();return}let E=this.registry.target($,"share");if(!E){M.writeHead(503,{"content-type":"text/plain"}).end("LocalDeck: service is not running");return}if(Q&&R.url==="/__localdeck/login"&&R.method==="POST"){let F=M7(R),w=U.retryAfterSeconds(F);if(w){M.writeHead(429,{"content-type":"text/html; charset=utf-8","retry-after":String(w)}).end(f1(Z,!1,w)),R.resume();return}let m="",p=0,k=!1;R.on("data",(g)=>{if(k)return;if(p+=g.length,p>T7)k=!0,m="";else m+=g}),R.on("end",()=>{if(k){M.writeHead(413,{"content-type":"text/plain; charset=utf-8"}).end("LocalDeck: login request is too large");return}let g=new URLSearchParams(m).get("password")??"";if(n5(g,Q)){let D0=this.shares.get($);if(D0)D0.info.visits++,this.registry.setShare($,D0.info);M.writeHead(303,{"set-cookie":`${y1}=${G}; Path=/; HttpOnly; SameSite=Lax; Secure`,location:"/"}).end()}else U.fail(F),M.writeHead(401,{"content-type":"text/html; charset=utf-8"}).end(f1(Z,!0))});return}if(!N(R)){M.writeHead(401,{"content-type":"text/html; charset=utf-8"}).end(f1(Z,!1));return}c5(R),d0(R,M,E,{responseBodies:this.store.responseBodies,onRequest:(F)=>this.store.request(F)})});O.on("upgrade",(R,M,E)=>{let F=this.registry.target($,"share");if(!F||!N(R))return M.destroy();c5(R),i0(R,M,E,F,{responseBodies:this.store.responseBodies,onRequest:(w)=>this.store.request(w)})});let B=new Set;O.on("connection",(R)=>{B.add(R),R.once("close",()=>B.delete(R))}),await new Promise((R,M)=>{O.once("error",M),O.listen(K,"127.0.0.1",R)});let L=process.env.LOCALDECK_CLOUDFLARED??"cloudflared",_=H7(L,["tunnel","--url",`http://127.0.0.1:${K}`,"--no-autoupdate"],{stdio:["ignore","pipe","pipe"]}),H;try{H=await new Promise((E,F)=>{let w=(g,b)=>{if(clearTimeout(p),Y.removeEventListener("abort",m),_.stdout?.off("data",k),_.stderr?.off("data",k),g)F(g);else E(b)},m=()=>w(Y.reason),p=setTimeout(()=>w(new N0("Cloudflare did not provide a tunnel URL within two minutes. Check your connection and try again.")),120000),k=(g)=>{let b=g.toString().match(L7);if(b)w(void 0,b[0])};if(_.stdout?.on("data",k),_.stderr?.on("data",k),_.once("error",(g)=>{w(g.code==="ENOENT"?new N0(`cloudflared is not installed or could not be found. Public HTTPS sharing requires it; local services and Clean URLs still work. ${process.platform==="darwin"?"Install with: brew install cloudflared.":process.platform==="win32"?"Install Cloudflare’s Windows package and ensure cloudflared.exe is on PATH.":"Install cloudflared from Cloudflare’s package repository or a package for your distribution."} Instructions: https://developers.cloudflare.com/tunnel/downloads/ — Check cloudflared --version, then retry. Restart LocalDeck after changing PATH. If LOCALDECK_CLOUDFLARED is set, check that executable path.`):g)}),_.once("exit",(g)=>{w(new N0(`cloudflared exited with code ${g}. Check your Cloudflare tunnel configuration and network connection.`))}),Y.addEventListener("abort",m,{once:!0}),Y.aborted)m()}),W=new URL(H).host;let R=this.registry.get($)?.shareStartup;this.registry.setShareStartup($,{status:"starting",startedAt:R?.status==="starting"?R.startedAt:Date.now(),url:H,protected:Boolean(Q)}),_.stdout?.resume(),_.stderr?.resume(),this.store.log({ts:Date.now(),service:$,stream:"system",source:"share",line:"LocalDeck: tunnel URL allocated; waiting for DNS and public connectivity."});let M=()=>z.abort(new N0("cloudflared exited before the public link became reachable."));_.once("exit",M);try{if(_.exitCode!==null||_.signalCode!==null)M();let E=new AbortController;try{await Promise.race([this.verify(H,J,AbortSignal.any([Y,E.signal])),D])}finally{E.abort()}Y.throwIfAborted()}finally{_.off("exit",M)}}catch(R){if(V.aborted&&!X.aborted)R=new N0("Tunnel did not become live within two minutes. Please try sharing again.");let M=await this.cleanupResources({tunnel:_,gate:O,sockets:B});if(M.length)throw this.cleanupTargets.set($,{tunnel:_,gate:O,sockets:B}),AggregateError([W$(R),...M],`share startup and cleanup failed for ${Z}`);throw R}if(X.aborted||!this.registry.target($)){let R=await this.cleanupResources({tunnel:_,gate:O,sockets:B});if(R.length)throw this.cleanupTargets.set($,{tunnel:_,gate:O,sockets:B}),AggregateError(R,`service "${Z}" stopped while sharing started and cleanup failed`);throw Error(`service "${Z}" stopped while sharing started`)}let T={url:H,provider:"cloudflare",protected:Boolean(Q),startedAt:Date.now(),visits:0},A={info:T,gate:O,gatePort:K,tunnel:_,password:Q,token:G,sockets:B};return this.shares.set($,A),_.on("exit",()=>{if(this.shares.get($)===A)this.stop($,"cloudflared exited").catch(()=>{})}),this.registry.setShare($,T),this.store.log({ts:Date.now(),service:$,stream:"system",source:"share",line:`LocalDeck: sharing ${Z} at ${H}${Q?" (password protected)":" (PUBLIC, no password)"}`}),T}async stop($,Z="stopped by user"){let Q=this.pendingStops.get($);if(Q)return Q;let X=this.stopNow($,Z);return this.pendingStops.set($,X),X.then(()=>{if(this.pendingStops.get($)===X)this.pendingStops.delete($)},()=>{if(this.pendingStops.get($)===X)this.pendingStops.delete($)}),X}async stopNow($,Z){let Q=this.pendingStarts.get($);if(this.startControllers.get($)?.abort(new N0("share startup cancelled")),Q)try{await Q}catch{}let X=this.shares.get($),G=X??this.cleanupTargets.get($);if(!G)return!1;let J=await this.cleanupResources(G);if(J.length){let z=this.registry.get($)?.name??$;throw AggregateError(J,`failed to stop share for ${z}`)}if(this.cleanupTargets.delete($),!X)return!0;this.shares.delete($),this.registry.setShare($,void 0);let V=this.registry.get($)?.name??$;return this.store.log({ts:Date.now(),service:$,stream:"system",source:"share",line:`LocalDeck: share for ${V} ended (${Z})`}),!0}async cleanupResources($){let Z=[];try{let Q=a5($.tunnel,1000);if($.tunnel.kill("SIGTERM"),!await Q){let X=a5($.tunnel,1000);if($.tunnel.kill("SIGKILL"),!await X)Z.push(Error("share tunnel did not exit after forced termination"))}}catch(Q){Z.push(W$(Q))}try{let Q=new Promise((X)=>$.gate.close((G)=>{if(G&&G.code!=="ERR_SERVER_NOT_RUNNING")Z.push(G);X()}));for(let X of $.sockets??[])X.destroy();if($.gate.closeAllConnections?.(),!await P7(Q,this.cleanupAfterMs))Z.push(Error("share gate did not close within the cleanup bound"))}catch(Q){Z.push(W$(Q))}return Z}stopAll(){if(this.shuttingDown=!0,this.shutdownPromise)return this.shutdownPromise;let $=new Set([...this.shares.keys(),...this.pendingStarts.keys(),...this.pendingStops.keys(),...this.cleanupTargets.keys()]),Z=Promise.allSettled([...$].map((Q)=>this.stop(Q,"daemon shutting down"))).then((Q)=>{let X=Q.flatMap((G)=>G.status==="rejected"?[W$(G.reason)]:[]);if(X.length)throw AggregateError(X,"failed to stop all shares")});return this.shutdownPromise=Z,Z.catch(()=>{if(this.shutdownPromise===Z)this.shutdownPromise=void 0}),Z}}function W$($){return $ instanceof Error?$:Error(String($))}function P7($,Z){return new Promise((Q)=>{let X=setTimeout(()=>Q(!1),Z);X.unref(),$.then(()=>{clearTimeout(X),Q(!0)},()=>{clearTimeout(X),Q(!0)})})}function a5($,Z){if($.pid===void 0||$.exitCode!==null||$.signalCode!==null)return Promise.resolve(!0);return new Promise((Q)=>{let X=!1,G=(z)=>{if(X)return;X=!0,clearTimeout(V),$.off("exit",J),$.off("error",J),Q(z)},J=()=>G(!0),V=setTimeout(()=>G(!1),Z);V.unref(),$.once("exit",J),$.once("error",J)})}function u($,Z){return`${$}:${Z}`}import{execFile as E7}from"node:child_process";import{execFile as I7}from"node:child_process";import{promisify as S7}from"node:util";var q7=S7(I7);async function s5($){let{stdout:Z}=await q7("powershell.exe",["-NoLogo","-NoProfile","-NonInteractive","-Command",$],{windowsHide:!0,timeout:1e4,maxBuffer:4194304});return Z}function t5($){let Z=JSON.parse($.replace(/^\uFEFF/,"").trim()||"[]");return(Array.isArray(Z)?Z:[Z]).filter((Q)=>Q!==null&&typeof Q==="object")}var t$=($)=>typeof $==="number"&&Number.isSafeInteger($)&&$>0;async function r5($,Z=s5){let Q=t5(await Z("Get-CimInstance Win32_Process -ErrorAction Stop | Select-Object ProcessId,ParentProcessId | ConvertTo-Json -Compress")),X=new Map;for(let J of Q){if(!t$(J.ProcessId)||!t$(J.ParentProcessId))continue;let V=X.get(J.ParentProcessId)??[];V.push(J.ProcessId),X.set(J.ParentProcessId,V)}let G=new Set([$]);for(let J of G)for(let V of X.get(J)??[])G.add(V);return[...G]}async function e5($,Z=s5){let Q=new Set($),X=t5(await Z("Get-NetTCPConnection -ErrorAction Stop | Where-Object State -eq Listen | Select-Object LocalAddress,LocalPort,OwningProcess | ConvertTo-Json -Compress")),G=[];for(let J of X){if(!t$(J.OwningProcess)||!Q.has(J.OwningProcess)||!t$(J.LocalPort)||J.LocalPort>65535||typeof J.LocalAddress!=="string")continue;let V=J.LocalAddress==="0.0.0.0"||J.LocalAddress==="::"?"*":J.LocalAddress;G.push({pid:J.OwningProcess,port:J.LocalPort,host:V})}return G}import{StringDecoder as w7}from"node:string_decoder";import{promisify as j7}from"node:util";var r$=j7(E7),Q4=new Set([9229,9230,9231,9232,9239,24678,6499]),$4=16384;async function C$($){try{if(process.platform==="win32")return await r5($);let{stdout:Z}=await r$("ps",["-Ao","pid=,ppid="]),Q=new Map;for(let J of Z.split(`
117
+ `)){let[V,z]=J.trim().split(/\s+/).map(Number);if(!V||Number.isNaN(z))continue;(Q.get(z)??Q.set(z,[]).get(z)).push(V)}let X=[],G=(J)=>{X.push(J);for(let V of Q.get(J)??[])G(V)};return G($),X}catch{return[$]}}async function B$($){if(!$.length)return[];if(process.platform==="win32")return e5($).catch(()=>[]);if(process.platform==="linux")try{return await g7($)}catch{}return h7($)}async function h7($){let{stdout:Z}=await r$("lsof",["-nP","-a","-iTCP","-sTCP:LISTEN","-p",$.join(","),"-Fpn"]).catch((G)=>({stdout:G.stdout??""})),Q=[],X=0;for(let G of Z.split(`
118
+ `))if(G.startsWith("p"))X=Number(G.slice(1));else if(G.startsWith("n")){let J=G.slice(1).match(/^(\*|\[[^\]]+\]|[\d.]+):(\d+)$/);if(J)Q.push({pid:X,host:X4(J[1]),port:Number(J[2])})}return Q}async function g7($){let{stdout:Z}=await r$("ss",["-Hltnp"]),Q=new Set($),X=[];for(let G of Z.split(`
119
+ `)){let J=G.trim().split(/\s+/);if(J.length<4)continue;let V=J[3].match(/^(.*):(\d+)$/);if(!V)continue;for(let z of G.matchAll(/pid=(\d+)/g)){let Y=Number(z[1]);if(Q.has(Y))X.push({pid:Y,host:X4(V[1]),port:Number(V[2])})}}return X}function X4($){let Z=$.replace(/^\[|\]$/g,"");return Z==="*"||Z==="0.0.0.0"||Z==="::"||Z===""?"*":Z}function G4($){return $.host==="*"||$.host==="127.0.0.1"||$.host==="::1"}function k1($,Z){let Q;for(let X of $){if(Q4.has(X.port)||!G4(X))continue;if(X.port===Z)return X;if(!Q||X.port<Q.port)Q=X}return Q}function u1($){let Z=$.filter((G)=>!Q4.has(G.port));if(Z.some(G4))return;let Q=Z[0];if(!Q)return;return`the process is listening only on ${Q.host.includes(":")?`[${Q.host}]:${Q.port}`:`${Q.host}:${Q.port}`}, which LocalDeck cannot reach. Bind it to localhost (127.0.0.1) or all interfaces (0.0.0.0) instead.`}function m1($){return $.host==="*"?"127.0.0.1":$.host}function e$($,Z){let Q=new w7("utf8"),X="",G=!1,J=(z,Y=!1)=>{if(!Y&&!z.trim())return;let K=Z4(z,Z);if(K)Z(K)},V=(z)=>{X+=z;let Y=X.split(/\r?\n/);X=Y.pop()??"";for(let K of Y)J(K,G),G=!1;X=Z4(X,(K)=>{Z(K),G=!0})};$.on("data",(z)=>V(typeof z==="string"?z:Q.write(z))),$.on("end",()=>{V(Q.end()),J(X,G),X="",G=!1})}function Z4($,Z){if(Buffer.byteLength($)<=$4)return $;let Q=0,X=0;for(let G=0;G<$.length;){let J=$.codePointAt(G),V=J<=127?1:J<=2047?2:J<=65535?3:4;if(Q+V>$4)Z($.slice(X,G)),X=G,Q=0;Q+=V,G+=J>65535?2:1}return $.slice(X)}async function f7($,Z,Q){await r$($,Z,Q)}async function l1($,Z,Q=process.platform,X=f7){if(!$.pid)return!1;if(Q==="win32"){let G=["/pid",String($.pid),"/t"];if(Z==="SIGKILL")G.push("/f");try{return await X("taskkill.exe",G,{timeout:5000,killSignal:"SIGKILL"}),!0}catch{try{return $.kill(Z)}catch{return!1}}}try{return process.kill(-$.pid,Z)}catch{try{return $.kill(Z)}catch{return!1}}}var b7=/[\u001B\u009B][[\]()#;?]*(?:(?:(?:[a-zA-Z\d]*(?:;[-a-zA-Z\d\/#&.:=?%@~_]*)*)?\u0007)|(?:(?:\d{1,4}(?:;\d{0,4})*)?[\dA-PR-TZcf-ntqry=><~]))/g;function $1($){return $.replace(b7,"")}var m7={".html":"text/html; charset=utf-8",".js":"text/javascript",".css":"text/css",".svg":"image/svg+xml",".json":"application/json",".png":"image/png",".ico":"image/x-icon",".woff":"font/woff",".woff2":"font/woff2"},J4=65536,p1=65536,l7=4096,p7=16384,d7=16384;function x($,Z,Q){$.writeHead(Z,{"content-type":"application/json"}),$.end(JSON.stringify(Q))}class I extends Error{status;constructor($,Z){super(Z);this.status=$}}function n($){return new Promise((Z,Q)=>{let X="",G=0,J=!1;$.on("data",(V)=>{if(J)return;if(G+=V.length,G>J4)J=!0,X="",Q(new I(413,`request body must not exceed ${J4} bytes`));else X+=V}),$.on("end",()=>{if(J)return;try{Z(X?JSON.parse(X):{})}catch{Q(new I(400,"request body must be valid JSON"))}})})}function V4($){let Z=$.searchParams.get("limit");if(Z===null)return 200;let Q=Number(Z);if(!/^\d+$/.test(Z)||!Number.isInteger(Q)||Q<1||Q>5000)throw new I(400,"limit must be an integer between 1 and 5000");return Q}function Y4($){try{return $.split("/").slice(2).map((Z)=>decodeURIComponent(Z))}catch{throw new I(400,"path must use valid URL encoding")}}function K4($){let Z=$.indexOf("?"),Q=Z===-1?$:$.slice(0,Z);if(!Q.startsWith("/"))throw new I(400,"request target must use origin form");return Q}function C4($,Z){let Q=$.headers.authorization;if(!Q?.startsWith("Bearer "))return!1;let X=Buffer.from(Q.slice(7),"utf8"),G=Buffer.from(Z,"utf8");return X.length===G.length&&v7(X,G)}function B4($){if($==="not_found")return 404;if($==="active")return 409;return 422}function i7($){return{ok:$.ok,...$.service?{service:$.service}:{},...$.error?{error:$.error}:{}}}function j($){if($.isShuttingDown())throw new I(503,"daemon is shutting down")}async function z4($,Z){try{let Q=await Z();return x($,Q.ok?200:Q.status??409,i7(Q))}catch(Q){if(Q instanceof I)return x($,Q.status,{ok:!1,error:Q.message});if(Q instanceof q)return x($,B4(Q.code),{ok:!1,error:Q.message});return x($,500,{ok:!1,error:"internal server error"})}}function N4($){return($??"").match(/^([a-z0-9-]+(?:\.[a-z0-9-]+)?)\.localhost(:\d+)?$/i)?.[1]}var _4=new Set(["localhost","127.0.0.1","[::1]"]);function c7($){try{let Z=new URL(`http://${$}`);return Z.host.toLowerCase()===$.toLowerCase()&&_4.has(Z.hostname.toLowerCase())}catch{return!1}}function H4($){try{let Z=new URL($);if(Z.protocol!=="http:"||Z.origin.toLowerCase()!==$.toLowerCase())return;if(Z.username||Z.password||Z.pathname!=="/"||Z.search||Z.hash||!Z.port)return;return Z.origin.toLowerCase()}catch{return}}function n7($){let Z=new Set;for(let Q of $??[]){let X=typeof Q==="string"?H4(Q):void 0;if(!X||!_4.has(new URL(X).hostname.toLowerCase()))throw Error(`invalid browser origin allowlist entry "${String(Q)}"`);Z.add(X)}return Z}function U4($,Z){let Q=$.headers.host??"";if(!c7(Q))return"invalid host";let X=$.headers.origin;if(!X)return;let G=H4(X),J=$.socket.localPort,V=J?new Set([`http://localhost:${J}`,`http://127.0.0.1:${J}`]):new Set;if(!G||!V.has(G)&&!Z.has(G))return"forbidden origin";return}function L4($){let{registry:Z,store:Q,shares:X}=$,G=n7($.allowedBrowserOrigins),J={responseBodies:Q.responseBodies,onRequest:(D)=>Q.request(D)},V=u7(),z=new g1(()=>{let D=Y.address();if(!D||typeof D==="string")throw Error("LocalDeck is not listening.");return D.port},V),Y=y7.createServer(async(D,O)=>{let B=N4(D.headers.host);if(B){let _=Z.resolveHostname(B);if(_.kind==="ambiguous"){O.writeHead(409,{"content-type":"text/plain; charset=utf-8"}).end(`LocalDeck: service name "${B}" is ambiguous; use ${_.alternatives.map((T)=>`${T}.localhost`).join(" or ")}`);return}let H=_.kind==="service"?Z.target(_.key):void 0;if(!H){O.writeHead(404,{"content-type":"text/plain"}).end(`LocalDeck: no running service named "${B}"`);return}return d0(D,O,H,J)}let L=U4(D,G);if(L)return x(O,403,{error:L});try{let _=D.url??"/",H=K4(_),T=new URL(_,"http://localhost");if(H==="/api/forwarder/probe"&&D.method==="GET")return O.writeHead(200,{"content-type":"text/plain","cache-control":"no-store"}),O.end(V);if(H==="/api/forwarder"&&(D.method==="GET"||D.method==="POST"||D.method==="DELETE")){if(O.setHeader("cache-control","no-store"),D.method!=="GET")j($);if(D.method==="DELETE")return x(O,200,await z.uninstall());if(D.method==="POST"){let A=await n(D);if(!A||typeof A!=="object"||Array.isArray(A)||Object.keys(A).some((R)=>!["install","automatic"].includes(R))||A.install!==void 0&&typeof A.install!=="boolean"||A.automatic!==void 0&&typeof A.automatic!=="boolean")throw new I(400,"invalid forwarding options");return x(O,200,await z.enable(A))}return x(O,200,await z.status())}if(H.split("/",3)[1]==="api")return await o7(D,O,T,Y4(H),$);return s7(T.pathname,O,$.dashboardDir)}catch(_){if(_ instanceof I)return x(O,_.status,{error:_.message});if(_ instanceof e)return x(O,422,{error:_.message});if(_ instanceof q)return x(O,B4(_.code),{error:_.message});return x(O,500,{error:"internal server error"})}}),K=new f$.default({noServer:!0}),N=new f$.default({noServer:!0,maxPayload:p1}),U=new Set;Y.on("connection",(D)=>{U.add(D),D.once("close",()=>U.delete(D))});let W=(D)=>{let O=JSON.stringify(D);for(let B of K.clients)if(B.readyState===Z$.default.OPEN)B.send(O)};Q.on("event",W),K.on("connection",(D)=>{D.send(JSON.stringify({type:"snapshot",services:Z.list()}))}),N.on("connection",(D)=>t7(D,$)),Y.on("upgrade",(D,O,B)=>{O.on("error",()=>O.destroy());let L=N4(D.headers.host);if(L){let _=Z.resolveHostname(L);if(_.kind==="ambiguous"){O.end(`HTTP/1.1 409 Conflict\r
120
+ Content-Type: text/plain; charset=utf-8\r
121
+ Connection: close\r
122
+ \r
123
+ LocalDeck: service name "${L}" is ambiguous; use ${_.alternatives.map((T)=>`${T}.localhost`).join(" or ")}`);return}let H=_.kind==="service"?Z.target(_.key):void 0;if(!H)return O.destroy();return i0(D,O,B,H,J)}if(U4(D,G))return O.destroy();try{let _=K4(D.url??"/");if(_.split("/",3)[1]!=="api")return O.destroy();let H=Y4(_);if(H.length===1&&H[0]==="events")K.handleUpgrade(D,O,B,(T)=>K.emit("connection",T,D));else if(H.length===1&&H[0]==="attach"){if(!C4(D,$.controlToken))return a7(O,401,"Unauthorized");N.handleUpgrade(D,O,B,(T)=>N.emit("connection",T,D))}else O.destroy()}catch{O.destroy()}});let C=Y.close.bind(Y);return Y.close=(D)=>{z.close();let O=!1,B=(H)=>{if(O)return;O=!0,D?.(H)},L=()=>{if(U.size===0)B()};for(let H of U)H.once("close",L);let _=C(B);for(let H of K.clients)H.terminate();for(let H of N.clients)H.terminate();for(let H of U)H.destroy();if(U.size===0)queueMicrotask(L);return _},Y}function a7($,Z,Q){$.end(`HTTP/1.1 ${Z} ${Q}\r
124
+ Connection: close\r
125
+ Content-Length: 0\r
126
+ \r
127
+ `)}async function o7($,Z,Q,X,G){let{registry:J,store:V,shares:z,projects:Y,supervisor:K}=G,N=$.method??"GET";if(N==="OPTIONS"){Z.writeHead(204).end();return}if(X.length===1&&X[0]==="status"&&N==="GET")return x(Z,200,{ok:!0,pid:process.pid,version:G.version,startedAt:G.startedAt,services:J.list().length});if(X.length===1&&X[0]==="shutdown"&&N==="POST"){let U=new Promise((C)=>{Z.once("finish",C),Z.once("close",C)}),W=G.shutdown(U);x(Z,200,{ok:!0}),W.catch(()=>{});return}if(await k5($,Z,Q,X,G))return;if(X[0]==="projects"){if(X.length===1&&N==="GET")return x(Z,200,Y.list());if(X.length===2&&X[1]==="remember"&&N==="POST"){if(j(G),!C4($,G.controlToken))throw new I(403,"forbidden");let U=await n($);if(j(G),!U||typeof U!=="object"||Array.isArray(U))throw new I(400,"request body must be a JSON object");let W=U.file;if(typeof W!=="string")throw new I(400,"file must be a string");try{return x(Z,200,Y.remember(W))}catch(C){if(C instanceof q)throw C;throw new q("invalid","project could not be remembered")}}if(X.length>=2&&X[1]!=="remember"){let U=X[1];if(X.length===3&&X[2]==="secrets"&&N==="GET"){let W=_$(Y,U);if(!W.available)throw new q("invalid",W.error??"project configuration is invalid");let C=G.listProjectSecrets??A0,D=W.commands.flatMap((L)=>L.secrets??[]),O=new Set(C(U)),B=[...new Set([...D,...O])].sort();return x(Z,200,{secrets:B.map((L)=>({name:L,configured:O.has(L)}))})}if(X.length===4&&X[2]==="secrets"&&(N==="PUT"||N==="DELETE")){j(G);let W=_$(Y,U);if(!W.available)throw new q("invalid",W.error??"project configuration is invalid");let C=X[3];if(N==="PUT"){let D=await n($);if(!D||typeof D!=="object"||Array.isArray(D)||Object.keys(D).length!==1||typeof D.value!=="string")throw new I(400,'request body must contain only a string "value"');(G.setProjectSecret??D$)(U,C,D.value)}else(G.deleteProjectSecret??O$)(U,C);return x(Z,200,{ok:!0})}if(X.length===3&&X[2]==="nickname"&&N==="PATCH"){j(G);let W=await n($);if(j(G),!W||typeof W!=="object"||Array.isArray(W)||Object.keys(W).length!==1||typeof W.nickname!=="string")throw new I(400,'request body must contain only a string "nickname"');let C=Y.saveConfigNickname(U,W.nickname);return J.refreshProjectUrls(U),x(Z,200,{...C,services:J.list(U)})}if(X.length===3&&X[2]==="diagnostics"&&N==="GET"){let W=Y.details(U),C=J.list(U),D=C.flatMap((L)=>V.logs(L.key,100)).sort((L,_)=>L.ts-_.ts),O=(G.listProjectSecrets??A0)(U),B=Object.values((G.resolveProjectSecrets??z0)(U,O));return x(Z,200,{report:b5(W,C,D,G.version,[G.controlToken,...B])})}if(X.length===3&&X[2]==="profiles"&&N==="GET"){let W=_$(Y,U);if(!W.available)throw new q("invalid",W.error??"project configuration is invalid");return x(Z,200,O4(W))}if(X.length===4&&X[2]==="profiles"&&X[3]==="active"&&N==="PUT"){j(G);let W=await n($);if(j(G),!W||typeof W!=="object"||Array.isArray(W)||Object.keys(W).some((D)=>D!=="profiles"))throw new I(400,'request body must be { "profiles": [...] }');let C=Y.setActiveProfiles(U,W.profiles);return x(Z,200,O4(C))}if(X.length===2&&N==="GET"){let W=Y.details(U);if(!W.available)throw new q("invalid",W.error??"project configuration is invalid");return x(Z,200,{...W,services:J.list(U)})}if(X.length===2&&N==="DELETE"){j(G);let W=new Set(J.list().filter((C)=>C.status!=="stopped").map((C)=>C.key));return Y.forget(U,W),x(Z,200,{ok:!0})}if(X.length===3&&N==="POST"&&(X[2]==="start"||X[2]==="stop")){j(G),await n($),j(G);let W=_$(Y,U);if(X[2]==="start"&&!W.available)throw new q("invalid",W.error??"project configuration is invalid");let C=X[2]==="start"?await K.startAll(U):await K.stopAll(U);return x(Z,200,{ok:C.every((D)=>D.ok),results:C})}if(X.length===5&&X[2]==="services"&&X[4]==="config"&&N==="PATCH"){j(G);let W=await n($);j(G);let C=Y.updateServiceConfig(U,X[3],W);return x(Z,200,{...C,services:J.list(U)})}if(X.length===5&&X[2]==="services"&&X[4]==="dependencies"&&N==="PATCH"){j(G);let W=await n($);if(j(G),!W||typeof W!=="object"||Array.isArray(W))throw new I(400,"request body must be a JSON object");let C=Object.keys(W);if(C.length!==1||C[0]!=="after")throw new I(400,'request body may contain only "after"');let D=W.after;if(!Array.isArray(D)||!D.every((B)=>typeof B==="string"))throw new I(400,"after must be an array of service names");let O=Y.updateDependencies(U,X[3],D);return x(Z,200,{...O,services:J.list(U)})}if(X.length===5&&X[2]==="services"&&N==="POST"&&(X[4]==="start"||X[4]==="stop"||X[4]==="restart"))return z4(Z,async()=>{j(G),await n($),j(G);let W=X[3],C=_$(Y,U),D=u(U,W.toLowerCase());if(X[4]==="stop"){let O=J.get(D);if(!O||O.status==="stopped"){if(!C.available)throw new q("not_found",`Project ${U} has no active service named ${W}`);Y.resolve(U,W)}return K.stop(D)}if(!C.available)throw new q("invalid",C.error??"project configuration is invalid");return Y.resolve(U,W),X[4]==="start"?K.start(U,W):K.restart(U,W)})}}if(X[0]==="services"){if(X.length===1&&N==="GET")return x(Z,200,J.list());let U=X.length===4&&X[2]==="share"&&X[3]==="new"&&N==="POST";if(X.length<2||X.length>3&&!U)return x(Z,404,{error:"not found"});let W=X[1],C=J.resolve(W);if(C.kind==="ambiguous")return x(Z,409,{error:`service name "${W}" is ambiguous`,alternatives:C.alternatives});if(C.kind==="missing")return x(Z,404,{error:`unknown service "${W}"`});let{key:D,service:O}=C,B=X[2];if(B==="response"&&N==="GET"){let L=V.requests(D,5000).find((H)=>H.id===Q.searchParams.get("requestId"));if(!L)throw new I(404,"Recorded request is no longer available");let _=L.responseBodyId?V.responseBodies.get(L.responseBodyId,D):void 0;if(!_)throw new I(404,"Full response is no longer cached. Make a new request through the LocalDeck URL. The cache holds up to 64 MiB and resets when the daemon restarts.");return Z.setHeader("cache-control","no-store"),x(Z,200,_)}if(B==="replay"&&N==="POST"){j(G);let L=await n($);if(j(G),!L||typeof L!=="object"||Array.isArray(L)||Object.keys(L).length!==1||typeof L.requestId!=="string")throw new I(400,"Provide only a recorded requestId");let _=V.requests(D,5000).find((H)=>H.id===L.requestId);if(!_)throw new I(404,"Recorded request is no longer available");try{return x(Z,200,await p$(O,_))}catch(H){throw new I(422,H instanceof Error?H.message:"Replay failed")}}if(!B&&N==="GET")return x(Z,200,O);if((B==="logs"||B==="requests")&&N==="DELETE")return j(G),x(Z,200,await V.clearHistory(D,B));if((B==="logs"||B==="requests")&&N==="GET"){let L=V.historyBoundary(D,B);if(L)Z.setHeader("x-localdeck-history-boundary",L)}if(B==="logs"&&N==="GET")return x(Z,200,V.logs(D,V4(Q)));if(B==="requests"&&N==="GET")return x(Z,200,V.requests(D,V4(Q)));if(B==="stop"&&N==="POST")return z4(Z,async()=>{return j(G),K.stop(D)});if(B==="share-password"&&N==="POST")return j(G),Z.setHeader("cache-control","no-store"),x(Z,200,{password:z.password(D)??null});if(B==="share"){if(N==="GET")return x(Z,200,z.get(D)??null);if(N==="POST"){if(j(G),O.serviceType&&O.serviceType!=="http")throw new I(422,"Database endpoints cannot be shared over HTTP");let L=await n($);if(j(G),!L||typeof L!=="object"||Array.isArray(L))throw new I(400,"request body must be a JSON object");let{password:_,public:H}=L;if(_!==void 0&&typeof _!=="string")throw new I(400,"password must be a string");if(H!==void 0&&typeof H!=="boolean")throw new I(400,"public must be a boolean");if(H&&_)throw new I(400,"a public link cannot have a password");let T=H?void 0:_||k7(12).toString("base64url");try{return x(Z,200,await z.start(D,T,{exclusive:U}))}catch(A){if(A instanceof N0)return x(Z,503,{error:A.message});return x(Z,500,{error:"Sharing failed. Check that the service is running and try again."})}}if(N==="DELETE")return j(G),x(Z,200,{ok:await z.stop(D)})}}x(Z,404,{error:"not found"})}function _$($,Z){return $.details(Z)}function s7($,Z,Q){if(!Q){Z.writeHead(200,{"content-type":"text/html; charset=utf-8"}),Z.end("<h1>LocalDeck daemon</h1><p>Dashboard not built. Run <code>bun run build</code> in the repo. API is at <a href=/api/services>/api/services</a>.</p>");return}let X=U0.join(Q,U0.normalize($).replace(/^(\.\.[/\\])+/,""));if(!X.startsWith(Q))X=U0.join(Q,"index.html");if(!Z1.existsSync(X)||Z1.statSync(X).isDirectory())X=U0.join(Q,"index.html");let G=U0.dirname(X)===U0.join(Q,"assets")&&/-[A-Za-z0-9_-]{8,}\.[a-z0-9]+$/i.test(U0.basename(X));Z.writeHead(200,{"content-type":m7[U0.extname(X)]??"application/octet-stream","cache-control":G?"public, max-age=31536000, immutable":"no-cache","x-frame-options":"DENY","content-security-policy":"frame-ancestors 'none'","x-content-type-options":"nosniff"}),Z1.createReadStream(X).pipe(Z)}function t7($,Z){let{registry:Q,store:X}=Z,G,J=!1,V=!1,z=!1,Y=(C)=>$.readyState===Z$.default.OPEN&&$.send(JSON.stringify(C)),K=Z.trackAttachOperation??((C)=>C),N=async()=>{let C=G;if(!C)return;G=void 0;try{await Z.shares.stop(C,"terminal service disconnected")}catch(D){X.log({ts:Date.now(),service:C,stream:"system",line:`LocalDeck: share cleanup failed: ${D instanceof Error?D.message:String(D)}; stop the share before starting this service again`})}finally{await Q.unregister(C)}},U=(C)=>{Y({type:"error",message:C}),$.close()},W=()=>{J=!0,K(N()).catch(()=>{})};$.on("error",W),$.on("message",(C)=>{let D=Promise.resolve().then(async()=>{let O;try{O=r7(C)}catch(B){U(B instanceof Error?B.message:"invalid attach frame");return}try{if(O.type==="register"){if(V){U("registration has already been attempted");return}if(V=!0,Z.isShuttingDown?.()||J){Y({type:"error",message:"daemon is shutting down"}),$.close();return}let B=await Q.register(Z6(O,Z),()=>Y({type:"stop"}));if(G=B.key,Z.isShuttingDown?.()||J){await N(),Y({type:"error",message:"daemon is shutting down"}),$.close();return}z=!0,Y({type:"registered",service:B})}else if(!z||!G)U("register must be the first attach frame");else if(O.type==="log")X.log({ts:Date.now(),service:G,stream:O.stream,line:O.line});else if(O.type==="pid")Q.setPid(G,O.pid);else if(O.type==="readiness")Q.setReadiness(G,O.status,O.message);else if(O.type==="upstream"){let B=Z.verifyAttachedUpstream??((_,H,T)=>Q6(Q,_,H,T)),L=G;try{if(!await B(L,O.port,O.host)){Y({type:"error",message:"reported upstream is not owned by the attached process; report ignored, retrying detection"});return}if(!J&&G===L)Q.setUpstream(L,O.port,O.host)}catch(_){Y({type:"error",message:`upstream report ignored: ${_ instanceof Error?_.message:String(_)}; retrying detection`})}}}catch(B){Y({type:"error",message:B?.message??String(B)}),$.close()}});K(D).catch(()=>{})}),$.on("close",W)}function r7($){let Z=e7($);if(Z.length>p1)throw Error(`attach frame must not exceed ${p1} bytes`);let Q;try{Q=JSON.parse(Z.toString("utf8"))}catch{throw Error("attach frame must be valid JSON")}if(!Q||typeof Q!=="object"||Array.isArray(Q))throw Error("attach frame must be a JSON object");let X=Q;if(typeof X.type!=="string")throw Error("attach frame type must be a string");if(X.type==="register"){if(L$(X.name,"service name",41),L$(X.cwd,"cwd",l7),L$(X.command,"command",p7),H$(X.key,"service key",256),H$(X.projectId,"project ID",64),H$(X.projectName,"project name",256),H$(X.projectSlug,"project slug",256),$6(X.stablePort,"stable"),d1(X.upstreamPort,"upstream"),X.upstreamSource!==void 0&&X.upstreamSource!=="assigned"&&X.upstreamSource!=="manual")throw Error("upstreamSource must be assigned or manual");if(D4(X.pid),X.profiles!==void 0&&(!Array.isArray(X.profiles)||X.profiles.length>64||!X.profiles.every((G)=>typeof G==="string"&&/^[a-z0-9][a-z0-9_-]{0,40}$/.test(G))))throw Error("profiles must be an array of profile names");return X}if(X.type==="log"){if(X.stream!=="stdout"&&X.stream!=="stderr")throw Error("log stream must be stdout or stderr");return L$(X.line,"log line",d7),X}if(X.type==="pid")return D4(X.pid,!0),X;if(X.type==="readiness"){if(!["checking","ready","failed"].includes(X.status))throw Error("invalid readiness status");return H$(X.message,"readiness message",2000),X}if(X.type==="upstream"){if(d1(X.port,"upstream"),X.host!==void 0&&X.host!=="127.0.0.1"&&X.host!=="::1")throw Error("upstream host must be loopback");return X}throw Error("unknown attach frame type")}function e7($){if(Buffer.isBuffer($))return $;if($ instanceof ArrayBuffer)return Buffer.from($);if(Array.isArray($)&&$.every(Buffer.isBuffer))return Buffer.concat($);throw Error("attach frame must be text or binary data")}function L$($,Z,Q){if(typeof $!=="string")throw Error(`${Z} must be a string`);if($.length>Q)throw Error(`${Z} is too long`)}function H$($,Z,Q){if($!==void 0)L$($,Z,Q)}function d1($,Z){if(!Number.isInteger($)||$<1||$>65535)throw Error(`${Z} port must be an integer between 1 and 65535`)}function $6($,Z){if($!==void 0)d1($,Z)}function D4($,Z=!1){if($===void 0&&!Z)return;if(!Number.isInteger($)||$<1||$>2147483647)throw Error("pid must be a positive integer")}function Z6($,Z){let Q=$.name.toLowerCase(),X=typeof $.key==="string"&&$.key.includes(":")?$.key.slice(0,$.key.lastIndexOf(":")):void 0;if($.projectId!==void 0&&X!==void 0&&$.projectId!==X)throw Error("service key and project ID do not match");let G=$.projectId??X??"standalone";if(G==="standalone")return W4($.cwd),{key:u("standalone",Q),projectId:"standalone",projectName:"standalone",projectSlug:"standalone",name:Q,managedBy:"terminal",stablePort:$.stablePort,upstreamPort:$.upstreamPort,upstreamSource:$.upstreamSource??"assigned",cwd:$.cwd,command:$.command,pid:$.pid};let J=Z.projects.details(G,$.profiles);if(!J.available)throw new q("invalid",J.error??"project configuration is invalid");let V=Z.projects.resolve(G,Q,$.profiles);if(V.serviceType&&V.serviceType!=="http"&&($.upstreamPort!==V.upstream||$.stablePort!==void 0))throw Error("database registration must use its configured published upstream port");let z=V.cwd?U0.resolve(J.directory,V.cwd):J.directory;return W4(z),{key:u(J.id,V.name),projectId:J.id,projectName:J.name,projectSlug:J.slug,name:V.name,serviceType:V.serviceType,managedBy:"terminal",stablePort:$.stablePort??V.port,upstreamPort:$.upstreamPort,upstreamSource:$.upstreamSource??(V.upstream===void 0?"assigned":"manual"),cwd:z,command:V.run,pid:$.pid,...J.activeProfiles?.length?{profiles:J.activeProfiles}:{},configFingerprint:P0(V)}}function O4($){return{profiles:$.profiles??[],active:$.activeProfiles??[],clashes:$.profileClashes??[],...$.profileError?{error:$.profileError}:{},...$.legacyProfiles?{legacyProfiles:$.legacyProfiles}:{}}}function W4($){try{if(!Z1.statSync($).isDirectory())throw Error("not a directory")}catch{throw Error(`working directory does not exist or is not a directory: ${$}`)}}async function Q6($,Z,Q,X){let G=$.get(Z)?.pid;if(!G)return!1;let J=new Set(await C$(G));return(await B$([...J])).some((z)=>J.has(z.pid)&&z.port===Q&&(X===void 0||z.host==="*"||z.host===X))}import X6 from"node:http";import G6 from"node:net";var J6=/^[a-z0-9][a-z0-9_-]{0,40}$/i,V6=/^[a-f0-9]{16}$/,Y6=/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/,K6=/^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?$/,z6="0123456789abcdefghijklmnopqrstuvwxyz-_",T4="x-",n1=63;function i1($,Z){if(!Number.isInteger($)||$<1||$>65535)throw Error(`${Z} port must be an integer between 1 and 65535`)}function N6($){if($.serviceType!==void 0&&!["http","postgres","redis","compose"].includes($.serviceType))throw Error("invalid service type");if($.serviceType&&$.serviceType!=="http"&&$.stablePort!==void 0)throw Error("database endpoints use upstream, not an HTTP proxy port");if(typeof $.name!=="string")throw Error("service name must be a string");if($.key!==void 0&&typeof $.key!=="string")throw Error("service key must be a string");if($.projectId!==void 0&&typeof $.projectId!=="string")throw Error("project ID must be a string");if($.projectName!==void 0&&typeof $.projectName!=="string")throw Error("project name must be a string");if($.projectSlug!==void 0&&typeof $.projectSlug!=="string")throw Error("project slug must be a string");if($.managedBy!==void 0&&$.managedBy!=="terminal"&&$.managedBy!=="daemon")throw Error("managedBy must be terminal or daemon");if(typeof $.cwd!=="string")throw Error("cwd must be a string");if(typeof $.command!=="string")throw Error("command must be a string");if($.upstreamSource!==void 0&&$.upstreamSource!=="assigned"&&$.upstreamSource!=="manual")throw Error("upstreamSource must be assigned or manual");if($.pid!==void 0&&(!Number.isInteger($.pid)||$.pid<1))throw Error("pid must be a positive integer")}function A4($){if($==="standalone")return"standalone";return BigInt(`0x${$}`).toString(36).padStart(13,"0")}function T$($){if(K6.test($)&&!$.startsWith(T4))return $;let Z=1n;for(let Q of $)Z=Z*38n+BigInt(z6.indexOf(Q));return`${T4}${Z.toString(36)}`}function c0($){let Z=T$($.name),Q=A4($.projectId),X=n1-Z.length-Q.length-5,G=$.projectSlug.slice(0,X);return`${Z}--${G}--p${Q}`}function c1($){let Z=`--p${A4($.projectId)}`;return`${$.projectSlug.length<=n1?$.projectSlug:`${$.projectSlug.slice(0,n1-Z.length)}${Z}`}.${T$($.name)}`}class a1{store;apiPort;nicknameForProject;entries=new Map;registrationQueue=Promise.resolve();constructor($,Z,Q=()=>{return}){this.store=$;this.apiPort=Z;this.nicknameForProject=Q}list($){return[...this.entries.values()].filter((Z)=>$===void 0||Z.info.projectId===$).map((Z)=>Z.info)}get($){return this.entries.get($)?.info}setReadiness($,Z,Q){let X=this.get($);if(!X||X.status==="stopped")return;X.readinessStatus=Z,X.readinessMessage=Q,this.store.emitEvent({type:"service",service:X})}resolve($){let Z=this.entries.get($);if(Z)return{kind:"service",key:Z.info.key,service:Z.info};let Q=$.toLowerCase(),X=this.findQualified(Q);if(X)return{kind:"service",key:X.info.key,service:X.info};return this.resolveMatches(Q,!0)}resolveHostname($){let Z=$.toLowerCase(),Q=[...this.entries.values()].find((G)=>G.info.status!=="stopped"&&c0(G.info)===Z);if(Q)return{kind:"service",key:Q.info.key,service:Q.info};let X=[...this.entries.values()].filter((G)=>G.info.status!=="stopped"&&(c1(G.info)===Z||this.nicknameHostname(G.info)===Z));if(X.length===1)return{kind:"service",key:X[0].info.key,service:X[0].info};if(X.length>1)return{kind:"ambiguous",alternatives:X.map((G)=>c0(G.info)).sort()};return this.resolveMatches(Z,!1)}findQualified($){return[...this.entries.values()].find((Z)=>Z.info.status!=="stopped"&&c0(Z.info)===$)}resolveMatches($,Z){let Q=[...this.entries.values()].filter((X)=>X.info.status!=="stopped"&&(T$(X.info.name)===$||Z&&X.info.name===$));if(Q.length===1){let X=Q[0].info;return{kind:"service",key:X.key,service:X}}if(Q.length>1)return{kind:"ambiguous",alternatives:Q.map((G)=>c0(G.info)).sort()};return{kind:"missing"}}target($,Z="local"){let Q=this.entries.get($);if(!Q||Q.info.status==="stopped"||Q.info.serviceType&&Q.info.serviceType!=="http")return;return{service:Q.info.key,upstreamPort:Q.info.upstreamPort,upstreamHost:Q.info.upstreamHost,upstreamReady:Q.info.upstreamReady,via:Z}}takenPorts(){let $=new Set([this.apiPort]);for(let Z of this.entries.values())if(Z.info.status!=="stopped")$.add(Z.info.stablePort);return $}async register($,Z){let Q,X=this.registrationQueue;this.registrationQueue=new Promise((G)=>{Q=G}),await X;try{return await this.registerNow($,Z)}finally{Q()}}async registerNow($,Z){N6($);let Q=$.name.toLowerCase();if(!J6.test(Q))throw Error(`invalid service name "${$.name}" (letters, digits, - and _ only)`);let X=$.key?.slice(0,$.key.lastIndexOf(":")),G=$.projectId??X??"standalone";if(G!=="standalone"&&!V6.test(G))throw Error("project ID must be standalone or 16 lowercase hexadecimal characters");let J=$.key??u(G,Q);if(J!==u(G,Q))throw Error(`service key "${J}" does not match project "${G}" and service "${Q}"`);let V=$.projectName??(G==="standalone"?"standalone":G),z=($.projectSlug??(G==="standalone"?"standalone":G)).toLowerCase();if(!Y6.test(z))throw Error("project slug must contain only lowercase letters, digits, and interior hyphens");let Y=$.managedBy??"terminal";if(i1($.upstreamPort,"upstream"),$.stablePort!==void 0)i1($.stablePort,"stable");let K=this.entries.get(J);if(K&&K.info.status!=="stopped")throw Error(`service "${Q}" is already running (pid ${K.info.pid??"?"})`);if(K?.info.share)throw Error(`previous share cleanup for "${Q}" is incomplete; stop the share before starting this service again`);if(($.upstreamSource??"manual")==="assigned"&&[...this.entries.values()].some((D)=>D.info.status!=="stopped"&&D.info.upstreamSource==="assigned"&&D.info.upstreamPort===$.upstreamPort))throw Error(`assigned upstream port ${$.upstreamPort} is already reserved by another LocalDeck service`);let N=$.stablePort,U=$.serviceType!==void 0&&$.serviceType!=="http";if(U)N=$.upstreamPort;else if(N!==void 0){if(this.takenPorts().has(N))throw Error(`port ${N} is already used by another LocalDeck service`);if(!await Y$(N))throw Error(`port ${N} is already in use by something outside LocalDeck`)}else N=await M5(J,this.takenPorts());this.store.resetStats(J);let W={key:J,projectId:G,projectName:V,projectSlug:z,name:Q,managedBy:Y,...$.serviceType?{serviceType:$.serviceType}:{},stablePort:N,upstreamPort:$.upstreamPort,upstreamHost:"127.0.0.1",upstreamSource:$.upstreamSource??"manual",status:"starting",pid:$.pid,cwd:$.cwd,command:$.command,...$.profiles?.length?{profiles:[...$.profiles]}:{},...$.configFingerprint?{configFingerprint:$.configFingerprint}:{},startedAt:Date.now(),upstreamReady:!1,urls:[`http://localhost:${N}`,`http://${c1({name:Q,projectSlug:z,projectId:G})}.localhost:${this.apiPort}`,`http://${c0({name:Q,projectSlug:z,projectId:G})}.localhost:${this.apiPort}`],stats:this.store.stats(J)},C={info:W,requestStop:Z,upstreamOwnershipVerified:W.upstreamSource!=="assigned"};this.entries.set(J,C);try{if(U)return W.urls=[],this.store.log({ts:Date.now(),service:J,stream:"system",line:`LocalDeck: ${Q} uses published database port ${$.upstreamPort}; HTTP proxy and sharing are unavailable`}),this.startHealthPolling(C),this.store.emitEvent({type:"service",service:W}),W;C.server=X6.createServer((O,B)=>{let L=this.target(J);if(!L){B.writeHead(503).end("LocalDeck: service stopped");return}d0(O,B,L,{responseBodies:this.store.responseBodies,onRequest:(_)=>this.store.request(_)})}),C.sockets=new Set,C.server.on("connection",(O)=>{C.sockets.add(O),O.once("close",()=>C.sockets?.delete(O))}),C.server.on("upgrade",(O,B,L)=>{let _=this.target(J);if(!_)return B.destroy();i0(O,B,L,_,{responseBodies:this.store.responseBodies,onRequest:(H)=>this.store.request(H)})}),await new Promise((O,B)=>{C.server.once("error",B),C.server.listen(N,"127.0.0.1",()=>{C.server.off("error",B),O()})}),C.server.on("error",(O)=>this.store.log({ts:Date.now(),service:J,stream:"system",line:`LocalDeck: proxy listener error: ${O.message}`})),R5(J,N),this.store.log({ts:Date.now(),service:J,stream:"system",line:`LocalDeck: ${Q} on http://localhost:${N} → waiting for the process to open a port (assigned PORT=${$.upstreamPort})`}),this.startHealthPolling(C);let D=new Set(this.refreshUrls(Q));D.add(C);for(let O of D)this.store.emitEvent({type:"service",service:O.info});return W}catch(D){if(C.info.status="stopped",C.healthTimer)clearTimeout(C.healthTimer);for(let O of C.sockets??[])O.destroy();if(C.server?.listening)await new Promise((O)=>C.server.close(()=>O()));if(this.entries.get(J)===C){if(K)this.entries.set(J,K);else this.entries.delete(J);this.refreshUrls(Q)}throw D}}startHealthPolling($){let Z=$.detectedHost?[$.detectedHost]:["127.0.0.1","::1"],Q=($.healthGeneration??0)+1;$.healthGeneration=Q;let X=0,G=()=>{if($.info.status==="stopped"||$.healthGeneration!==Q)return;if(!$.upstreamOwnershipVerified){$.healthTimer=setTimeout(G,400),$.healthTimer.unref();return}let J=$.info.upstreamReady?$.info.upstreamHost:Z[X++%Z.length],V=G6.connect({port:$.info.upstreamPort,host:J}),z=(Y)=>{if(V.destroy(),$.info.status==="stopped"||$.healthGeneration!==Q)return;if(!Y&&!$.info.upstreamReady&&X%Z.length!==0)return void($.healthTimer=setTimeout(G,100));let K=Y!==$.info.upstreamReady;if($.info.upstreamReady=Y,Y)$.info.upstreamHost=J;if(Y&&$.info.status==="starting")$.info.status="running";if(K)this.store.log({ts:Date.now(),service:$.info.key,stream:"system",line:Y?`upstream ready on ${J}:${$.info.upstreamPort}`:`upstream on ${$.info.upstreamHost}:${$.info.upstreamPort} stopped answering`}),this.store.emitEvent({type:"service",service:$.info});$.healthTimer=setTimeout(G,Y?3000:400)};V.once("connect",()=>z(!0)),V.once("error",()=>z(!1))};G()}setUpstream($,Z,Q){let X=this.entries.get($);if(!X||X.info.status==="stopped")return;if(i1(Z,"upstream"),Q!==void 0&&Q!=="127.0.0.1"&&Q!=="::1")throw Error("upstream host must be 127.0.0.1 or ::1");let G=X.info.upstreamPort!==Z||Boolean(Q&&X.info.upstreamHost!==Q);if(X.info.upstreamPort=Z,X.detectedHost=Q,Q)X.info.upstreamHost=Q;if(X.info.upstreamSource="detected",X.upstreamOwnershipVerified=!0,X.info.upstreamReady=!1,X.healthTimer)clearTimeout(X.healthTimer);if(G)this.store.log({ts:Date.now(),service:X.info.key,stream:"system",line:`detected process listening on ${Q??"localhost"}:${Z} — proxying there`});this.startHealthPolling(X),this.store.emitEvent({type:"service",service:X.info})}setPid($,Z){let Q=this.entries.get($);if(!Q)return;if(Q.info.pid!==void 0&&Q.info.pid!==Z){if(Q.info.upstreamReady=!1,Q.info.status="starting",Q.upstreamOwnershipVerified=Q.info.upstreamSource==="manual",Q.healthTimer)clearTimeout(Q.healthTimer);this.startHealthPolling(Q)}Q.info.pid=Z,this.store.emitEvent({type:"service",service:Q.info})}requestStop($){let Z=this.entries.get($);if(!Z||Z.info.status==="stopped"||!Z.requestStop)return!1;return Z.requestStop(),!0}async unregister($){let Z=this.entries.get($);if(!Z||Z.info.status==="stopped")return;if(Z.info.status="stopped",Z.info.stoppedAt=Date.now(),Z.info.upstreamReady=!1,Z.info.pid=void 0,Z.healthTimer)clearTimeout(Z.healthTimer);for(let X of Z.sockets??[])X.destroy();await new Promise((X)=>Z.server?Z.server.close(()=>X()):X()),Z.server=void 0,Z.sockets=void 0,Z.requestStop=void 0,this.store.log({ts:Date.now(),service:Z.info.key,stream:"system",line:`LocalDeck: ${Z.info.name} stopped, released port ${Z.info.stablePort}`});let Q=new Set(this.refreshUrls(Z.info.name));Q.add(Z);for(let X of Q)this.store.emitEvent({type:"service",service:X.info})}setShare($,Z){let Q=this.entries.get($);if(!Q)return;Q.info.share=Z,Q.info.shareStartup=void 0,this.store.emitEvent({type:"service",service:Q.info})}setShareStartup($,Z){let Q=this.entries.get($);if(!Q)return;Q.info.shareStartup=Z,this.store.emitEvent({type:"service",service:Q.info})}async closeAll(){for(let $ of this.entries.keys())await this.unregister($)}refreshProjectUrls($){for(let Z of new Set(this.list($).map((Q)=>Q.name)))for(let Q of this.refreshUrls(Z))this.store.emitEvent({type:"service",service:Q.info})}nicknameHostname($){let Z=this.nicknameForProject($.projectId);return Z?`${Z}.${T$($.name)}`:void 0}refreshUrls($){let Z=[...this.entries.values()].filter((X)=>X.info.name===$&&X.info.status!=="stopped"),Q=[];for(let X of this.entries.values()){if(X.info.name!==$)continue;if(X.info.serviceType&&X.info.serviceType!=="http"){X.info.urls=[];continue}let G=[`http://localhost:${X.info.stablePort}`,`http://${c1(X.info)}.localhost:${this.apiPort}`,`http://${c0(X.info)}.localhost:${this.apiPort}`],J=this.nicknameHostname(X.info);if(J)G.unshift(`http://${J}.localhost:${this.apiPort}`);else if(X.info.status!=="stopped"&&Z.length===1)G.unshift(`http://${T$(X.info.name)}.localhost:${this.apiPort}`);if(X.info.urls.length!==G.length||X.info.urls.some((V,z)=>V!==G[z]))Q.push(X);X.info.urls=G}return Q}}import f from"node:fs";import R4 from"node:fs";import U6 from"node:path";import{randomUUID as D6,createHash as q4}from"node:crypto";function n0($,Z){if($.startsWith("legacy-"))return!1;let[Q,X]=$.split("-").map((V)=>Number.parseInt(V,36)),[G,J]=Z.split("-").map((V)=>Number.parseInt(V,36));return Q>G||Q===G&&X>J}var O6=/\b(error|exception|unhandled|fatal|EADDRINUSE|ECONNREFUSED)\b/i,F4=2000,M4=50;function x4($,Z){if($.ts!==Z.ts)return $.ts-Z.ts;if($.id===Z.id)return 0;return n0($.id,Z.id)?1:n0(Z.id,$.id)?-1:$.id.localeCompare(Z.id)}function P4($,Z){let Q=$.replace(/([?&])([^=&#\s]+)=([^&#\s]*)/g,(X,G,J,V)=>{let Y=[...new URLSearchParams(`${J}=${V}`)][0];if(Y&&/password|passwd|secret|token|api[_-]?key|credential|session|signature|authorization|cookie/i.test(Y[0]))return`${G}${J}=[REDACTED]`;if(Y&&Z.some((K)=>K&&Y[1].includes(K)))return`${G}${J}=[REDACTED]`;return X});return U$(Q,Z.flatMap((X)=>[X,encodeURIComponent(X)]))}function I4($){return $.length<=300?$:`${$.slice(0,230)}… [${q4("sha256").update($).digest("hex")}]`}function W6($){if(!$||typeof $!=="object")return!1;let Z=$;return typeof Z.id==="string"&&Number.isFinite(Z.ts)&&typeof Z.service==="string"&&Z.service.includes(":")&&["lifecycle","clear"].includes(Z.kind)&&["info","error"].includes(Z.severity)&&typeof Z.title==="string"&&Z.title.length<=2000&&(Z.kind!=="lifecycle"||!!Z.transition&&typeof Z.transition.status==="string")}function C6($){if(!$||typeof $!=="object")return!1;let Z=$,Q=Z.before,X=Z.coverage;return typeof Z.id==="string"&&typeof Z.projectId==="string"&&Array.isArray(Z.services)&&Z.services.length>0&&Z.services.length<=100&&Z.services.every((G)=>typeof G==="string"&&G.startsWith(`${Z.projectId}:`))&&typeof Z.label==="string"&&Z.label.length<=100&&Number.isFinite(Z.ts)&&typeof Z.boundary==="string"&&!!Q&&[Q.from,Q.to,Q.requests,Q.requestErrors,Q.errorLines,Q.restarts].every(Number.isFinite)&&(Q.errorRate===null||Number.isFinite(Q.errorRate))&&typeof Q.truncated==="boolean"&&Array.isArray(Q.signatures)&&Q.signatures.length<=100&&Q.signatures.every((G)=>typeof G==="string"&&G.length<=300)&&Array.isArray(Q.routes)&&Q.routes.length<=100&&Q.routes.every((G)=>G&&typeof G.route==="string"&&G.route.length<=300&&[G.count,G.errors,G.avgLatencyMs].every(Number.isFinite))&&!!X&&typeof X.partial==="boolean"&&Array.isArray(X.reasons)&&X.reasons.every((G)=>typeof G==="string")}function S4($,Z,Q,X=[]){let G=new Set,J=new Map,V=0,z=0,Y=0,K=0,N=!1;for(let U of $)if(U.kind==="request"&&U.request){if(V++,U.severity==="error")z++;let W=P4(`${U.request.method} ${U.request.path}`,X),C=I4(W);if(W.length>300)N=!0;if(U.severity==="error")if(G.size<100)G.add(C);else N=!0;if(!J.has(C)&&J.size<100)J.set(C,{route:C,count:0,errors:0,total:0});let D=J.get(C);if(D)D.count++,D.errors+=Number(U.severity==="error"),D.total+=U.request.durationMs;else N=!0}else if(U.kind==="log"&&U.severity==="error"){Y++;let W=P4(U.title,X),C=I4(W);if(W.length>300)N=!0;if(G.size<100)G.add(C);else N=!0}else if(U.kind==="lifecycle"&&U.title==="Service restarted")K++;return{from:Z,to:Q,requests:V,requestErrors:z,errorRate:V?z/V:null,errorLines:Y,restarts:K,signatures:[...G],routes:[...J.values()].map(({total:U,...W})=>({...W,avgLatencyMs:Math.round(U/W.count)})),truncated:N}}class o1{store;data;persistenceFailed=!1;file;constructor($,Z){this.store=$;this.file=U6.join(Z,"activity.json"),this.data={version:1,events:[],markers:[],startedAt:Date.now()};try{if(R4.statSync(this.file).size>16777216)throw Error("Activity history too large");let Q=JSON.parse(R4.readFileSync(this.file,"utf8"));if(Q.version!==1||!Array.isArray(Q.events)||!Array.isArray(Q.markers)||!Number.isFinite(Q.startedAt))throw Error("Invalid activity history");let X=Q.events.filter(W6),G=Q.markers.filter(C6);if(X.length!==Q.events.length||G.length!==Q.markers.length)this.persistenceFailed=!0;this.data={...Q,events:X.slice(-F4),markers:G.slice(-M4)}}catch(Q){if(Q.code!=="ENOENT")this.persistenceFailed=!0}}persist($=!1){try{K0(this.file,this.data)}catch(Z){if(this.persistenceFailed=!0,$)throw Error("Could not save baseline history")}}capture($){let Z;if($.type==="service"){let Q=$.service,X={status:Q.status,readiness:Q.readinessStatus,ready:Q.upstreamReady,startedAt:Q.startedAt},G=[...this.data.events].reverse().find((V)=>V.service===Q.key&&V.kind==="lifecycle");if(G&&JSON.stringify(G.transition)===JSON.stringify(X))return;let J=!!G?.transition?.startedAt&&G.transition.startedAt!==Q.startedAt&&(Q.status==="starting"||Q.status==="running");Z={id:$.eventId,ts:Date.now(),service:Q.key,kind:"lifecycle",severity:Q.readinessStatus==="failed"?"error":"info",title:J?"Service restarted":Q.readinessStatus==="failed"?"Readiness failed":Q.status==="running"&&Q.upstreamReady?"Service ready":`Service ${Q.status}`,transition:X}}else if($.type==="service:removed")Z={id:$.eventId,ts:Date.now(),service:$.name,kind:"lifecycle",severity:"info",title:"Service removed",transition:{status:"removed"}};else if($.type==="history:cleared")Z={id:$.eventId,ts:Date.now(),service:$.service,kind:"clear",severity:"info",title:`${$.kind==="logs"?"Logs":"Requests"} cleared`};if(!Z)return;if(this.data.events.push(Z),this.data.events.length>F4)this.data.droppedBefore=this.data.events.shift().ts;this.persist()}scope($,Z){if(!$||!Z.length||Z.length>100||Z.some((Q)=>!Q.startsWith(`${$}:`)))throw Error("Select 1–100 services belonging to this project")}records($,Z){this.scope($,Z);let Q=new Set(Z),X=this.data.events.filter((G)=>Q.has(G.service));for(let G of Q){for(let J of this.store.logs(G,2000))X.push({id:J.id,ts:J.ts,service:G,kind:"log",severity:J.stream==="stderr"||O6.test(J.line)?"error":"info",title:J.line.slice(0,2000)});for(let J of this.store.requests(G,5000))X.push({id:J.id,ts:J.ts,service:G,kind:"request",severity:J.error||J.status>=400||J.status===0?"error":"info",title:`${J.method} ${J.path}`.slice(0,2000),request:{method:J.method,path:J.path,status:J.status,durationMs:J.durationMs,via:J.via}})}return X.sort(x4)}coverage($,Z,Q){let X=new Set;if(this.persistenceFailed)X.add("Lifecycle history persistence was unavailable.");if(this.data.droppedBefore!==void 0&&(Q===void 0||Q<=this.data.droppedBefore))X.add("Older lifecycle events have expired.");if(Q!==void 0&&Q<this.data.startedAt)X.add("The observation window begins before lifecycle recording started.");for(let G of $)this.store.activityCoverage(G).reasons.forEach((V)=>X.add(V));return{partial:X.size>0,reasons:[...X],...Z[0]?{retainedFrom:Z[0].ts}:{}}}timeline($,Z,Q={}){let X=Q.limit??100;if(!Number.isInteger(X)||X<1||X>200)throw Error("limit must be between 1 and 200");if(Q.filter&&!["all","incidents"].includes(Q.filter))throw Error("Unknown activity filter");if(Q.query&&Q.query.length>200)throw Error("Search must be at most 200 characters");let G=this.records($,Z),J=this.coverage(Z,G),V,z=q4("sha256").update([...new Set(Z)].sort().join(",")).digest("hex");if(Q.cursor)try{if(Q.cursor.length>4096)throw 0;if(V=JSON.parse(Buffer.from(Q.cursor,"base64url").toString()),!V||!Number.isFinite(V.ts)||typeof V.id!=="string"||V.projectId!==$||V.scope!==z)throw 0}catch{throw Error("Invalid activity cursor for this project and service selection")}let Y=Q.query?.toLowerCase(),K=G.filter((W)=>(!V||x4(W,V)<0)&&(!Q.eventId||W.id===Q.eventId)&&(Q.filter!=="incidents"||W.severity==="error"||W.kind==="lifecycle"||W.kind==="clear")&&(!Y||`${W.title} ${W.service}`.toLowerCase().includes(Y))).reverse(),N=K.slice(0,X),U=N.at(-1);return{items:N,coverage:J,...U&&K.length>X?{nextCursor:Buffer.from(JSON.stringify({ts:U.ts,id:U.id,projectId:$,scope:z})).toString("base64url")}:{}}}markers($){return this.data.markers.filter((Z)=>Z.projectId===$).slice().reverse()}mark($,Z,Q={}){let X=Q.now??Date.now(),G=this.records($,Z);if(Q.label!==void 0&&(typeof Q.label!=="string"||Q.label.length>100))throw Error("Baseline label must be at most 100 characters");let J=G.filter((Y)=>Y.ts>=X-300000&&Y.ts<=X),V={id:D6(),projectId:$,services:[...new Set(Z)],label:Q.label?.trim()||"Before my change",ts:X,boundary:this.store.activityBoundary(),before:S4(J,X-300000,X,Q.secrets),coverage:this.coverage(Z,G,X-300000),...Q.git?{git:Q.git}:{}},z=this.data.markers;this.data.markers=[...z,V].slice(-M4);try{this.persist(!0)}catch(Y){throw this.data.markers=z,Y}return V}compare($,Z,Q=Date.now(),X=[]){let G=this.data.markers.find((Y)=>Y.id===Z&&Y.projectId===$);if(!G)throw Error("Baseline not found or expired");let J=this.records($,G.services),V=S4(J.filter((Y)=>n0(Y.id,G.boundary)&&Y.ts<=Q),G.ts,Q,X),z=this.coverage(G.services,J,G.ts);return z.partial||=G.coverage.partial,z.reasons=[...new Set([...G.coverage.reasons,...z.reasons])],{marker:G,before:G.before,after:V,newlyObserved:V.signatures.filter((Y)=>!G.before.signatures.includes(Y)),notObservedAgain:G.before.signatures.filter((Y)=>!V.signatures.includes(Y)),insufficientEvidence:V.requests<5||G.before.requests<5,coverage:z}}}import{randomUUID as B6}from"node:crypto";var _6=67108864,H6=5000;class s1{capacity;entries=new Map;bytes=0;constructor($=_6){this.capacity=$}start($){let Z=B6();while(this.entries.size>=H6)this.remove(this.entries.keys().next().value);return this.entries.set(Z,{service:$,body:new l0(this.capacity),bytes:0,finished:!1,complete:!1}),{id:Z,append:(Q)=>{let X=this.entries.get(Z);if(!X||X.finished)return;if(X.bytes+Q.length>this.capacity){this.remove(Z);return}while(this.bytes+Q.length>this.capacity){let G=this.entries.keys().next().value;if(this.remove(G),G===Z)return}X.body.append(Q),X.bytes+=Q.length,this.bytes+=Q.length},finish:(Q,X)=>{let G=this.entries.get(Z);if(G)G.finished=!0,G.complete=Q,G.encoding=X}}}get($,Z){let Q=this.entries.get($);if(!Q?.finished||Q.service!==Z)return;return Q.body.snapshot(Q.complete,Q.encoding)}clear($){for(let[Z,Q]of this.entries)if(!$||Q.service===$)this.remove(Z)}remove($){let Z=this.entries.get($);if(Z)this.bytes-=Z.bytes,this.entries.delete($)}}import E4 from"node:path";import{createHash as L6}from"node:crypto";import{EventEmitter as T6}from"node:events";import{finished as A6}from"node:stream/promises";import{Writable as w4}from"node:stream";var t1=2000,r1=5000,R6=1000,F6=/\b(error|exception|unhandled|fatal|EADDRINUSE|ECONNREFUSED)\b/i;class $8{cap;maxBytes;buf;sizes;size=0;next=0;bytes=0;constructor($,Z=1/0){this.cap=$;this.maxBytes=Z;this.buf=Array($),this.sizes=Array($).fill(0)}push($,Z=0){if(this.size===this.cap)this.bytes-=this.sizes[this.next];this.buf[this.next]=$,this.sizes[this.next]=Z,this.bytes+=Z,this.next=(this.next+1)%this.cap,this.size=Math.min(this.size+1,this.cap);while(this.bytes>this.maxBytes&&this.size>1){let Q=(this.next-this.size+this.cap)%this.cap;this.bytes-=this.sizes[Q],this.buf[Q]=void 0,this.sizes[Q]=0,this.size--}}last($){let Z=Math.min(Math.max(0,$),this.size),Q=(this.next-this.size+this.cap)%this.cap,X=Math.max(0,this.size-Z),G=[];for(let J=X;J<this.size;J++)G.push(this.buf[(Q+J)%this.cap]);return G}clear(){this.buf.fill(void 0),this.sizes.fill(0),this.size=0,this.next=0,this.bytes=0}}function j4(){return{requests:0,ok:0,clientErrors:0,serverErrors:0,proxyErrors:0,avgLatencyMs:0,logLines:0,errorLines:0}}class Z8 extends T6{responseBodies=new s1;activity;buckets=new Map;logsDir;daemonStartedAt;sequence=0;closePromise;closing=!1;closeAfterMs;streamFactory;maxFileBytes;maxHistoryBytes;constructor($={}){super();if(this.logsDir=$.logsDir??R1,this.daemonStartedAt=$.daemonStartedAt??Date.now(),this.closeAfterMs=$.closeAfterMs??R6,this.streamFactory=$.streamFactory??((Z,Q)=>f.createWriteStream(Z,Q)),this.maxFileBytes=Math.max(1,$.maxFileBytes??5242880),this.maxHistoryBytes=Math.max(1,$.maxHistoryBytes??8388608),$.logsDir===void 0)y$();else f.mkdirSync(this.logsDir,{recursive:!0});this.activity=new o1(this,this.logsDir)}nextId(){return`${this.daemonStartedAt.toString(36)}-${(++this.sequence).toString(36)}`}compatibilityId($,Z,Q,X){return`legacy-${L6("sha256").update(`${$}\x00${Z}\x00${Q}\x00${X}`).digest("hex")}`}historyFile($,Z){let Q=Z==="log"?"log.jsonl":"requests.jsonl";return E4.join(this.logsDir,`${encodeURIComponent($)}.${Q}`)}legacyHistoryFile($,Z){let Q=$.replace(/[^a-z0-9_-]/gi,"_"),X=Z==="log"?"log.jsonl":"requests.jsonl";return E4.join(this.logsDir,`${Q}.${X}`)}loadHistory($,Z,Q,X,G,J=this.maxFileBytes){let V=`${this.historyFile(Q,Z)}.cleared`,z=f.existsSync(V)?f.readFileSync(V,"utf8"):void 0,Y,K;try{Y=f.openSync($,"r"),K=f.fstatSync(Y).size}catch(O){if(O.code==="ENOENT")return 0;throw O}let N=Math.min(K,Math.max(0,J)),U=K-N,W=Buffer.alloc(N);try{if(N)f.readSync(Y,W,0,N,U)}finally{f.closeSync(Y)}let C=W.toString("binary").split(`
128
+ `),D=U;if(U>0&&W[0]!==10)D+=Buffer.byteLength(C.shift()??"","binary")+1;for(let O of C){let B=Buffer.from(O,"binary"),_=(B[B.length-1]===13?B.subarray(0,B.length-1):B).toString("utf8"),H=D+B.length+1;if(_)try{let T=JSON.parse(_);if(T&&typeof T==="object"&&!Array.isArray(T)){let A=T;if(A.service===Q||A.service===G){let R=typeof A.id==="string"?A.id:this.compatibilityId(Z,Q,D,_);if(!z||n0(R,z))X.push({...A,service:Q,id:R},_.length)}}}catch{}D=H}return K}bucket($){let Z=this.buckets.get($);if(!Z){let Q=this.historyFile($,"log"),X=this.historyFile($,"request"),G=this.legacyHistoryFile($,"log"),J=this.legacyHistoryFile($,"request");if(Z={logs:new $8(t1,this.maxHistoryBytes),requests:new $8(r1,this.maxHistoryBytes),stats:j4(),latencyTotal:0,logFile:void 0,reqFile:void 0,persistenceDiagnosticEmitted:!1},G!==Q)this.loadHistory(G,"log",$,Z.logs);if(J!==X)this.loadHistory(J,"request",$,Z.requests);if($.startsWith("standalone:")){let N=$.slice(11),U=this.legacyHistoryFile(N,"log"),W=this.legacyHistoryFile(N,"request");if(U!==Q&&U!==G)this.loadHistory(U,"log",$,Z.logs,N);if(W!==X&&W!==J)this.loadHistory(W,"request",$,Z.requests,N)}let V=`${Q}.1`,z=`${X}.1`,Y=(()=>{try{return f.statSync(Q).size}catch{return 0}})(),K=(()=>{try{return f.statSync(X).size}catch{return 0}})();if(this.loadHistory(V,"log",$,Z.logs,void 0,Math.max(0,this.maxFileBytes-Math.min(Y,this.maxFileBytes))),this.loadHistory(Q,"log",$,Z.logs,void 0,this.maxFileBytes),this.loadHistory(z,"request",$,Z.requests,void 0,Math.max(0,this.maxFileBytes-Math.min(K,this.maxFileBytes))),this.loadHistory(X,"request",$,Z.requests,void 0,this.maxFileBytes),Z.logFile=this.persistenceStream($,"log",Q),Z.reqFile=this.persistenceStream($,"request",X),this.buckets.set($,Z),Z.logFile.failedDuringCreate)this.reportPersistenceFailure($,Z,"log");if(Z.reqFile.failedDuringCreate)this.reportPersistenceFailure($,Z,"request")}return Z}resetStats($){let Z=this.bucket($);Z.stats=j4(),Z.latencyTotal=0}stats($){return this.bucket($).stats}log($){let Z={...$,id:this.nextId()},Q=this.bucket(Z.service),X=JSON.stringify(Z);if(Q.logs.push(Z,X.length),Q.stats.logLines++,Z.stream==="stderr"||F6.test(Z.line))Q.stats.errorLines++;return this.persist(Z.service,Q,Q.logFile,X+`
129
+ `),this.emitEvent({type:"log",log:Z}),Z}request($){let Z={...$,id:this.nextId()},Q=this.bucket(Z.service),X=JSON.stringify(Z);Q.requests.push(Z,X.length);let G=Q.stats;if(G.requests++,G.lastRequestAt=Z.ts,Z.error)G.proxyErrors++;else if(Z.status>=500)G.serverErrors++;else if(Z.status>=400)G.clientErrors++;else G.ok++;return Q.latencyTotal+=Z.durationMs,G.avgLatencyMs=Math.round(Q.latencyTotal/G.requests),this.persist(Z.service,Q,Q.reqFile,X+`
130
+ `),this.emitEvent({type:"request",request:Z}),Z}logs($,Z=200){return this.bucket($).logs.last(Z)}requests($,Z=200){return this.bucket($).requests.last(Z)}historyBoundary($,Z){let Q=`${this.historyFile($,Z==="logs"?"log":"request")}.cleared`;return f.existsSync(Q)?f.readFileSync(Q,"utf8"):void 0}async clearHistory($,Z){if(this.closing)throw Error("History is unavailable during shutdown");let Q=this.bucket($),X=Z==="logs"?Q.logFile:Q.reqFile,G=this.nextId(),J=`${X.file}.cleared`;if(f.writeFileSync(`${J}.tmp`,G,{mode:384}),f.renameSync(`${J}.tmp`,J),Q[Z].clear(),Z==="requests")this.responseBodies.clear($);let V=X.queue.then(async()=>{await this.closeStream(X.stream),f.writeFileSync(X.file,"",{mode:384}),f.rmSync(`${X.file}.1`,{force:!0}),X.bytes=0,X.stream=this.streamFactory(X.file,{flags:"a",mode:384,highWaterMark:65536}),X.disabled=!1,X.stream.on("error",()=>{X.disabled=!0,this.reportPersistenceFailure($,Q,"history")})});X.queue=V.catch(()=>{X.disabled=!0,this.reportPersistenceFailure($,Q,"history clear")});let z=this.emitEvent({type:"history:cleared",service:$,kind:Z,beforeId:G});return await V,z}emitEvent($){let Z={...$,eventId:this.nextId()};return this.activity.capture(Z),this.emit("event",Z),Z}activityBoundary(){return this.nextId()}activityCoverage($){let Z=this.bucket($),Q=[];if(this.historyBoundary($,"logs")||this.historyBoundary($,"requests"))Q.push("Some history was explicitly cleared.");if(Z.logs.last(t1).length===t1||Z.requests.last(r1).length===r1||f.existsSync(`${Z.logFile.file}.1`)||f.existsSync(`${Z.reqFile.file}.1`))Q.push("Older logs or requests may have expired from bounded history.");if(Z.persistenceDiagnosticEmitted)Q.push("Some log or request history could not be persisted.");return{reasons:Q}}close(){if(!this.closePromise){this.closing=!0,this.responseBodies.clear();let $=[...this.buckets.values()];this.closePromise=(async()=>{let Z=$.flatMap((G)=>[G.logFile,G.reqFile]);Z.forEach((G)=>{G.accepting=!1});let Q=await Promise.all(Z.map((G)=>e1(G.queue,this.closeAfterMs)));Z.forEach((G,J)=>{if(!Q[J]){G.closing=!0;try{G.stream.destroy()}catch{}}});let X=$.flatMap((G)=>[G.logFile.stream,G.reqFile.stream]);await Promise.allSettled(X.map((G)=>this.closeStream(G)))})()}return this.closePromise}async closeStream($){let Z=A6($).then(()=>{return},()=>{return});try{if(!$.destroyed&&!$.writableEnded)$.end()}catch{try{$.destroy()}catch{}}if(await e1(Z,this.closeAfterMs))return;try{$.destroy()}catch{}await e1(Z,this.closeAfterMs)}persistenceStream($,Z,Q){let X,G=!1;try{if(this.closing)G=!0,X=new w4({write(V,z,Y){Y()}}),X.end();else X=this.streamFactory(Q,{flags:"a",mode:384,highWaterMark:65536})}catch{G=!0,X=new w4({write(V,z,Y){Y()}})}try{if(f.existsSync(Q))f.chmodSync(Q,384)}catch{}let J={stream:X,file:Q,bytes:(()=>{try{return f.statSync(Q).size}catch{return 0}})(),queue:Promise.resolve(),pending:0,closing:!1,accepting:!0,disabled:G,backpressured:!1,failedDuringCreate:G};return X.on("error",()=>{if(J.disabled)return;J.disabled=!0,J.backpressured=!1;let V=this.buckets.get($);if(V)this.reportPersistenceFailure($,V,Z)}),X.on("drain",()=>{J.backpressured=!1}),J}persist($,Z,Q,X){if(Q.disabled||!Q.accepting)return;if(Q.pending++,Q.pending>1e4){Q.pending--,Q.disabled=!0,this.reportPersistenceFailure($,Z,"history");return}Q.queue=Q.queue.then(async()=>{if(Q.disabled){Q.pending--;return}try{let G=Buffer.byteLength(X);if(G>this.maxFileBytes){this.reportPersistenceFailure($,Z,"history record too large");return}if(Q.bytes>0&&Q.bytes+G>this.maxFileBytes)await this.rotate($,Z,Q);if(!Q.stream.write(X))Q.backpressured=!0,await new Promise((J)=>{let V=()=>{Q.stream.off("drain",V),Q.stream.off("error",V),Q.stream.off("close",V),J()};Q.stream.once("drain",V),Q.stream.once("error",V),Q.stream.once("close",V)}),Q.backpressured=!1;Q.bytes+=G}catch{Q.disabled=!0,this.reportPersistenceFailure($,Z,"history")}finally{Q.pending--}})}async rotate($,Z,Q){if(await this.closeStream(Q.stream),Q.closing)throw Q.disabled=!0,Error("history rotation interrupted");let X=`${Q.file}.1`;try{f.rmSync(X,{force:!0}),f.renameSync(Q.file,X)}catch{throw Q.disabled=!0,this.reportPersistenceFailure($,Z,"history rotation"),Error("history rotation failed")}Q.stream=this.streamFactory(Q.file,{flags:"a",mode:384,highWaterMark:65536});try{f.chmodSync(Q.file,384)}catch{}Q.bytes=0,Q.stream.on("error",()=>{Q.disabled=!0,this.reportPersistenceFailure($,Z,"history")}),Q.stream.on("drain",()=>{Q.backpressured=!1})}reportPersistenceFailure($,Z,Q){if(Z.persistenceDiagnosticEmitted)return;Z.persistenceDiagnosticEmitted=!0;let X={id:this.nextId(),ts:Date.now(),service:$,stream:"system",line:`LocalDeck: ${Q} persistence unavailable; continuing with in-memory history`};Z.logs.push(X),Z.stats.logLines++,Z.stats.errorLines++,this.emitEvent({type:"log",log:X})}}function e1($,Z){return new Promise((Q)=>{let X=!1,G=(V)=>{if(X)return;X=!0,clearTimeout(J),Q(V)},J=setTimeout(()=>G(!1),Z);J.unref(),$.then(()=>G(!0),()=>G(!0))})}import{spawn as f6}from"node:child_process";import X1 from"node:path";import b6 from"node:fs";function h4($){let Z=$.replace(/\x1b\[[0-9;]*m/g,"");if(!/\bEADDRINUSE\b|\b(?:port|address)\b[^\n]*already in use/i.test(Z))return;let Q=/\bport\s+(\d+)\s+is already in use/i.exec(Z)?.[1]??/\b(?:listen|address already in use)[^\n]*:(\d+)\b/i.exec(Z)?.[1],X=Q&&Number(Q)>0&&Number(Q)<=65535?Q:void 0,G=X?`Port ${X} is already in use.`:"The service’s port is already in use.",J=/\bvite\b|\bhttpServerStart\b/.test(Z);return{title:G,steps:J?["Check server.port and server.strictPort in your Vite config. With strictPort: true, Vite exits when that port is occupied.",`To use LocalDeck’s assigned port, set server.port to Number(process.env.PORT) || ${X??"5173"}. You can keep strictPort: true.`,"Alternatively, stop the other instance, or set strictPort: false to let Vite try another port. Automatic port detection must be enabled in LocalDeck (leave upstream unset)."]:["Stop the other instance, or configure the app to listen on the PORT environment variable supplied by LocalDeck.","If the app requires a fixed port, choose an unused port in the app and set LocalDeck’s upstream to match."]}}import g4 from"node:fs";import E0 from"node:path";function X8($,Z,Q){let X=new Set,G=(V,z)=>{if(X.size>=16)return;let Y=typeof V==="string"?M6(V):V;if(!Y?.length)return;let K=E0.basename(Y[0]).replace(/\.cmd$/,"");if(Y[0].includes("=")||["echo","printf"].includes(K))return;if(["npm","pnpm","yarn","bun"].includes(K)){let C=z,D,O;for(let H=1;H<Y.length;H++){let T=Y[H];if(T==="--")break;if(T==="run"||T==="run-script")continue;let A=/^(--prefix|--cwd|--dir|-C|--workspace|-w)(?:=(.*))?$/.exec(T);if(A){let R=A[2]??Y[++H];if(!R||/[$`]/.test(R))return;if(A[1]==="--workspace"||A[1]==="-w"){if(D)return;D=R}else C=E0.resolve(z,R)}else if(T.startsWith("-")||O)return;else O=T}if(!O||/[$`]/.test(O))return;if(D){let H=x6(C,D);if(!H)return;C=H}let B=`${C}\x00${O}`;if(X.has(B))return;X.add(B);let _=Q8(C)?.scripts?.[O];return typeof _==="string"?G(_,C):void 0}let N=Y.slice(1).flatMap((C,D)=>C==="--port"?[Y[D+2]??""]:C.startsWith("--port=")?[C.slice(7)]:[]);if(N.length!==1)return;let U=/^(?:\$([A-Za-z_][A-Za-z0-9_]*)|\$\{([A-Za-z_][A-Za-z0-9_]*)(?::?-\d+)?\})$/.exec(N[0]),W=U?.[1]??U?.[2];if(W&&W!=="PORT"&&!W.startsWith("LOCALDECK_"))return W},J=G($,E0.resolve(Z));return J?{[J]:String(Q)}:{}}function M6($){let Z=[],Q="",X="",G=!1;for(let J=0;J<$.length;J++){let V=$[J];if(V==="`"||V==="\\"||V===`
131
+ `||$.slice(J,J+2)==="$(")return;if(X)if(V===X)X="";else Q+=X==="'"&&V==="$"?"\x00":V;else if(V==='"'||V==="'")X=V,G=!0;else if(/\s/.test(V)){if(G)Z.push(Q);Q="",G=!1}else{if(/[;&|<>()#]/.test(V))return;Q+=V,G=!0}}if(X)return;if(G)Z.push(Q);return Z}function Q8($){try{let Z=JSON.parse(g4.readFileSync(E0.join($,"package.json"),"utf8"));return Z&&typeof Z==="object"&&!Array.isArray(Z)?Z:void 0}catch{return}}function x6($,Z){let Q=Q8($)?.workspaces,X=Array.isArray(Q)?Q:Q?.packages;if(!Array.isArray(X))return;let G=new Set;for(let J of X.slice(0,100)){if(typeof J!=="string"||E0.isAbsolute(J))continue;let V=J.replace(/^\.\//,"").replace(/\/$/,"").split("/");if(V.some((Y)=>!Y||Y===".."||/[^\w@.*-]/.test(Y)||Y.includes("**")))continue;let z=[$];for(let Y of V){let K=new RegExp(`^${Y.replace(/\./g,"\\.").replace(/\*/g,".*")}$`),N=[];for(let U of z)try{for(let W of g4.readdirSync(U,{withFileTypes:!0})){if(W.isDirectory()&&!["node_modules",".git"].includes(W.name)&&K.test(W.name))N.push(E0.join(U,W.name));if(N.length>100)return}}catch{}z=N}for(let Y of z){let K=Q8(Y);if(K&&(Y===E0.resolve($,Z)||K.name===Z))G.add(Y)}}return G.size===1?[...G][0]:void 0}import P6 from"node:http";import{spawn as I6}from"node:child_process";async function G8($,Z,Q={}){let X=Date.now()+$.ready.timeoutMs;for(;;){w6($.name,Q.signal);let G=await Z();if(!G||G.status==="stopped")throw Error(`${$.name} exited before it became ready`);let J=X-Date.now();if(J<=0)throw Error(`${$.name} readiness timed out after ${$.ready.timeoutMs}ms`);let V=!1;if($.ready.type==="command")V=await q6($.ready.run,$.ready.expectedOutput,G,Q.cwd,J,Q.signal,Q.env);else if(G.upstreamReady)V=$.ready.type==="tcp"||await S6(G,$.ready.path,$.ready.status,J,Q.signal);if(V)return{...G,urls:[...G.urls],stats:{...G.stats}};let z=X-Date.now();if(z<=0)throw Error(`${$.name} readiness timed out after ${$.ready.timeoutMs}ms`);await E6(Math.min($.ready.intervalMs,z),$.name,Q.signal)}}function S6($,Z,Q,X,G){return new Promise((J,V)=>{if(G?.aborted)return V(Error(`${$.name} readiness cancelled`));let z=!1,Y=(U,W)=>{if(z)return;if(z=!0,G?.removeEventListener("abort",N),W)V(W);else J(U)},K=P6.request({host:$.upstreamHost,port:$.upstreamPort,path:Z,method:"GET",timeout:Math.max(1,Math.min(X,2000))},(U)=>{U.resume();let W=U.statusCode??0;Y(Q===void 0?W>=200&&W<400:W===Q)}),N=()=>{K.destroy(),Y(!1,Error(`${$.name} readiness cancelled`))};G?.addEventListener("abort",N,{once:!0}),K.once("timeout",()=>K.destroy()),K.once("error",()=>Y(!1)),K.end()})}function q6($,Z,Q,X,G,J,V){return new Promise((z,Y)=>{if(J?.aborted)return Y(Error(`${Q.name} readiness cancelled`));let K=$.replaceAll("{upstream}",String(Q.upstreamPort)).replaceAll("{port}",String(Q.stablePort)),N=V$(K),U=!1,W=I6(N[0],N.slice(1),{cwd:X,stdio:["ignore","pipe","ignore"],detached:process.platform!=="win32",env:{...process.env,...V,PORT:String(Q.upstreamPort),LOCALDECK_PORT:String(Q.stablePort),LOCALDECK_SERVICE:Q.name,LOCALDECK_URL:Q.urls[0]}}),C=[],D=0;W.stdout?.on("data",(_)=>{if(D>=8192)return;let H=_.subarray(0,8192-D);C.push(H),D+=H.length});let O=(_,H)=>{if(U)return;if(U=!0,clearTimeout(L),J?.removeEventListener("abort",B),H)Y(H);else z(_)},B=()=>{f4(W),O(!1,Error(`${Q.name} readiness cancelled`))},L=setTimeout(()=>{f4(W),O(!1)},Math.max(1,Math.min(G,2000)));L.unref(),J?.addEventListener("abort",B,{once:!0}),W.once("error",()=>O(!1)),W.once("close",(_)=>O(_===0&&(Z===void 0||Buffer.concat(C).toString("utf8").trim()===Z)))})}function f4($){if(!$.pid)return;try{if(process.platform!=="win32")process.kill(-$.pid,"SIGKILL");else $.kill("SIGKILL")}catch{}}function E6($,Z,Q){return new Promise((X,G)=>{if(Q?.aborted)return G(Error(`${Z} readiness cancelled`));let J=setTimeout(z,$),V=()=>{clearTimeout(J),Q?.removeEventListener("abort",V),G(Error(`${Z} readiness cancelled`))};function z(){Q?.removeEventListener("abort",V),X()}Q?.addEventListener("abort",V,{once:!0})})}function w6($,Z){if(Z?.aborted)throw Error(`${$} readiness cancelled`)}import{Transform as j6}from"node:stream";import{StringDecoder as h6}from"node:string_decoder";import{stripVTControlCharacters as g6}from"node:util";function Q1($){let Z=new h6("utf8"),Q="",X="text";function G(V){if(!$.size)return V;let z="";for(let Y of V)if(X==="text")if(Y==="\x1B")X="escape";else if(Y==="›")X="csi";else z+=Y;else if(X==="escape")X=Y==="["?"csi":Y==="]"?"osc":Y>=" "&&Y<="/"?"intermediate":"text";else if(X==="intermediate"){if(Y>="0"&&Y<="~")X="text"}else if(X==="csi"){if(Y>="@"&&Y<="~")X="text"}else if(X==="osc"){if(Y==="\x07")X="text";else if(Y==="\x1B")X="osc-escape"}else X=Y==="\\"||Y==="\x07"?"text":Y==="\x1B"?"osc-escape":"osc";return z}function J(V){let z=[...$].map(g6).filter(Boolean).sort((N,U)=>U.length-N.length);if(!z.length){let N=Q;return Q="",N}let Y="",K=0;while(K<Q.length){let N=Q.slice(K);if(!V&&z.some((W)=>W.length>N.length&&W.startsWith(N)))break;let U=z.find((W)=>Q.startsWith(W,K));if(U)Y+="[REDACTED]",K+=U.length;else Y+=Q[K++]}return Q=Q.slice(K),Y}return new j6({transform(V,z,Y){Q+=G(Z.write(V)),Y(null,J(!1))},flush(V){Q+=G(Z.end()),V(null,J(!0))}})}var y6=5000,v6=300,k6=5000,u6=20,m6=4000;class J1{projects;registry;store;active=new Map;pending=new Map;forceAfterMs;detectAfterMs;terminalStopAfterMs;killTree;shareLifecycle;allocatePort;resolveSecrets;upstreamReservations=new Set;retries=new Map;redactionValues=new Set;retryDelayMs;shuttingDown=!1;shutdownPromise;constructor($,Z,Q,X={}){this.projects=$;this.registry=Z;this.store=Q;this.retryDelayMs=X.retryDelayMs??3000,this.forceAfterMs=X.forceAfterMs??y6,this.detectAfterMs=X.detectAfterMs??v6,this.terminalStopAfterMs=X.terminalStopAfterMs??k6,this.killTree=X.killProcessTree??l1,this.shareLifecycle=X.shareLifecycle,this.allocatePort=X.getFreePort??K$,this.resolveSecrets=X.resolveProjectSecrets??z0}start($,Z){let Q=Z.toLowerCase();return this.startSelection($,[Q]).then((X)=>X.find((G)=>G.name===Q)??h(u($,Q),Q,`Project ${$} has no service named ${Z}`))}stop($,Z){return this.cancelRetries($),this.enqueue($,()=>this.stopNow($,Z))}async restart($,Z){let Q=Z.toLowerCase(),X=u($,Q);if(this.shuttingDown)return h(X,Q,"daemon is shutting down");let G=await this.stop(X,"restart");if(!G.ok)return G;return this.start($,Q)}startAll($){return this.startSelection($)}async startSelection($,Z){let Q=this.projects.details($);if(!Q.available)throw new q("invalid",Q.error);let X=u$(Q.commands,Z),G=new Set(X.flat().map((K)=>K.name));if(this.shuttingDown)return Q.commands.filter((K)=>G.has(K.name)).map((K)=>h(u($,K.name),K.name,"daemon is shutting down"));let J=new Map,V=new Map,z=new Map(Q.commands.map((K)=>[K.name,K])),Y=(K)=>{let N=V.get(K.name);if(N)return N;let U=(async()=>{let W=K.after.map((H)=>Y(z.get(H))),C=W.length?await Promise.all(W):[],D=K.after.filter((H,T)=>!C[T].ok);if(D.length)return h(u($,K.name),K.name,`${K.name} was not started because ${D.join(", ")} failed`);let O=u($,K.name),B;try{B=await this.enqueue(O,()=>this.startOne($,K.name,O))}catch(H){if(Z&&H instanceof q)throw H;return h(O,K.name,l(H))}if(!B.ok)return B;let L=Q.commands.some((H)=>H.after.includes(K.name));if(K.ready.type==="tcp"&&!L){let H=K.cwd?X1.resolve(Q.directory,K.cwd):Q.directory;return this.verifyReadiness(K,O,H),B}let _=K.cwd?X1.resolve(Q.directory,K.cwd):Q.directory;return this.verifyReadiness(K,O,_,B)})();return V.set(K.name,U),U};await Promise.all(Q.commands.filter((K)=>G.has(K.name)).map(async(K)=>{let N=await Y(K);J.set(K.name,N)}));for(let K of Q.commands){if(!G.has(K.name)||J.has(K.name))continue;let N=K.after.filter((U)=>!J.get(U)?.ok);J.set(K.name,h(u($,K.name),K.name,N.length?`${K.name} was not started because ${N.join(", ")} failed`:"daemon is shutting down"))}return Q.commands.filter((K)=>G.has(K.name)).map((K)=>J.get(K.name))}async verifyReadiness($,Z,Q,X){let G=this.registry.get(Z),J=this.active.get(Z),V=()=>G!==void 0&&this.registry.get(Z)===G&&(J?this.active.get(Z)===J:G.managedBy==="terminal");if(G)G.readinessCheck=$.ready.type;this.setReadiness(Z,"checking",$.ready.type==="tcp"?"Waiting for the service to listen":"Running configured readiness check"),this.store.log({ts:Date.now(),service:Z,stream:"system",line:`LocalDeck: checking readiness for ${$.name}`});try{let z=J?.commandEnv;if(!z&&G){let N=this.resolveSecrets(G.projectId,$.secrets??[]);for(let U of Object.values(N))this.redactionValues.add(U);z={...this.expandCommandEnv($.env,$.after,G.projectId),...N}}if(await G8($,()=>V()?G:void 0,{cwd:Q,env:z}),!V()||G.status==="stopped"||G.status==="stopping")return h(Z,$.name,"readiness cancelled");let Y=$.ready.type==="tcp"?"Listening on its upstream port":"Configured readiness check passed";if(G.status==="starting")G.status="running";this.setReadiness(Z,"ready",Y),this.store.log({ts:Date.now(),service:Z,stream:"system",line:`LocalDeck: ${$.name} ${$.ready.type==="tcp"?"is listening":"passed its configured readiness check"}`});let K=this.registry.get(Z)??X?.service;return K?A$(K):h(Z,$.name,"service exited before it became ready")}catch(z){let Y=l(z);if(!V()||G.status==="stopped"||G.status==="stopping")return h(Z,$.name,Y);return this.setReadiness(Z,"failed",Y),this.setLastError(Z,Y),await this.stop(Z,"readiness failed"),h(Z,$.name,Y,this.registry.get(Z))}}async stopAll($){let Z=this.projects.details($),Q=new Map(this.registry.list($).filter((J)=>J.status!=="stopped"||J.share!==void 0).map((J)=>[J.key,{key:J.key,name:J.name}]));for(let J of new Set([...this.active.keys(),...this.retries.keys()]))if(J.startsWith(`${$}:`)&&!Q.has(J)){let V=J.slice(J.lastIndexOf(":")+1);Q.set(J,{key:J,name:V})}let X=[];if(Z.available)for(let J of S1(Z.commands)){let V=u($,J.name),z=Q.get(V);if(z)X.push(z),Q.delete(V)}X.push(...Q.values());for(let J of X)this.cancelRetries(J.key);let G=[];for(let J of X)try{G.push(await this.stop(J.key,"stop all"))}catch(V){G.push(h(J.key,J.name,l(V)))}return G}shutdown(){if(this.shutdownPromise)return this.shutdownPromise;this.shuttingDown=!0;for(let $ of this.retries.keys())this.cancelRetries($);return this.shutdownPromise=this.shutdownNow(),this.shutdownPromise}async shutdownNow(){await Promise.allSettled([...this.pending.values()]);let $=await Promise.allSettled([...this.active.keys()].map((Q)=>this.stop(Q,"daemon shutdown")));await Promise.allSettled([...this.pending.values()]);let Z=[];for(let Q of $)if(Q.status==="rejected")Z.push(p6(Q.reason));else if(!Q.value.ok)Z.push(Error(`${Q.value.key}: ${Q.value.error??"stop failed"}`));for(let Q of this.active.values())if(y4(Q.child))Z.push(Error(`${Q.key}: supervised child ${Q.child.pid??"?"} is still running`));if(Z.length)throw AggregateError(Z,"failed to stop all supervised processes during shutdown")}enqueue($,Z){let Q=this.pending.get($),G=(Q?Q.then(Z,Z):Z()).finally(()=>{if(this.pending.get($)===G)this.pending.delete($)});return this.pending.set($,G),G}async startOne($,Z,Q){if(this.shuttingDown)return h(Q,Z,"daemon is shutting down");let X=this.active.get(Q);if(X){if(X.child.exitCode===null&&X.child.signalCode===null){let F=this.registry.get(Q);return F?A$(F):h(Q,Z,"service process has no registry entry")}if(await X.completion,this.active.get(Q)===X)return h(Q,Z,"previous process cleanup is incomplete; stop the service again before restarting")}if(this.retries.get(Q)?.timer)this.cancelRetries(Q);let J=this.registry.get(Q);if(J&&J.status!=="stopped")return A$(J);let V=this.retries.get(Q)??{attempts:0,cancelled:!1};this.retries.set(Q,V);let z=this.projects.resolve($,Z),Y=this.projects.details($);if(!Y.available)throw new q("invalid",Y.error);let K=z.cwd?X1.resolve(Y.directory,z.cwd):Y.directory;try{if(!b6.statSync(K).isDirectory())throw Error("not a directory")}catch{throw new q("invalid",`configured working directory does not exist or is not a directory: ${K}`)}let N;try{N=this.resolveSecrets($,z.secrets??[]);for(let F of Object.values(N))this.redactionValues.add(F)}catch(F){return h(Q,Z,l(F))}let U;try{U=z.upstream??await this.reserveAutomaticUpstream()}catch(F){return h(Q,Z,l(F))}let W=z.upstream===void 0?U:void 0,C;try{C={...this.expandCommandEnv(z.env,z.after,$),...N}}catch(F){return this.releaseAutomaticUpstream(W),h(Q,Z,l(F))}let D;try{D=await this.registry.register({key:Q,projectId:$,projectName:Y.name,projectSlug:Y.slug,name:Z,managedBy:"daemon",stablePort:z.port,upstreamPort:U,upstreamSource:z.upstream===void 0?"assigned":"manual",cwd:K,command:z.run,serviceType:z.serviceType,...Y.activeProfiles?.length?{profiles:Y.activeProfiles}:{},configFingerprint:P0(z)},()=>void this.stop(Q,"stop requested"))}catch(F){return this.releaseAutomaticUpstream(W),h(Q,Z,l(F))}let O=V$(z.run.replaceAll("{port}",String(U))),B=D.serviceType!==void 0&&D.serviceType!=="http",L=B?{}:X8(z.run,K,U);C={...L,...C};for(let F of Object.keys(L))if(C[F]===L[F])this.store.log({ts:Date.now(),service:Q,stream:"system",line:`LocalDeck: supplying assigned port ${U} through ${F}`});let _={...process.env,...C,PORT:String(U),LOCALDECK_PORT:String(D.stablePort),LOCALDECK_SERVICE:D.name,...B?{}:{LOCALDECK_URL:`http://localhost:${D.stablePort}`}};this.setReadiness(Q,"waiting","Waiting for process to listen");let H;try{H=f6(O[0],O.slice(1),{cwd:K,env:_,detached:process.platform!=="win32",stdio:["ignore","pipe","pipe"]})}catch(F){return this.setLastError(Q,l(F)),await this.registry.unregister(Q),this.releaseAutomaticUpstream(W),h(Q,Z,l(F))}let T,A={key:Q,name:Z,child:H,stderr:[],completion:new Promise((F)=>{T=F}),reservedUpstreamPort:W,commandEnv:C};this.active.set(Q,A);let R=!1,M,E=async(F,w,m)=>{if(R)return;R=!0;let p=!1;if(A.detectTimer)clearTimeout(A.detectTimer);this.releaseAutomaticUpstream(A.reservedUpstreamPort);try{if(this.active.get(Q)!==A)return;if(A.stopping){p=!0;return}else if(!await this.cleanupLeaderFirstExit(A))A.cleanupError=Error(`process group ${A.child.pid??"?"} survived forced cleanup after its leader exited`),p=!0;let k=l6(A.stderr),g=this.registry.get(Q)?.status==="starting";if(!A.stopping&&(m||F!==0||w!==null||g&&k)){this.setLastError(Q,k||m?.message||`process exited (${w??`code ${F}`})`);let b=h4(k);if(b)this.store.log({ts:Date.now(),service:Q,stream:"system",line:[b.title,...b.steps].join(`
132
+ `)})}if(this.store.log({ts:Date.now(),service:Q,stream:"system",line:U$(`process exited (${m?m.message:w??`code ${F}`})`,[...this.redactionValues])}),p){let b=this.registry.get(Q);if(b)b.status="stopping",this.store.emitEvent({type:"service",service:b});return}await this.registry.unregister(Q)}catch(k){A.cleanupError=k,p=!0}finally{if(!p&&this.active.get(Q)===A)this.active.delete(Q);if(T(),!p&&!A.stopping&&!V.cancelled&&!this.shuttingDown&&!["SIGINT","SIGTERM","SIGHUP"].includes(w??"")&&![130,143,129].includes(F??-1))this.scheduleRetry($,Z,Q,V)}};e$(H.stdout.pipe(Q1(this.redactionValues)),(F)=>{this.store.log({ts:Date.now(),service:Q,stream:"stdout",line:$1(F)})}),e$(H.stderr.pipe(Q1(this.redactionValues)),(F)=>{let w=$1(F);if(A.stderr.push(w),A.stderr.length>u6)A.stderr.shift();this.store.log({ts:Date.now(),service:Q,stream:"stderr",line:w})}),H.once("close",(F,w)=>void E(F,w,M)),H.once("error",(F)=>{M=F});try{await new Promise((F,w)=>{H.once("spawn",F),H.once("error",w)})}catch(F){return await A.completion,h(Q,Z,l(A.cleanupError??F))}if(!H.pid){let F=Error(`failed to start ${O[0]}`);return await E(null,null,F),h(Q,Z,F.message)}if(this.registry.setPid(Q,H.pid),z.upstream===void 0)this.scheduleDetection(A,U);return A$(this.registry.get(Q)??D)}cancelRetries($){let Z=this.retries.get($);if(!Z)return;if(Z.cancelled=!0,Z.timer)clearTimeout(Z.timer);let Q=this.registry.get($);if(Q&&!this.active.has($)&&Q.status==="starting")Q.status="stopped",this.store.emitEvent({type:"service",service:Q});this.retries.delete($)}scheduleRetry($,Z,Q,X){if(X.cancelled||this.shuttingDown||X.timer)return;if(X.attempts>=3){let z=this.registry.get(Q)?.lastError;this.setLastError(Q,[z,"Service exited after 3 automatic restart attempts. Start it manually to try again."].filter(Boolean).join(`
133
+ `)),this.store.log({ts:Date.now(),service:Q,stream:"system",line:"LocalDeck: automatic restart limit reached (3/3)"}),this.retries.delete(Q);return}let G=++X.attempts,J=`Restarting in ${this.retryDelayMs/1000} seconds (attempt ${G}/3)`,V=this.registry.get(Q);if(V)V.status="starting",V.readinessStatus="waiting",V.readinessMessage=J,this.store.emitEvent({type:"service",service:V});this.store.log({ts:Date.now(),service:Q,stream:"system",line:`LocalDeck: ${J}`}),X.timer=setTimeout(()=>{X.timer=void 0,this.enqueue(Q,async()=>{if(X.cancelled||this.shuttingDown)return h(Q,Z,"restart cancelled");let z=this.registry.get(Q);if(z)z.status="stopped";try{let Y=await this.startOne($,Z,Q);if(!Y.ok)this.scheduleRetry($,Z,Q,X);else{let K=this.projects.resolve($,Z),N=this.projects.details($),U=K.cwd?X1.resolve(N.directory,K.cwd):N.directory;this.verifyReadiness(K,Q,U)}return Y}catch(Y){return this.setLastError(Q,l(Y)),this.scheduleRetry($,Z,Q,X),h(Q,Z,l(Y))}})},this.retryDelayMs),X.timer.unref()}async stopNow($,Z){let Q=this.registry.get($),X=Q?.name??$.slice($.lastIndexOf(":")+1);if(Z==="restart"&&Q?.managedBy==="terminal"&&Q.status!=="stopped")return h($,X,"This service is owned by a terminal. Restart it there with Ctrl-C, then rerun its LocalDeck command.");let G=await this.stopShare($,Z),J=this.active.get($);if(!J){if(Q&&Q.status!=="stopped"&&Q.managedBy==="terminal"){let Y=await this.stopTerminal(Q);return G?h($,X,b4(G,Y.error),this.registry.get($)??Q):Y}if(G)return h($,X,G,Q);return{key:$,name:X,ok:!0,...Q?{service:G1(Q)}:{}}}let V=Q?.status==="stopping"?Q.upstreamReady?"running":"starting":Q?.status,z=()=>{J.stopping=!1;let Y=this.registry.get($);if(Y&&this.active.get($)===J&&y4(J.child)&&Y.status==="stopping")Y.status=V??(Y.upstreamReady?"running":"starting"),this.store.emitEvent({type:"service",service:Y})};try{if(J.stopping=!0,Q&&Q.status!=="stopped")Q.status="stopping",this.store.emitEvent({type:"service",service:Q});if(Z)this.store.log({ts:Date.now(),service:$,stream:"system",line:`LocalDeck: stopping ${X} (${Z})`});if(await w0(Promise.resolve().then(()=>this.killTree(J.child,"SIGTERM")),this.forceAfterMs),!await w0(J.completion,this.forceAfterMs)){if(await w0(Promise.resolve().then(()=>this.killTree(J.child,"SIGKILL")),this.forceAfterMs),!await w0(J.completion,this.forceAfterMs))return z(),h($,X,`service did not exit within ${this.forceAfterMs}ms after forced termination`,this.registry.get($))}if(process.platform!=="win32"&&!await this.cleanupLeaderFirstExit(J))throw Error(`process group ${J.child.pid??"?"} survived forced cleanup after its leader exited`);if(J.cleanupError=void 0,await this.registry.unregister($),this.active.get($)===J)this.active.delete($);let K=this.registry.get($);if(G)return h($,X,G,K);return{key:$,name:X,ok:!0,...K?{service:G1(K)}:{}}}catch(Y){return z(),h($,X,b4(G,l(Y)),this.registry.get($))}}async stopShare($,Z){if(!this.shareLifecycle)return;try{await this.shareLifecycle.stop($,Z==="restart"?"service restarting":"service stopping");return}catch(Q){return l(Q)}}async cleanupLeaderFirstExit($){if(!$.child.pid)return!0;if(process.platform==="win32")return await w0(Promise.resolve().then(()=>this.killTree($.child,"SIGTERM")),this.forceAfterMs),!0;if(!k4($.child.pid))return!0;if(await w0(Promise.resolve().then(()=>this.killTree($.child,"SIGTERM")),this.forceAfterMs),await v4($.child.pid,this.forceAfterMs))return!0;return await w0(Promise.resolve().then(()=>this.killTree($.child,"SIGKILL")),this.forceAfterMs),v4($.child.pid,this.forceAfterMs)}async stopTerminal($){let Z=await new Promise((X)=>{let G=!1,J=(Y)=>{if(G)return;G=!0,clearTimeout(z),this.store.off("event",V),X(Y)},V=(Y)=>{if(Y.type==="service"&&Y.service.key===$.key&&Y.service.status==="stopped")J(!0);if(Y.type==="service:removed"&&Y.name===$.key)J(!0)},z=setTimeout(()=>J(!1),this.terminalStopAfterMs);if(z.unref(),this.store.on("event",V),!this.registry.requestStop($.key))J(!1)}),Q=this.registry.get($.key);if(!Z)return h($.key,$.name,`terminal service did not stop within ${this.terminalStopAfterMs}ms`,Q??$);return Q?A$(Q):{key:$.key,name:$.name,ok:!0}}scheduleDetection($,Z){let Q,X,G=0,J=async()=>{if(this.active.get($.key)!==$||$.child.exitCode!==null||$.child.signalCode)return;try{let V=await B$(await C$($.child.pid)),z=k1(V,Z),Y=z?void 0:u1(V);if(Y&&Y!==X)this.store.log({ts:Date.now(),service:$.key,stream:"system",line:`LocalDeck: ${Y}`}),this.setLastError($.key,Y);else if(z&&X&&this.registry.get($.key)?.lastError===X)this.setLastError($.key,void 0);if(X=Y,z){let K=m1(z),N=`${K}:${z.port}`;if(N!==Q)Q=N,this.registry.setUpstream($.key,z.port,K),this.releaseAutomaticUpstream($.reservedUpstreamPort),$.reservedUpstreamPort=void 0;G++}}catch{}if(this.active.get($.key)===$)$.detectTimer=setTimeout(J,Q?Math.min(2000+G*500,1e4):400),$.detectTimer.unref()};$.detectTimer=setTimeout(J,this.detectAfterMs),$.detectTimer.unref()}setLastError($,Z){let Q=this.registry.get($);if(!Q)return;Q.lastError=Z,this.store.emitEvent({type:"service",service:Q})}setReadiness($,Z,Q){let X=this.registry.get($);if(!X)return;X.readinessStatus=Z,X.readinessMessage=Q,this.store.emitEvent({type:"service",service:X})}expandCommandEnv($,Z,Q){if(!$)return{};let X=new Set(Z),G=/\{service:([^}:]+):(port|url)\}/g,J={};for(let[V,z]of Object.entries($))if(J[V]=z.replace(G,(Y,K,N)=>{let U=K.toLowerCase();if(!X.has(U))throw Error(`environment variable ${V} references undeclared prerequisite "${K}"`);let W=this.registry.get(u(Q,U));if(!W)throw Error(`environment variable ${V} references unresolved prerequisite "${K}"`);if(N==="port")return String(W.serviceType&&W.serviceType!=="http"?W.upstreamPort:W.stablePort);if(W.serviceType&&W.serviceType!=="http")throw Error(`environment variable ${V} cannot use a URL for database prerequisite "${K}"`);return`http://localhost:${W.stablePort}`}),J[V].includes("{service:"))throw Error(`environment variable ${V} has an invalid service reference`);return J}async reserveAutomaticUpstream(){for(let $=0;$<32;$++){let Z=await this.allocatePort();if(!Number.isInteger(Z)||Z<1||Z>65535)throw Error("upstream allocator returned an invalid port");if(this.upstreamReservations.has(Z))continue;return this.upstreamReservations.add(Z),Z}throw Error("could not reserve a unique automatic upstream port after 32 attempts")}releaseAutomaticUpstream($){if($!==void 0)this.upstreamReservations.delete($)}}function A$($){return{key:$.key,name:$.name,ok:!0,service:G1($)}}function h($,Z,Q,X,G){return{key:$,name:Z,ok:!1,...X?{service:G1(X)}:{},error:Q,...G?{status:G}:{}}}function G1($){return{...$,urls:[...$.urls],stats:{...$.stats},...$.share?{share:{...$.share}}:{}}}function l6($){return $.join(`
134
+ `).slice(-m6)}function l($){return $ instanceof Error?$.message:String($)}function b4($,Z){return[$,Z].filter(Boolean).join("; ")||"stop failed"}function p6($){return $ instanceof Error?$:Error(String($))}function y4($){return $.exitCode===null&&$.signalCode===null}function w0($,Z){return new Promise((Q)=>{let X=setTimeout(()=>Q(!1),Z);$.then(()=>{clearTimeout(X),Q(!0)},()=>{clearTimeout(X),Q(!0)})})}function k4($){try{return process.kill(-$,0),!0}catch(Z){return Z.code==="EPERM"}}async function v4($,Z){let Q=Date.now()+Z;while(k4($)){if(Date.now()>=Q)return!1;await new Promise((X)=>setTimeout(X,Math.min(20,Z)))}return!0}var u4="1.7.1";var l4=u4;async function uX($={}){J$(),y$();let Z={createStore:()=>new Z8,createRegistry:(M,E)=>new a1(M,E,(F)=>Y.nickname(F)),createShareManager:(M,E)=>new v1(M,E),createProjectRegistry:(M)=>new l$({catalogFile:M}),createProcessSupervisor:(M,E,F,w)=>new J1(M,E,F,{shareLifecycle:w}),createApiServer:L4,writePrivateState:K0,...$.dependencies},Q=$.homeDir?m4.join($.homeDir,"daemon.json"):b$,X=$.homeDir?m4.join($.homeDir,"projects.json"):Q$,G=$.apiPort??G$,J=Z.createStore(),V=Z.createRegistry(J,G),z=Z.createShareManager(V,J),Y=Z.createProjectRegistry(X),K=Z.createProcessSupervisor(Y,V,J,z),N=n6(),U=Date.now(),W=i6.randomBytes(32).toString("base64url"),C=!1,D,O,B,L=new Promise((M,E)=>{O=M,B=E});L.catch(()=>{});let _,H=!1,T,A=(M,E)=>{C=!0;let F=[],w=(g)=>{try{return Promise.resolve(g())}catch(b){F.push(p4(b));return}},m=w(()=>z.stopAll()),p=w(()=>K.shutdown()),k=w(async()=>{if(await E,_?.listening)await new Promise((g,b)=>_.close((D0)=>D0?b(D0):g()))});return(async()=>{let g=async(b)=>{if(!b)return;try{await b}catch(D0){F.push(p4(D0))}};return await g(m),await g(p),await g(k),await g(w(()=>N.waitForIdle())),await g(w(()=>V.closeAll())),await g(w(()=>J.close())),await g(w(()=>{if(M==="failed-write"){if(!H)return;if(X0.rmSync(`${Q}.${process.pid}.tmp`,{force:!0}),T)c6(Q,T.contents,T.mode);else X0.rmSync(Q,{force:!0});return}if(r(Q,null)?.pid===process.pid)X0.unlinkSync(Q)})),F})()},R=(M)=>{if(D)return D;return C=!0,D=A("owned",M).then((E)=>{if(E.length)throw AggregateError(E,"daemon shutdown cleanup failed")}),D.then(O,B),D};_=Z.createApiServer({registry:V,store:J,shares:z,projects:Y,supervisor:K,controlToken:W,isShuttingDown:()=>C,trackAttachOperation:N.track,dashboardDir:$.dashboardDir,allowedBrowserOrigins:$.allowedBrowserOrigins,version:l4,startedAt:U,shutdown:R,listProjectSecrets:A0,setProjectSecret:D$,deleteProjectSecret:O$,resolveProjectSecrets:z0});try{if(await new Promise((M,E)=>{_.once("error",E),_.listen(G,"127.0.0.1",()=>{_.off("error",E),M()})}),_.on("error",(M)=>console.error(`LocalDeck: API server error: ${M.message}`)),X0.existsSync(Q)){let M=X0.statSync(Q);T={contents:X0.readFileSync(Q),mode:M.mode&511}}return H=!0,Z.writePrivateState(Q,{pid:process.pid,apiPort:G,startedAt:U,version:l4,controlToken:W}),{apiPort:G,stop:R,stopped:L}}catch(M){let E=await A("failed-write");if(E.length)throw AggregateError([M,...E],"daemon startup failed and cleanup encountered errors",{cause:M});throw M}}function c6($,Z,Q){let X=`${$}.${process.pid}.restore.tmp`;X0.writeFileSync(X,Z,{mode:Q}),X0.chmodSync(X,Q),X0.renameSync(X,$)}function p4($){return $ instanceof Error?$:Error(String($))}function n6(){let $=new Set;return{track:(X)=>{return $.add(X),X.then(()=>$.delete(X),()=>$.delete(X)),X},waitForIdle:async()=>{while($.size)await Promise.allSettled([...$])}}}async function J8($=b$){let Z;try{Z=JSON.parse(X0.readFileSync($,"utf8"))}catch(Q){let X=Q.code;if(X==="EACCES"||X==="EPERM")throw Error(`Cannot read LocalDeck daemon state at ${$}: permission denied. The daemon may still be running under another user (often after sudo). If it was started with sudo, run sudo localdeck daemon stop, then localdeck daemon start without sudo. Do not make the state file world-readable; it contains a private control token.`);if(X==="ENOENT"||Q instanceof SyntaxError)return null;throw Error(`Cannot read LocalDeck daemon state at ${$}${X?` (${X})`:""}. Check the file and directory permissions.`)}if(!Z)return null;try{let Q=await fetch(`http://127.0.0.1:${Z.apiPort}/api/status`,{signal:AbortSignal.timeout(1000)});if(!Q.ok)return null;return(await Q.json()).pid===Z.pid?Z:null}catch{return null}}import{spawn as a6,spawnSync as o6}from"node:child_process";import V1 from"node:fs";import j0 from"node:path";import{fileURLToPath as d4}from"node:url";function VG(){let $=j0.dirname(d4(import.meta.url));return[j0.resolve($,"../dashboard"),j0.resolve($,"../../dashboard/dist")].find((Q)=>V1.existsSync(j0.join(Q,"index.html")))}function s6(){let $=process.argv[1];if(Boolean(process.versions.bun)){let Q=j0.resolve(j0.dirname(d4(import.meta.url)),"../dist/index.js"),X=o6("node",["--version"],{stdio:"ignore"}).status===0;if(V1.existsSync(Q)&&X)return["node",[Q,"daemon","run"]];console.warn("LocalDeck: starting daemon under Bun — WebSocket proxying (HMR) will not work. Run `bun run build` and make sure `node` is on PATH.")}if(!$||$.startsWith("/$bunfs")||$.includes("~BUN"))return[process.execPath,["daemon","run"]];return[process.execPath,[$,"daemon","run"]]}async function YG(){J$();let $=await J8();if($)return $;V1.mkdirSync(j0.dirname(X$),{recursive:!0});let Z=V1.openSync(X$,"a"),[Q,X]=s6();a6(Q,X,{detached:!0,stdio:["ignore",Z,Z],env:process.env}).unref();let J=Date.now()+8000;while(Date.now()<J){await new Promise((z)=>setTimeout(z,150));let V=await J8();if(V)return V}throw Error(`LocalDeck daemon did not start on port ${G$}. See ${X$}`)}class t6{port;fetch;timeoutMs;constructor($,Z=globalThis.fetch,Q){this.port=$;this.fetch=Z;this.timeoutMs=Q}get base(){return`http://127.0.0.1:${this.port}`}async call($,Z,Q,X){let G=await this.fetch(this.base+Z,{method:$,...this.timeoutMs?{signal:AbortSignal.timeout(this.timeoutMs)}:{},headers:{...Q?{"content-type":"application/json"}:{},...X},body:Q?JSON.stringify(Q):void 0}),J=await G.json().catch(()=>({}));if(!G.ok){let V=Array.isArray(J.alternatives)&&J.alternatives.every((z)=>typeof z==="string")?`; alternatives: ${J.alternatives.join(", ")}`:"";throw Error(`${J.error??`${$} ${Z} → ${G.status}`}${V}`)}return J}projects=()=>this.call("GET","/api/projects");project=($)=>this.call("GET",`/api/projects/${encodeURIComponent($)}`);timeline=($,Z={})=>{let Q=new URLSearchParams;if(Z.services)Q.set("services",Z.services.join(","));for(let X of["filter","query","cursor","limit"])if(Z[X]!==void 0)Q.set(X,String(Z[X]));return this.call("GET",`/api/projects/${encodeURIComponent($)}/activity?${Q}`)};markBaseline=($,Z)=>this.call("POST",`/api/projects/${encodeURIComponent($)}/baselines`,Z);baselines=($)=>this.call("GET",`/api/projects/${encodeURIComponent($)}/baselines`);compareBaseline=($,Z)=>this.call("GET",`/api/projects/${encodeURIComponent($)}/baselines/${encodeURIComponent(Z)}`);environments=($)=>this.call("GET",`/api/projects/${encodeURIComponent($)}/environments`);registerEnvironment=($,Z)=>this.call("POST",`/api/projects/${encodeURIComponent($)}/environments/${encodeURIComponent(Z)}/register`,{});exportRequest=($,Z)=>this.call("GET",`/api/services/${encodeURIComponent($)}/reproduction?requestId=${encodeURIComponent(Z)}`);saveCheck=($,Z)=>this.call("POST",`/api/projects/${encodeURIComponent($)}/checks`,Z);checks=($)=>this.call("GET",`/api/projects/${encodeURIComponent($)}/checks`);runCheck=($,Z)=>this.call("POST",`/api/projects/${encodeURIComponent($)}/checks/${encodeURIComponent(Z)}/run`,{});serviceAction=($,Z,Q)=>this.call("POST",`/api/projects/${encodeURIComponent($)}/services/${encodeURIComponent(Z)}/${Q}`,{});shareInfo=($)=>this.call("GET",`/api/services/${encodeURIComponent($)}/share`);replay=($,Z)=>this.call("POST",`/api/services/${encodeURIComponent($)}/replay`,{requestId:Z});services=()=>this.call("GET","/api/services");forwarder=()=>this.call("GET","/api/forwarder");profiles=($)=>this.call("GET",`/api/projects/${encodeURIComponent($)}/profiles`);setActiveProfiles=($,Z)=>this.call("PUT",`/api/projects/${encodeURIComponent($)}/profiles/active`,{profiles:Z});rememberProject=($,Z)=>this.call("POST","/api/projects/remember",{file:$},{authorization:`Bearer ${Z}`});async servicePath($){let Z=$.lastIndexOf("/");if(Z===-1)return encodeURIComponent($);let Q=$.slice(0,Z).toLowerCase(),X=$.slice(Z+1).toLowerCase(),G=(await this.services()).filter((J)=>J.name===X&&(J.projectId.toLowerCase()===Q||J.projectName.toLowerCase()===Q||J.projectSlug.toLowerCase()===Q));if(G.length===1)return encodeURIComponent(G[0].key);if(G.length>1)throw Error(`service reference "${$}" is ambiguous; alternatives: ${G.map((J)=>J.key).join(", ")}`);return encodeURIComponent($)}service=async($)=>this.call("GET",`/api/services/${await this.servicePath($)}`);logs=async($,Z)=>this.call("GET",`/api/services/${await this.servicePath($)}/logs?limit=${Z}`);response=($,Z)=>this.call("GET",`/api/services/${encodeURIComponent($)}/response?requestId=${encodeURIComponent(Z)}`);requests=async($,Z)=>this.call("GET",`/api/services/${await this.servicePath($)}/requests?limit=${Z}`);stop=async($)=>this.call("POST",`/api/services/${await this.servicePath($)}/stop`);share=async($,Z,Q=!1,X=!1)=>this.call("POST",`/api/services/${await this.servicePath($)}/share${Q?"/new":""}`,X?{public:!0}:{password:Z});unshare=async($)=>this.call("DELETE",`/api/services/${await this.servicePath($)}/share`);shutdown=()=>this.call("POST","/api/shutdown")}
135
+ export{O0 as J,d as K,r6 as L,y as M,TZ as N,o as O,b$ as P,G$ as Q,J$ as R,Y$ as S,K$ as T,K5 as U,z5 as V,q3 as W,L0 as X,I1 as Y,V$ as Z,U$ as _,c$ as $,A0 as aa,z0 as ba,L5 as ca,u as da,C$ as ea,B$ as fa,k1 as ga,u1 as ha,m1 as ia,e$ as ja,l1 as ka,$1 as la,h4 as ma,X8 as na,u$ as oa,G8 as pa,Q1 as qa,l4 as ra,uX as sa,J8 as ta,VG as ua,YG as va,t6 as wa};