@tdk-landscape/tdk-cli-core 1.3.144 → 1.3.145
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/cli/dist/commands/doctor.js +6 -0
- package/cli/dist/commands/status.js +17 -20
- package/cli/dist/commands/up.js +10 -1
- package/cli/dist/generator/template-engine.js +6 -3
- package/cli/dist/utils/doctor-host.js +66 -0
- package/cli/dist-bundle/{chunk-2PTDOT3Y.js → chunk-47CDYJ5E.js} +57 -56
- package/cli/dist-bundle/cli.js +206 -206
- package/cli/dist-bundle/{cold-preflight-CGPSYGDB.js → cold-preflight-F2FM46HK.js} +1 -1
- package/cli/package.json +1 -1
- package/ext/ide-components/shared/templates/base.html +4 -8
- package/package.json +1 -1
|
@@ -1,44 +1,45 @@
|
|
|
1
1
|
import{createRequire as __tdkRequire}from'node:module';const require=__tdkRequire(import.meta.url);
|
|
2
|
-
import{c as
|
|
2
|
+
import{c as pn}from"./chunk-42IVF3YT.js";import{execFileSync as Ns}from"node:child_process";import{readFileSync as Kc}from"node:fs";import{join as Gc}from"node:path";import{execFileSync as lc,execSync as ws}from"node:child_process";import{existsSync as C,readdirSync as pc,readFileSync as ie}from"node:fs";import{join as E,normalize as tn,relative as nn}from"node:path";function fn(e,t,n){let r=e.indexOf(t);if(r===-1)return e;let s=t.length,o=0,i="";do i+=e.slice(o,r)+t+n,o=r+s,r=e.indexOf(t,o);while(r!==-1);return i+=e.slice(o),i}function mn(e,t,n,r){let s=0,o="";do{let i=e[r-1]==="\r";o+=e.slice(s,i?r-1:r)+t+(i?`\r
|
|
3
3
|
`:`
|
|
4
4
|
`)+n,s=r+1,r=e.indexOf(`
|
|
5
|
-
`,s)}while(r!==-1);return o+=e.slice(s),o}var
|
|
6
|
-
`);return o!==-1&&(t=
|
|
5
|
+
`,s)}while(r!==-1);return o+=e.slice(s),o}var hn=(e=0)=>t=>`\x1B[${t+e}m`,et=(e=0)=>t=>`\x1B[${38+e};5;${t}m`,tt=(e=0)=>(t,n,r)=>`\x1B[${38+e};2;${t};${n};${r}m`,Is=e=>`\x1B[58;5;${e<90?e-30:e-90+8}m`,T={modifier:{reset:[0,0],bold:[1,22],dim:[2,22],italic:[3,23],underline:[4,24],underlineDouble:["4:2",24],underlineCurly:["4:3",24],underlineDotted:["4:4",24],underlineDashed:["4:5",24],overline:[53,55],inverse:[7,27],hidden:[8,28],strikethrough:[9,29]},color:{black:[30,39],red:[31,39],green:[32,39],yellow:[33,39],blue:[34,39],magenta:[35,39],cyan:[36,39],white:[37,39],blackBright:[90,39],gray:[90,39],grey:[90,39],redBright:[91,39],greenBright:[92,39],yellowBright:[93,39],blueBright:[94,39],magentaBright:[95,39],cyanBright:[96,39],whiteBright:[97,39]},bgColor:{bgBlack:[40,49],bgRed:[41,49],bgGreen:[42,49],bgYellow:[43,49],bgBlue:[44,49],bgMagenta:[45,49],bgCyan:[46,49],bgWhite:[47,49],bgBlackBright:[100,49],bgGray:[100,49],bgGrey:[100,49],bgRedBright:[101,49],bgGreenBright:[102,49],bgYellowBright:[103,49],bgBlueBright:[104,49],bgMagentaBright:[105,49],bgCyanBright:[106,49],bgWhiteBright:[107,49]},underlineColor:{underlineBlack:["58;5;0",59],underlineRed:["58;5;1",59],underlineGreen:["58;5;2",59],underlineYellow:["58;5;3",59],underlineBlue:["58;5;4",59],underlineMagenta:["58;5;5",59],underlineCyan:["58;5;6",59],underlineWhite:["58;5;7",59],underlineBlackBright:["58;5;8",59],underlineGray:["58;5;8",59],underlineGrey:["58;5;8",59],underlineRedBright:["58;5;9",59],underlineGreenBright:["58;5;10",59],underlineYellowBright:["58;5;11",59],underlineBlueBright:["58;5;12",59],underlineMagentaBright:["58;5;13",59],underlineCyanBright:["58;5;14",59],underlineWhiteBright:["58;5;15",59]}},Zc=Object.keys(T.modifier),Fs=Object.keys(T.color),Ms=Object.keys(T.bgColor),Qc=Object.keys(T.underlineColor),eu=[...Fs,...Ms];function Ls(){let e=new Map;for(let[t,n]of Object.entries(T)){for(let[r,s]of Object.entries(n))T[r]={open:`\x1B[${s[0]}m`,close:`\x1B[${s[1]}m`},n[r]=T[r],e.set(Number.parseInt(s[0],10),s[1]);Object.defineProperty(T,t,{value:n,enumerable:!1})}return Object.defineProperty(T,"codes",{value:e,enumerable:!1}),T.color.close="\x1B[39m",T.bgColor.close="\x1B[49m",T.underlineColor.close="\x1B[59m",T.color.ansi=hn(),T.color.ansi256=et(),T.color.ansi16m=tt(),T.bgColor.ansi=hn(10),T.bgColor.ansi256=et(10),T.bgColor.ansi16m=tt(10),T.underlineColor.ansi=Is,T.underlineColor.ansi256=et(20),T.underlineColor.ansi16m=tt(20),Object.defineProperties(T,{rgbToAnsi256:{value(t,n,r){return t===n&&n===r?t<8?16:t>248?231:Math.round((t-8)/247*24)+232:16+36*Math.round(t/255*5)+6*Math.round(n/255*5)+Math.round(r/255*5)},enumerable:!1},hexToRgb:{value(t){let n=/[\da-f]{6}|[\da-f]{3}/i.exec(t.toString(16));if(!n)return[0,0,0];let[r]=n;r.length===3&&(r=[...r].map(o=>o+o).join(""));let s=Number.parseInt(r,16);return[s>>16&255,s>>8&255,s&255]},enumerable:!1},hexToAnsi256:{value:t=>T.rgbToAnsi256(...T.hexToRgb(t)),enumerable:!1},ansi256ToAnsi:{value(t){if(t<8)return 30+t;if(t<16)return 90+(t-8);let n,r,s;if(t>=232)n=((t-232)*10+8)/255,r=n,s=n;else{t-=16;let a=t%36;n=Math.floor(t/36)/5,r=Math.floor(a/6)/5,s=a%6/5}let o=Math.max(n,r,s)*2;if(o===0)return 30;let i=30+(Math.round(s)<<2|Math.round(r)<<1|Math.round(n));return o===2&&(i+=60),i},enumerable:!1},rgbToAnsi:{value:(t,n,r)=>T.ansi256ToAnsi(T.rgbToAnsi256(t,n,r)),enumerable:!1},hexToAnsi:{value:t=>T.ansi256ToAnsi(T.hexToAnsi256(t)),enumerable:!1}}),T}var Bs=Ls(),L=Bs;import nt from"node:process";import Us from"node:os";import gn from"node:tty";function N(e,t=globalThis.Deno?globalThis.Deno.args:nt.argv){let n=e.startsWith("-")?"":e.length===1?"-":"--",r=t.indexOf(n+e),s=t.indexOf("--");return r!==-1&&(s===-1||r<s)}var{env:x}=nt,$e;N("no-color")||N("no-colors")||N("color=false")||N("color=never")?$e=0:(N("color")||N("colors")||N("color=true")||N("color=always"))&&($e=1);function yn(){return/^\d+$/.test(x.FORCE_COLOR)}function Hs(){if("FORCE_COLOR"in x){if(x.FORCE_COLOR==="false")return 0;if(x.FORCE_COLOR==="true"||x.FORCE_COLOR.length===0)return 1;if(yn())return Math.min(Number.parseInt(x.FORCE_COLOR,10),3)}}function Vs(e){return e===0?!1:{level:e,hasBasic:!0,has256:e>=2,has16m:e>=3}}function Ks(e,{streamIsTTY:t,sniffFlags:n=!0}={}){let r=Hs();r!==void 0&&($e=r);let s=n?$e:r;if(s===0)return 0;if(n){if(N("color=16m")||N("color=full")||N("color=truecolor"))return 3;if(N("color=256"))return 2}if(s!==void 0&&yn())return s;if("TF_BUILD"in x&&"AGENT_NAME"in x)return 1;if(e&&!t&&s===void 0)return 0;let o=s||0;if(x.TERM==="dumb")return o;if(nt.platform==="win32"){let i=Us.release().split(".");return Number(i[0])>=10&&Number(i[2])>=10586?Number(i[2])>=14931?3:2:1}if("CI"in x)return["GITHUB_ACTIONS","GITEA_ACTIONS","CIRCLECI"].some(i=>i in x)?3:["TRAVIS","APPVEYOR","GITLAB_CI","BUILDKITE","DRONE"].some(i=>i in x)||x.CI_NAME==="codeship"?1:o;if("TEAMCITY_VERSION"in x)return/^(?:9\.0*[1-9]\d*\.|\d{2,}\.)/.test(x.TEAMCITY_VERSION)?1:0;if(x.COLORTERM==="truecolor"||x.TERM==="xterm-kitty"||x.TERM==="xterm-ghostty"||x.TERM==="wezterm")return 3;if("TERM_PROGRAM"in x){let i=Number.parseInt((x.TERM_PROGRAM_VERSION||"").split(".",1)[0],10);switch(x.TERM_PROGRAM){case"iTerm.app":return i>=3?3:2;case"Apple_Terminal":return 2}}return/-256(?:color)?$/i.test(x.TERM)?2:/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(x.TERM)||"COLORTERM"in x?1:o}function kn(e,t={}){let n=Ks(e,{streamIsTTY:e&&e.isTTY,...t});return Vs(n)}var Gs={stdout:kn({isTTY:gn.isatty(1)}),stderr:kn({isTTY:gn.isatty(2)})},Sn=Gs;var{stdout:bn,stderr:Tn}=Sn,de=Symbol("GENERATOR"),le=Symbol("STYLER"),_e=Symbol("IS_EMPTY"),Re=Symbol("LEVEL"),pe=Object.create(null),xn=e=>{if(!Number.isSafeInteger(e)||e<0||e>3)throw new Error("The `level` should be an integer from 0 to 3")},Ws={enumerable:!0,get(){return this[Re]},set(e){xn(e),this[Re]=e}},Js=(e,t={})=>{t.level!==void 0&&xn(t.level);let n=bn?bn.level:0;e[Re]=t.level===void 0?n:t.level};var qs=e=>{let t=(...n)=>n.join(" ");return Js(t,e),Object.setPrototypeOf(t,fe.prototype),t};function fe(e){return qs(e)}Object.setPrototypeOf(fe.prototype,Function.prototype);for(let[e,t]of Object.entries(L))pe[e]={get(){let n=st(this,Pn(t.open,t.close,this[le]),this[_e]);return Object.defineProperty(this,e,{value:n}),n}};pe.visible={get(){let e=st(this,this[le],!0);return Object.defineProperty(this,"visible",{value:e}),e}};var Ys=(e,t)=>{let n=L[t];if(e==="rgb"){let s=(i,a,c)=>n.ansi(L.rgbToAnsi(i,a,c));return[s,s,(i,a,c)=>n.ansi256(L.rgbToAnsi256(i,a,c)),n.ansi16m]}if(e==="hex"){let s=i=>n.ansi(L.hexToAnsi(i));return[s,s,i=>n.ansi256(L.hexToAnsi256(i)),i=>n.ansi16m(...L.hexToRgb(i))]}let r=s=>n.ansi(L.ansi256ToAnsi(s));return[r,r,n.ansi256,n.ansi256]},zs=["rgb","hex","ansi256"];for(let e of zs){let t=e[0].toUpperCase()+e.slice(1);for(let[n,r]of[[e,"color"],["bg"+t,"bgColor"],["underline"+t,"underlineColor"]]){let{close:s}=L[r],o=Ys(e,r);pe[n]={get(){let i=function(a,c,u){let d=o[this.level](a,c,u);return st(this,Pn(d,s,this[le]),this[_e])};return Object.defineProperty(this,n,{value:i}),i}}}}var Xs=Object.defineProperties(()=>{},{...pe,level:{enumerable:!0,get(){return this[de].level},set(e){this[de].level=e}}}),Pn=(e,t,n)=>{let r,s;return n===void 0?(r=e,s=t):(r=n.openAll+e,s=t+n.closeAll),{open:e,close:t,openAll:r,closeAll:s,parent:n}},st=(e,t,n)=>{let r=(...s)=>s.length===1?rt(r,""+s[0]):s.length===2?rt(r,`${s[0]??""} ${s[1]??""}`):rt(r,s.join(" "));return Object.setPrototypeOf(r,Xs),r[de]=e[de]??e,r[le]=t,r[_e]=n,r},rt=(e,t)=>{if(e[de][Re]<=0||!t)return e[_e]?"":t;let n=e[le];if(n===void 0)return t;let{openAll:r,closeAll:s}=n;if(t.includes("\x1B"))for(;n!==void 0;)t=fn(t,n.close,n.open),n=n.parent;let o=t.indexOf(`
|
|
6
|
+
`);return o!==-1&&(t=mn(t,s,r,o)),r+t+s};Object.defineProperties(fe.prototype,{...pe,level:Ws});var Zs=fe(),uu=fe({level:Tn?Tn.level:0});var f=Zs;import{Command as fc}from"commander";import{existsSync as Qs}from"node:fs";var Oe="docs/agent-hosts.md",ot=`WebContainers cannot run TDK: there is no Docker daemon or Tilt. Run \`tdk up\` on a machine with Docker. See ${Oe}.`,En=`Docker is not reachable from this Dev Container. Mount the host Docker socket (-v /var/run/docker.sock:/var/run/docker.sock) or add the docker-outside-of-docker feature to devcontainer.json, then retry. Docker-in-docker is not supported. See ${Oe}.`;function eo(){return{env:process.env,versions:process.versions,platform:process.platform,fileExists:Qs}}function wn(e=eo()){let{env:t,versions:n,platform:r,fileExists:s}=e;return n.webcontainer?{kind:"webcontainer",canUp:!1}:t.CODESPACES==="true"?{kind:"codespaces",canUp:!0}:t.REMOTE_CONTAINERS||s("/.dockerenv")&&t.DEVCONTAINER?{kind:"devcontainer",canUp:!0}:r==="win32"?{kind:"native-windows",canUp:t.TDK_ALLOW_NATIVE_WINDOWS==="1"}:r==="linux"&&t.WSL_DISTRO_NAME?{kind:"wsl2",canUp:!0}:{kind:"local",canUp:!0}}function vn(e){return e==="devcontainer"||e==="codespaces"}function v(e){return e==="backend"||e==="mcp"}function Ae(e){return e.some(t=>v(t.config?.appType)||t.config?.appType==="frontend"||t.config?.appType==="worker")}var A="Container Runtime",B="bring-your-own";var U="database-management",gu=".tiltignore",$n="service.json",me="docker-compose.yml",F=".autogenerated",to="TILT_TECH_STACK.star",no="TILT_RESOURCE_DEFAULTS.star",P="project.json",D="package.json",it=[to,no,"spec.master"],ku=["backend","frontend","library","sdk","worker","migrator","mcp",B],at={backend:["dev","build","start"],worker:["dev","build","start"],migrator:["dev","build","start"],mcp:["dev","build","start"],frontend:["dev","build"],library:["dev","build"],sdk:["dev","build"],[B]:[]};var ct=["monitoring","elk","debezium","golden_image","verdaccio"],yu={frontend:{base:3e3,min:3e3,max:3999,range:"3000-3999"},backend:{base:4e3,min:4e3,max:4999,range:"4000-4999"},mcp:{base:4e3,min:4e3,max:5999,range:"4000-5999"},[B]:{base:4e3,min:4e3,max:5999,range:"4000-5999"},worker:{base:6e3,min:6e3,max:6999,range:"6000-6999"},health:{base:5e3,min:5e3,max:5999,range:"5000-5999"},migrator:{base:7e3,min:7e3,max:7999,range:"7000-7999"}},Rn={tiltUi:10350,traefik:8080},ut="https://tdk-landscape.github.io/tdk-website/docs/quickstart/";var _n=["node_modules",".git",".tilt",".tilt-engine","dist","build",".prisma",".turbo","coverage","tmp","temp","__tests__","test","tests",".github",".vscode","docs"],On=["Dockerfile",me,"docker-compose.yaml","Tiltfile","vite.config.ts","tsconfig.json","tsconfig.build.json"],ro={infra:"\u{1F3D7}\uFE0F",core:"\u{1F527}",api:"\u26A1",app:"\u{1F3A8}",orchestrator:"\u2699\uFE0F"};function Su(e){let t=e.toLowerCase();for(let[n,r]of Object.entries(ro))if(t.includes(n))return r;return"\u{1F4E6}"}import{existsSync as so,readFileSync as oo}from"node:fs";import{join as io,relative as An,resolve as Dn,sep as ao}from"node:path";var co=2,Cn=["services/*/*"];function Nn(e){return e.split(ao).filter(Boolean)}function uo(e,t){let n=0,r=0,s=-1,o=0;for(;r<t.length;)if(n<e.length&&e[n]!=="*"&&(e[n]==="?"||e[n]===t[r]))n++,r++;else if(n<e.length&&e[n]==="*")s=n++,o=r;else if(s!==-1)n=s+1,r=++o;else return!1;for(;n<e.length&&e[n]==="*";)n++;return n===e.length}function lo(e,t){return e.length===t.length&&e.every((n,r)=>uo(n,t[r]))}function dt(e){let t=io(e,".tdk",P);if(!so(t))return Cn;try{let n=JSON.parse(oo(t,"utf-8"))?.discovery?.paths;if(Array.isArray(n)&&n.every(r=>typeof r=="string"))return n}catch{}return Cn}function De(e,t,n){let r=Nn(An(e,Dn(e,t)));return n.some(s=>{let o=Nn(An(e,Dn(e,s)));for(let i=0;i<=co;i++){let a=r.length-i;if(a>0&&lo(o,r.slice(0,a)))return!0}return!1})}function Eu(e,t,n,r){let s=dt(e);if(De(e,t,s))return{path:t};let o=`services/${n}/${r}`;return De(e,o,s)?{path:o,adjustedFrom:t}:{path:t}}import{statfsSync as po}from"node:fs";import{homedir as fo}from"node:os";var Ce="Disk Space",mo=1024**3,ho=2,go=10,jn=["Free disk space, then retry: tdk doctor"," docker system prune -af # unused images and build cache (needs Docker running)"," npm cache clean --force"," bun pm cache rm"," brew cleanup -s"].join(`
|
|
7
|
+
`);function In(e=po,t=fo()){let n;try{let s=e(t);n=Number(s.bavail)*Number(s.bsize)/mo}catch{return{name:Ce,didPass:!0,isSkipped:!0,message:"Could not read free disk space"}}let r=`${n.toFixed(1)} GB free`;return n<ho?{name:Ce,didPass:!1,message:`${r}: Docker cannot build or start containers`,fix:jn}:n<go?{name:Ce,didPass:!1,isWarning:!0,message:`${r}: image builds may fail`,fix:jn}:{name:Ce,didPass:!0,message:r}}var ko="Quit Docker Desktop completely (whale icon > Quit Docker Desktop), reopen it, and wait until it shows Running. If it keeps getting stuck, check free disk space. Then retry: tdk doctor";function Fn(e,t=process.platform){return t!=="darwin"||!e?null:{name:"Container Runtime",didPass:!1,message:"Docker Desktop is open, but its engine is not responding",fix:ko}}async function Ln(e,t){let n=[],r=[],s=o=>{o.status==="fulfilled"?n.push(o.value):r.push({code:"INTERNAL",message:o.reason instanceof Error?o.reason.message:String(o.reason)})};for(let o of await Promise.allSettled(e.map(i=>Promise.resolve().then(i))))s(o);for(let o of t)for(let i of await Promise.allSettled([Promise.resolve().then(o)]))s(i);return{checks:n,errors:r}}function Mn(e){let t=e.find(n=>n.name===A);return t?t.didPass:null}function z(e,t,n=[],r,s){return{schemaVersion:1,data:{ready:n.length===0&&e.every(o=>o.didPass||o.isSkipped||o.isWarning),inProject:t,checks:e,...s?{host:{...s,containerRuntimeReachable:Mn(e),canUp:s.canUp&&Mn(e)!==!1}}:{},...r!==void 0?{ports:{http:{requested:r?.requested.ingressHttp??80,chosen:r?.ingressHttp??null,explicit:r?.explicit.ingressHttp??!!process.env.TDK_HTTP_PORT,reason:r?.reason.ingressHttp??"port planning failed"},https:{requested:r?.requested.ingressHttps??443,chosen:r?.ingressHttps??null,explicit:r?.explicit.ingressHttps??!!process.env.TDK_HTTPS_PORT,reason:r?.reason.ingressHttps??"port planning failed"},postgres:{requested:r?.requested.postgres??5432,chosen:r?.postgres??null,explicit:r?.explicit.postgres??!!process.env.TDK_POSTGRES_PORT,reason:r?.reason.postgres??"port planning failed"}}}:{}},errors:n}}function Bn(e){return e.errors.length>0?2:e.data.ready?0:1}import{execFileSync as wr,execSync as Te}from"node:child_process";import{existsSync as _t,readdirSync as Ei,readFileSync as Ot}from"node:fs";import{join as te}from"node:path";function yo(e,t,n){return e===1?t:n||`${t}s`}function S(e,t,n){return`${e} ${yo(e,t,n)}`}var So={month:"short",day:"numeric",hour:"2-digit",minute:"2-digit"};function Du(e){return new Date(e).toLocaleString("en-US",So)}function Cu(e){return new Date(e).toLocaleDateString("en-US",{month:"short",day:"numeric"})}var lt={success:{color:"green",icon:"\u2713",chalkFn:f.green},error:{color:"red",icon:"\u2717",chalkFn:f.red},warning:{color:"yellow",icon:"\u25CB",chalkFn:f.yellow},unknown:{color:"gray",icon:"?",chalkFn:f.gray}};function pt(e){if(!e)return"unknown";let t=e.toLowerCase();return t==="ready"||t==="healthy"||t==="active"||t==="running"?"success":t==="error"||t==="failed"||t==="critical"||t==="stopped"?"error":t==="pending"||t==="starting"||t==="building"||t==="degraded"?"warning":"unknown"}function Nu(e){return lt[pt(e)].color}function ju(e){return lt[pt(e)].icon}function Iu(e,t){return lt[pt(t)].chalkFn(e)}var bo={resources:{singular:"resource",command:"tdk resource <name>",context:`
|
|
7
8
|
To create a resource:`},stacks:{singular:"stack",command:"tdk stack <stack-name>",context:`
|
|
8
9
|
To create a stack, use:`},services:{singular:"service",command:"tdk resource <name>",context:`
|
|
9
10
|
To create a service:`},"stack-services":{singular:"service",command:"tdk resource <name> --stack <stack-name>",context:`
|
|
10
|
-
To add services to this stack:`}};function
|
|
11
|
-
Or create a new resource with a stack:`)),console.log(f.gray(" tdk resource <name> --stack <stack-name>")))}function
|
|
12
|
-
`))}function $u(e,t){console.log(f.green(`All ${e} are ${t}!`))}var pt=62;function Ru(e="\u2500",t=pt){return e.repeat(t)}function In(e,t=pt-2){let n=Math.max(0,t-e.length),r=Math.floor(n/2),s=n-r;return" ".repeat(r)+e+" ".repeat(s)}function _u(e,t){return e.length>t?`${e.slice(0,t-1)}\u2026`:e.padEnd(t)}function Ou(e,t){return e.length<=t?e:`${e.slice(0,t-3)}...`}function Au(e){console.log(f.green(`\u2713 ${e}`))}function Du(e){console.log(f.blue(e))}function Cu(e,t=2){console.log(f.gray(`${" ".repeat(t)}${e}`))}function Nu(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function ju(e,t,n=pt){let r=n-2,s="\u2500".repeat(r);console.log(),console.log(f.cyan(`\u256D${s}\u256E`)),console.log(f.cyan("\u2502")+f.bold.white(In(e,r))+f.cyan("\u2502")),t&&(console.log(f.cyan(`\u251C${s}\u2524`)),console.log(f.cyan("\u2502")+f.gray(In(t,r))+f.cyan("\u2502"))),console.log(f.cyan(`\u2570${s}\u256F`))}import{existsSync as po}from"node:fs";import{dirname as fo,join as mo,resolve as Mn}from"node:path";import{cwd as ho}from"node:process";var Fn={name:"tdk-cli-internal",private:!0,version:"1.3.144",description:"TDK CLI \u2014 start services on your machine.",keywords:["tdk","tilt","cli","local-dev","microservices"],homepage:"https://github.com/tdk-landscape/tdk-cli-core#readme",bugs:{url:"https://github.com/tdk-landscape/tdk-cli-core/issues"},repository:{type:"git",url:"git+https://github.com/tdk-landscape/tdk-cli-core.git",directory:"cli"},license:"MIT",author:"TDK Team",type:"module",main:"./dist/index.js",types:"./dist/index.d.ts",bin:{tdk:"bin/tdk.js","tdk-cli":"bin/tdk.js"},files:["dist","dist-bundle","bin","templates","README.md","Tiltfile","engine","discovery","specs","ext","!ext/ide-components/code_executor","shared-platform-engineering/docker-templates"],scripts:{build:"tsc && node scripts/bundle.mjs","build:watch":"tsc --watch",lint:"biome check .","lint:fix":"biome check . --write",typecheck:"tsc --project tsconfig.typecheck.json",clean:"rm -rf dist",dev:"bun run build:watch",test:"vitest run","test:watch":"vitest",prepack:"../scripts/stage-npm-engine.sh && npm run build"},dependencies:{commander:"^15.0.0",handlebars:"^4.7.8"},devDependencies:{"@biomejs/biome":"^2.5.13","@types/node":"^22.0.0","@types/react":"^19.3.0",ajv:"^8.17.1",chalk:"^6.0.1",esbuild:"^0.28.2",ink:"^7.1.1",knip:"^6.38.0",react:"^19.3.0","react-devtools-core":"^8.0.0",typescript:"^7.0.2",vite:"^8.3.1",vitest:"^5.0.0"},engines:{node:">=22.12.0"}};function m(e=ho()){let t=Mn(e),n=Mn("/");for(;t!==n;){if(po(mo(t,".tdk",E)))return t;let r=fo(t);if(r===t)break;t=r}return null}var Ce=null;function go(){if(Ce)return Ce;let e=Fn;if(!e||typeof e!="object"||Array.isArray(e))throw new Error("Invalid package.json: expected object");let t=e;return Ce={name:String(t.name??"@tdk-landscape/tdk-cli-core"),version:String(t.version??"0.0.0"),fullPackage:t},Ce}function Ln(){return go().version}import{readFileSync as ko}from"node:fs";import{join as yo}from"node:path";function Ne(){let e=m();if(e)try{let t=ko(yo(e,".tdk",E),"utf-8"),n=JSON.parse(t);if(n?.project?.name)return n.project.name}catch{}return"tdk-project"}function ft(e){let t=Ne(),n=process.env.TDK_SERVICE_BASE_URL??`http://${t}.localhost${e?`:${e}`:""}`;try{let r=new URL(n.includes("://")?n:`http://${n}`),s=r.hostname,o=r.port||(e?String(e):"");if(s==="localhost"||/^\d+\.\d+\.\d+\.\d+$/.test(s))return{appBase:`${r.protocol}//${s}${o?`:${o}`:""}`,apiBase:`${r.protocol}//${s}${o?`:${o}`:""}`};let i=s.replace(/^(app|api)\./,"");return{appBase:`${r.protocol}//app.${i}${o?`:${o}`:""}`,apiBase:`${r.protocol}//api.${i}${o?`:${o}`:""}`}}catch{return{appBase:`http://app.${t}.localhost`,apiBase:`http://api.${t}.localhost`}}}function So(e){return`${e.replace(/\/+$/,"")}/health`}function mt(e){if(w(e.config?.appType)){let t=e.name.replace(/-api$/,"");return e.config?.apiPath??`/api/${t}`}return e.config?.basePath??`/${e.name}`}function Bn(e,t){let{appBase:n,apiBase:r}=ft(t);return e.filter(s=>s.config?.appType==="frontend"||w(s.config?.appType)).map(s=>{let o=w(s.config.appType)?r:n;return{name:s.name,appType:s.config.appType,url:`${o}${So(mt(s))}`}})}async function bo(e,t){try{let n=await fetch(e.url,{method:"GET",redirect:"manual",signal:AbortSignal.timeout(t)});return{...e,ok:n.ok,status:n.status}}catch(n){let r=n instanceof Error&&n.name==="TimeoutError"?`no response within ${t}ms`:n instanceof Error?n.message:String(n);return{...e,ok:!1,error:r}}}async function Un(e,t){return Promise.all(e.map(n=>bo(n,t)))}import{existsSync as ee,readdirSync as lr,readFileSync as pr,statSync as xt}from"node:fs";import{dirname as oi,join as J}from"node:path";var he=class{data;options;constructor(t){this.data=new Map,this.options=t}has(t){let n=this.data.get(t);return n?Date.now()-n.timestamp>this.options.ttlMs?(this.data.delete(t),!1):!0:!1}get(t){if(this.has(t))return this.data.get(t)?.value}set(t,n){this.data.set(t,{value:n,timestamp:Date.now()})}delete(t){this.data.delete(t)}clear(){this.data.clear()}keys(){let t=[];for(let n of this.data.keys())this.has(n)&&t.push(n);return t}size(){return this.keys().length}};function Hn(e){let t=0;return{isValid(){return Date.now()-t<e},markUpdated(){t=Date.now()},reset(){t=0}}}import{execFileSync as _o,execSync as Oo}from"node:child_process";import{existsSync as vo}from"node:fs";import{delimiter as wo,extname as $o,join as Ro}from"node:path";import{delimiter as Zu,extname as To}from"node:path";function je(){return process.platform==="win32"}function xo(e){return e==="linux"?"linux":e==="darwin"?"darwin":e==="win32"?"windows":null}function Eo(e){return e==="x64"?"amd64":e==="arm64"?"arm64":null}function Po(e,t){let n=xo(e),r=Eo(t);if(!n||!r||n==="windows"&&r!=="amd64")return null;let s=`tdk-${n}-${r}`;return n==="windows"?`${s}.exe`:s}function Qu(){return Po(process.platform,process.arch)}function ed(){return je()?"tdk.exe":"tdk"}function Vn(e,t=je()){return t?To(e)?[e]:[e,`${e}.exe`,`${e}.cmd`,`${e}.bat`]:[e]}function $(e){let t=process.env.PATH??process.env.Path??"",n=je(),r=Vn(e,n);if(n&&!$o(e))for(let s of(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";")){let o=s.toLowerCase();o&&!r.includes(`${e}${o}`)&&r.push(`${e}${o}`)}for(let s of t.split(wo))if(s)for(let o of r){let i=Ro(s,o);if(vo(i))return i}return null}var Gn=1e4;function Kn(){let e=!1;if(process.platform==="win32")try{return _o($("docker")??"docker",["ps"],{stdio:"ignore",timeout:Gn,windowsHide:!0}),"running"}catch(t){return t.code==="ETIMEDOUT"?"unresponsive":"missing"}for(let t of["docker ps","colima status","podman ps"])try{return Oo(t,{stdio:"ignore",timeout:Gn}),"running"}catch(n){n.code==="ETIMEDOUT"&&(e=!0)}return e?"unresponsive":"missing"}function Ie(e,t){return e[t]??0}function Ao(e,t){let n=Array.from({length:t.length+1},(r,s)=>s);for(let r=1;r<=e.length;r++){let s=[r];for(let o=1;o<=t.length;o++){let i=e[r-1]===t[o-1]?0:1;s[o]=Math.min(Ie(s,o-1)+1,Ie(n,o)+1,Ie(n,o-1)+i)}n=s}return Ie(n,t.length)}function Do(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length-1;n++)if(e[n]!==t[n]&&e[n]===t[n+1]&&e[n+1]===t[n]&&e.slice(0,n)===t.slice(0,n)&&e.slice(n+2)===t.slice(n+2))return!0;return!1}function Wn(e,t){if(e.length<2||t.length===0||t.includes(e))return;let n=e.toLowerCase(),r,s=Number.POSITIVE_INFINITY;for(let o of t){if(o.length===0)continue;let i=o.toLowerCase(),a=Do(n,i)?1:Ao(n,i),c=Math.max(1,Math.min(2,Math.floor(Math.max(n.length,i.length)/3)));a>c||(a<s||a===s&&(r===void 0||o<r))&&(r=o,s=a)}return r}import{spawn as Co}from"node:child_process";import{join as No}from"node:path";function jo(e,t=[],n={}){return new Promise((r,s)=>{let o=[e,...t];n.verbose&&console.log(`Executing: tilt ${o.join(" ")}`);let i=Co($("tilt")??"tilt",o,{stdio:n.inheritStdio?"inherit":"pipe",shell:!1,windowsHide:process.platform==="win32",timeout:n.timeoutMs}),a="",c="";n.inheritStdio||(i.stdout?.on("data",u=>{a+=u.toString()}),i.stderr?.on("data",u=>{c+=u.toString()})),i.on("close",u=>{r({exitCode:u??1,stdout:a,stderr:c})}),i.on("error",u=>{s(new Error(`Failed to spawn tilt: ${u.message}`))})})}async function Jn(){try{return(await jo("version",[],{inheritStdio:!1,timeoutMs:1e4})).exitCode===0}catch{return!1}}function Io(){let e=m();if(!e)throw H.notInProject();return No(e,".tdk",".tdk-out","Tiltfile")}function qn(e){let t=Io();e.push("-f",t)}function hd(e,t={}){let n=[];return qn(n),t.focusTargets&&t.focusTargets.length>0&&n.push("--",`--focus=${t.focusTargets.join(",")}`),n.push(...e),t.verbose&&!t.quiet&&n.push("--verbose"),t.watch&&n.push("--watch"),n}function gd(e={}){let t=[];return qn(t),e.force&&t.push("--force"),e.focusTargets&&e.focusTargets.length>0&&t.push("--",`--focus=${e.focusTargets.join(",")}`),t}function Yn(e){return e instanceof Error?e.message:String(e)}function Pd(e,t){if(process.env.TDK_VERBOSE){let n=t!==void 0?`: ${Yn(t)}`:"";console.warn(f.gray(`${e}${n}`))}}var R=class extends Error{suggestions;exitCode;constructor(t,n=[],r=1){super(t),this.name="TdkError",this.suggestions=n,this.exitCode=r}display(){Lo(this.message,void 0,this.suggestions)}exit(){this.display(),process.exit(this.exitCode)}};function ht(e,t,n=!1){let r=new Set;for(let s of e){let o=Wn(s,t);o&&r.add(n?`Did you mean "${o}" for "${s}"?`:`Did you mean "${o}"?`)}return[...r]}var H={tiltNotInstalled:()=>new R("Tilt CLI is not installed",["Install Tilt: `brew install tilt` (macOS)","Or download from: https://docs.tilt.dev/install.html","Verify with: `tilt version`",`Setup guide: ${ct}`]),dockerNotAvailable:()=>new R("Docker (or a compatible container runtime) is not running",["Start Docker Desktop, then verify with: `docker ps`","Or start Colima: `colima start`","Or start the Docker service on Linux: `sudo systemctl start docker`",`Setup guide: ${ct}`]),dockerNotResponding:()=>new R("Docker is running but not responding (`docker ps` hung for 10s)",["Quit and reopen Docker Desktop, or run `colima restart`","Then verify with: `docker ps`"]),stackNotFound:(e,t=[])=>new R(`Stack "${e}" not found`,[...ht([e],t),"Run `tdk stacks` to see available stacks","Run `tdk stack` to assign resources to a stack"]),resourceNotFound:(e,t=[])=>new R(`Resource "${e}" not found`,[...ht([e],t),"Run `tdk resources` to list all resources","Check the resource name spelling"]),unknownServices:(e,t)=>{let n=ht(e,t,e.length>1);return new R(`Unknown service ${e.join(", ")}. Valid names: ${t.join(", ")}`,n,2)},directoryExists:e=>new R(`Directory already exists: ${e}`,["Use `--path` to specify a different location","Remove the existing directory if no longer needed"]),invalidPath:e=>new R(`Invalid path: ${e}`,["Path must be within the project directory",'Path cannot contain special characters like <>:"|?*']),notInProject:()=>new R("Could not find project root (no .tdk/project.json found)",["Run this from within a TDK project","Run `tdk project --yes` to initialize a new project"])};function vd(){let e=m();return e||H.notInProject().exit()}function Fo(e){e instanceof R&&e.exit(),console.error(f.red(`Error: ${Yn(e)}`)),process.exit(1)}async function Mo(e,t){try{return await e()}catch(n){return t?.verbose&&n instanceof Error&&n.stack&&console.error(f.gray(n.stack)),Fo(n)}}async function wd(e,t){let n=[],r=Kn();return r==="unresponsive"?n.push(H.dockerNotResponding()):r==="missing"&&n.push(H.dockerNotAvailable()),await Jn()||n.push(H.tiltNotInstalled()),n.length>0&&(console.error(f.red(`
|
|
11
|
+
To add services to this stack:`}};function Fu(e,t){let n=bo[e];console.log(t?f.yellow(`No ${n.singular}s found${t}.`):f.yellow(`No ${n.singular}s found.`)),console.log(f.gray(n.context)),console.log(f.gray(` ${n.command}`)),e==="stacks"&&(console.log(f.gray(`
|
|
12
|
+
Or create a new resource with a stack:`)),console.log(f.gray(" tdk resource <name> --stack <stack-name>")))}function Mu(e){console.log(f.yellow(e||"Cancelled."))}function Lu(e){console.log(f.blue(`TDK ${e}
|
|
13
|
+
`))}function Bu(e,t){console.log(f.green(`All ${e} are ${t}!`))}var ft=62;function Uu(e="\u2500",t=ft){return e.repeat(t)}function Un(e,t=ft-2){let n=Math.max(0,t-e.length),r=Math.floor(n/2),s=n-r;return" ".repeat(r)+e+" ".repeat(s)}function Hu(e,t){return e.length>t?`${e.slice(0,t-1)}\u2026`:e.padEnd(t)}function Vu(e,t){return e.length<=t?e:`${e.slice(0,t-3)}...`}function Ku(e){console.log(f.green(`\u2713 ${e}`))}function Gu(e){console.log(f.blue(e))}function Wu(e,t=2){console.log(f.gray(`${" ".repeat(t)}${e}`))}function Ju(e){return e<1024?`${e} B`:e<1024*1024?`${(e/1024).toFixed(1)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function qu(e,t,n=ft){let r=n-2,s="\u2500".repeat(r);console.log(),console.log(f.cyan(`\u256D${s}\u256E`)),console.log(f.cyan("\u2502")+f.bold.white(Un(e,r))+f.cyan("\u2502")),t&&(console.log(f.cyan(`\u251C${s}\u2524`)),console.log(f.cyan("\u2502")+f.gray(Un(t,r))+f.cyan("\u2502"))),console.log(f.cyan(`\u2570${s}\u256F`))}import{existsSync as xo}from"node:fs";import{dirname as Po,join as Eo,resolve as Vn}from"node:path";import{cwd as wo}from"node:process";var Hn={name:"tdk-cli-internal",private:!0,version:"1.3.145",description:"TDK CLI \u2014 start services on your machine.",keywords:["tdk","tilt","cli","local-dev","microservices"],homepage:"https://github.com/tdk-landscape/tdk-cli-core#readme",bugs:{url:"https://github.com/tdk-landscape/tdk-cli-core/issues"},repository:{type:"git",url:"git+https://github.com/tdk-landscape/tdk-cli-core.git",directory:"cli"},license:"MIT",author:"TDK Team",type:"module",main:"./dist/index.js",types:"./dist/index.d.ts",bin:{tdk:"bin/tdk.js","tdk-cli":"bin/tdk.js"},files:["dist","dist-bundle","bin","templates","README.md","Tiltfile","engine","discovery","specs","ext","!ext/ide-components/code_executor","shared-platform-engineering/docker-templates"],scripts:{build:"tsc && node scripts/bundle.mjs","build:watch":"tsc --watch",lint:"biome check .","lint:fix":"biome check . --write",typecheck:"tsc --project tsconfig.typecheck.json",clean:"rm -rf dist",dev:"bun run build:watch",test:"vitest run","test:watch":"vitest",prepack:"../scripts/stage-npm-engine.sh && npm run build"},dependencies:{commander:"^15.0.0",handlebars:"^4.7.8"},devDependencies:{"@biomejs/biome":"^2.5.13","@types/node":"^22.0.0","@types/react":"^19.3.0",ajv:"^8.17.1",chalk:"^6.0.1",esbuild:"^0.28.2",ink:"^7.1.1",knip:"^6.38.0",react:"^19.3.0","react-devtools-core":"^8.0.0",typescript:"^7.0.2",vite:"^8.3.1",vitest:"^5.0.0"},engines:{node:">=22.12.0"}};function m(e=wo()){let t=Vn(e),n=Vn("/");for(;t!==n;){if(xo(Eo(t,".tdk",P)))return t;let r=Po(t);if(r===t)break;t=r}return null}var Ne=null;function vo(){if(Ne)return Ne;let e=Hn;if(!e||typeof e!="object"||Array.isArray(e))throw new Error("Invalid package.json: expected object");let t=e;return Ne={name:String(t.name??"@tdk-landscape/tdk-cli-core"),version:String(t.version??"0.0.0"),fullPackage:t},Ne}function Kn(){return vo().version}import{readFileSync as $o}from"node:fs";import{join as Ro}from"node:path";function je(){let e=m();if(e)try{let t=$o(Ro(e,".tdk",P),"utf-8"),n=JSON.parse(t);if(n?.project?.name)return n.project.name}catch{}return"tdk-project"}function mt(e){let t=je(),n=process.env.TDK_SERVICE_BASE_URL??`http://${t}.localhost${e?`:${e}`:""}`;try{let r=new URL(n.includes("://")?n:`http://${n}`),s=r.hostname,o=r.port||(e?String(e):"");if(s==="localhost"||/^\d+\.\d+\.\d+\.\d+$/.test(s))return{appBase:`${r.protocol}//${s}${o?`:${o}`:""}`,apiBase:`${r.protocol}//${s}${o?`:${o}`:""}`};let i=s.replace(/^(app|api)\./,"");return{appBase:`${r.protocol}//app.${i}${o?`:${o}`:""}`,apiBase:`${r.protocol}//api.${i}${o?`:${o}`:""}`}}catch{return{appBase:`http://app.${t}.localhost`,apiBase:`http://api.${t}.localhost`}}}function _o(e){return`${e.replace(/\/+$/,"")}/health`}function ht(e){if(v(e.config?.appType)){let t=e.name.replace(/-api$/,"");return e.config?.apiPath??`/api/${t}`}return e.config?.basePath??`/${e.name}`}function Gn(e,t){let{appBase:n,apiBase:r}=mt(t);return e.filter(s=>s.config?.appType==="frontend"||v(s.config?.appType)).map(s=>{let o=v(s.config.appType)?r:n;return{name:s.name,appType:s.config.appType,url:`${o}${_o(ht(s))}`}})}async function Oo(e,t){try{let n=await fetch(e.url,{method:"GET",redirect:"manual",signal:AbortSignal.timeout(t)});return{...e,ok:n.ok,status:n.status}}catch(n){let r=n instanceof Error&&n.name==="TimeoutError"?`no response within ${t}ms`:n instanceof Error?n.message:String(n);return{...e,ok:!1,error:r}}}async function Wn(e,t){return Promise.all(e.map(n=>Oo(n,t)))}import{existsSync as ee,readdirSync as gr,readFileSync as kr,statSync as Pt}from"node:fs";import{dirname as hi,join as J}from"node:path";var he=class{data;options;constructor(t){this.data=new Map,this.options=t}has(t){let n=this.data.get(t);return n?Date.now()-n.timestamp>this.options.ttlMs?(this.data.delete(t),!1):!0:!1}get(t){if(this.has(t))return this.data.get(t)?.value}set(t,n){this.data.set(t,{value:n,timestamp:Date.now()})}delete(t){this.data.delete(t)}clear(){this.data.clear()}keys(){let t=[];for(let n of this.data.keys())this.has(n)&&t.push(n);return t}size(){return this.keys().length}};function Jn(e){let t=0;return{isValid(){return Date.now()-t<e},markUpdated(){t=Date.now()},reset(){t=0}}}import{execFileSync as Lo,execSync as Bo}from"node:child_process";import{existsSync as jo}from"node:fs";import{delimiter as Io,extname as Fo,join as Mo}from"node:path";import{delimiter as ld,extname as Ao}from"node:path";function Ie(){return process.platform==="win32"}function Do(e){return e==="linux"?"linux":e==="darwin"?"darwin":e==="win32"?"windows":null}function Co(e){return e==="x64"?"amd64":e==="arm64"?"arm64":null}function No(e,t){let n=Do(e),r=Co(t);if(!n||!r||n==="windows"&&r!=="amd64")return null;let s=`tdk-${n}-${r}`;return n==="windows"?`${s}.exe`:s}function pd(){return No(process.platform,process.arch)}function fd(){return Ie()?"tdk.exe":"tdk"}function qn(e,t=Ie()){return t?Ao(e)?[e]:[e,`${e}.exe`,`${e}.cmd`,`${e}.bat`]:[e]}function $(e){let t=process.env.PATH??process.env.Path??"",n=Ie(),r=qn(e,n);if(n&&!Fo(e))for(let s of(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";")){let o=s.toLowerCase();o&&!r.includes(`${e}${o}`)&&r.push(`${e}${o}`)}for(let s of t.split(Io))if(s)for(let o of r){let i=Mo(s,o);if(jo(i))return i}return null}var Yn=1e4;function zn(){let e=!1;if(process.platform==="win32")try{return Lo($("docker")??"docker",["ps"],{stdio:"ignore",timeout:Yn,windowsHide:!0}),"running"}catch(t){return t.code==="ETIMEDOUT"?"unresponsive":"missing"}for(let t of["docker ps","colima status","podman ps"])try{return Bo(t,{stdio:"ignore",timeout:Yn}),"running"}catch(n){n.code==="ETIMEDOUT"&&(e=!0)}return e?"unresponsive":"missing"}function Fe(e,t){return e[t]??0}function Uo(e,t){let n=Array.from({length:t.length+1},(r,s)=>s);for(let r=1;r<=e.length;r++){let s=[r];for(let o=1;o<=t.length;o++){let i=e[r-1]===t[o-1]?0:1;s[o]=Math.min(Fe(s,o-1)+1,Fe(n,o)+1,Fe(n,o-1)+i)}n=s}return Fe(n,t.length)}function Ho(e,t){if(e.length!==t.length)return!1;for(let n=0;n<e.length-1;n++)if(e[n]!==t[n]&&e[n]===t[n+1]&&e[n+1]===t[n]&&e.slice(0,n)===t.slice(0,n)&&e.slice(n+2)===t.slice(n+2))return!0;return!1}function Xn(e,t){if(e.length<2||t.length===0||t.includes(e))return;let n=e.toLowerCase(),r,s=Number.POSITIVE_INFINITY;for(let o of t){if(o.length===0)continue;let i=o.toLowerCase(),a=Ho(n,i)?1:Uo(n,i),c=Math.max(1,Math.min(2,Math.floor(Math.max(n.length,i.length)/3)));a>c||(a<s||a===s&&(r===void 0||o<r))&&(r=o,s=a)}return r}import{spawn as Vo}from"node:child_process";import{join as Ko}from"node:path";function Go(e,t=[],n={}){return new Promise((r,s)=>{let o=[e,...t];n.verbose&&console.log(`Executing: tilt ${o.join(" ")}`);let i=Vo($("tilt")??"tilt",o,{stdio:n.inheritStdio?"inherit":"pipe",shell:!1,windowsHide:process.platform==="win32",timeout:n.timeoutMs}),a="",c="";n.inheritStdio||(i.stdout?.on("data",u=>{a+=u.toString()}),i.stderr?.on("data",u=>{c+=u.toString()})),i.on("close",u=>{r({exitCode:u??1,stdout:a,stderr:c})}),i.on("error",u=>{s(new Error(`Failed to spawn tilt: ${u.message}`))})})}async function Zn(){try{return(await Go("version",[],{inheritStdio:!1,timeoutMs:1e4})).exitCode===0}catch{return!1}}function Wo(){let e=m();if(!e)throw H.notInProject();return Ko(e,".tdk",".tdk-out","Tiltfile")}function Qn(e){let t=Wo();e.push("-f",t)}function Rd(e,t={}){let n=[];return Qn(n),t.focusTargets&&t.focusTargets.length>0&&n.push("--",`--focus=${t.focusTargets.join(",")}`),n.push(...e),t.verbose&&!t.quiet&&n.push("--verbose"),t.watch&&n.push("--watch"),n}function _d(e={}){let t=[];return Qn(t),e.force&&t.push("--force"),e.focusTargets&&e.focusTargets.length>0&&t.push("--",`--focus=${e.focusTargets.join(",")}`),t}function er(e){return e instanceof Error?e.message:String(e)}function Fd(e,t){if(process.env.TDK_VERBOSE){let n=t!==void 0?`: ${er(t)}`:"";console.warn(f.gray(`${e}${n}`))}}var R=class extends Error{suggestions;exitCode;constructor(t,n=[],r=1){super(t),this.name="TdkError",this.suggestions=n,this.exitCode=r}display(){Yo(this.message,void 0,this.suggestions)}exit(){this.display(),process.exit(this.exitCode)}};function gt(e,t,n=!1){let r=new Set;for(let s of e){let o=Xn(s,t);o&&r.add(n?`Did you mean "${o}" for "${s}"?`:`Did you mean "${o}"?`)}return[...r]}var H={tiltNotInstalled:()=>new R("Tilt CLI is not installed",["Install Tilt: `brew install tilt` (macOS)","Or download from: https://docs.tilt.dev/install.html","Verify with: `tilt version`",`Setup guide: ${ut}`]),dockerNotAvailable:()=>new R("Docker (or a compatible container runtime) is not running",["Start Docker Desktop, then verify with: `docker ps`","Or start Colima: `colima start`","Or start the Docker service on Linux: `sudo systemctl start docker`",`Setup guide: ${ut}`]),dockerNotResponding:()=>new R("Docker is running but not responding (`docker ps` hung for 10s)",["Quit and reopen Docker Desktop, or run `colima restart`","Then verify with: `docker ps`"]),stackNotFound:(e,t=[])=>new R(`Stack "${e}" not found`,[...gt([e],t),"Run `tdk stacks` to see available stacks","Run `tdk stack` to assign resources to a stack"]),resourceNotFound:(e,t=[])=>new R(`Resource "${e}" not found`,[...gt([e],t),"Run `tdk resources` to list all resources","Check the resource name spelling"]),unknownServices:(e,t)=>{let n=gt(e,t,e.length>1);return new R(`Unknown service ${e.join(", ")}. Valid names: ${t.join(", ")}`,n,2)},directoryExists:e=>new R(`Directory already exists: ${e}`,["Use `--path` to specify a different location","Remove the existing directory if no longer needed"]),invalidPath:e=>new R(`Invalid path: ${e}`,["Path must be within the project directory",'Path cannot contain special characters like <>:"|?*']),notInProject:()=>new R("Could not find project root (no .tdk/project.json found)",["Run this from within a TDK project","Run `tdk project --yes` to initialize a new project"])};function Md(){let e=m();return e||H.notInProject().exit()}function Jo(e){e instanceof R&&e.exit(),console.error(f.red(`Error: ${er(e)}`)),process.exit(1)}async function qo(e,t){try{return await e()}catch(n){return t?.verbose&&n instanceof Error&&n.stack&&console.error(f.gray(n.stack)),Jo(n)}}async function Ld(e,t){let n=[],r=zn();return r==="unresponsive"?n.push(H.dockerNotResponding()):r==="missing"&&n.push(H.dockerNotAvailable()),await Zn()||n.push(H.tiltNotInstalled()),n.length>0&&(console.error(f.red(`
|
|
13
14
|
TDK can't start - missing prerequisites:
|
|
14
|
-
`)),n.forEach((s,o)=>{o>0&&console.error(""),s.display()}),console.error(f.gray("\nRun `tdk doctor` for a full environment check.")),process.exit(1)),
|
|
15
|
-
\u{1F4A1} Suggestions:`));for(let r of n)console.error(f.cyan(` \u2192 ${r}`))}}function
|
|
16
|
-
tilt ${e} failed with exit code ${t}`)),process.exit(t)}import{existsSync as
|
|
17
|
-
`),s&&(zn(i,Q(o,"last-success.json")),r===void 0?Xn(Q(o,"last-success-body.txt"),{force:!0}):zn(a,Q(o,"last-success-body.txt"))),i}catch{return}}function qo(e){let t=Buffer.from(e,"utf8");if(t.length<=nr)return{body:e,truncated:!1,bytes:t.length};let n=t.subarray(0,nr).toString("utf8").replace(/\uFFFD$/,"");return{body:n,truncated:!0,bytes:Buffer.byteLength(n,"utf8")}}async function Yo(e,t={}){let n=t.fetch??((d,l)=>fetch(d,l)),r=t.now??Date.now,s=t.sleep??(d=>new Promise(l=>setTimeout(l,d))),o=(e.smoke.timeoutSeconds??Uo)*1e3,i=r()+o,a={},c=kt(e.smoke);if(c.length>0)return{name:e.name,ok:!1,failure:`${e.name}: invalid smoke block: ${c.join("; ")}`};if(e.readyPath){let d=`${e.baseUrl}${e.readyPath}`;for(;;){try{let l=await n(d,{method:"GET",signal:AbortSignal.timeout(er)});if(await l.text(),!rr.has(l.status)&&l.status<500)break}catch{}if(r()>=i)break;await s(Qn)}}i=r()+o;let u=new Map;for(let[d,l]of e.smoke.steps.entries()){let h=l.name??`step ${d+1}`,k=(l.method??"GET").toUpperCase(),g=`${e.baseUrl}${sr(l.path,a)}`,p=l.expect??200,y=l.body!==void 0,v,j="",G,Ze;for(;;){G=void 0,Ze=void 0,v=void 0;let I=!1;try{let _=await n(g,{method:k,headers:y?{"content-type":"application/json"}:void 0,body:y?JSON.stringify(gt(l.body,a)):void 0,signal:AbortSignal.timeout(er)});v=_.status,j=await _.text()}catch(_){I=Go(_,k),G=_ instanceof Error?_.message:String(_);let Y=K(_)?_.code??(K(_.cause)?_.cause.code:void 0):void 0;Ze=typeof Y=="string"?Y:void 0}if(!(G!==void 0&&I||v!==void 0&&v!==p&&rr.has(v))||r()>=i)break;await s(Qn)}let ae=`${e.name}: ${h}: ${k} ${g}`,un;if(t.recordDir){let I=v===void 0?void 0:qo(j),ue=G===void 0&&v===p&&(l.bodyContains===void 0||j.includes(l.bodyContains));un=Jo(t.recordDir,Wo(u,h),{service:e.name,step:h,method:k,url:g,expectedStatus:p,status:v??null,...G===void 0?{}:{error:Ze??G},truncated:I?.truncated??!1,bodyBytes:I?.bytes??0},I?.body,ue)}let ce=I=>({name:e.name,ok:!1,failure:I,recordPath:un});if(G!==void 0)return ce(`${ae} never answered (${G})`);if(v!==p)return ce(`${ae} returned ${v}, expected ${p}${j?`: ${Fe(j)}`:""}`);if(l.bodyContains!==void 0&&!j.includes(l.bodyContains))return ce(`${ae} returned ${v} but the body does not contain "${l.bodyContains}": ${Fe(j)}`);if(l.save){let I;try{I=JSON.parse(j)}catch{return ce(`${ae} returned a body that is not JSON, cannot save: ${Fe(j)}`)}for(let[ue,_]of Object.entries(l.save)){let Y=Ko(I,_);if(Y==null||typeof Y=="object")return ce(`${ae} response has no ${_} to save as {{${ue}}}: ${Fe(j)}`);a[ue]=String(Y)}}}return{name:e.name,ok:!0}}function Id(e){return`Smoke check failed: ${e.failure}${e.recordPath?` (record: ${e.recordPath})`:""}`}async function Fd(e,t={}){return Promise.all(e.map(n=>Yo(n,t)))}var ge=1,Ud="https://tdk-landscape.github.io/schema.service.json",zo={dependencies:"deprecated, use dependsOn (still read for now)",envVars:"deprecated, use params (still read when params is absent)",jwtSecret:"ignored. A secret must not be committed: remove it and set JWT_SECRET in the project .env"},Xo=new Set(["$schema","apiBasePath","apiPath","appName","appType","backendName","basePath","build","buildContext","databaseName","dependencies","dev","dependsOn","dockerfile","enabled","exposeViaProxy","featuresEnabled","framework","healthCheckPath","image","language","name","nats","params","playwright","port","replicas","restart","runtime","sablier","schemaVersion","secrets","smoke","stack","syncs","traefik","type"]),Zo=[{path:["healthCheckPath"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /health"},{path:["traefik","host"],pattern:/^[A-Za-z0-9.-]+$/,expected:"a hostname such as shop.backend.myproject.local"},{path:["traefik","pathPrefix"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /api/v1/shop-management"},{path:["traefik","healthCheck"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /health"},{path:["nats","queueGroup"],pattern:/^[A-Za-z0-9_.-]+$/,expected:"letters, digits, '_', '.' or '-'"},{path:["databaseName"],pattern:/^[A-Za-z0-9_-]+$/,expected:"letters, digits, '_' or '-'"},{path:["stack"],pattern:/^[A-Za-z0-9_-]+$/,expected:"letters, digits, '_' or '-'"},{path:["image"],pattern:/^[A-Za-z0-9._/:@-]+$/,expected:"an image reference such as ghcr.io/acme/app:1.0"}];function Me(e,t){let n=[],r=new Set;for(let{path:s,pattern:o,expected:i}of Zo){let a=e;for(let u of s)a=a&&typeof a=="object"&&!Array.isArray(a)?a[u]:void 0;if(a==null||a==="")continue;let c=`${t}.${s.join(".")}`;(typeof a!="string"||!o.test(a))&&r.add(c),typeof a!="string"?n.push(`${c}: expected a string`):o.test(a)||n.push(`${c}: must be ${i} (no spaces, line breaks or YAML syntax)`)}for(let[s,o]of Qo(e,t))r.has(s)||n.push(`${s}: ${o}`);return n}function yt(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n<32||n===127||n===133||n===8232||n===8233)return!0}return!1}function Qo(e,t){let n=[],r=Object.entries(e).filter(([s])=>s!=="smoke").map(([s,o])=>[o,`${t}.${s}`]);for(let s of Object.keys(e))yt(s)&&n.push([t,"a key contains a line break"]);for(;r.length>0;){let[s,o]=r.pop();if(typeof s=="string")yt(s)&&n.push([o,"must not contain line breaks or control characters"]);else if(Array.isArray(s))for(let[i,a]of s.entries())r.push([a,`${o}[${i}]`]);else if(s&&typeof s=="object")for(let[i,a]of Object.entries(s))yt(i)?n.push([o,"a key contains a line break"]):r.push([a,`${o}.${i}`])}return n.sort(([s],[o])=>s.localeCompare(o))}var ei=["apiPath","basePath"];function St(e){if(!e||typeof e!="object"||Array.isArray(e))return[];let t=e;return ei.filter(n=>n in t&&typeof t[n]!="string")}function bt(e,t){if(!e||typeof e!="object"||Array.isArray(e))return{errors:[`${t}: expected a JSON object`],warnings:[]};let n=e,r=[];for(let a of["appName","appType","stack","schemaVersion"])a in n||r.push(`${t}.${a}: required field is missing`);for(let a of["appName","appType","stack"])a in n&&typeof n[a]!="string"&&r.push(`${t}.${a}: expected a string`);"schemaVersion"in n&&n.schemaVersion!==ge&&r.push(`${t}.schemaVersion: unsupported version ${String(n.schemaVersion)} (supported: ${ge})`);for(let a of St(n))r.push(`${t}.${a}: expected a string`);let s=n.dev,o=s&&typeof s=="object"&&!Array.isArray(s)?s.liveReload:void 0;if(o!==void 0&&typeof o!="boolean"&&r.push(`${t}.dev.liveReload: expected true or false`),r.push(...Me(n,t)),"smoke"in n)for(let a of kt(n.smoke))r.push(`${t}.${a}`);let i=Object.keys(n).flatMap(a=>{let c=zo[a];return c?[`${t}.${a}: ${c}`]:Xo.has(a)?[]:[`${t}.${a}: unknown field is preserved`]});return o===!0&&n.language!=="go"&&i.push(`${t}.dev.liveReload: only applies to Go services (language "go"); it is ignored here`),{errors:r,warnings:i,manifest:n}}function Hd(e,t){if(!ir(e))return[];try{let n=JSON.parse(ar(e,"utf-8"));return!n||typeof n!="object"||Array.isArray(n)?[]:Me(n,t)}catch{return[]}}function Vd(e,t){if(!ir(e))return{errors:[`${t}: file is missing`],warnings:[]};try{let n=JSON.parse(ar(e,"utf-8"));return bt(n,t)}catch(n){let r=n instanceof Error?n.message:String(n);return{errors:[`${t}: invalid JSON (${r})`],warnings:[]}}}function cr(e){if(e.length===0||e.every(n=>n==="unknown"))return"unknown";let t=e.filter(n=>n==="ready").length/e.length;return t>.9?"healthy":t>.5?"degraded":"error"}var ti=/^[a-z0-9-]+$/;function ur(e){return ti.test(e)}var ni="Use lowercase letters, numbers, and hyphens only";function dr(e,t){return`${e} "${t}" is not valid. ${ni}, e.g. "${e==="Resource name"?"my-service":"my-stack"}".`}function ri(e){return e.trim()?ur(e)?{valid:!0}:{valid:!1,error:dr("Resource name",e)}:{valid:!1,error:"Resource name is required"}}function si(e){return e.trim()?ur(e)?{valid:!0}:{valid:!1,error:dr("Stack name",e)}:{valid:!1,error:"Stack name is required"}}function Jd(e){let t=e==="resource"?ri:si;return n=>{let r=t(n);return r.valid?!0:r.error??"Invalid name"}}function qd(e){return Tt(at,e)?{valid:!0}:{valid:!1,error:`Invalid service. Must be one of: ${at.join(", ")}`}}function Yd(e){return Number.isInteger(e)&&e>0&&e<=65535}function zd(e){return!e.includes("\0")&&!/[<>:"|?*]/.test(e)}function Xd(e,t="_"){return e.replace(/[^a-zA-Z0-9-]/g,t).substring(0,100)}function Tt(e,t){return e.includes(t)}var ii=vn;function wt(e,t=5,n=0){let r=[];if(n>t)return r;let s=lr(e,{withFileTypes:!0});for(let o of s){let i=J(e,o.name);if(o.isDirectory()){if(ai(o.name))continue;r.push(...wt(i,t,n+1))}else o.isFile()&&o.name===ii&&r.push(i)}return r}function ul(e){return wt(e)}function ai(e){return Tt($n,e)||e.startsWith(".")}function ci(e){if(!e||typeof e!="object")return!1;let t=e,n=typeof t.runtime=="string"||typeof t.appType=="string"||typeof t.type=="string";return typeof t.appName=="string"&&n}var Le=new Set;var W=class extends Error{reason;constructor(t){super(t),this.reason=t,this.name="InvalidServiceJsonError"}};function Et(e){return e instanceof Error?e.message:String(e)}function ui(e){let t;try{t=pr(e,"utf-8")}catch(c){throw new W(`could not read file: ${Et(c)}`)}let n;try{n=JSON.parse(t)}catch(c){throw new W(`invalid JSON: ${Et(c)}`)}if(!ci(n))throw new W("missing required fields (appName, runtime or appType)");let r=St(n);if(r.length>0)throw new W(r.map(c=>`${c}: expected a string`).join("; "));let s=Me(n,e);if(s.length>0)throw new W(s.join("; "));let o=n;for(let c of bt(n,e).warnings)Le.has(c)||(Le.add(c),console.warn(`\u26A0\uFE0F ${c}`));let i={...o,appType:o.appType||o.type},a=oi(e);return{name:i.appName,path:a,configPath:e,config:i,stack:i.stack,port:i.port,type:i.appType}}function fr(e){let t=wt(e),n=[],r=[];for(let s of t)try{n.push(ui(s))}catch(o){r.push({path:s,reason:o instanceof W?o.reason:Et(o)})}return{resources:n,problems:r}}function di(e){for(let t of e){let n=`skipped ${t.path}: ${t.reason}`;Le.has(n)||(Le.add(n),console.warn(`\u26A0\uFE0F ${n}`))}}function b(e){let{resources:t,problems:n}=fr(e);return di(n),t}function ye(){let e=m();if(!e)throw H.notInProject();return b(e)}function dl(){let e=m();if(!e)throw H.notInProject();let{resources:t,problems:n}=fr(e);if(n.length>0)throw new Error(n.map(r=>`Invalid service.json at ${r.path}: ${r.reason}`).join(`
|
|
18
|
-
`));return t}function
|
|
15
|
+
`)),n.forEach((s,o)=>{o>0&&console.error(""),s.display()}),console.error(f.gray("\nRun `tdk doctor` for a full environment check.")),process.exit(1)),qo(e,t)}function Bd(e,t=1){console.error(f.red(`Error: ${e}`)),process.exit(t)}function Yo(e,t,n){if(console.error(f.red(`\u274C ${e}`)),t&&console.error(f.gray(` ${t}`)),n&&n.length>0){console.error(f.yellow(`
|
|
16
|
+
\u{1F4A1} Suggestions:`));for(let r of n)console.error(f.cyan(` \u2192 ${r}`))}}function Ud(e,t){console.error(f.red(`
|
|
17
|
+
tilt ${e} failed with exit code ${t}`)),process.exit(t)}import{existsSync as lr,readFileSync as pr}from"node:fs";import{copyFileSync as tr,mkdirSync as zo,rmSync as nr,writeFileSync as rr}from"node:fs";import{join as Q}from"node:path";var Xo=60,sr=1e3,or=1e4,ir=200,ar=64*1024,cr=new Set([404,502,503,504]),Zo=new Set(["ECONNREFUSED","ENOTFOUND","EAI_AGAIN","EHOSTUNREACH","ENETUNREACH"]),Qo=new Set(["GET","HEAD","OPTIONS"]);function G(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}function ei(e,t){if(Qo.has(t))return!0;if(!G(e))return!1;let n=G(e.cause)?e.cause:void 0,r=e.code??n?.code;return typeof r=="string"&&Zo.has(r)}function yt(e){if(!G(e))return['smoke: must be an object with "via" and "steps"'];let t=[];return e.via!=="proxy"&&t.push('smoke.via: only "proxy" is supported (the check must go through the public URL)'),e.timeoutSeconds!==void 0&&!(typeof e.timeoutSeconds=="number"&&e.timeoutSeconds>0)&&t.push("smoke.timeoutSeconds: must be a number greater than 0"),!Array.isArray(e.steps)||e.steps.length===0?(t.push("smoke.steps: needs at least one step"),t):(e.steps.forEach((n,r)=>{let s=`smoke.steps[${r}]`;if(!G(n)){t.push(`${s}: must be an object`);return}let o=n.path;(typeof o!="string"||!o.startsWith("/")||o.startsWith("//"))&&t.push(`${s}.path: must start with "/" and is appended to the public URL; a full URL or relative path would skip the proxy`),n.expect!==void 0&&!(typeof n.expect=="number"&&Number.isInteger(n.expect)&&n.expect>=100&&n.expect<=599)&&t.push(`${s}.expect: must be an HTTP status between 100 and 599`),n.bodyContains!==void 0&&typeof n.bodyContains!="string"&&t.push(`${s}.bodyContains: must be a string`),n.save!==void 0&&(G(n.save)&&Object.values(n.save).every(a=>typeof a=="string"&&a.startsWith("$."))||t.push(`${s}.save: must map names to paths such as "$.id"`))}),t)}function qd(e,t){let{appBase:n,apiBase:r}=mt(t),s=[];for(let o of e){let i=o.config;if(!i?.smoke)continue;let a=i.appType,c=v(a)||a===B;if(!c&&a!=="frontend"||i.exposeViaProxy===!1)continue;let u=c?r:n,d=i.healthCheckPath||(c&&a!==B?"/health":void 0);s.push({name:o.name,baseUrl:`${u}${ht(o).replace(/\/+$/,"")}`,...d?.startsWith("/")?{readyPath:d}:{},smoke:i.smoke})}return s}function ti(e,t){let n=t.replace(/^\$\.?/,"").match(/[^.[\]]+/g)??[],r=e;for(let s of n){if(r==null||s==="__proto__"||s==="constructor"||s==="prototype"||!Object.hasOwn(r,s))return;let o=Object.getOwnPropertyDescriptor(r,s);if(!o||!("value"in o))return;r=o.value}return r}function ur(e,t){return e.replace(/\{\{(\w+)\}\}/g,(n,r)=>t[r]??n)}function kt(e,t){return typeof e=="string"?ur(e,t):Array.isArray(e)?e.map(n=>kt(n,t)):G(e)?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,kt(r,t)])):e}function Me(e){let t=e.replace(/\s+/g," ").trim();return t.length>ir?`${t.slice(0,ir)}...`:t}function dr(e){return e.toLowerCase().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")||"step"}function ni(e,t){let n=dr(t),r=(e.get(n)??0)+1;return e.set(n,r),r===1?n:`${n}-${r}`}function ri(e,t,n,r,s){try{let o=Q(e,dr(n.service),t);zo(o,{recursive:!0});let i=Q(o,"latest.json"),a=Q(o,"body.txt");return r===void 0?nr(a,{force:!0}):rr(a,r),rr(i,`${JSON.stringify({...n,bodyPath:r===void 0?null:"body.txt"},null,2)}
|
|
18
|
+
`),s&&(tr(i,Q(o,"last-success.json")),r===void 0?nr(Q(o,"last-success-body.txt"),{force:!0}):tr(a,Q(o,"last-success-body.txt"))),i}catch{return}}function si(e){let t=Buffer.from(e,"utf8");if(t.length<=ar)return{body:e,truncated:!1,bytes:t.length};let n=t.subarray(0,ar).toString("utf8").replace(/\uFFFD$/,"");return{body:n,truncated:!0,bytes:Buffer.byteLength(n,"utf8")}}async function oi(e,t={}){let n=t.fetch??((d,l)=>fetch(d,l)),r=t.now??Date.now,s=t.sleep??(d=>new Promise(l=>setTimeout(l,d))),o=(e.smoke.timeoutSeconds??Xo)*1e3,i=r()+o,a={},c=yt(e.smoke);if(c.length>0)return{name:e.name,ok:!1,failure:`${e.name}: invalid smoke block: ${c.join("; ")}`};if(e.readyPath){let d=`${e.baseUrl}${e.readyPath}`;for(;;){try{let l=await n(d,{method:"GET",signal:AbortSignal.timeout(or)});if(await l.text(),!cr.has(l.status)&&l.status<500)break}catch{}if(r()>=i)break;await s(sr)}}i=r()+o;let u=new Map;for(let[d,l]of e.smoke.steps.entries()){let h=l.name??`step ${d+1}`,k=(l.method??"GET").toUpperCase(),g=`${e.baseUrl}${ur(l.path,a)}`,p=l.expect??200,y=l.body!==void 0,w,j="",K,Qe;for(;;){K=void 0,Qe=void 0,w=void 0;let I=!1;try{let _=await n(g,{method:k,headers:y?{"content-type":"application/json"}:void 0,body:y?JSON.stringify(kt(l.body,a)):void 0,signal:AbortSignal.timeout(or)});w=_.status,j=await _.text()}catch(_){I=ei(_,k),K=_ instanceof Error?_.message:String(_);let Y=G(_)?_.code??(G(_.cause)?_.cause.code:void 0):void 0;Qe=typeof Y=="string"?Y:void 0}if(!(K!==void 0&&I||w!==void 0&&w!==p&&cr.has(w))||r()>=i)break;await s(sr)}let ae=`${e.name}: ${h}: ${k} ${g}`,ln;if(t.recordDir){let I=w===void 0?void 0:si(j),ue=K===void 0&&w===p&&(l.bodyContains===void 0||j.includes(l.bodyContains));ln=ri(t.recordDir,ni(u,h),{service:e.name,step:h,method:k,url:g,expectedStatus:p,status:w??null,...K===void 0?{}:{error:Qe??K},truncated:I?.truncated??!1,bodyBytes:I?.bytes??0},I?.body,ue)}let ce=I=>({name:e.name,ok:!1,failure:I,recordPath:ln});if(K!==void 0)return ce(`${ae} never answered (${K})`);if(w!==p)return ce(`${ae} returned ${w}, expected ${p}${j?`: ${Me(j)}`:""}`);if(l.bodyContains!==void 0&&!j.includes(l.bodyContains))return ce(`${ae} returned ${w} but the body does not contain "${l.bodyContains}": ${Me(j)}`);if(l.save){let I;try{I=JSON.parse(j)}catch{return ce(`${ae} returned a body that is not JSON, cannot save: ${Me(j)}`)}for(let[ue,_]of Object.entries(l.save)){let Y=ti(I,_);if(Y==null||typeof Y=="object")return ce(`${ae} response has no ${_} to save as {{${ue}}}: ${Me(j)}`);a[ue]=String(Y)}}}return{name:e.name,ok:!0}}function Yd(e){return`Smoke check failed: ${e.failure}${e.recordPath?` (record: ${e.recordPath})`:""}`}async function zd(e,t={}){return Promise.all(e.map(n=>oi(n,t)))}var ge=1,el="https://tdk-landscape.github.io/schema.service.json",ii={dependencies:"deprecated, use dependsOn (still read for now)",envVars:"deprecated, use params (still read when params is absent)",jwtSecret:"ignored. A secret must not be committed: remove it and set JWT_SECRET in the project .env"},ai=new Set(["$schema","apiBasePath","apiPath","appName","appType","backendName","basePath","build","buildContext","databaseName","dependencies","dev","dependsOn","dockerfile","enabled","exposeViaProxy","featuresEnabled","framework","healthCheckPath","image","language","name","nats","params","playwright","port","replicas","restart","runtime","sablier","schemaVersion","secrets","smoke","stack","syncs","traefik","type"]),ci=[{path:["healthCheckPath"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /health"},{path:["traefik","host"],pattern:/^[A-Za-z0-9.-]+$/,expected:"a hostname such as shop.backend.myproject.local"},{path:["traefik","pathPrefix"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /api/v1/shop-management"},{path:["traefik","healthCheck"],pattern:/^\/[a-z0-9/-]*$/,expected:"a path such as /health"},{path:["nats","queueGroup"],pattern:/^[A-Za-z0-9_.-]+$/,expected:"letters, digits, '_', '.' or '-'"},{path:["databaseName"],pattern:/^[A-Za-z0-9_-]+$/,expected:"letters, digits, '_' or '-'"},{path:["stack"],pattern:/^[A-Za-z0-9_-]+$/,expected:"letters, digits, '_' or '-'"},{path:["image"],pattern:/^[A-Za-z0-9._/:@-]+$/,expected:"an image reference such as ghcr.io/acme/app:1.0"}];function Le(e,t){let n=[],r=new Set;for(let{path:s,pattern:o,expected:i}of ci){let a=e;for(let u of s)a=a&&typeof a=="object"&&!Array.isArray(a)?a[u]:void 0;if(a==null||a==="")continue;let c=`${t}.${s.join(".")}`;(typeof a!="string"||!o.test(a))&&r.add(c),typeof a!="string"?n.push(`${c}: expected a string`):o.test(a)||n.push(`${c}: must be ${i} (no spaces, line breaks or YAML syntax)`)}for(let[s,o]of ui(e,t))r.has(s)||n.push(`${s}: ${o}`);return n}function St(e){for(let t=0;t<e.length;t++){let n=e.charCodeAt(t);if(n<32||n===127||n===133||n===8232||n===8233)return!0}return!1}function ui(e,t){let n=[],r=Object.entries(e).filter(([s])=>s!=="smoke").map(([s,o])=>[o,`${t}.${s}`]);for(let s of Object.keys(e))St(s)&&n.push([t,"a key contains a line break"]);for(;r.length>0;){let[s,o]=r.pop();if(typeof s=="string")St(s)&&n.push([o,"must not contain line breaks or control characters"]);else if(Array.isArray(s))for(let[i,a]of s.entries())r.push([a,`${o}[${i}]`]);else if(s&&typeof s=="object")for(let[i,a]of Object.entries(s))St(i)?n.push([o,"a key contains a line break"]):r.push([a,`${o}.${i}`])}return n.sort(([s],[o])=>s.localeCompare(o))}var di=["apiPath","basePath"];function bt(e){if(!e||typeof e!="object"||Array.isArray(e))return[];let t=e;return di.filter(n=>n in t&&typeof t[n]!="string")}function Tt(e,t){if(!e||typeof e!="object"||Array.isArray(e))return{errors:[`${t}: expected a JSON object`],warnings:[]};let n=e,r=[];for(let a of["appName","appType","stack","schemaVersion"])a in n||r.push(`${t}.${a}: required field is missing`);for(let a of["appName","appType","stack"])a in n&&typeof n[a]!="string"&&r.push(`${t}.${a}: expected a string`);"schemaVersion"in n&&n.schemaVersion!==ge&&r.push(`${t}.schemaVersion: unsupported version ${String(n.schemaVersion)} (supported: ${ge})`);for(let a of bt(n))r.push(`${t}.${a}: expected a string`);let s=n.dev,o=s&&typeof s=="object"&&!Array.isArray(s)?s.liveReload:void 0;if(o!==void 0&&typeof o!="boolean"&&r.push(`${t}.dev.liveReload: expected true or false`),r.push(...Le(n,t)),"smoke"in n)for(let a of yt(n.smoke))r.push(`${t}.${a}`);let i=Object.keys(n).flatMap(a=>{let c=ii[a];return c?[`${t}.${a}: ${c}`]:ai.has(a)?[]:[`${t}.${a}: unknown field is preserved`]});return o===!0&&n.language!=="go"&&i.push(`${t}.dev.liveReload: only applies to Go services (language "go"); it is ignored here`),{errors:r,warnings:i,manifest:n}}function tl(e,t){if(!lr(e))return[];try{let n=JSON.parse(pr(e,"utf-8"));return!n||typeof n!="object"||Array.isArray(n)?[]:Le(n,t)}catch{return[]}}function nl(e,t){if(!lr(e))return{errors:[`${t}: file is missing`],warnings:[]};try{let n=JSON.parse(pr(e,"utf-8"));return Tt(n,t)}catch(n){let r=n instanceof Error?n.message:String(n);return{errors:[`${t}: invalid JSON (${r})`],warnings:[]}}}function fr(e){if(e.length===0||e.every(n=>n==="unknown"))return"unknown";let t=e.filter(n=>n==="ready").length/e.length;return t>.9?"healthy":t>.5?"degraded":"error"}var li=/^[a-z0-9-]+$/;function mr(e){return li.test(e)}var pi="Use lowercase letters, numbers, and hyphens only";function hr(e,t){return`${e} "${t}" is not valid. ${pi}, e.g. "${e==="Resource name"?"my-service":"my-stack"}".`}function fi(e){return e.trim()?mr(e)?{valid:!0}:{valid:!1,error:hr("Resource name",e)}:{valid:!1,error:"Resource name is required"}}function mi(e){return e.trim()?mr(e)?{valid:!0}:{valid:!1,error:hr("Stack name",e)}:{valid:!1,error:"Stack name is required"}}function il(e){let t=e==="resource"?fi:mi;return n=>{let r=t(n);return r.valid?!0:r.error??"Invalid name"}}function al(e){return xt(ct,e)?{valid:!0}:{valid:!1,error:`Invalid service. Must be one of: ${ct.join(", ")}`}}function cl(e){return Number.isInteger(e)&&e>0&&e<=65535}function ul(e){return!e.includes("\0")&&!/[<>:"|?*]/.test(e)}function dl(e,t="_"){return e.replace(/[^a-zA-Z0-9-]/g,t).substring(0,100)}function xt(e,t){return e.includes(t)}var gi=$n;function $t(e,t=5,n=0){let r=[];if(n>t)return r;let s=gr(e,{withFileTypes:!0});for(let o of s){let i=J(e,o.name);if(o.isDirectory()){if(ki(o.name))continue;r.push(...$t(i,t,n+1))}else o.isFile()&&o.name===gi&&r.push(i)}return r}function xl(e){return $t(e)}function ki(e){return xt(_n,e)||e.startsWith(".")}function yi(e){if(!e||typeof e!="object")return!1;let t=e,n=typeof t.runtime=="string"||typeof t.appType=="string"||typeof t.type=="string";return typeof t.appName=="string"&&n}var Be=new Set;var W=class extends Error{reason;constructor(t){super(t),this.reason=t,this.name="InvalidServiceJsonError"}};function Et(e){return e instanceof Error?e.message:String(e)}function Si(e){let t;try{t=kr(e,"utf-8")}catch(c){throw new W(`could not read file: ${Et(c)}`)}let n;try{n=JSON.parse(t)}catch(c){throw new W(`invalid JSON: ${Et(c)}`)}if(!yi(n))throw new W("missing required fields (appName, runtime or appType)");let r=bt(n);if(r.length>0)throw new W(r.map(c=>`${c}: expected a string`).join("; "));let s=Le(n,e);if(s.length>0)throw new W(s.join("; "));let o=n;for(let c of Tt(n,e).warnings)Be.has(c)||(Be.add(c),console.warn(`\u26A0\uFE0F ${c}`));let i={...o,appType:o.appType||o.type},a=hi(e);return{name:i.appName,path:a,configPath:e,config:i,stack:i.stack,port:i.port,type:i.appType}}function yr(e){let t=$t(e),n=[],r=[];for(let s of t)try{n.push(Si(s))}catch(o){r.push({path:s,reason:o instanceof W?o.reason:Et(o)})}return{resources:n,problems:r}}function bi(e){for(let t of e){let n=`skipped ${t.path}: ${t.reason}`;Be.has(n)||(Be.add(n),console.warn(`\u26A0\uFE0F ${n}`))}}function b(e){let{resources:t,problems:n}=yr(e);return bi(n),t}function ye(){let e=m();if(!e)throw H.notInProject();return b(e)}function Pl(){let e=m();if(!e)throw H.notInProject();let{resources:t,problems:n}=yr(e);if(n.length>0)throw new Error(n.map(r=>`Invalid service.json at ${r.path}: ${r.reason}`).join(`
|
|
19
|
+
`));return t}function El(e){let t=b(e),n=new Set;for(let r of t)r.stack&&n.add(r.stack);return Array.from(n).sort()}function wl(e){let t=e||ye(),n=new Set;for(let r of t)r.stack&&n.add(r.stack);return Array.from(n).sort()}function vl(e=ye()){let t=new Map;for(let r of e)if(r.stack){let s=t.get(r.stack);s?s.push(r):t.set(r.stack,[r])}let n=[];for(let[r,s]of t)n.push({name:r,description:S(s.length,"resource"),resources:s,resourceCount:s.length});return n.sort((r,s)=>r.name.localeCompare(s.name))}function $l(e,t){return(t??ye()).some(r=>r.stack===e)}var Rt=5e3,wt=new he({ttlMs:Rt}),vt=new he({ttlMs:Rt}),ke=Jn(Rt);function Rl(){wt.clear(),vt.clear(),ke.reset()}function Ti(e,t){if(e==="Dockerfile"||e.startsWith("docker-compose"))return"docker";if(e==="Tiltfile"||e.endsWith(".star"))return"tilt";if(e==="vite.config.ts"||e==="tsconfig.json"||e===D)return"config";if(e==="schema.prisma"||e.includes("migration"))return"prisma";if(t){let n=t.split(`
|
|
19
20
|
`).slice(0,10).join(`
|
|
20
|
-
`);if(n.includes("GENERATED BY TDK")||n.includes("AUTOGENERATED"))return"generated"}return"unknown"}function
|
|
21
|
-
`)){let o=s.trim();if(!o)continue;let i=o.indexOf(" "),a=i>=0?o.slice(0,i):o,c=i>=0?o.slice(i+1):"",u=[];for(let d of n)c.split(/[\s,]+/).some(h=>h.startsWith(`${d}->`)||h.includes(`:${d}->`))&&u.push(d);u.length>0&&r.push({name:a,ports:c,publishedPorts:u})}return r}function
|
|
21
|
+
`);if(n.includes("GENERATED BY TDK")||n.includes("AUTOGENERATED"))return"generated"}return"unknown"}function xi(e){let t=e.configPath;if(ke.isValid()){let k=wt.get(t);if(k)return k}let n=e.path,r=Pt(e.configPath),s=r.mtime.toISOString(),o=r.mtime.toISOString(),i=Pi(n),a=ee(J(n,"Dockerfile")),c=ee(J(n,"Tiltfile")),u=ee(J(n,me))||ee(J(n,"docker-compose.yaml")),d=e.config?.appType,l=d||"backend";d||(e.name.includes("frontend")?l="frontend":(e.name.includes("sdk")||e.name.includes("lib")||e.name.includes("infra"))&&(l="library"));let h={name:e.name,stack:e.stack,type:l,port:e.config?.port,createdAt:s,lastModified:o,dependencies:e.config?.dependsOn??[],hasDockerfile:a,hasTiltfile:c,hasDockerCompose:u,autogeneratedFiles:i,status:"unknown"};return wt.set(t,h),ke.markUpdated(),h}function Pi(e){let t=[];for(let r of On){let s=J(e,r);if(ee(s)){let o=Pt(s),i=kr(s,"utf-8");t.push({name:r,path:s,type:Ti(r,i),size:o.size,lastModified:o.mtime.toISOString()})}}let n=J(e,"prisma");if(ee(n)){let r=gr(n);for(let s of r)if(s==="schema.prisma"||s.includes("migration")){let o=J(n,s),i=Pt(o);t.push({name:`prisma/${s}`,path:o,type:"prisma",size:i.size,lastModified:i.mtime.toISOString()})}}return t.sort((r,s)=>r.name.localeCompare(s.name))}function _l(e){let t=e.name;if(ke.isValid()){let c=vt.get(t);if(c)return c}let n=e.resources.map(c=>xi(c)),r=n.map(c=>new Date(c.createdAt).getTime()),s=Math.min(...r),o=Math.max(...r),i=fr(n.map(c=>c.status)),a={name:e.name,resourceCount:n.length,createdAt:new Date(s).toISOString(),lastModified:new Date(o).toISOString(),resources:n,overallStatus:i};return vt.set(t,a),ke.markUpdated(),a}function Sr(e,t){return e==="pending"||e==="in_progress"||e==="none"||t==="pending"||t==="none"}var br="container is running, but its health check is failing";function Tr(e){let t=e?.runtimeStatus??"";if(t!=="ok")return t;let n=e?.composeResourceInfo?.healthStatus;return n==="unhealthy"?"error":n==="starting"?"pending":t}var Se=1e4,xr=3e3,wi="http://localhost:4873";function vr(e){return`'${e.replace(/'/g,"'\\''")}'`}function be(e,t,n,r,s){return process.platform==="win32"?wr($(t)??t,n,{...s,windowsHide:!0}):e(r,s)}var vi=[80,443];function $i(e){return e.replace(/-/g,"_")}function Ri(e,t){let n=new Set(t),r=[];for(let s of e.split(`
|
|
22
|
+
`)){let o=s.trim();if(!o)continue;let i=o.indexOf(" "),a=i>=0?o.slice(0,i):o,c=i>=0?o.slice(i+1):"",u=[];for(let d of n)c.split(/[\s,]+/).some(h=>h.startsWith(`${d}->`)||h.includes(`:${d}->`))&&u.push(d);u.length>0&&r.push({name:a,ports:c,publishedPorts:u})}return r}function $r(e,t){let n=e.toLowerCase(),r=t.toLowerCase();return n===`${r}_traefik`||n.startsWith(`${r}_traefik`)}function _i(e,t){return e.filter(n=>!$r(n.name,t))}function Oi(){try{return new Set(ye().filter(e=>e.config?.sablier?.enable&&e.config?.sablier?.deferStart).map(e=>e.name))}catch{return new Set}}function Ai(e,t=new Set){let r=JSON.parse(e).items??[],s=[],o=0,i=0,a=0;for(let c of r){let u=c.metadata?.name??"unknown",d=c.status?.updateStatus??"",l=Tr(c.status),h=l==="error"&&c.status?.runtimeStatus==="ok",g=(c.status?.buildHistory?.[0]?.error??"").trim()||(h?br:"");if(d==="error"||l==="error"){s.push({name:u,updateStatus:d,runtimeStatus:l,error:g.replace(/\s+/g," ").slice(0,800)});continue}if(d==="ok"&&(l==="ok"||l==="not_applicable")){a+=1;continue}u!=="(Tiltfile)"&&Sr(d,l)&&(t.has(u)?i+=1:o+=1)}return{failures:s,pendingCount:o,deferredCount:i,okCount:a,total:r.length}}var Di=/failed to resolve source metadata for docker\.io\/library\/([A-Za-z0-9._-]+-l[1-4](?:-[a-z]+)*)(?::[^\s:]+)?:/i;function At(e){let t=e.replace(/\s+/g," ").trim(),n=t.match(/Bind for [^ ]+:(\d+) failed: port is already allocated/i);if(n)return`host port ${n[1]} is already allocated`;if(/port is already allocated/i.test(t))return"a required host port is already allocated";let r=[...t.matchAll(/ConnectionRefused downloading package manifest (@[A-Za-z0-9._/-]+)/gi)].map(a=>a[1]);if(r.length>0){let a=[...new Set(r)],c=a.slice(0,4).join(", "),u=a.length>4?` (+${a.length-4} more)`:"";return`private registry ConnectionRefused for ${c}${u} \u2014 Verdaccio (:4873) is down or unreachable from the build`}let s=t.match(Di);if(s)return`base image ${s[1]} was missing when this build started (the golden layers weren't built yet, or golden-layers-build failed) - Tilt does not retry a failed build by itself`;if(/install-deps\.sh/i.test(t)||/bun install(?: --production)?/i.test(t)||/npm (?:ci|install)/i.test(t))return"dependency install failed during ImageBuild \u2014 usually Verdaccio (:4873) unreachable or missing @scoped packages (ConnectionRefused downloading package manifest)";let o=t.match(/No such image:\s*([^\s]+)/i)?.[1]??t.match(/pull access denied for ([^,:\s]+)/i)?.[1]??void 0,i=t.match(/\bup\s+-d\s+--no-build\s+([A-Za-z0-9._-]+)/i)?.[1];if(o||i||/docker compose .*\bup\s+-d\s+--no-build\b/i.test(t)){let a=o??`${i??"service"}:dev`,c=i?` for ${i}`:"";return`compose run failed because image is missing (${a})${c} \u2014 wait for the ImageBuild resource to finish, then re-trigger the *-run-only resource`}return/bun run build/i.test(t)?"ImageBuild failed during `bun run build` (compile/typecheck) \u2014 open the resource logs in Tilt for the TypeScript/build error":(/ImageBuild:/i.test(t)||/^Command "/i.test(t),t.slice(0,220))}function Pr(e){return/ConnectionRefused downloading package manifest|Verdaccio|private registry|dependency install failed during ImageBuild|install-deps\.sh|bun install/i.test(e)}function Dt(e=m()??process.cwd()){let t=te(e,".tdk",P);if(!_t(t))return!1;try{let n=JSON.parse(Ot(t,"utf-8"));return n.optional_infra?.verdaccio===!0||Object.values(n.phases??{}).some(r=>(r.enabledStacks??[]).includes("verdaccio"))}catch{return!1}}function Rr(e){for(let t of[te(e,".npmrc"),te(e,D)])if(_t(t))try{let n=Ot(t,"utf-8");if(/:4873\b/.test(n)||/verdaccio/i.test(n))return!0}catch{}return!1}function Ci(e=m()??process.cwd()){return Dt(e)||Rr(e)}function Ct(e=Te,t=m()??process.cwd(),n=process.env.VERDACCIO_URL??process.env.NPM_REGISTRY_URL??wi,r=!0){if(!r&&!Rr(t))return{name:"Private npm registry",didPass:!0,isSkipped:!0,message:"Verdaccio is enabled in the project config but needs a Premium license, so TDK will not start it - skipped"};if(!Ci(t))return{name:"Private npm registry",didPass:!0,isSkipped:!0,message:"Private npm registry (Verdaccio) not enabled for this project - skipped"};let s=!1;try{let a=be(e,"docker",["ps","--format","{{.Names}}"],"docker ps --format '{{.Names}}'",{stdio:"pipe",encoding:"utf-8",timeout:Se});s=/verdaccio/i.test(a)}catch{}let o=!1,i="";try{let a=process.platform==="win32"?wr("curl.exe",["-fsS","-o","NUL","-w","%{http_code}","--max-time","2",n],{stdio:"pipe",encoding:"utf-8",timeout:xr+1e3,windowsHide:!0}).trim():e(`curl -fsS -o /dev/null -w '%{http_code}' --max-time 2 ${vr(n)}`,{stdio:"pipe",encoding:"utf-8",timeout:xr+1e3}).trim();o=/^[23]\d\d$/.test(a),i=`HTTP ${a}`}catch(a){i=a instanceof Error?a.message.slice(0,120):"request failed"}return o?{name:"Private npm registry",didPass:!0,message:`Private npm registry reachable at ${n}${s?" (verdaccio container running)":""}`}:s?{name:"Private npm registry",didPass:!1,message:`Verdaccio container is running but ${n} is not responding (${i}). ImageBuilds that install @scoped packages will fail with ConnectionRefused downloading package manifest.`,fix:"Check `docker logs` for the verdaccio container, confirm port 4873 is published, then re-run `tdk doctor`."}:{name:"Private npm registry",didPass:!1,message:`Private npm registry (Verdaccio) is not reachable at ${n}. Docker ImageBuilds will fail with ConnectionRefused downloading package manifests for @tdk-landscape/* and project-scoped packages.`,fix:"Start the registry with `bun run verdaccio:start` (or `docker compose -f docker-compose.verdaccio.yml up -d`), publish packages with `bun run publish:all` / `scripts/build/publish-to-verdaccio.sh`, then `tilt trigger` failed resources or re-run `tdk up`."}}function Nt(e=Te,t=je(),n=vi){let r=$i(t),s="";try{s=be(e,"docker",["ps","--format","{{.Names}}\\t{{.Ports}}"],"docker ps --format '{{.Names}}\\t{{.Ports}}'",{stdio:"pipe",encoding:"utf-8",timeout:Se})}catch{return{name:"Ingress Ports",didPass:!0,isSkipped:!0,message:"Docker not available - skipped ingress port check"}}let o=Ri(s,n),i=_i(o,r);if(i.length===0){let c=o.filter(u=>$r(u.name,r));return c.length>0?{name:"Ingress Ports",didPass:!0,message:`Ingress ports ${n.join("/")} held by this project's Traefik (${c.map(u=>u.name).join(", ")})`}:{name:"Ingress Ports",didPass:!0,message:`Ingress ports ${n.join("/")} are free for Traefik`}}return{name:"Ingress Ports",didPass:!1,message:`Traefik cannot bind ingress ports because another container already owns them:
|
|
22
23
|
${i.map(c=>{let u=c.publishedPorts.join(", ");return`${c.name} (host ports ${u})`}).join(`
|
|
23
|
-
`)}`,fix:`Stop the foreign container(s), e.g. \`docker stop ${i[0]?.name}\`, or shut down the other TDK/Tilt project using that Traefik. Then re-run \`tdk up\`.`}}function
|
|
24
|
+
`)}`,fix:`Stop the foreign container(s), e.g. \`docker stop ${i[0]?.name}\`, or shut down the other TDK/Tilt project using that Traefik. Then re-run \`tdk up\`.`}}function Ni(e){let{status:t}=e;return t===void 0?e.error??"no response":t===404?"HTTP 404: Traefik is answering but has no route for this URL (container not started yet, or not running)":t===502||t===503||t===504?`HTTP ${t}: Traefik found the route but the container isn't answering (still starting, or unhealthy)`:`HTTP ${t}`}function jt(e){let t=e.filter(o=>o.status!==void 0),n=e.filter(o=>!o.ok);if(t.length===0)return{name:"Service Health",didPass:!0,isSkipped:!0,message:`No services responded - skipped ping of ${S(e.length,"service")} (stack may be down, or Traefik never bound :80)`,fix:"If `tdk up` is already running, check Traefik/port 80 in the Tilt UI. Otherwise start with: tdk up"};if(n.length===0)return{name:"Service Health",didPass:!0,message:`All ${S(e.length,"service")} responding on /health`};let r=n.map(o=>`${o.name} (${Ni(o)})
|
|
24
25
|
${o.url}`).join(`
|
|
25
26
|
`),s=n.some(o=>o.status===404);return{name:"Service Health",didPass:!1,message:`${S(n.length,"service")} not healthy (${e.length-n.length}/${e.length} healthy):
|
|
26
|
-
${r}`,fix:s?"If `tdk up` just started, images may still be building: re-run `tdk doctor` in a minute. Otherwise check `docker ps` and the resource in the Tilt UI, and compare `tdk networks` with the URL above.":"Check container state and routing: docker ps, then tdk networks to compare the advertised URLs against Traefik's routers"}}function
|
|
27
|
+
${r}`,fix:s?"If `tdk up` just started, images may still be building: re-run `tdk doctor` in a minute. Otherwise check `docker ps` and the resource in the Tilt UI, and compare `tdk networks` with the URL above.":"Check container state and routing: docker ps, then tdk networks to compare the advertised URLs against Traefik's routers"}}function It(e=Te){let t="";try{t=be(e,"tilt",["get","uiresources","-o","json"],"tilt get uiresources -o json",{stdio:"pipe",encoding:"utf-8",timeout:Se})}catch{return{name:"Tilt Resources",didPass:!0,isSkipped:!0,message:"Tilt is not running - skipped resource status check",fix:"Start them with: tdk up"}}let n;try{n=Ai(t,Oi())}catch{return{name:"Tilt Resources",didPass:!0,isSkipped:!0,message:"Could not parse Tilt resource status - skipped"}}if(n.total===0)return{name:"Tilt Resources",didPass:!0,isSkipped:!0,message:"No Tilt UIResources found"};if(n.failures.length===0){let y=n.deferredCount>0?`, ${n.deferredCount} deferred`:"";return{name:"Tilt Resources",didPass:!0,message:`Tilt resources healthy (${n.okCount} ok, ${n.pendingCount} pending${y})`}}let r=Ii(n.failures),o=r.slice(0,20),i=r.length-o.length,a=o.map(y=>({failure:y,why:Mi(y,e)})),c=a.map(({failure:y,why:w})=>`${y.name}: ${w}`).join(`
|
|
27
28
|
`),u=i>0?`
|
|
28
29
|
\u2026and ${S(i,"more failed resource")}`:"",d=n.pendingCount>0?`
|
|
29
30
|
${S(n.pendingCount,"resource")} still pending/not started \u2014 often blocked by the failures above.`:"",l=n.deferredCount>0?`
|
|
30
|
-
${S(n.deferredCount,"resource")} intentionally deferred (sablier.deferStart) \u2014 not started until first request, unrelated to the failures above.`:"",h=r.some(y=>/port is already allocated/i.test(y.error)),k=r.some(y=>
|
|
31
|
-
${c}${u}${d}${l}`,fix:p}}var
|
|
32
|
-
`).map(u=>u.trim()).filter(Boolean),s=`-autogenerated-${e}-1`,o=r.find(u=>u===e)??r.find(u=>u.startsWith(`${n}-`)&&u.endsWith(s))??r.find(u=>u.endsWith(s))??r.find(u=>u.includes(e));if(!o)return null;let i=be(t,"docker",["logs","--tail","120",o],`docker logs --tail 120 ${
|
|
31
|
+
${S(n.deferredCount,"resource")} intentionally deferred (sablier.deferStart) \u2014 not started until first request, unrelated to the failures above.`:"",h=r.some(y=>/port is already allocated/i.test(y.error)),k=r.some(y=>Pr(y.error)||Pr(At(y.error))),g=a.some(({why:y})=>/Kafka broker unreachable|kafka:9092/i.test(y)),p="Open the Tilt UI URL printed by tdk up (default port "+Rn.tiltUi+" when TILT_PORT is unset), inspect the red resources, fix the listed errors, then `tilt trigger <resource>` or re-run `tdk up`.";return h?p="Free the conflicting host port (usually 80/443): `docker ps --filter publish=80` then `docker stop <other-traefik>`. Re-trigger Traefik in the Tilt UI or run `tdk up` again.":k?p="Start Verdaccio (`bun run verdaccio:start`), ensure packages are published (`bun run publish:all` or `bash scripts/build/publish-to-verdaccio.sh`), confirm `curl http://localhost:4873` works, then `tilt trigger` the failed resources.":g&&(p="Kafka is not running (optional infra). Start it, point the bridge at a real broker, or disable Kafka-dependent resources until Kafka is enabled."),{name:"Tilt Resources",didPass:!1,message:`Tilt reports ${S(n.failures.length,"failed resource")}:
|
|
32
|
+
${c}${u}${d}${l}`,fix:p}}var ji=/^(traefik|postgres|nats|infisical|verdaccio|proxy)([.-]|$)/i;function Er(e){return ji.test(e)}function Ii(e){return[...e].sort((t,n)=>{let r=Er(t.name)?0:1,s=Er(n.name)?0:1;return r!==s?r-s:t.name.localeCompare(n.name)})}function Fi(e,t=Te,n=je()){try{let r=be(t,"docker",["ps","-a","--format","{{.Names}}"],"docker ps -a --format '{{.Names}}'",{stdio:"pipe",encoding:"utf-8",timeout:Se}).split(`
|
|
33
|
+
`).map(u=>u.trim()).filter(Boolean),s=`-autogenerated-${e}-1`,o=r.find(u=>u===e)??r.find(u=>u.startsWith(`${n}-`)&&u.endsWith(s))??r.find(u=>u.endsWith(s))??r.find(u=>u.includes(e));if(!o)return null;let i=be(t,"docker",["logs","--tail","120",o],`docker logs --tail 120 ${vr(o)} 2>&1`,{stdio:"pipe",encoding:"utf-8",timeout:Se});if(/getaddrinfo ENOTFOUND/i.test(i)&&/kafka:9092/i.test(i))return"runtime crash: Kafka broker unreachable (getaddrinfo ENOTFOUND kafka:9092)";if(/ECONNREFUSED/i.test(i)&&/kafka/i.test(i))return"runtime crash: Kafka connection refused";let a=i.match(/ConnectionRefused downloading package manifest (@[A-Za-z0-9._/-]+)/i);if(a?.[1])return`runtime/build log: private registry ConnectionRefused for ${a[1]}`;if(/ZodError/i.test(i)){let u=[...i.matchAll(/"path"\s*:\s*\[\s*"([^"]+)"\s*\]/g)].map(l=>l[1]),d=[...new Set(u)].slice(0,6);return d.length>0?`runtime crash: ZodError missing required config/env: ${d.join(", ")}`:"runtime crash: ZodError during config/env validation"}let c=i.match(/error:\s+Failed to [^:\n]+[^\n]{0,120}/i)?.[0]??i.match(/Failed to (?:start|initialize) [^\n]{0,120}/i)?.[0]??i.match(/^\s*error:\s+[^\n]{0,160}/im)?.[0];if(c)return`runtime crash: ${c.replace(/\s+/g," ").trim().slice(0,180)}`}catch{return null}return null}function Mi(e,t=Te){return e.error?At(e.error):e.runtimeStatus==="error"?Fi(e.name,t)??"runtime error (container crashed or unhealthy \u2014 check Tilt/docker logs)":e.updateStatus||e.runtimeStatus||"unknown error"}var Li=/\.(ts|tsx|mts|js|mjs|cjs)$/,Bi=new Set(["node_modules","dist",F,"tests","__tests__"]);function _r(e){let t=[];for(let n of Ei(e,{withFileTypes:!0}))n.isDirectory()?Bi.has(n.name)||t.push(..._r(te(e,n.name))):Li.test(n.name)&&!/\.(test|spec)\./.test(n.name)&&t.push(te(e,n.name));return t}function Ui(e){let t=e?.healthCheckPath||"/health";return{container:t,traefik:e?.traefik?.healthCheck||t}}function Hi(e){let t=[];for(let n of e){if(!v(n.config?.appType))continue;let r=te(n.path,"src");if(!_t(r))continue;let s=_r(r);if(s.length===0)continue;let o=s.map(u=>Ot(u,"utf-8")),{container:i,traefik:a}=Ui(n.config),c=i===a?[{path:i,usedBy:"container and Traefik healthchecks"}]:[{path:i,usedBy:"container healthcheck"},{path:a,usedBy:"Traefik healthcheck"}];for(let{path:u,usedBy:d}of c){let l=["'",'"',"`"].map(h=>`${h}${u}${h}`);o.some(h=>l.some(k=>h.includes(k)))||t.push({name:n.name,healthPath:u,usedBy:d})}}return t}function Or(e=m()??process.cwd()){let t=[];try{t=b(e)}catch{return{name:"Health Routes",didPass:!0,isSkipped:!0,message:"Could not read services - skipped health route check"}}let n=t.filter(o=>v(o.config?.appType));if(n.length===0)return{name:"Health Routes",didPass:!0,isSkipped:!0,message:"No backend services to check"};let r=Hi(n);return r.length===0?{name:"Health Routes",didPass:!0,message:`All ${S(n.length,"backend")} define their health route`}:{name:"Health Routes",didPass:!1,message:`Backends without a health route (the container never turns healthy, so Traefik returns 404):
|
|
33
34
|
${r.map(o=>`${o.name}: no "${o.healthPath}" route in src/ (probed by the ${o.usedBy})`).join(`
|
|
34
|
-
`)}`,fix:`Add the route, e.g. for Hono: app.get("${r[0]?.healthPath}", (c) => c.json({ status: "ok" })). To use a different path, set "healthCheckPath" (container healthcheck) or "traefik.healthCheck" (Traefik) in its service.json.`}}import{existsSync as
|
|
35
|
+
`)}`,fix:`Add the route, e.g. for Hono: app.get("${r[0]?.healthPath}", (c) => c.json({ status: "ok" })). To use a different path, set "healthCheckPath" (container healthcheck) or "traefik.healthCheck" (Traefik) in its service.json.`}}import{existsSync as Mt,readFileSync as Ar}from"node:fs";import{dirname as Vi,join as Ft,normalize as Ki}from"node:path";function Gi(e){let t=new Set,n=/^load\s*\(([\s\S]*?)\)/gm;for(let r of e.matchAll(n)){let s=r[1]??"",o=/["']([^"']+)["']/g,i=Array.from(s.matchAll(o),a=>a[1]);for(let a of i.slice(1))a.startsWith("_")&&t.add(a)}return Array.from(t).sort()}function Dr(e,t,n){return t==="ext://tdk-cli"?Ft(n,".tdk",".tdk-out","tdk-cli-ext","Tiltfile"):t.startsWith(".")||!t.includes("://")&&!t.startsWith("@")?Ki(Ft(Vi(e),t)):null}function Wi(e,t,n){let r=[],s=/^load\s*\(([\s\S]*?)\)/gm;for(let o of t.matchAll(s)){let c=(o[1]??"").match(/["']([^"']+)["']/)?.[1];if(!c)continue;let u=Dr(e,c,n);u&&(Mt(u)||r.push(`${e}: ${c} -> ${u}`))}return r}function Ji(e,t,n){let r=[],s=/^load\s*\(([\s\S]*?)\)/gm;for(let o of t.matchAll(s)){let c=(o[1]??"").match(/["']([^"']+)["']/)?.[1];if(c){let u=Dr(e,c,n);u&&r.push(u)}}return r}function qi(e,t){let n=new Set,r=[e];for(;r.length>0;){let s=r.pop();if(!s||n.has(s)||!Mt(s))continue;n.add(s);let o=Ar(s,"utf-8");for(let i of Ji(s,o,t))n.has(i)||r.push(i)}return Array.from(n).sort()}function Cr(){let e=m()??process.cwd(),t=Ft(e,".tdk",".tdk-out","Tiltfile");if(!Mt(t))return{name:"Starlark Load Exports",didPass:!0,isSkipped:!0,message:"No generated Tiltfile to check"};let n=[],r=[],s=qi(t,e);for(let i of s){let a=Ar(i,"utf-8"),c=Gi(a);c.length>0&&n.push(`${i}: ${c.join(", ")}`);for(let u of Wi(i,a,e))r.push(u)}if(n.length===0&&r.length===0)return{name:"Starlark Load Exports",didPass:!0,message:`${S(s.length,"reachable Starlark file")} ${s.length===1?"has":"have"} valid load exports and paths`};let o=[];return n.length>0&&o.push(`Private exported symbols:
|
|
35
36
|
${n.join(`
|
|
36
37
|
`)}`),r.length>0&&o.push(`Missing relative load targets:
|
|
37
38
|
${r.join(`
|
|
38
39
|
`)}`),{name:"Starlark Load Exports",didPass:!1,message:`Starlark load() issues will stop Tilt before services start:
|
|
39
40
|
${o.join(`
|
|
40
41
|
|
|
41
|
-
`)}`,fix:"Regenerate with a current TDK (`tdk config regenerate`). If the issue remains, rename loaded symbols without leading underscores and update stale load paths."}}import{execFileSync as
|
|
42
|
+
`)}`,fix:"Regenerate with a current TDK (`tdk config regenerate`). If the issue remains, rename loaded symbols without leading underscores and update stale load paths."}}import{execFileSync as ca,execSync as ua}from"node:child_process";import{existsSync as Ht,readdirSync as qr,readFileSync as Pe}from"node:fs";import{basename as da,dirname as la,join as O,relative as xe}from"node:path";function Yl(e){return`import { Hono } from 'hono';
|
|
42
43
|
|
|
43
44
|
const app = new Hono();
|
|
44
45
|
|
|
@@ -78,7 +79,7 @@ export default {
|
|
|
78
79
|
port,
|
|
79
80
|
fetch: app.fetch,
|
|
80
81
|
};
|
|
81
|
-
`}var
|
|
82
|
+
`}var Nr={id:"bun",label:"Bun + Hono",installHint:"bun install"};var Yi="go run .",jr={id:"go",label:"Go 1.23 (net/http)",devCommand:Yi,watch:["**/*.go","go.mod","go.sum"],installHint:"go mod tidy # optional: Docker builds the image for you",createFiles(e){return[{filename:"go.mod",content:`module ${e}
|
|
82
83
|
|
|
83
84
|
go 1.23
|
|
84
85
|
`,description:"Generating go.mod",emoji:"\u{1F4E6}"},{filename:"main.go",content:`package main
|
|
@@ -141,7 +142,7 @@ func TestHealth(t *testing.T) {
|
|
|
141
142
|
t.Fatalf("GET /health = %d, want %d", rec.Code, http.StatusOK)
|
|
142
143
|
}
|
|
143
144
|
}
|
|
144
|
-
`,description:"Generating smoke test",emoji:"\u{1F9EA}"}]}};var
|
|
145
|
+
`,description:"Generating smoke test",emoji:"\u{1F9EA}"}]}};var zi="uvicorn main:app --app-dir src --host 0.0.0.0 --port ${PORT:-4000} --reload --reload-dir src",Ir={id:"python",label:"Python 3.12 + FastAPI",devCommand:zi,watch:["src/**/*"],installHint:'pip install -e ".[dev]" # optional: Docker builds the image for you',createFiles(e){return[{filename:"pyproject.toml",content:`[project]
|
|
145
146
|
name = "${e}"
|
|
146
147
|
version = "0.0.1"
|
|
147
148
|
requires-python = ">=3.12"
|
|
@@ -199,7 +200,7 @@ def test_health() -> None:
|
|
|
199
200
|
response = client.get("/health")
|
|
200
201
|
assert response.status_code == 200
|
|
201
202
|
assert response.json() == {"status": "ok", "service": "${e}"}
|
|
202
|
-
`,description:"Generating test file",emoji:"\u{1F9EA}"}]}};var
|
|
203
|
+
`,description:"Generating test file",emoji:"\u{1F9EA}"}]}};var Xi="cargo run",Fr={id:"rust",label:"Rust (axum)",devCommand:Xi,watch:["src/**/*.rs","Cargo.toml","Cargo.lock"],installHint:"cargo build # optional: Docker builds the image for you",createFiles(e){return[{filename:"Cargo.toml",content:`[package]
|
|
203
204
|
name = "${e}"
|
|
204
205
|
version = "0.1.0"
|
|
205
206
|
edition = "2021"
|
|
@@ -253,63 +254,63 @@ mod tests {
|
|
|
253
254
|
assert_eq!(body["status"], "ok");
|
|
254
255
|
}
|
|
255
256
|
}
|
|
256
|
-
`,description:"Generating backend source and smoke test",emoji:"\u{1F4BB}"}]}};var
|
|
257
|
+
`,description:"Generating backend source and smoke test",emoji:"\u{1F4BB}"}]}};var Mr="bun",ne={bun:Nr,python:Ir,go:jr,rust:Fr};function Zi(e){let t=(e??Mr).trim().toLowerCase(),n=Object.hasOwn(ne,t)?ne[t]:void 0;if(!n){let r=Object.keys(ne).join(", ");throw new R(`Unknown backend language "${e}". Supported languages: ${r}.`,[`Use one of: ${r}`,`Omit --language to use ${Mr}`])}return n}function op(e,t){if(e!=="backend"){if(t!==void 0)throw new R("--language can only be used with --type backend.",["Add --type backend, or drop --language for this resource type"]);return}return Zi(t)}import{exec as Qi,execFile as ea}from"node:child_process";import{promisify as Lr}from"node:util";var ta=Lr(Qi),M=async(e,t)=>{if(process.platform==="win32"){let r=e.match(/(?:[^\s"']+|"[^"]*"|'[^']*')+/g)??[],[s,...o]=r.map(c=>c.startsWith('"')||c.startsWith("'")?c.slice(1,-1):c);if(!s)throw new Error("Command is empty");let i=$(s)??s,{stdout:a}=await Lr(ea)(i,o,{encoding:"utf-8",timeout:t,windowsHide:!0,shell:!1});return a}let{stdout:n}=await ta(e,{encoding:"utf-8",timeout:t});return n};function Br(e){let t=e;return t?.code==="ETIMEDOUT"||t?.killed===!0}import{existsSync as na,readFileSync as Ur}from"node:fs";import{join as q}from"node:path";var Lt=[U,"proxy"];var Hr=["postgres",U],Vr=["pre_alpha","alpha","beta","out_of_scope"];function ra(e){return Hr.includes(e)}function Kr(e){try{return JSON.parse(Ur(q(e,".tdk",P),"utf-8"))}catch{return}}function re(e){try{return na(e)?Ur(e,"utf-8"):void 0}catch{return}}function Gr(e,t){let n=s=>{let o=s;for(;o<e.length&&/\s/.test(e[o]);)o+=1;return o},r=0;for(;;){let s=e.indexOf(t,r);if(s===-1)return;let o=n(s+t.length);if(e[o]==="="&&(o=n(o+1),e[o]==="[")){let i=e.indexOf("]",o+1);return i===-1?void 0:[...e.slice(o+1,i).matchAll(/"([^"]+)"|'([^']+)'/g)].map(a=>a[1]??a[2]??"")}r=s+t.length}}function Wr(e){let t=q(e,".tdk",".tdk-out","Tiltfile"),n=re(t);if(n)return Gr(n,"ALWAYS_ENABLED_INFRA")}function sa(e){let t=q(e,".tdk",".tdk-out","spec.master"),n=re(t);if(n!==void 0)return/"database-management"\s*:\s*True/.test(n)}function oa(e){let t=q(e,".tdk",".tdk-out"),n=re(q(t,"Tiltfile")),r=re(q(t,"spec.master")),s=re(q(t,"tdk-cli-ext","discovery","config.star")),o=re(q(t,"tdk-cli-ext","engine","topologies","tilt","config","profiles.star"));if(!n||!r||!s||!o)return!1;let i=r.match(/PRE_ALPHA_RESOURCES\s*=\s*\{([^}]*)\}/)?.[1],a=Gr(s,"CORE_INFRA");return/FOCUS_MODE\s*,\s*FOCUS_ENABLED_ALL\s*,\s*FOCUS_ENABLED_RESOURCES\s*=\s*Config\.apply_focus\(cfg\)/.test(n)&&/if FOCUS_MODE and FOCUS_ENABLED_ALL\s*:/.test(n)&&/"[^"]+"\s*:\s*True|'[^']+'\s*:\s*True/.test(i??"")&&(a?.includes("postgres")??!1)&&/["']postgres["']\s*:\s*["']database-management["']/.test(s)&&/for infra in CORE_INFRA_EXPORT\s*:/.test(o)&&/needed\[INFRA_STACK_MAP_EXPORT\[infra\]\]\s*=\s*True/.test(o)}function ia(e){let t=Kr(e);if(!t)return!1;let n=t.phases??{};for(let s of Vr){let o=n[s]?.enabledStacks;if(Array.isArray(o)&&o.includes(U))return!0}let r=t.always_enabled_infra??Lt;return Array.isArray(r)&&r.includes(U)}function aa(e){let t=new Set;for(let s of Hr)t.add(s);for(let s of b(e))t.add(s.name),s.stack&&t.add(s.stack);let n=Kr(e);if(n){let s=n.phases??{};for(let i of Vr){let a=s[i]?.enabledStacks;if(Array.isArray(a))for(let c of a)t.add(c)}let o=n.always_enabled_infra??Lt;if(Array.isArray(o))for(let i of o)t.add(i)}let r=Wr(e);if(Array.isArray(r))for(let s of r)t.add(s);return t}function Bt(e){let t=ia(e),n=Wr(e),r=Array.isArray(n)&&n.includes(U),s=sa(e)===!0,o=t||r||s,i=!t&&oa(e),a=aa(e),c=[],u=[];for(let h of b(e)){let k=h.config?.dependsOn??[],g=!1;for(let p of k){if(ra(p)){g=!0;continue}a.has(p)||u.push({resource:h.name,name:p})}g&&c.push(h.name)}let d=o||c.length>0,l=o?"feature":c.length>0?"dependsOn":"none";return{featureOn:o,featureOnFromProjectJson:t,featureOnFromTiltfile:r,featureOnFromSpecMaster:s,focusWouldEnableDatabaseManagement:i,dependsOnUsers:c,willStart:d,reason:l,unknownDependsOnNames:u}}var He=1e4,pa=/\.(?:[cm]?[jt]sx?|vue)$/,fa=/(?:\.test\.|\.spec\.|\/tests?\/|\/__tests__\/)/,ma=7,ha=new Set(["node_modules",F,"dist","tests","__tests__"]);function Yr(e){try{let t=JSON.parse(Pe(O(e,".tdk",P),"utf-8"));return typeof t?.project?.name=="string"?t.project.name:void 0}catch{return}}function ga(e){try{let t=JSON.parse(Pe(e,"utf-8")).params;return t&&typeof t=="object"?t:{}}catch{return{}}}function Ut(e){try{let t=JSON.parse(Pe(O(e,D),"utf-8"));return t&&typeof t=="object"?t:{}}catch{return{}}}function Jr(e){if(typeof e!="string")return;let t=e.match(/(?:^|[^0-9])(\d+)(?:\.|$)/);return t?Number(t[1]):void 0}function ka(e){let t=Ke(e);if(t===void 0)return["missing prisma/schema.prisma"];let n=t.replace(/\/\*[\s\S]*?\*\//g,"").replace(/^\s*\/\/.*$/gm,""),r=[],s=n.match(/datasource\s+\w+\s*\{([^}]*)\}/)?.[1]??"";return/provider\s*=\s*["']postgresql["']/.test(s)||r.push("schema provider is not postgresql"),/\b(?:url|directUrl)\s*=/.test(n)&&r.push("schema still declares url/directUrl"),r}function ya(e){let t=O(e,F,"prisma.config.autogenerated.ts"),r=[O(e,"prisma.config.ts"),t].find(i=>Ht(i));if(!r)return["missing prisma.config.ts or generated Prisma config"];let o=(Ke(r)??"").match(/datasource\s*:\s*\{([^}]*)\}/)?.[1]??"";return/url\s*:\s*(?:env\(["']DATABASE_URL["']\)|process\.env\.DATABASE_URL)\s*,?/.test(o)?[]:['Prisma config datasource.url is not env("DATABASE_URL")']}function zr(e=m()??process.cwd()){let t=b(e),n=t.filter(o=>o.config?.featuresEnabled?.includes("prisma")),r=[],s=t.filter(o=>o.config?.appType==="migrator");for(let o of t){let i=o.config?.features;Array.isArray(i)&&i.includes("prisma")&&!o.config?.featuresEnabled?.includes("prisma")&&r.push(`${o.name}: use featuresEnabled, not features, for Prisma`)}if(n.length===0)return r.length===0?{name:"Prisma 7 consistency",didPass:!0,isSkipped:!0,message:"No resources enable Prisma; Prisma consistency checks were skipped"}:{name:"Prisma 7 consistency",didPass:!1,message:`${S(r.length,"Prisma consistency error")}:
|
|
257
258
|
${r.join(`
|
|
258
|
-
`)}`,fix:"Use featuresEnabled to opt into the validated Prisma 7 shape"};for(let o of n){let i=
|
|
259
|
+
`)}`,fix:"Use featuresEnabled to opt into the validated Prisma 7 shape"};for(let o of n){let i=Ut(o.path).dependencies,c={...Ut(o.path).devDependencies??{},...i??{}},u=Jr(c.prisma),d=Jr(c["@prisma/client"]);if(u===void 0||d===void 0?r.push(`${o.name}: prisma and @prisma/client are required`):(u!==d||u!==ma)&&r.push(`${o.name}: prisma packages must both be major 7`),r.push(...ka(O(o.path,"prisma","schema.prisma")).map(h=>`${o.name}: ${h}`)),r.push(...ya(o.path).map(h=>`${o.name}: ${h}`)),(o.config?.appType??o.type)==="migrator")o.config?.dependsOn?.some(k=>k==="postgres"||k===U)||r.push(`${o.name}: migrator must depend on postgres or database-management`);else{o.config?.dependsOn?.some(p=>s.some(y=>y.name===p))||r.push(`${o.name}: API must depend on its Prisma migrator`);let k=Ut(o.path).scripts;Object.entries(k??{}).some(([p,y])=>os.has(p)&&typeof y=="string"&&/prisma\s+migrate/.test(y))&&r.push(`${o.name}: API start script must not run prisma migrate`);let g=O(o.path,o.config?.dockerfile??"Dockerfile");Ue(g,!0)&&r.push(`${o.name}: API image/startup must not run Prisma migrations`)}}return n.length>0&&!Bt(e).willStart&&r.push("shared platform Postgres will not start for the Prisma resources"),r.length===0?{name:"Prisma 7 consistency",didPass:!0,message:"Prisma resources use the validated Prisma 7 shape"}:{name:"Prisma 7 consistency",didPass:!1,message:`${S(r.length,"Prisma consistency error")}:
|
|
259
260
|
${r.join(`
|
|
260
|
-
`)}`,fix:"Use Prisma 7 packages and config, put migrations in a migrator, and make the API depend on that migrator"}}function
|
|
261
|
+
`)}`,fix:"Use Prisma 7 packages and config, put migrations in a migrator, and make the API depend on that migrator"}}function Xr(e){let t=new Map;for(let n of e){let r=n.config?.port;v(n.config?.appType)&&typeof r=="number"&&t.set(n.name,r)}return t}function Sa(e){let t=e.config?.language;return typeof t=="string"&&Object.hasOwn(ne,t)&&ne[t].createFiles!==void 0}function ba(e){return(e.config?.appType??e.type)===B}function Zr(e=m()??process.cwd()){let t=b(e).filter(n=>!ba(n)&&!Sa(n)&&!Ht(O(n.path,D))).map(n=>n.name);return t.length===0?{name:"Resource package.json",didPass:!0,message:"Every resource has a package.json"}:{name:"Resource package.json",didPass:!1,message:`${S(t.length,"resource")} without a package.json: ${t.join(", ")}. The image build stops at "COPY .../package.json: not found"`,fix:"Add a package.json next to each service.json (copy one from a working resource), or delete the folder's service.json if it is not a service"}}function Ve(e=m()??process.cwd()){let t=new Map;for(let s of b(e)){let o=t.get(s.name)??[];o.push(xe(e,s.configPath)||s.configPath),t.set(s.name,o)}let n=[...t].filter(([,s])=>s.length>1);if(n.length===0)return{name:"Duplicate resource names",didPass:!0,message:"Every resource has a unique appName"};let r=n.map(([s,o])=>`"${s}" in ${o.join(" and ")}`);return{name:"Duplicate resource names",didPass:!1,message:`${S(n.length,"appName")} used by more than one resource:
|
|
261
262
|
${r.join(`
|
|
262
|
-
`)}`,fix:'Give each resource its own "appName" in its service.json. The name becomes the Compose service and the Traefik router, so two resources with one name collide'}}function
|
|
263
|
+
`)}`,fix:'Give each resource its own "appName" in its service.json. The name becomes the Compose service and the Traefik router, so two resources with one name collide'}}function Ta(e){let t=e.config?.appType;return v(t)?!0:t===B&&e.config?.exposeViaProxy!==!1}function Qr(e=m()??process.cwd()){let t=new Map;for(let s of b(e)){let o=s.config?.port;if(typeof o!="number"||!Ta(s))continue;let i=t.get(o)??[];i.push(s.name),t.set(o,i)}let n=[...t].filter(([,s])=>s.length>1);if(n.length===0)return{name:"Duplicate resource ports",didPass:!0,message:"No two routed resources use the same port"};let r=n.map(([s,o])=>`port ${s}: ${o.join(", ")}`);return{name:"Duplicate resource ports",didPass:!1,isWarning:!0,message:`${S(n.length,"port")} used by more than one routed resource:
|
|
263
264
|
${r.join(`
|
|
264
|
-
`)}`,fix:'Usually a copied service.json. Each container can listen on the same port, but pick distinct "port" values (tdk resource assigns free ones) so URLs like http://<resource>:<port> and localhost checks stay unambiguous'}}var
|
|
265
|
+
`)}`,fix:'Usually a copied service.json. Each container can listen on the same port, but pick distinct "port" values (tdk resource assigns free ones) so URLs like http://<resource>:<port> and localhost checks stay unambiguous'}}var xa=/https?:\/\/([a-z][a-z0-9-]*):(\d+)/g;function es(e=m()??process.cwd()){let t=b(e),n=Xr(t),r=new Map([...n].map(([o,i])=>[i,o])),s=[];for(let o of t)for(let[i,a]of Object.entries(ga(o.configPath)))for(let[,c,u]of String(a).matchAll(xa)){let d=Number(u),l=n.get(c);l!==void 0&&l!==d?s.push(`${o.name} param ${i}: ${c}:${d}, but ${c} listens on ${l}`):(c==="localhost"||c==="127.0.0.1")&&r.has(d)&&r.get(d)!==o.name&&s.push(`${o.name} param ${i}: localhost:${d} is ${o.name} itself inside its container; ${r.get(d)} is reached as ${r.get(d)}:${d}`)}return s.length===0?{name:"Service URL ports",didPass:!0,message:"Service URLs in params point at the ports the services listen on"}:{name:"Service URL ports",didPass:!1,message:`${S(s.length,"service URL")} in params that cannot connect:
|
|
265
266
|
${s.join(`
|
|
266
|
-
`)}`,fix:'TDK runs each backend on the "port" in its service.json, and containers reach each other by resource name (http://<resource>:<port>). Use that port in the URL'}}function
|
|
267
|
-
`),fix:'Call each backend at /api/<name>, move one backend to its own stack, or give each its own "traefik.pathPrefix" in service.json'}}function
|
|
268
|
-
`).forEach((a,c)=>{if(!
|
|
267
|
+
`)}`,fix:'TDK runs each backend on the "port" in its service.json, and containers reach each other by resource name (http://<resource>:<port>). Use that port in the URL'}}function Vt(e){let t=[],n;try{n=qr(e,{withFileTypes:!0})}catch{return t}for(let r of n){let s=O(e,r.name);r.isDirectory()?ha.has(r.name)||t.push(...Vt(s)):pa.test(r.name)&&!fa.test(s)&&t.push(s)}return t}var Pa=/(?:localhost|127\.0\.0\.1):(\d{2,5})\b/g,ts=/^\s*(?:\/\/|\/\*|\*|<!--|#)/;function ns(e=m()??process.cwd()){let t=new Map;for(let r of b(e)){let s=r.config;if(!(v(s?.appType)||s?.appType===B&&s.exposeViaProxy!==!1))continue;let i=la(r.path),a=s?.stack??da(i),c=`${i}\0${a}`,u=t.get(c)??{stack:a,resources:[]};u.resources.push(r),t.set(c,u)}let n=[];for(let{stack:r,resources:s}of t.values()){if(s.length<2)continue;let o=a=>!!(a.config?.traefik?.host||a.config?.traefik?.pathPrefix),i=s.filter(a=>!o(a)).map(a=>a.name);i.length>0&&n.push(`stack "${r}": ${i.sort().join(", ")} lose the shared /api/${r}-management route because ${s.length} backends share the stack; they are routed at /api/<name> only`);for(let a of["host","pathPrefix"]){let c=new Map;for(let u of s){let d=u.config?.traefik?.[a];d&&c.set(d,[...c.get(d)??[],u.name])}for(let[u,d]of c)d.length>1&&n.push(`stack "${r}": ${d.sort().join(" and ")} both set traefik.${a} "${u}", so Traefik cannot tell them apart`)}}return n.length===0?{name:"Stack API routes",didPass:!0,message:"No two backends in one service directory compete for one stack route"}:{name:"Stack API routes",didPass:!1,isWarning:!0,message:n.join(`
|
|
268
|
+
`),fix:'Call each backend at /api/<name>, move one backend to its own stack, or give each its own "traefik.pathPrefix" in service.json'}}function rs(e=m()??process.cwd()){let t=b(e),n=new Map([...Xr(t)].map(([o,i])=>[i,o])),r=[];for(let o of t.filter(i=>i.config?.appType==="frontend"))for(let i of Vt(O(o.path,"src")))Pe(i,"utf-8").split(`
|
|
269
|
+
`).forEach((a,c)=>{if(!ts.test(a))for(let[,u]of a.matchAll(Pa)){let d=n.get(Number(u));d&&r.push(`${xe(e,i)}:${c+1} calls localhost:${u} (${d})`)}});if(r.length===0)return{name:"Frontend backend URLs",didPass:!0,message:"No frontend calls a backend through a localhost port"};let s=Yr(e)??"<project>";return{name:"Frontend backend URLs",didPass:!1,message:`${S(r.length,"frontend call")} to a backend port that TDK does not publish on localhost:
|
|
269
270
|
${r.join(`
|
|
270
|
-
`)}`,fix:`Backends are only reachable through Traefik: http://api.${s}.localhost/api/<name without -api>/... (for example catalog-api is /api/catalog). Use that URL, or the generated .autogenerated/env.ts`}}var
|
|
271
|
-
`).some(r=>
|
|
271
|
+
`)}`,fix:`Backends are only reachable through Traefik: http://api.${s}.localhost/api/<name without -api>/... (for example catalog-api is /api/catalog). Use that URL, or the generated .autogenerated/env.ts`}}var ss=/\b(?:prisma\s+(?:migrate\s+(?:deploy|dev|resolve)|db\s+push)|drizzle-kit\s+(?:migrate|push)|knex\s+migrate:\w+|typeorm\s+migration:run|mikro-orm\s+migration:up|sequelize(?:-cli)?\s+db:migrate|dbmate\s+(?:up|migrate)|atlas\s+migrate\s+apply|alembic\s+upgrade)\b/,os=new Set(["start","dev","serve","prestart","predev","preserve"]),Ea=/\.(?:sh|bash)$/,wa=/^\s*(?:CMD|ENTRYPOINT)\b/i;function Ke(e){try{return Pe(e,"utf-8")}catch{return}}function va(e){let t=Ke(O(e,D));if(t===void 0)return[];let n={};try{n=JSON.parse(t)?.scripts??{}}catch{return[]}return Object.entries(n).filter(([r,s])=>os.has(r)&&typeof s=="string"&&ss.test(s)).map(([r])=>`package.json "${r}" script`)}function Ue(e,t){let n=Ke(e);return n===void 0?!1:n.split(`
|
|
272
|
+
`).some(r=>ss.test(r.replace(/["'`,[\]]+/g," "))&&!ts.test(r)&&(!t||wa.test(r)))}function is(e=m()??process.cwd()){let t=[];for(let n of b(e)){let r=n.config?.appType??n.type;if(r!=="backend"&&r!=="worker")continue;let s=n.path;for(let a of va(s))t.push(`${n.name}: ${a}`);let o=O(s,n.config?.dockerfile??"Dockerfile");Ue(o,!0)&&t.push(`${n.name}: ${xe(e,o)} CMD or ENTRYPOINT`);let i=[];try{i=qr(s,{withFileTypes:!0})}catch{}for(let a of i){let c=O(s,a.name);a.isFile()&&Ea.test(a.name)&&Ue(c,!1)&&t.push(`${n.name}: ${xe(e,c)}`)}for(let a of Vt(O(s,"src")))Ue(a,!1)&&t.push(`${n.name}: ${xe(e,a)}`)}return t.length===0?{name:"Migrations outside the API",didPass:!0,message:"No backend or worker runs a migration command from its own start-up"}:{name:"Migrations outside the API",didPass:!1,isWarning:!0,message:`${S(t.length,"migration command")} run from a backend or worker's own start-up:
|
|
272
273
|
${t.join(`
|
|
273
|
-
`)}`,fix:"Move the migration into a `migrator` resource (appType migrator) that the service depends on, so it runs once before the service starts instead of on every start and restart"}}function Ge(e=m()??process.cwd()){let t=b(e).filter(r=>r.config?.featuresEnabled?.includes("nats")).map(r=>r.name);if(t.length===0)return{name:"NATS broker",didPass:!0,message:"No resource enables the nats feature",isSkipped:!0};if(
|
|
274
|
-
`)){let r=n.match(/^\s*(\d+)\s+.*\btilt up\b.*?\s-f\s+(\S+)/i);r&&t.push({pid:Number(r[1]),root:r[2].split(/[\\/]\.tdk[\\/]/i)[0]})}return t}function
|
|
275
|
-
`,r:"\r",t:" ",'"':'"',"\\":"\\",$:"$"};return a.replace(/\\([nrt"\\$])/g,(u,d)=>c[d]??d)}return a.replace(/\\'/g,"'")}}return t}let r=e.search(/\s#/);return(r===-1?e:e.slice(0,r)).trim()}function oe(e){let t=new Map,n=e.startsWith("\uFEFF")?e.slice(1):e;for(let r of n.split(/\r?\n/)){let s=r.trim();if(!s||s.startsWith("#"))continue;let o=s.startsWith("export ")?s.slice(7).trim():s,i=o.indexOf("=");if(i<=0)continue;let a=o.slice(0,i).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&t.set(a,
|
|
276
|
-
`)}function
|
|
274
|
+
`)}`,fix:"Move the migration into a `migrator` resource (appType migrator) that the service depends on, so it runs once before the service starts instead of on every start and restart"}}function Ge(e=m()??process.cwd()){let t=b(e).filter(r=>r.config?.featuresEnabled?.includes("nats")).map(r=>r.name);if(t.length===0)return{name:"NATS broker",didPass:!0,message:"No resource enables the nats feature",isSkipped:!0};if(Ht(O(e,"services","platform","messaging",me)))return{name:"NATS broker",didPass:!0,message:`${S(t.length,"resource")} enable nats and services/platform/messaging/docker-compose.yml is present`};let n=(Yr(e)??"project").replace(/-/g,"_");return{name:"NATS broker",didPass:!1,message:`${t.join(", ")} enable the nats feature, but no NATS server will start: TDK only starts one when services/platform/messaging/docker-compose.yml exists, and it does not generate that file`,fix:`Create it with a "nats" service (image nats with -js, container_name ${n}_nats, network ${n}_backend, external) and a "redis" service, which TDK registers alongside it`}}function as(e=m()??process.cwd()){let t=Bt(e),n=" (project resource set; tdk up may select a subset and not start Postgres)",r=t.focusWouldEnableDatabaseManagement?" Warning: generated Tiltfile default focus expands CORE_INFRA to database-management while project.json has it off; default tdk up takes the feature path.":"";if(t.unknownDependsOnNames.length>0){let o=t.unknownDependsOnNames.map(({resource:a,name:c})=>`"${c}" (from ${a})`).join(", "),i=t.willStart?` Postgres will start because ${t.reason==="feature"?"database-management is enabled":`resource(s) ${t.dependsOnUsers.join(", ")} depend on postgres/database-management`}${n}`:" Postgres will not start for this project.json/generated Tiltfile state.";return{name:"Shared platform Postgres",didPass:!1,message:`${S(t.unknownDependsOnNames.length,"unknown dependsOn name")}: ${o}. These are not known services or stacks, and are not the shared platform database names (postgres, database-management).${i}${r}`,fix:'Use "postgres" or "database-management" in dependsOn for the shared platform database, or fix the name to match an existing service'}}if(!t.willStart)return{name:"Shared platform Postgres",didPass:!0,isWarning:!!r,isSkipped:!r,message:r?r.trim():"Shared platform Postgres will not start: database-management is off and no resource depends on postgres or database-management."};if(t.reason==="feature"&&t.dependsOnUsers.length===0){let o=t.featureOnFromTiltfile||t.featureOnFromSpecMaster?" (generated Tiltfile/spec.master)":"";return{name:"Shared platform Postgres",didPass:!0,isWarning:!!r,message:`Shared platform Postgres will start because the database-management feature is enabled${o} (project-wide; not a tdk up selection).${r}`}}let s=t.reason==="feature"?`the database-management feature is enabled and resource(s) ${t.dependsOnUsers.join(", ")} depend on postgres/database-management`:`resource(s) ${t.dependsOnUsers.join(", ")} depend on postgres/database-management`;return{name:"Shared platform Postgres",didPass:!0,isWarning:!!r,message:`Shared platform Postgres will start because ${s}${n}${r}`}}function $a(e){let t=[];for(let n of e.split(`
|
|
275
|
+
`)){let r=n.match(/^\s*(\d+)\s+.*\btilt up\b.*?\s-f\s+(\S+)/i);r&&t.push({pid:Number(r[1]),root:r[2].split(/[\\/]\.tdk[\\/]/i)[0]})}return t}function cs(e=m()??process.cwd(),t=ua){let n;try{n=process.platform==="win32"?ca("powershell.exe",["-NoProfile","-Command","Get-CimInstance Win32_Process | Where-Object { $_.Name -eq 'tilt.exe' } | ForEach-Object { '{0} {1}' -f $_.ProcessId, $_.CommandLine }"],{encoding:"utf-8",timeout:He,windowsHide:!0}):t("ps -Ao pid=,command=",{encoding:"utf-8",timeout:He})}catch{return{name:"Tilt processes",didPass:!0,isSkipped:!0,message:"Could not list processes"}}let r=$a(n),s=r.filter(i=>i.root===e),o=r.filter(i=>i.root!==e);return s.length>1?{name:"Tilt processes",didPass:!1,message:`${s.length} Tilt processes are running for this project (pids ${s.map(i=>i.pid).join(", ")}). They fight over ports and containers`,fix:`Stop them all, then start one: tdk down && kill ${s.map(i=>i.pid).join(" ")} && tdk up`}:o.length>0?{name:"Tilt processes",didPass:!0,isSkipped:!0,message:`Another project's Tilt is running: ${o.map(a=>`${a.root} (pid ${a.pid})`).join(", ")}`,fix:"tdk up will use the next free Tilt UI port (10351, ...). If it is a leftover, run tdk down in that project"}:{name:"Tilt processes",didPass:!0,message:"No stray Tilt processes"}}async function us(e=M){let t=`tdk_doctor_probe_${process.pid}`;try{await e(`docker network create ${t}`,He)}catch(n){let r=String(n.stderr??n);return/address pools/i.test(r)?{name:"Docker networks",didPass:!1,message:"Docker cannot create another network: all predefined address pools are in use. Each TDK project needs several",fix:"run tdk down --prune-networks in projects you are not using, or docker network prune (removes all unused networks)"}:{name:"Docker networks",didPass:!0,isSkipped:!0,message:"Could not test network creation"}}try{await e(`docker network rm ${t}`,He)}catch{}return{name:"Docker networks",didPass:!0,message:"Docker can create networks"}}import{randomBytes as ls}from"node:crypto";import{existsSync as Gt,readFileSync as ps,writeFileSync as fs}from"node:fs";import{join as Wt}from"node:path";import{randomBytes as Ra}from"node:crypto";import{closeSync as _a,fchmodSync as Oa,fsyncSync as Aa,openSync as Da,renameSync as Ca,rmSync as Na,statSync as ja,writeFileSync as Ia}from"node:fs";import{basename as Fa,dirname as Ma,join as La}from"node:path";function ds(e,t){let n=La(Ma(e),`.${Fa(e)}.${process.pid}.${Ra(4).toString("hex")}.tmp`),r;try{r=ja(e).mode&511}catch{r=void 0}try{let s=Da(n,"wx");try{r!==void 0&&Oa(s,r),Ia(s,t,"utf-8"),Aa(s)}finally{_a(s)}Ca(n,e)}catch(s){throw Na(n,{force:!0}),s}}var se=[{name:"VERDACCIO_URL_DOCKER",description:"Docker-internal URL of the private npm registry (Verdaccio, a paid feature)",required:!1,default:"http://verdaccio:4873",example:"http://verdaccio:4873"},{name:"VERDACCIO_URL",description:"Local URL of the private npm registry (Verdaccio, a paid feature)",required:!1,default:"http://localhost:4873"},{name:"TILT_ENV",description:"Tilt environment name",required:!0,default:"dev",example:"dev",complete:!0},{name:"DATABASE_URL",description:"PostgreSQL connection string (uses the generated DB_PASSWORD below)",required:!1},{name:"DB_PASSWORD",description:"PostgreSQL superuser password (docker-compose POSTGRES_PASSWORD)",required:!0,example:"postgres",complete:!0},{name:"JWT_SECRET",description:"Secret that signs local-jwt tokens (generated once per project; never shared between projects)",required:!1,complete:!0}],ms=()=>ls(16).toString("hex"),Ba=()=>ls(32).toString("hex");function Kt(e,t){return e==="DB_PASSWORD"?t:e==="JWT_SECRET"?Ba():e==="DATABASE_URL"?`postgresql://postgres:${t}@postgres:5432/app_dev`:se.find(n=>n.name===e)?.default??""}function Ua(e){let t=e.trim(),n=t[0];if(n==='"'||n==="'"){let s=!1;for(let o=1;o<t.length;o+=1){let i=t[o];if(s){s=!1;continue}if(i==="\\"){s=!0;continue}if(i===n){let a=t.slice(1,o);if(n==='"'){let c={n:`
|
|
276
|
+
`,r:"\r",t:" ",'"':'"',"\\":"\\",$:"$"};return a.replace(/\\([nrt"\\$])/g,(u,d)=>c[d]??d)}return a.replace(/\\'/g,"'")}}return t}let r=e.search(/\s#/);return(r===-1?e:e.slice(0,r)).trim()}function oe(e){let t=new Map,n=e.startsWith("\uFEFF")?e.slice(1):e;for(let r of n.split(/\r?\n/)){let s=r.trim();if(!s||s.startsWith("#"))continue;let o=s.startsWith("export ")?s.slice(7).trim():s,i=o.indexOf("=");if(i<=0)continue;let a=o.slice(0,i).trim();/^[A-Za-z_][A-Za-z0-9_]*$/.test(a)&&t.set(a,Ua(o.slice(i+1)))}return t}function hs(e){let t=[`# ${e.description}`];return e.required&&t.push("# Required (the value below is a working default)"),e.example&&t.push(`# Example: ${e.example}`),t}function gs(){let e=ms(),t=["# \u{1F527} TDK Environment Configuration","# Generated by `tdk project`. The defaults work as-is; edit only to change them.","# Keep this file out of git: it holds a generated database password and JWT secret.","#","# After editing, run: tdk config regenerate && tdk up",""];for(let n of se)t.push(...hs(n)),t.push(`${n.name}=${Kt(n.name,e)}`),t.push("");return t.join(`
|
|
277
|
+
`)}function Ha(e){let t=e.match(/^[a-z][a-z0-9+.-]*:\/\/[^:/@\s]+:([^@\s]*)@/i);if(!(!t||t[1].includes("$")))return t[1]}function ks(e){let t=Wt(e,".env"),n={missing:[],invalid:[],warnings:[]};if(!Gt(t))return{missing:se.filter(i=>i.required).map(i=>i.name),invalid:[],warnings:[".env file not found - will be auto-generated"]};let r=oe(ps(t,"utf-8"));for(let i of se)i.required&&!r.has(i.name)&&n.missing.push(i.name),r.has(i.name)&&!(r.get(i.name)??"").trim()&&n.invalid.push(`${i.name} is set but empty`);let s=r.get("DATABASE_URL"),o=r.get("DB_PASSWORD");if(s&&o){let i=Ha(s);i!==void 0&&i!==o&&n.warnings.push("DATABASE_URL carries a different password than DB_PASSWORD; the database container uses DB_PASSWORD")}return n}function Va(e,t,n){if(!oe(e).has(t))return e;let s=e.indexOf("=");if(s<0)return e;let o=e.slice(s+1),i=o.search(/\s#/),a=i<0?"":o.slice(i);return e.slice(0,s+1)+n+a}function Lp(e){let t=Wt(e,".env");if(!Gt(t))return fs(t,gs(),{mode:384}),se.map(l=>l.name);let n=ps(t,"utf-8"),r=oe(n),s=se.filter(l=>l.complete?r.has(l.name)?!(r.get(l.name)??"").trim():!0:!1);if(s.length===0)return[];let o=s.filter(l=>!r.has(l.name)),i=s.filter(l=>r.has(l.name)),a=r.get("DB_PASSWORD"),c=a?.trim()?a:ms(),u=n.split(/(\r\n|\n|\r)/);for(let l of i){let h=-1;for(let k=0;k<u.length;k+=2)oe(u[k]).has(l.name)&&(h=k);if(h<0)throw new Error(`Could not locate empty .env assignment for ${l.name}`);u[h]=Va(u[h],l.name,Kt(l.name,c))}let d=u.join("");if(o.length>0){let l=["","# Added by TDK: keys this version expects. Existing values above were not changed.",""];for(let k of o)l.push(...hs(k)),l.push(`${k.name}=${Kt(k.name,c)}`),l.push("");let h=d.endsWith(`
|
|
277
278
|
`)||d.endsWith("\r")?"":`
|
|
278
279
|
`;d+=h+l.join(`
|
|
279
|
-
`)}return
|
|
280
|
-
`).some(r=>{let[s="",o=""]=r.split("|"),i=s.toLowerCase(),a=t.toLowerCase();return(i.startsWith(`${a}_`)||i.startsWith(`${a}-`))&&o.includes(`:${n}->`)})}function
|
|
281
|
-
`,{encoding:"utf-8",mode:384})}function
|
|
280
|
+
`)}return ds(t,d),s.map(l=>l.name)}function Bp(e){let t=Wt(e,".env");return Gt(t)?!1:(fs(t,gs(),{mode:384}),!0)}import{execFileSync as Ya}from"node:child_process";import{existsSync as za,mkdirSync as Xa,readFileSync as Ss,writeFileSync as Za}from"node:fs";import{join as we}from"node:path";import{createServer as Ga}from"node:net";import{connect as Ka}from"node:net";function ys(e,t=500){return new Promise(n=>{let r=Ka({port:e,host:"127.0.0.1"}),s=o=>{r.destroy(),n(o)};r.setTimeout(t,()=>s(!1)),r.once("connect",()=>s(!0)),r.once("error",()=>s(!1))})}var Wa={ingressHttp:{start:8080,end:8180},ingressHttps:{start:8443,end:8543},postgres:{start:15432,end:15532}},We={ingressHttp:"TDK_HTTP_PORT",ingressHttps:"TDK_HTTPS_PORT",postgres:"TDK_POSTGRES_PORT"},Ja={ingressHttp:80,ingressHttps:443,postgres:5432};async function Jt(e){return await ys(e)?!1:new Promise(t=>{let n=Ga();n.once("error",()=>t(!1)),n.listen(e,"127.0.0.1",()=>n.close(()=>t(!0)))})}function qa(e,t){let n=Number(t);if(!Number.isInteger(n)||n<1||n>65535)throw new Error(`${e} must be an integer between 1 and 65535 (received ${JSON.stringify(t)})`);return n}async function Ee(e={}){let t=e.env??process.env,n=e.isAvailable??Jt,r={ingressHttp:!1,ingressHttps:!1,postgres:!1},s={ingressHttp:"",ingressHttps:"",postgres:""},o={explicit:r},i=new Set;for(let a of["ingressHttp","ingressHttps","postgres"]){let c=t[We[a]],u=c!==void 0&&c.trim()!=="",d=e.ranges?.[a]??Wa[a],l=u?[qa(We[a],c)]:Array.from({length:d.end-d.start+1},(k,g)=>d.start+g),h;for(let k of l)if(!i.has(k)){if(await n(k)){h=k;break}if(u)throw new Error(`${We[a]}=${k} is already in use. Choose a free host port and retry.`)}if(h===void 0)throw new Error(`No available host port in ${d.start}-${d.end} for ${a}. Set ${We[a]} to a free port and retry.`);i.add(h),o[a]=h,r[a]=u,s[a]=u?"explicit override":`selected from fallback range ${d.start}-${d.end}`}return{...o,requested:{...Ja},reason:s}}function Wp(e){return`Host ports: HTTP ${e.ingressHttp}, HTTPS ${e.ingressHttps}, Postgres ${e.postgres}`}var bs=we(".tdk",".tdk-out","host-ports.json");function Qa(e,t,n){return e.split(`
|
|
281
|
+
`).some(r=>{let[s="",o=""]=r.split("|"),i=s.toLowerCase(),a=t.toLowerCase();return(i.startsWith(`${a}_`)||i.startsWith(`${a}-`))&&o.includes(`:${n}->`)})}function ec(e){let t=we(e,bs);if(!za(t))return null;try{let n=JSON.parse(Ss(t,"utf-8"));if(!n||typeof n!="object")return null;let r=n;return!Number.isInteger(r.ingressHttp)||!Number.isInteger(r.ingressHttps)||!Number.isInteger(r.postgres)||!r.requested||!r.explicit||!r.reason?null:r}catch{return null}}function Qp(e,t){let n=we(e,bs);Xa(we(e,".tdk",".tdk-out"),{recursive:!0}),Za(n,`${JSON.stringify(t,null,2)}
|
|
282
|
+
`,{encoding:"utf-8",mode:384})}function ef(e){process.env.TDK_HTTP_PORT=String(e.ingressHttp),process.env.TDK_HTTPS_PORT=String(e.ingressHttps),process.env.TDK_POSTGRES_PORT=String(e.postgres)}async function Je(e,t={}){let n=ec(e),r=["TDK_HTTP_PORT","TDK_HTTPS_PORT","TDK_POSTGRES_PORT"].some(c=>process.env[c]);if(t.inspectDocker===!1&&n&&!r)return n;let s="";try{let c=JSON.parse(Ss(we(e,".tdk",P),"utf-8"));s=String(c?.project?.name??"tdk-project").replace(/-/g,"_").toLowerCase()}catch{s="tdk_project"}let o="";if(t.inspectDocker!==!1)try{o=Ya("docker",["ps","--format","{{.Names}}|{{.Ports}}"],{encoding:"utf-8",timeout:5e3})}catch{}let i=c=>Qa(o,s,c),a=async c=>await Jt(c)||i(c);if(n&&!r){for(let c of[n.ingressHttp,n.ingressHttps,n.postgres])if(!await a(c))return Ee({isAvailable:a});return n}return Ee({isAvailable:a})}import{existsSync as tc,readFileSync as nc}from"node:fs";import{join as rc}from"node:path";var sc="[REDACTED]",ve=class extends Error{path;constructor(t,n){super(`Could not read ${t}: ${n}`),this.path=t,this.name="EnvUnreadableError"}},oc=8;function Ts(e){let t=rc(e,".env");if(!tc(t))return[];let n;try{n=nc(t,"utf-8")}catch(s){throw new ve(t,s instanceof Error?s.message:String(s))}let r=[...oe(n).values()].filter(s=>s.length>=oc);return[...new Set(r)].sort((s,o)=>o.length-s.length)}function qt(e,t){let n=e;for(let r of t)n=n.split(r).join(sc);return n}function qe(e,t){return t.length===0?e:typeof e=="string"?qt(e,t):Array.isArray(e)?e.map(n=>qe(n,t)):e!==null&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([n,r])=>[n,qe(r,t)])):e}import{relative as ic}from"node:path";function Ye(e,t){return ic(e,t.configPath)||t.configPath}function xs(e){let t=e.config?.dependsOn;return t===void 0?[]:Array.isArray(t)&&t.every(n=>typeof n=="string")?t:null}function ac(e){let t=new Set(e.map(a=>a.name)),n=new Map(e.map(a=>[a.name,(xs(a)??[]).filter(c=>t.has(c))])),r=new Map,s=new Map,o=[],i=a=>{s.set(a,"visiting"),o.push(a);for(let c of n.get(a)??[])if(s.get(c)==="visiting"){let u=o.slice(o.indexOf(c)),d=u.indexOf([...u].sort()[0]??c),l=[...u.slice(d),...u.slice(0,d)];r.set(l.join(">"),[...l,l[0]??c])}else s.has(c)||i(c);o.pop(),s.set(a,"done")};for(let a of[...n.keys()].sort())s.has(a)||i(a);return[...r.values()]}function Yt(e=m()??process.cwd()){let t=b(e).flatMap(n=>xs(n)===null?[`${Ye(e,n)} dependsOn ${JSON.stringify(n.config?.dependsOn)}: expected an array of service names`]:[]);return t.length===0?{name:"dependsOn",didPass:!0,message:"Every dependsOn is a list of service names"}:{name:"dependsOn",didPass:!1,message:`${S(t.length,"invalid dependsOn","invalid dependsOn")}:
|
|
282
283
|
${t.join(`
|
|
283
|
-
`)}`,fix:'Write "dependsOn" as an array of service names, for example ["postgres", "api"]'}}function
|
|
284
|
+
`)}`,fix:'Write "dependsOn" as an array of service names, for example ["postgres", "api"]'}}function zt(e=m()??process.cwd()){let t=b(e),n=new Map(t.map(o=>[o.name,o])),r=ac(t);if(r.length===0)return{name:"Circular dependencies",didPass:!0,message:"No service depends on itself through dependsOn"};let s=r.map(o=>{let i=n.get(o[0]??""),a=o[1]??"";return`${i?Ye(e,i):o[0]} dependsOn "${a}": circular dependency ${o.join(" -> ")}`});return{name:"Circular dependencies",didPass:!1,message:`${r.length} ${r.length===1?"circular dependency":"circular dependencies"}:
|
|
284
285
|
${s.join(`
|
|
285
|
-
`)}`,fix:'Remove one "dependsOn" entry in each cycle so the services no longer wait on each other, or move what they share into a third service'}}function
|
|
286
|
+
`)}`,fix:'Remove one "dependsOn" entry in each cycle so the services no longer wait on each other, or move what they share into a third service'}}function Xt(e=m()??process.cwd()){let t=b(e).flatMap(n=>{let r=n.config?.port;return r===void 0?[]:typeof r=="number"&&Number.isInteger(r)&&r>=1&&r<=65535?[]:[`${Ye(e,n)} port ${JSON.stringify(r)}: not an integer from 1 to 65535`]});return t.length===0?{name:"Service ports",didPass:!0,message:"Every declared port is valid"}:{name:"Service ports",didPass:!1,message:`${S(t.length,"invalid port")}:
|
|
286
287
|
${t.join(`
|
|
287
|
-
`)}`,fix:'Set "port" to the port the service listens on, an integer from 1 to 65535'}}function
|
|
288
|
+
`)}`,fix:'Set "port" to the port the service listens on, an integer from 1 to 65535'}}function Zt(e=m()??process.cwd(),t=!1){let n=[],r=[];for(let o of b(e)){let i=o.config?.schemaVersion;if(i===ge)continue;let a=Ye(e,o);i===void 0?n.push(`${a} schemaVersion: missing`):r.push(`${a} schemaVersion ${JSON.stringify(i)}: this tdk supports ${ge}`)}if(n.length===0&&r.length===0)return{name:"schemaVersion",didPass:!0,message:"Every service.json has a supported schemaVersion"};let s=[...n.length>0?["Run `tdk config migrate` to add the missing schemaVersion"]:[],...r.length>0?["A version this tdk does not support cannot be migrated: upgrade tdk"]:[]];return{name:"schemaVersion",didPass:!1,isWarning:!t,message:`${S(n.length+r.length,"service.json file")} without a supported schemaVersion:
|
|
288
289
|
${[...n,...r].join(`
|
|
289
|
-
`)}`,fix:s.join(". ")}}function
|
|
290
|
+
`)}`,fix:s.join(". ")}}function mf(e){let t=Zt(e);t.didPass||(console.warn(f.yellow(`\u26A0 ${t.message}`)),t.fix&&console.warn(f.gray(` ${t.fix}`)))}function hf(e,t={},n=process.exit){let r=[Ve(e),Yt(e),zt(e),Xt(e)].filter(o=>!o.didPass);if(r.length===0)return;let s=r.map(o=>`${o.message}${o.fix?`
|
|
290
291
|
Fix: ${o.fix}`:""}`).join(`
|
|
291
|
-
`);t.onInvalid?.(s);for(let o of r)console.error(f.red(`\u2717 ${o.message}`)),o.fix&&console.error(f.gray(` Fix: ${o.fix}`));n(1)}import{readFileSync as
|
|
292
|
+
`);t.onInvalid?.(s);for(let o of r)console.error(f.red(`\u2717 ${o.message}`)),o.fix&&console.error(f.gray(` Fix: ${o.fix}`));n(1)}import{readFileSync as cc}from"node:fs";import{join as uc}from"node:path";function Ps(e){let t=e.trim().match(/(\d+)\.(\d+)(?:\.(\d+))?/);return t?[Number(t[1]),Number(t[2]),Number(t[3]??0)]:null}function dc(e){try{return JSON.parse(cc(uc(e,".tdk",P),"utf-8"))?.minTdkVersion}catch{return}}function Es(e,t){let n=dc(e);if(n===void 0)return{status:"none"};let r=typeof n=="string"?Ps(n):null;if(!r||!/^\d+\.\d+\.\d+$/.test(String(n).trim()))return{status:"malformed",message:`.tdk/project.json minTdkVersion ${JSON.stringify(n)} is not a version like "1.3.80"`,fix:'Set minTdkVersion to a MAJOR.MINOR.PATCH string, for example "1.3.80".'};let s=Ps(t),o=s!==null&&(()=>{for(let[a,c]of r.entries()){let u=s[a]??0;if(u!==c)return u>c}return!0})(),i=r.join(".");return o?{status:"ok",required:i}:{status:"too-old",required:i,message:`tdk ${t} is older than the ${i} this project requires (minTdkVersion)`,fix:"Run: tdk upgrade"}}var V=1e4,X={dockerMissing:"See https://docs.docker.com/get-docker/",dockerDaemonDown:"Start Docker Desktop, OrbStack, or Colima, then retry: tdk doctor",tiltMissing:"curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash",bunMissing:"curl -fsSL https://bun.sh/install | bash",port80:"Stop the process bound to port 80, or stop local nginx/caddy. Then: tdk doctor",port5432:"Stop local Postgres or change the host port. Then: tdk doctor",notProject:"tdk project --yes"},vs="WSL2 detected. Use Docker Desktop WSL integration. Guide: docs/wsl2.md",$s="Native Windows landscape boot is unsupported. Use WSL2 Ubuntu with Docker Desktop integration. Guide: docs/wsl2.md",Qt=[0,25,0],Z=[1,2,0];function ze(e,t){let n=rn(e);return n?sn(n,t):!1}function mc(e,t,n=process.platform==="linux"&&!!process.env.WSL_DISTRO_NAME){if(!n)return{name:"WSL project location",didPass:!0,isSkipped:!0,message:"Not running in WSL2 - skipped project filesystem check"};let r=e.replace(/\\/g,"/").replace(/\/+$/,"").toLowerCase();if(r!=="/mnt/c"&&!r.startsWith("/mnt/c/"))return{name:"WSL project location",didPass:!0,message:`${vs} Project is on the WSL filesystem.`};let s=`${vs} Project is under /mnt/c (${e}); hot reload may be broken. Move it into the WSL filesystem, such as ~/projects.`;return{name:"WSL project location",didPass:!t,isWarning:!t,message:s,fix:"Move the repository under your WSL home directory (for example, ~/projects) and retry tdk doctor."}}function hc(e){let t=e.replace(/^\[(.*)\]$/,"$1");return t==="0.0.0.0"||/^[0:]*:0\.0\.0\.0$/.test(t)?!0:t.includes(":")&&/^[0:]+$/.test(t)}function gc(e=process.env,t=!1){let n=(e.TDK_BIND_ADDRESS??"").trim();return hc(n)?{name:"Dev Port Bind Address",didPass:!t,isWarning:!t,message:`TDK_BIND_ADDRESS is ${n}: Traefik and Postgres are reachable from other machines on the network.`,fix:"Unset TDK_BIND_ADDRESS to keep dev ports on 127.0.0.1. Keep it only when you test from another device on purpose."}:{name:"Dev Port Bind Address",didPass:!0,message:n?`Dev ports bind to ${n}`:"Dev ports bind to 127.0.0.1 (this machine only)"}}function Rs(e){let t=e.filter(r=>!r.didPass&&!r.isSkipped&&!r.isWarning),n=e.filter(r=>r.didPass||r.isSkipped||r.isWarning);return t.sort((r,s)=>{let o=i=>i.name==="Host Ports"&&/\b5432\b/.test(i.message)?0:i.name==="Host Ports"?1:i.name==="Ingress Ports"?2:3;return o(r)-o(s)}),[...t,...n]}function kc(e,t){return t?e?"Doctor passed. Next: tdk up":"Doctor passed. Next: tdk project example":"Doctor failed. Fix the items above, then run: tdk doctor"}function Os(e){return Br(e)}function yc(e,t,n,r,s){return async()=>{try{return await M(t,V),{name:e,didPass:!0,message:n}}catch{return{name:e,didPass:!1,message:r,fix:s}}}}async function en(e){try{return await M(e,V),!0}catch{return!1}}async function an(){if(process.platform==="win32")try{return await M("docker ps",V),{name:A,didPass:!0,message:"Docker Desktop Linux container engine is running"}}catch{return{name:A,didPass:!1,message:"Docker is not running",fix:X.dockerDaemonDown}}let e=!!$("docker");try{return await M("docker ps",V),{name:A,didPass:!0,message:"Docker daemon is running"}}catch(n){if(Os(n))return{name:A,didPass:!1,message:"Docker daemon is not responding",fix:X.dockerDaemonDown}}let t=Fn(await en("pgrep -f com.docker.backend"));return t||(await en("colima status")?{name:A,didPass:!0,message:"Colima (Docker runtime) is running"}:$("colima")?{name:A,didPass:!1,message:"Colima is installed but not running",fix:X.dockerDaemonDown}:await en("podman ps")?{name:A,didPass:!0,message:"Podman is running"}:e?{name:A,didPass:!1,message:"Docker daemon is not running",fix:X.dockerDaemonDown}:{name:A,didPass:!1,message:"Docker is not running",fix:X.dockerMissing})}var cn=yc("Docker Compose","docker compose version","Docker Compose plugin available","Docker Compose plugin not found","Install Docker Compose: https://docs.docker.com/compose/install/"),Sc=[25,0,0],bc=[2,20,2];function rn(e){let t=e.trim().match(/(\d+)\.(\d+)(?:\.(\d+))?/);return t?[Number(t[1]),Number(t[2]),Number(t[3]??0)]:null}function sn(e,t){for(let[n,r]of t.entries()){let s=e[n]??0;if(s!==r)return s>r}return!0}async function un(e=M){let t=async a=>String(await e(a,V)).trim(),n,r;try{[n,r]=await Promise.all([t("docker version --format '{{.Server.Version}}'"),t("docker compose version --short")])}catch{return{name:"Docker Versions",didPass:!0,isSkipped:!0,message:"Could not read Docker Engine/Compose versions - skipped version check"}}let s=rn(n),o=rn(r);if(!s||!o)return{name:"Docker Versions",didPass:!0,isSkipped:!0,message:`Unrecognized Docker version output (engine "${n}", compose "${r}") - skipped version check`};let i=[];return sn(s,Sc)||i.push(`Docker Engine ${n} (need 25.0+)`),sn(o,bc)||i.push(`Docker Compose ${r} (need 2.20.2+)`),i.length===0?{name:"Docker Versions",didPass:!0,message:`Docker Engine ${n} and Compose ${r} support generated healthchecks`}:{name:"Docker Versions",didPass:!1,message:`Docker is too old for generated healthchecks (they use start_interval):
|
|
292
293
|
${i.join(`
|
|
293
|
-
`)}`,fix:"Update Docker Desktop, or on Linux update docker-ce and the docker-compose-plugin package"}}async function
|
|
294
|
+
`)}`,fix:"Update Docker Desktop, or on Linux update docker-ce and the docker-compose-plugin package"}}async function dn(e=M){let t;try{t=String(await e("tilt version",V)).trim()}catch{return{name:"Tilt CLI",didPass:!1,message:"Tilt CLI not found",fix:X.tiltMissing}}return ze(t,Qt)?{name:"Tilt CLI",didPass:!0,message:`Tilt ${t} is available`}:{name:"Tilt CLI",didPass:!1,message:`Tilt ${t||"version unknown"} is below the required v${Qt.join(".")} floor`,fix:`Install Tilt v${Qt.join(".")} or newer: https://docs.tilt.dev/install.html`}}async function Tc(e=M){let t;try{t=String(await e("docker info --format '{{.OSType}}'",V)).trim().toLowerCase()}catch{return{name:"Docker OS",didPass:!0,isSkipped:!0,message:"Docker OS unavailable - daemon failure reported separately"}}return t!=="linux"?{name:"Docker OS",didPass:!1,message:`Docker is using the ${t||"unknown"} engine; TDK requires Linux containers`,fix:"Switch Docker Desktop to Linux containers, enable WSL2 integration, then retry tdk doctor."}:{name:"Docker OS",didPass:!0,message:"Docker is using Linux containers"}}async function xc(e=M){let t=m();if(!t)return{name:"Bun",didPass:!0,isSkipped:!0,message:"Not in a project - skipping Bun check"};if(!Ae(b(t)))return{name:"Bun",didPass:!0,isSkipped:!0,message:"No generated JS services - skipping Bun check"};try{let n=String(await e("bun --version",V)).trim();return ze(n,Z)?{name:"Bun",didPass:!0,message:`Bun ${n} is available`}:{name:"Bun",didPass:!1,message:`Bun ${n||"version unknown"} is below the required ${Z.join(".")} floor`,fix:`Install Bun ${Z.join(".")} or newer: https://bun.sh/install`}}catch{return{name:"Bun",didPass:!1,message:"Bun is not available",fix:X.bunMissing}}}function Pc(){let e=m()??process.cwd(),t=ks(e);if(t.missing.length>0)return{name:"Environment Variables",didPass:!1,message:`Missing required env variables: ${t.missing.join(", ")}`,fix:C(E(e,".env"))?`Edit .env and set these values:
|
|
294
295
|
${t.missing.map(r=>`${r}=<value>`).join(`
|
|
295
|
-
`)}`:"No .env file yet. Run `tdk project` to create one with working defaults."};if(t.invalid.length>0)return{name:"Environment Variables",didPass:!1,message:`Invalid env variables: ${t.invalid.join(", ")}`,fix:"Edit .env and provide values for empty variables"};let n=t.warnings.filter(r=>!r.startsWith(".env file not found"));return{name:"Environment Variables",didPass:!0,message:n.length>0?`All required environment variables are set (warning: ${n.join("; ")})`:"All required environment variables are set"}}function
|
|
296
|
+
`)}`:"No .env file yet. Run `tdk project` to create one with working defaults."};if(t.invalid.length>0)return{name:"Environment Variables",didPass:!1,message:`Invalid env variables: ${t.invalid.join(", ")}`,fix:"Edit .env and provide values for empty variables"};let n=t.warnings.filter(r=>!r.startsWith(".env file not found"));return{name:"Environment Variables",didPass:!0,message:n.length>0?`All required environment variables are set (warning: ${n.join("; ")})`:"All required environment variables are set"}}function Ec(){let e=m()??process.cwd(),t=E(e,".tdk",".tdk-out"),n=it.filter(r=>!C(E(t,r)));return n.length===0?{name:"Master Configs",didPass:!0,message:`${it.join(", ")} found`}:{name:"Master Configs",didPass:!1,message:`Master configs missing: ${n.join(", ")}`,fix:"Run: tdk project"}}function wc(e=Kn()){let t=m();if(!t)return{name:"TDK version",didPass:!0,isSkipped:!0,message:"Not in a project - skipping TDK version check"};let n=Es(t,e);return n.status==="none"?{name:"TDK version",didPass:!0,isSkipped:!0,message:`tdk ${e} (no minTdkVersion in .tdk/project.json)`}:n.status==="malformed"||n.status==="too-old"?{name:"TDK version",didPass:!1,message:n.message,fix:n.fix}:{name:"TDK version",didPass:!0,message:`tdk ${e} meets minTdkVersion ${n.required}`}}function vc(){let e=m()??process.cwd(),t=dt(e),n=b(e).filter(s=>!De(e,s.path,t));if(n.length===0)return{name:"Resource Discovery",didPass:!0,message:`All resources are covered by discovery.paths ${JSON.stringify(t)}`};let r=n.map(s=>tn(nn(e,s.path))).join(", ");return{name:"Resource Discovery",didPass:!1,message:`${S(n.length,"resource")} outside discovery.paths ${JSON.stringify(t)}: ${r}. \`tdk up\` will not start them`,fix:"Move each under services/<stack>/<name>, or add a matching pattern to discovery.paths in .tdk/project.json and run: tdk config regenerate"}}var $c=["install-deps.sh","bun-hoisted-symlink-fix.sh","prisma-bun-client-link-fix.sh","prisma-normalize-client.sh","infisical-entrypoint.sh"],Rc=/shared-platform-engineering\/docker-templates\/([\w.-]+)/g;function _c(e){let t=new Set;for(let n of b(e)){let r=E(n.path,F);if(C(r)){for(let s of pc(r))if(!(!s.startsWith("Dockerfile")||s.endsWith(".dockerignore")))for(let o of ie(E(r,s),"utf-8").matchAll(Rc))t.add(o[1])}}return[...t]}function Oc(){let e=m()??process.cwd(),t=[];C(E(e,D))||t.push(`${D} (workspace root manifest)`);let n=E(e,"shared-platform-engineering","docker-templates"),r=[];try{r=_c(e)}catch{}for(let s of new Set([...$c,...r]))C(E(n,s))||t.push(`shared-platform-engineering/docker-templates/${s}`);return t.length===0?{name:"Generated Runtime Assets",didPass:!0,message:"Generated Docker runtime assets are present"}:{name:"Generated Runtime Assets",didPass:!1,message:`Generated Dockerfiles reference missing project runtime assets:
|
|
296
297
|
${t.join(`
|
|
297
|
-
`)}`,fix:"Run `tdk project --yes` (or `tdk config regenerate`) with an updated TDK. `tdk up` also refreshes these assets before starting Tilt."}}function
|
|
298
|
+
`)}`,fix:"Run `tdk project --yes` (or `tdk config regenerate`) with an updated TDK. `tdk up` also refreshes these assets before starting Tilt."}}function Ac(){let e=m()??process.cwd(),t=b(e),n=[];for(let r of t){let s=E(r.path,D);if(!C(s))continue;let o=r.config?.appType??"backend",i=at[o]??at.backend,a;try{a=JSON.parse(ie(s,"utf-8")).scripts??{}}catch{n.push(`${r.name} (package.json is invalid JSON)`);continue}let c=i.filter(u=>!a[u]);c.length>0&&n.push(`${r.name}: missing "${c.join('", "')}"`)}return n.length===0?{name:"Startup Scripts",didPass:!0,message:"All services have required package.json scripts"}:{name:"Startup Scripts",didPass:!1,message:`Services missing required package.json scripts:
|
|
298
299
|
${n.join(`
|
|
299
300
|
`)}`,fix:`Add the missing scripts to each service's package.json, e.g.:
|
|
300
301
|
"dev": "bun run src/index.ts",
|
|
301
302
|
"build": "tsc",
|
|
302
|
-
"start": "bun run dist/index.js"`}}function
|
|
303
|
+
"start": "bun run dist/index.js"`}}function As(e){if(e.startsWith("@"))return[e.split("/").slice(0,2).join("/")];let t=e.split("/")[0]??e;return[`@types/${t}`,t]}function Ds(e,t,n=0){let r=e[t];if(typeof r!="string"||n>3)return!1;if(/(^|[\s;&|(])tsc(\s|$)/.test(r))return!0;for(let s of r.matchAll(/\b(?:bun|npm|pnpm|yarn)\s+run\s+([\w:.-]+)/g))if(Ds(e,s[1],n+1))return!0;return!1}function _s(e){let t=As(e);return e.includes("/")||e.startsWith("@")?t[t.length-1]:t[0]}var Dc={"@types/bun":"^1.4.2","@types/node":"^20.0.0"};function Cc(e,t){return(t.includes("bun")||e.has("@types/bun"))&&!e.has("@types/node")}function Nc(){let e=m()??process.cwd(),t=b(e),n=[],r=new Set;for(let o of t){let i=E(o.path,D),a=E(o.path,F,"tsconfig.docker.autogenerated.json");if(!C(i)||!C(a))continue;let d=on(a)?.compilerOptions?.types;if(!Array.isArray(d))continue;let l=on(i),h=l?.scripts??{};if(!Ds(h,"build"))continue;let k=new Set([...Object.keys(l?.devDependencies??{}),...Object.keys(l?.dependencies??{})]),g=d.filter(p=>typeof p=="string").filter(p=>!As(p).some(y=>k.has(y)));for(let p of g)r.add(_s(p));if(g.length>0){let p=g.map(y=>`"${y}" (needs ${_s(y)})`).join(", ");n.push(`${o.name}: "types" lists ${p}`)}Cc(k,d)&&(r.add("@types/node"),n.push(`${o.name}: uses @types/bun, which references node types internally, but @types/node is not a direct dependency`))}if(n.length===0)return{name:"TypeScript Type Dependencies",didPass:!0,message:`Every service's Docker tsconfig "types" entry has its @types package installed`};let s=[...r].map(o=>{let i=Dc[o];return i?`"${o}": "${i}"`:`${o} (bun add -d ${o})`});return{name:"TypeScript Type Dependencies",didPass:!1,message:`\`bun run build\` will fail with TS2688 (Cannot find type definition file) because a @types package it needs is not a direct dependency:
|
|
303
304
|
${n.join(`
|
|
304
|
-
`)}`,fix:`Add to each service's package.json devDependencies: ${s.join(", ")}`}}function
|
|
305
|
+
`)}`,fix:`Add to each service's package.json devDependencies: ${s.join(", ")}`}}function on(e){try{return JSON.parse(ie(e,"utf-8"))}catch{return null}}function jc(e){let n=on(e)?.compilerOptions;return n?.allowSyntheticDefaultImports===!0||n?.esModuleInterop===!0}function Ic(){let e=m()??process.cwd(),t=b(e).filter(r=>r.config?.appType==="frontend");if(t.length===0)return{name:"Frontend Docker Preflight",didPass:!0,isSkipped:!0,message:"No frontend services to check"};let n=[];for(let r of t){C(E(r.path,"public"))||n.push(`${r.name}: no public/ folder, but the Docker build copies it. Create it: mkdir -p ${tn(nn(e,E(r.path,"public")))} && touch ${tn(nn(e,E(r.path,"public",".gitkeep")))}`);let s=E(r.path,F,"Dockerfile.app.autogenerated"),o=E(r.path,F,"tsconfig.docker.autogenerated.json");if(C(s)){let i=ie(s,"utf-8"),a=/\bEXPOSE\s+80\b/.test(i),c=r.config?.stack,u=c?E(e,"services",c,F,"docker-compose.app.autogenerated.yml"):"";if(a&&u&&C(u)){let d=ie(u,"utf-8"),l=r.name.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),h=new RegExp(`traefik\\.http\\.services\\.${l}\\.loadbalancer\\.server\\.port=(\\d+)`),g=d.match(h)?.[1];g&&g!=="80"&&n.push(`${r.name}: nginx runtime exposes 80, but generated Traefik routes to ${g}`)}}if(C(o)&&!jc(o)){let i=E(r.path,"src","main.tsx");if(C(i)){let a=ie(i,"utf-8"),c=[/import\s+\w+\s+from\s+["']react["']/,/import\s+\w+\s+from\s+["']react-dom\/client["']/].filter(u=>u.test(a)).map(u=>u.source.includes("react-dom")?"react-dom/client":"react");c.length>0&&n.push(`${r.name}: Docker tsconfig does not allow synthetic default imports, but src/main.tsx default-imports ${c.join(" and ")}`)}}}return n.length===0?{name:"Frontend Docker Preflight",didPass:!0,message:`${S(t.length,"frontend")} ${t.length===1?"has":"have"} compatible Docker build/routing metadata`}:{name:"Frontend Docker Preflight",didPass:!1,message:`Frontend Docker metadata has issues that will make \`tdk up\` fail or route 404:
|
|
305
306
|
${n.join(`
|
|
306
|
-
`)}`,fix:'Regenerate with a current TDK (`tdk config regenerate`) and ensure frontend nginx runtimes route to port 80. For React entrypoints, prefer named imports: `import { StrictMode } from "react"` and `import { createRoot } from "react-dom/client"`.'}}var
|
|
307
|
-
`).map(t=>t.trim()).filter(Boolean).map(t=>{let[n,r,s]=t.split(",");return{name:n??"unknown",memPct:Number.parseFloat((r??"").replace(/%/g,"")),cpuPct:Number.parseFloat((s??"").replace(/%/g,""))}}).filter(t=>Number.isFinite(t.memPct)&&Number.isFinite(t.cpuPct))}function
|
|
307
|
+
`)}`,fix:'Regenerate with a current TDK (`tdk config regenerate`) and ensure frontend nginx runtimes route to port 80. For React entrypoints, prefer named imports: `import { StrictMode } from "react"` and `import { createRoot } from "react-dom/client"`.'}}var Fc=90,Mc=80;function Lc(e){return e.split(`
|
|
308
|
+
`).map(t=>t.trim()).filter(Boolean).map(t=>{let[n,r,s]=t.split(",");return{name:n??"unknown",memPct:Number.parseFloat((r??"").replace(/%/g,"")),cpuPct:Number.parseFloat((s??"").replace(/%/g,""))}}).filter(t=>Number.isFinite(t.memPct)&&Number.isFinite(t.cpuPct))}function Bc(){let e;try{e=lc($("docker")??"docker",["stats","--no-stream","--format","{{.Name}},{{.MemPerc}},{{.CPUPerc}}"],{stdio:"pipe",encoding:"utf-8",timeout:V,windowsHide:process.platform==="win32"})}catch(s){return{name:"Container Resource Health",didPass:!0,isSkipped:!0,message:Os(s)?"Docker not responding - skipped container resource check":"Docker not running - skipped container resource check"}}let t=Lc(e);if(t.length===0)return{name:"Container Resource Health",didPass:!0,isSkipped:!0,message:"No running containers to check"};let n=t.filter(s=>s.memPct>=Fc&&s.cpuPct>=Mc);if(n.length===0)return{name:"Container Resource Health",didPass:!0,message:`${S(t.length,"container")} within normal resource usage`};let r=n.map(s=>`${s.name} (mem ${s.memPct.toFixed(0)}%, cpu ${s.cpuPct.toFixed(0)}%)`).join(`
|
|
308
309
|
`);return{name:"Container Resource Health",didPass:!1,message:`${S(n.length,"container")} pinned near its memory limit while burning CPU -- likely stuck in a boot-time retry/fetch loop, not a normal crash:
|
|
309
|
-
${r}`,fix:"Check the container's boot logs for a network fetch loop (e.g. `bunx <pkg>` re-downloading a CLI on every start instead of using one already installed): docker logs <container>. If a Prisma auto-migration is the cause, set AUTO_MIGRATE=false in the project's .env as a temporary unblock."}}var
|
|
310
|
+
${r}`,fix:"Check the container's boot logs for a network fetch loop (e.g. `bunx <pkg>` re-downloading a CLI on every start instead of using one already installed): docker logs <container>. If a Prisma auto-migration is the cause, set AUTO_MIGRATE=false in the project's .env as a temporary unblock."}}var Uc=5e3;async function Hc(e,t){let n=m()??process.cwd(),r=Gn(b(n),t);return r.length===0?{name:"Service Health",didPass:!0,isSkipped:!0,message:"No routable services to ping"}:jt(await Wn(r,e))}var Vc=new fc("doctor").description("Check environment readiness for TDK").option("--json","Output a versioned JSON readiness report",!1).exitOverride(e=>{e.exitCode===0&&process.exit(0),Vc.opts().json&&console.log(JSON.stringify(z([],!1,[{code:"USAGE",message:e.message}]))),process.exit(2)}).option("--no-ping","Skip pinging running services' /health endpoints").option("--strict","Fail warnings such as a WSL project under /mnt/c").option("--ping-timeout <ms>","Per-service ping timeout in milliseconds",String(Uc)).action(async e=>{let t=Number(e.pingTimeout);if(!/^\d+$/.test(e.pingTimeout)||!Number.isSafeInteger(t)||t<=0){let p="--ping-timeout must be a positive integer number of milliseconds";e.json&&console.log(JSON.stringify(z([],!1,[{code:"USAGE",message:p}]))),console.error(p),process.exit(2);return}e.json||console.log("TDK doctor checks your local Docker + Tilt development environment; it does not check cluster deployments.");let n=wn();if(process.platform==="win32"){if(e.json){let p=null;try{p=await Ee()}catch{}console.log(JSON.stringify(z([{name:"Native Windows support",didPass:!1,message:$s,fix:"Use WSL2 Ubuntu with Docker Desktop integration. Guide: docs/wsl2.md"}],!!m(),[],p,{...n,canUp:!1})))}console.error($s),process.exit(1);return}if(n.kind==="webcontainer"){let p=z([{name:"Host",didPass:!1,message:ot,fix:`Use a machine with Docker. Guide: ${Oe}`}],!!m(),[],void 0,n);e.json&&console.log(JSON.stringify(p)),console.error(ot),process.exit(1);return}e.json||(console.log(`
|
|
310
311
|
${f.bold("\u{1F50D} TDK Doctor")}
|
|
311
312
|
`),console.log(`Checking environment...
|
|
312
|
-
`));let r=m(),s,o;try{s=await
|
|
313
|
+
`));let r=m(),s,o;try{s=await Je(r??process.cwd())}catch(p){s=null,o=p instanceof Error?p.message:String(p)}let i=[()=>s?{name:"Host Ports",didPass:!0,message:`HTTP ${s.ingressHttp}, HTTPS ${s.ingressHttps}, Postgres ${s.postgres}`}:{name:"Host Ports",didPass:!1,message:o??"Could not select host ports",fix:"Set TDK_HTTP_PORT, TDK_HTTPS_PORT, or TDK_POSTGRES_PORT to available host ports."},()=>s?Nt(ws,void 0,[s.ingressHttp,s.ingressHttps]):{name:"Ingress Ports",didPass:!1,message:"Ingress port plan is unavailable"},an,()=>In(),Tc,dn,cn,un,xc,()=>mc(m()??process.cwd(),e.strict),()=>gc(process.env,e.strict),()=>us()],a=[()=>wc(),Ec,Oc,Cr,Ac,()=>Or(),Nc,Ic,vc,()=>Zr(),()=>Ve(),()=>Yt(),()=>zt(),()=>Xt(),()=>Zt(void 0,e.strict),()=>Qr(),()=>es(),()=>rs(),()=>ns(),()=>Ge(),()=>zr(),()=>as(),()=>is(),()=>cs(),Pc,async()=>{let p=m()??process.cwd(),y=Dt(p)?await pn(p):!0;return Ct(ws,p,void 0,y)},Bc,It];e.ping&&a.push(()=>Hc(t,s?.ingressHttp));let c=!!r,{checks:u,errors:d}=await Ln(i,c?a:[]);if(vn(n.kind))for(let p of u)p.name===A&&!p.didPass&&(p.fix=En);let l=z(Rs(u),c,d,s,n),h=Bn(l),k=l.data.ready;if(e.json){let p;try{p=Ts(m()??process.cwd())}catch(y){if(!(y instanceof ve))throw y;console.log(JSON.stringify(z([],c,[...d,{code:"ENV_UNREADABLE",message:y.message}]))),console.error(y.message),process.exit(1)}console.log(JSON.stringify(qe(l,p)));for(let y of d)console.error(qt(y.message,p));h!==0&&process.exit(h);return}for(let p of d)console.error(`${f.red("\u2717")} Doctor check failed: ${p.message}`);for(let p of Rs(u))!p.didPass&&!p.isSkipped&&!p.isWarning?(console.log(`${f.red("\u2717")} ${p.message}`),p.fix&&console.log(`${f.blue("\u2139")} Fix: ${p.fix}`)):p.isWarning?(console.log(`${f.yellow("\u26A0")} ${f.yellow(p.message)}`),p.fix&&console.log(`${f.blue("\u2139")} Fix: ${p.fix}`)):p.isSkipped?(console.log(`${f.gray("\u25CB")} ${f.gray(p.message)}`),p.fix&&console.log(`${f.blue("\u2139")} ${p.fix}`)):console.log(`${f.green("\u2713")} ${p.message}`);console.log(""),k&&!c&&(console.log(`${f.gray("\u25CB")} ${f.gray("Not in a TDK project, so project checks were skipped")}`),console.log(""));let g=kc(c,k);console.log(`${k?f.green(f.bold("\u2713")):f.red(f.bold("\u2717"))} ${g}`),h!==0&&process.exit(h)});function Cs(e){return ze(e,Z)}var Xe=`${Z[0]}.${Z[1]}+`;function Wc(e,t){return{id:e,ok:t.didPass||!!t.isSkipped,message:t.message,fix:t.fix}}function js(e){let[t=0,n=0]=String(e).split(".").map(r=>Number.parseInt(r,10));return!Number.isFinite(t)||!Number.isFinite(n)||t<22||t===22&&n<12}async function Ze(e,t,n){try{return Wc(e,await t())}catch{return{id:e,ok:!1,message:n}}}function Jc(e){return e.isSkipped?{...e,didPass:!1,isSkipped:!1,message:`Could not verify Docker Engine/Compose minimum versions: ${e.message}`,fix:e.fix??"Start Docker and ensure Docker Engine 25+ and Compose 2.20.2+ are installed."}:e}function qc(e){try{return b(e).some(t=>t.config?.featuresEnabled?.includes("prisma")??!1)}catch{return!1}}async function Yc(e={}){let t=e.cwd??process.cwd(),n=m(t),r=!!n,s=[],o=process.versions.node;s.push({id:"node",ok:!js(o),message:o,fix:js(o)?`Install Node.js 22.12+ (current: ${o}). https://nodejs.org`:void 0}),s.push(await Ze("docker",an,"Docker daemon is not running")),s.push(await Ze("compose",async()=>{let[g,p]=await Promise.all([cn(),un()]);return g.didPass?Jc(p):g},"Docker Engine or Compose version check failed")),s.push(await Ze("tilt",dn,"Tilt CLI not found"));let i=n?Ae(b(n)):!0,a=!1,c=i?$("bun"):void 0;if(c)try{let g=Ns(c,["--version"],{encoding:"utf-8",timeout:3e3}).trim();a=Cs(g)}catch{}s.push(i?{id:"bun",ok:a,message:a?`Bun ${Xe} is available on PATH`:`Bun ${Xe} not found on PATH`,fix:a?void 0:"curl -fsSL https://bun.sh/install | bash"}:{id:"bun",ok:!0,message:"Bun not needed: no generated JS services"});try{let g=await Je(n??t);s.push({id:"ports",ok:!0,message:`HTTP ${g.ingressHttp}, HTTPS ${g.ingressHttps}, Postgres ${g.postgres}`})}catch(g){s.push({id:"ports",ok:!1,message:g instanceof Error?g.message:String(g),fix:"Set TDK_HTTP_PORT, TDK_HTTPS_PORT, or TDK_POSTGRES_PORT to available host ports."})}if(n){let g=await Ze("nats",()=>Ge(n),"NATS broker check failed");if(g.ok||s.push(g),qc(n)){let p=!1;try{let y=JSON.parse(Kc(Gc(n,".tdk",P),"utf-8")),w=String(y?.project?.name??"").replace(/-/g,"_");w&&(p=Ns($("docker")??"docker",["ps","--filter",`label=com.docker.compose.project=${w}`,"--filter","label=com.docker.compose.service=postgres","--filter","health=healthy","--format","{{.Names}}"],{encoding:"utf-8",timeout:3e3}).trim().length>0)}catch{}p||s.push({id:"prisma",ok:!1,message:"A Prisma resource is configured, but the project Postgres service is not healthy",fix:"Run `tdk up` to start the bundled Postgres, then check `tdk doctor`."})}}let u=s.filter(g=>!g.ok).slice(0,8),d=u.some(g=>["node","docker","compose","tilt","bun","ports"].includes(g.id)),l=u.some(g=>g.id==="bun"),h=u.length?d?l?`Cold start blocked. Bun ${Xe} must be installed on PATH.
|
|
313
314
|
Prisma/NATS configuration is project-specific and generated after \`tdk project\`. Fix the machine checks below.`:"Cold start blocked. Bun/Prisma/NATS are not the first failure.\nThey are generated after `tdk project`. Fix the machine checks below.":"Machine is ready. Project wiring is not.":"",k=u.length?"":r?"Environment ready for TDK":`This machine is ready for TDK.
|
|
314
|
-
Next: tdk project --yes`;return{ok:u.length===0,inProject:r,items:u,header:h,footer:k}}function
|
|
315
|
-
`)}async function
|
|
315
|
+
Next: tdk project --yes`;return{ok:u.length===0,inProject:r,items:u,header:h,footer:k}}function zc(e,t={}){let n=[e.header];for(let r of e.items)n.push(`FAIL ${r.id.padEnd(7)} ${r.message}`),r.fix&&n.push(` ${r.fix}`);return e.footer&&(t.includeSuccessFooter??!0)&&n.push(e.footer),n.filter(Boolean).join(`
|
|
316
|
+
`)}async function dm(){let e=await Yc();e.items.some(n=>["node","docker","compose","tilt","bun","ports"].includes(n.id))&&(console.error(zc(e)),process.exit(1))}export{f as a,Hn as b,B as c,U as d,gu as e,$n as f,me as g,F as h,to as i,no as j,P as k,D as l,it as m,ku as n,yu as o,Rn as p,Su as q,ds as r,Lt as s,v as t,m as u,Kn as v,mt as w,_o as x,ht as y,qd as z,Yd as A,zd as B,ge as C,el as D,Tt as E,tl as F,nl as G,Jn as H,Ie as I,pd as J,fd as K,$ as L,Go as M,Zn as N,Wo as O,Rd as P,_d as Q,er as R,Fd as S,R as T,H as U,Md as V,qo as W,Ld as X,Bd as Y,Ud as Z,S as _,Du as $,Cu as aa,Nu as ba,ju as ca,Iu as da,Fu as ea,Mu as fa,Lu as ga,Bu as ha,ft as ia,Uu as ja,Hu as ka,Vu as la,Ku as ma,Gu as na,Wu as oa,Ju as pa,qu as qa,fr as ra,fi as sa,mi as ta,il as ua,al as va,cl as wa,ul as xa,dl as ya,xt as za,xl as Aa,yr as Ba,bi as Ca,b as Da,ye as Ea,Pl as Fa,El as Ga,wl as Ha,vl as Ia,$l as Ja,Rl as Ka,xi as La,_l as Ma,Yl as Na,op as Oa,Bt as Pa,zr as Qa,ot as Ra,En as Sa,wn as Ta,vn as Ua,dt as Va,De as Wa,Eu as Xa,Sr as Ya,Tr as Za,Oi as _a,Ai as $a,At as ab,ks as bb,Lp as cb,Bp as db,Ee as eb,Wp as fb,ec as gb,Qp as hb,ef as ib,Je as jb,ve as kb,Ts as lb,qt as mb,qe as nb,mf as ob,hf as pb,Es as qb,Vc as rb,js as sb,Jc as tb,Yc as ub,zc as vb,dm as wb};
|