@habeetat/cli 0.1.0-dev.20260624145259.c5f7eb0 → 0.1.0

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/constants.ts","../src/templates/docker-compose.ts","../src/templates/nginx.ts","../src/templates/host-nginx.ts","../src/templates/caddy.ts","../src/templates/lego-script.ts","../src/utils/crypto.ts","../src/templates/env.ts","../src/utils/logger.ts","../src/utils/docker.ts","../src/utils/config.ts","../src/templates/bootstrap-script.ts","../src/templates/otel-collector-config.ts"],"names":["SYSTEM_APP_LOGTO_IDS"],"mappings":";;;;;;;;AAAO,IAAM,WAAA,GAAc;AACpB,IAAM,QAAA,GAAW;AACjB,IAAM,YAAA,GAAe;AAErB,IAAM,eAAA,GAAkB;AAExB,IAAM,MAAA,GAAS;AAAA,EACpB,OAAA,EAAS,8BAAA;AAAA,EACT,QAAA,EAAU,+BAAA;AAAA,EACV,UAAA,EAAY,kCAAA;AAAA,EACZ,eAAA,EAAiB,uCAAA;AAAA,EACjB,SAAA,EAAW,gCAAA;AAAA,EACX,SAAA,EAAW,iCAAA;AAAA,EACX,WAAA,EAAa;AACf;AAEO,IAAM,kBAAA,GAAqB;AAAA,EAChC,QAAA,EAAU,oBAAA;AAAA,EACV,KAAA,EAAO,iBAAA;AAAA,EACP,KAAA,EAAO,mBAAA;AAAA,EACP,KAAA,EAAO,gBAAA;AAAA,EACP,OAAA,EAAS,iBAAA;AAAA,EACT,IAAA,EAAM,qBAAA;AAAA,EACN,SAAA,EAAW,eAAA;AAAA,EACX,UAAA,EAAY,4CAAA;AAAA,EACZ,oBAAA,EAAsB,uCAAA;AAAA,EACtB,mBAAA,EAAqB,sCAAA;AAAA,EACrB,WAAA,EAAa,6BAAA;AAAA,EACb,cAAA,EAAgB;AAClB;AAEO,IAAM,aAAA,GAAgB;AAAA,EAC3B,IAAA,EAAM,EAAA;AAAA,EACN,KAAA,EAAO,GAAA;AAAA,EACP,SAAA,EAAW;AACb;AAEO,IAAM,QAAA,GAAW;AAAA,EACtB,UAAA;AAAA,EACA,aAAA;AAAA,EACA,YAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,sBAAA;AAAA,EACA,kBAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,WAAA;AAAA,EACA,YAAA;AAAA,EACA,yBAAA;AAAA,EACA,gBAAA;AAAA,EACA,sBAAA;AAAA,EACA;AACF;AClDO,SAAS,sBAAsB,MAAA,EAAgC;AACpE,EAAA,MAAM,GAAA,GAAM,OAAO,MAAA,CAAO,QAAA;AAC1B,EAAA,MAAM,QAAA,GAAW,OAAO,MAAA,CAAO,QAAA;AAE/B,EAAA,MAAM,QAAA,GAAoC;AAAA,IACxC,UAAA,EAAY;AAAA,MACV,OAAO,kBAAA,CAAmB,QAAA;AAAA,MAC1B,WAAA,EAAa;AAAA,QACX,aAAA,EAAe,kBAAA;AAAA,QACf,iBAAA,EAAmB,sBAAA;AAAA,QACnB,WAAA,EAAa;AAAA,OACf;AAAA,MACA,OAAA,EAAS,CAAC,wCAAwC,CAAA;AAAA,MAClD,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS,gBAAA;AAAA,MACT,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,CAAC,WAAA,EAAa,oDAAoD,CAAA;AAAA,QACxE,QAAA,EAAU,IAAA;AAAA,QACV,OAAA,EAAS,IAAA;AAAA,QACT,OAAA,EAAS;AAAA;AACX,KACF;AAAA,IAEA,aAAA,EAAe;AAAA,MACb,OAAO,kBAAA,CAAmB,QAAA;AAAA,MAC1B,WAAA,EAAa;AAAA,QACX,aAAA,EAAe,qBAAA;AAAA,QACf,iBAAA,EAAmB,yBAAA;AAAA,QACnB,WAAA,EAAa;AAAA,OACf;AAAA,MACA,OAAA,EAAS,CAAC,2CAA2C,CAAA;AAAA,MACrD,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS,gBAAA;AAAA,MACT,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,CAAC,WAAA,EAAa,0DAA0D,CAAA;AAAA,QAC9E,QAAA,EAAU,IAAA;AAAA,QACV,OAAA,EAAS,IAAA;AAAA,QACT,OAAA,EAAS;AAAA;AACX,KACF;AAAA,IAEA,YAAA,EAAc;AAAA,MACZ,OAAO,kBAAA,CAAmB,KAAA;AAAA,MAC1B,UAAA,EAAY,CAAC,IAAA,EAAM,IAAI,CAAA;AAAA,MACvB,OAAA,EAAS,CAAC,mEAAmE,CAAA;AAAA,MAC7E,UAAA,EAAY;AAAA,QACV,UAAA,EAAY,EAAE,SAAA,EAAW,iBAAA;AAAkB,OAC7C;AAAA,MACA,WAAA,EAAa;AAAA,QACX,MAAA,EAAQ,iFAAA;AAAA,QACR,QAAA,EAAU,mBAAA;AAAA,QACV,cAAA,EAAgB,yBAAA;AAAA,QAChB,iBAAA,EAAmB,yBAAA;AAAA,QACnB,UAAA,EAAY,MAAA;AAAA,QACZ,kBAAA,EAAoB,GAAA;AAAA,QACpB,WAAA,EAAa,mBAAA;AAAA,QACb,eAAA,EAAiB,4JAAA;AAAA,QACjB,oBAAA,EAAsB,4JAAA;AAAA,QACtB,6BAAA,EAA+B;AAAA,OACjC;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS,gBAAA;AAAA,MACT,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,CAAC,WAAA,EAAa,wFAAwF,CAAA;AAAA,QAC5G,QAAA,EAAU,KAAA;AAAA,QACV,OAAA,EAAS,IAAA;AAAA,QACT,OAAA,EAAS,EAAA;AAAA,QACT,YAAA,EAAc;AAAA;AAChB,KACF;AAAA,IAEA,OAAA,EAAS;AAAA,MACP,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,kBAAA,EAAqB,GAAG,CAAA,CAAA;AAAA,MAC1C,UAAA,EAAY;AAAA,QACV,YAAA,EAAc,EAAE,SAAA,EAAW,iBAAA,EAAkB;AAAA,QAC7C,aAAA,EAAe,EAAE,SAAA,EAAW,iBAAA;AAAkB,OAChD;AAAA,MACA,WAAA,EAAa;AAAA,QACX,QAAA,EAAU,YAAA;AAAA,QACV,YAAA,EAAc,6FAAA;AAAA,QACd,cAAA,EAAgB,wBAAA;AAAA,QAChB,YAAA,EAAc,wBAAA;AAAA,QACd,YAAA,EAAc,iBAAA;AAAA,QACd,cAAA,EAAgB,wBAAA;AAAA,QAChB,uBAAA,EAAyB,mBAAA;AAAA,QACzB,gBAAA,EAAkB,iBAAA;AAAA,QAClB,eAAA,EAAiB,oBAAA;AAAA,QACjB,kBAAkB,oBAAA,CAAqB,GAAA;AAAA,QACvC,oBAAA,EAAsB,yBAAA;AAAA,QACtB,cAAA,EAAgB,mBAAA;AAAA,QAChB,YAAA,EAAc,iBAAA;AAAA,QACd,eAAA,EAAiB,oBAAA;AAAA,QACjB,oBAAA,EAAsB,yBAAA;AAAA,QACtB,aAAA,EAAe,kBAAA;AAAA,QACf,UAAA,EAAY,eAAA;AAAA,QACZ,MAAA,EAAQ,WAAA;AAAA,QACR,uBAAA,EAAyB,4BAAA;AAAA,QACzB,uBAAA,EAAyB,4BAAA;AAAA,QACzB,wBAAA,EAA0B,6BAAA;AAAA,QAC1B,YAAA,EAAc,iBAAA;AAAA,QACd,GAAI,MAAA,CAAO,QAAA,CAAS,MAAA,IAAU;AAAA,UAC5B,uBAAA,EAAyB,4BAAA;AAAA,UACzB,cAAA,EAAgB;AAAA;AAClB,OACF;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS,gBAAA;AAAA,MACT,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,CAAC,KAAA,EAAO,MAAA,EAAQ,MAAM,uCAAuC,CAAA;AAAA,QACnE,QAAA,EAAU,KAAA;AAAA,QACV,OAAA,EAAS,KAAA;AAAA,QACT,OAAA,EAAS,CAAA;AAAA,QACT,YAAA,EAAc;AAAA;AAChB;AACF,GACF;AAEA,EAAA,IAAI,MAAA,CAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,QAAA,CAAS,UAAU,CAAA,GAAI;AAAA,MACrB,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,mBAAA,EAAsB,GAAG,CAAA,CAAA;AAAA,MAC3C,UAAA,EAAY,CAAC,SAAS,CAAA;AAAA,MACtB,WAAA,EAAa;AAAA,QACX,uBAAA,EAAyB,mBAAA;AAAA,QACzB,iBAAA,EAAmB,iBAAA;AAAA,QACnB,iBAAiB,oBAAA,CAAqB,QAAA;AAAA,QACtC,iBAAA,EAAmB,iBAAA;AAAA,QACnB,qBAAA,EAAuB,oBAAA;AAAA;AAAA;AAAA,QAGvB,oBAAA,EAAsB;AAAA,OACxB;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,SAAS,mBAAA,EAAqB;AACvC,IAAA,QAAA,CAAS,sBAAsB,CAAA,GAAI;AAAA,MACjC,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,sBAAA,EAAyB,GAAG,CAAA,CAAA;AAAA,MAC9C,UAAA,EAAY,CAAC,SAAS,CAAA;AAAA,MACtB,WAAA,EAAa;AAAA,QACX,mBAAA,EAAqB,mBAAA;AAAA,QACrB,mBAAmB,oBAAA,CAAqB,mBAAA;AAAA,QACxC,uBAAA,EAAyB,iBAAA;AAAA,QACzB,iBAAA,EAAmB,oBAAA;AAAA,QACnB,oBAAA,EAAsB;AAAA,OACxB;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,SAAS,eAAA,EAAiB;AACnC,IAAA,QAAA,CAAS,kBAAkB,CAAA,GAAI;AAAA,MAC7B,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,2BAAA,EAA8B,GAAG,CAAA,CAAA;AAAA,MACnD,UAAA,EAAY,CAAC,SAAS,CAAA;AAAA,MACtB,WAAA,EAAa;AAAA,QACX,mBAAA,EAAqB,mBAAA;AAAA,QACrB,mBAAmB,oBAAA,CAAqB,eAAA;AAAA,QACxC,uBAAA,EAAyB,iBAAA;AAAA,QACzB,iBAAA,EAAmB,yBAAA;AAAA,QACnB,oBAAA,EAAsB;AAAA,OACxB;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,SAAS,SAAA,EAAW;AAC7B,IAAA,QAAA,CAAS,WAAW,CAAA,GAAI;AAAA,MACtB,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,oBAAA,EAAuB,GAAG,CAAA,CAAA;AAAA,MAC5C,UAAA,EAAY,CAAC,SAAS,CAAA;AAAA,MACtB,WAAA,EAAa;AAAA,QACX,mBAAA,EAAqB,mBAAA;AAAA,QACrB,mBAAmB,oBAAA,CAAqB,SAAA;AAAA,QACxC,uBAAA,EAAyB,iBAAA;AAAA,QACzB,iBAAA,EAAmB,kBAAA;AAAA,QACnB,oBAAA,EAAsB,oBAAA;AAAA,QACtB,iBAAA,EAAmB;AAAA,OACrB;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AAEA,EAAA,IAAI,MAAA,CAAO,SAAS,SAAA,EAAW;AAC7B,IAAA,QAAA,CAAS,YAAY,CAAA,GAAI;AAAA,MACvB,KAAA,EAAO,CAAA,EAAG,QAAQ,CAAA,qBAAA,EAAwB,GAAG,CAAA,CAAA;AAAA,MAC7C,UAAA,EAAY,CAAC,SAAS,CAAA;AAAA,MACtB,WAAA,EAAa;AAAA,QACX,mBAAA,EAAqB,mBAAA;AAAA,QACrB,uBAAA,EAAyB,iBAAA;AAAA,QACzB,qBAAA,EAAuB,oBAAA;AAAA,QACvB,iBAAA,EAAmB;AAAA,OACrB;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AAGA,EAAA,IAAI,MAAA,CAAO,SAAS,MAAA,EAAQ;AAC1B,IAAA,QAAA,CAAS,WAAW,CAAA,GAAI;AAAA,MACtB,OAAO,kBAAA,CAAmB,SAAA;AAAA,MAC1B,WAAA,EAAa;AAAA,QACX,0BAAA,EAA4B,gBAAA;AAAA,QAC5B,sBAAA,EAAwB;AAAA,OAC1B;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS,gBAAA;AAAA,MACT,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,CAAC,WAAA,EAAa,2CAA2C,CAAA;AAAA,QAC/D,QAAA,EAAU,KAAA;AAAA,QACV,OAAA,EAAS,IAAA;AAAA,QACT,OAAA,EAAS;AAAA;AACX,KACF;AAEA,IAAA,QAAA,CAAS,YAAY,CAAA,GAAI;AAAA,MACvB,OAAO,kBAAA,CAAmB,UAAA;AAAA,MAC1B,UAAA,EAAY;AAAA,QACV,SAAA,EAAW,EAAE,SAAA,EAAW,iBAAA;AAAkB,OAC5C;AAAA,MACA,OAAA,EAAS;AAAA,QACP,qCAAA;AAAA,QACA,4CAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS,gBAAA;AAAA,MACT,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,CAAC,WAAA,EAAa,iEAAiE,CAAA;AAAA,QACrF,QAAA,EAAU,KAAA;AAAA,QACV,OAAA,EAAS,IAAA;AAAA,QACT,OAAA,EAAS,EAAA;AAAA,QACT,YAAA,EAAc;AAAA;AAChB,KACF;AAEA,IAAA,QAAA,CAAS,yBAAyB,CAAA,GAAI;AAAA,MACpC,OAAO,kBAAA,CAAmB,oBAAA;AAAA,MAC1B,OAAA,EAAS,CAAC,6BAA6B,CAAA;AAAA,MACvC,UAAA,EAAY;AAAA,QACV,UAAA,EAAY,EAAE,SAAA,EAAW,iBAAA;AAAkB,OAC7C;AAAA,MACA,WAAA,EAAa;AAAA,QACX,yBAAA,EAA2B;AAAA,OAC7B;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB;AAAA,KAC/B;AAEA,IAAA,QAAA,CAAS,gBAAgB,CAAA,GAAI;AAAA,MAC3B,OAAO,kBAAA,CAAmB,mBAAA;AAAA,MAC1B,OAAA,EAAS;AAAA,QACP,0CAAA;AAAA,QACA,2CAAA;AAAA,QACA,4CAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,IAAA,EAAM,MAAA;AAAA,MACN,UAAA,EAAY;AAAA,QACV,UAAA,EAAY,EAAE,SAAA,EAAW,iBAAA,EAAkB;AAAA,QAC3C,yBAAA,EAA2B,EAAE,SAAA,EAAW,gCAAA,EAAiC;AAAA,QACzE,sBAAA,EAAwB,EAAE,SAAA,EAAW,iBAAA;AAAkB,OACzD;AAAA,MACA,OAAA,EAAS;AAAA,QACP,wEAAA;AAAA,QACA;AAAA,OACF;AAAA,MACA,WAAA,EAAa;AAAA,QACX,wBAAA,EAA0B,qCAAA;AAAA,QAC1B,yBAAA,EAA2B,OAAA;AAAA,QAC3B,+BAAA,EAAiC;AAAA,OACnC;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS;AAAA,KACX;AAEA,IAAA,QAAA,CAAS,sBAAsB,CAAA,GAAI;AAAA,MACjC,OAAO,kBAAA,CAAmB,WAAA;AAAA,MAC1B,UAAA,EAAY;AAAA,QACV,UAAA,EAAY,EAAE,SAAA,EAAW,iBAAA;AAAkB,OAC7C;AAAA,MACA,OAAA,EAAS,CAAC,6BAA6B,CAAA;AAAA,MACvC,WAAA,EAAa;AAAA,QACX,aAAA,EAAe,uBAAA;AAAA,QACf,OAAA,EAAS,YAAA;AAAA,QACT,OAAA,EAAS,WAAA;AAAA,QACT,oBAAA,EAAsB;AAAA,OACxB;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS,gBAAA;AAAA,MACT,WAAA,EAAa;AAAA,QACX,IAAA,EAAM,CAAC,WAAA,EAAa,gFAAgF,CAAA;AAAA,QACpG,QAAA,EAAU,KAAA;AAAA,QACV,OAAA,EAAS,IAAA;AAAA,QACT,OAAA,EAAS,EAAA;AAAA,QACT,YAAA,EAAc;AAAA;AAChB,KACF;AAEA,IAAA,QAAA,CAAS,iBAAiB,CAAA,GAAI;AAAA,MAC5B,OAAO,kBAAA,CAAmB,cAAA;AAAA,MAC1B,UAAA,EAAY;AAAA,QACV,sBAAA,EAAwB,EAAE,SAAA,EAAW,iBAAA;AAAkB,OACzD;AAAA,MACA,WAAA,EAAa;AAAA,QACX,gBAAA,EAAkB;AAAA,OACpB;AAAA,MACA,QAAA,EAAU,CAAC,kBAAkB,CAAA;AAAA,MAC7B,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AAGA,EAAA,MAAM,cAAA,GAAiB,CAAC,YAAA,EAAc,SAAS,CAAA;AAC/C,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,QAAA,EAAU,cAAA,CAAe,KAAK,UAAU,CAAA;AAC5D,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,mBAAA,EAAqB,cAAA,CAAe,KAAK,sBAAsB,CAAA;AACnF,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,eAAA,EAAiB,cAAA,CAAe,KAAK,kBAAkB,CAAA;AAC3E,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,SAAA,EAAW,cAAA,CAAe,KAAK,WAAW,CAAA;AAC9D,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,SAAA,EAAW,cAAA,CAAe,KAAK,YAAY,CAAA;AAC/D,EAAA,IAAI,MAAA,CAAO,SAAS,MAAA,EAAQ;AAC1B,IAAA,cAAA,CAAe,KAAK,iBAAiB,CAAA;AACrC,IAAA,cAAA,CAAe,KAAK,sBAAsB,CAAA;AAAA,EAC5C;AAEA,EAAA,MAAM,QAAA,GAAW,OAAO,KAAA,CAAM,QAAA;AAE9B,EAAA,QAAA,CAAS,OAAO,CAAA,GAAI;AAAA,IAClB,OAAO,kBAAA,CAAmB,KAAA;AAAA,IAC1B,UAAA,EAAY,cAAA;AAAA,IACZ,OAAA,EAAS,CAAC,yDAAyD,CAAA;AAAA,IACnE,KAAA,EAAO,CAAC,CAAA,UAAA,EAAa,QAAQ,CAAA,GAAA,CAAK,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASlC,UACE,MAAA,CAAO,GAAA,EAAK,SAAS,WAAA,GACjB,CAAC,kBAAkB,CAAA,GACnB;AAAA,MACE,kBAAA,EAAoB;AAAA,QAClB,OAAA,EAAS,CAAC,CAAA,IAAA,EAAO,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,CAAA,YAAA,EAAe,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,CAAE;AAAA;AACpF,KACF;AAAA,IACN,OAAA,EAAS,gBAAA;AAAA,IACT,OAAA,EAAS,CAAA,+FAAA;AAAA,GACX;AAMA,EAAA,IAAI,MAAA,CAAO,GAAA,EAAK,IAAA,KAAS,WAAA,EAAa;AACpC,IAAA,QAAA,CAAS,OAAO,CAAA,GAAI;AAAA,MAClB,OAAO,kBAAA,CAAmB,KAAA;AAAA;AAAA;AAAA,MAG1B,UAAA,EAAY;AAAA,QACV,KAAA,EAAO,EAAE,SAAA,EAAW,iBAAA,EAAkB;AAAA,QACtC,OAAA,EAAS,EAAE,SAAA,EAAW,iBAAA;AAAkB,OAC1C;AAAA,MACA,KAAA,EAAO,CAAC,OAAA,EAAS,SAAA,EAAW,aAAa,CAAA;AAAA,MACzC,OAAA,EAAS;AAAA,QACP,2CAAA;AAAA,QACA,kBAAA;AAAA,QACA;AAAA,OACF;AAAA;AAAA;AAAA;AAAA,MAIA,QAAA,EAAU;AAAA,QACR,kBAAA,EAAoB;AAAA,UAClB,OAAA,EAAS,CAAC,CAAA,IAAA,EAAO,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,CAAA,EAAI,CAAA,YAAA,EAAe,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,CAAE;AAAA;AACpF,OACF;AAAA,MACA,OAAA,EAAS;AAAA,KACX;AAAA,EACF;AAYA,EAAA,IAAI,MAAA,CAAO,GAAA,EAAK,IAAA,KAAS,UAAA,EAAY;AACnC,IAAC,QAAA,CAAS,YAAY,CAAA,CAAiC,WAAA,GAAc;AAAA,MACnE,CAAA,IAAA,EAAO,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,aAAA,CAAA;AAAA,MAC7B,CAAA,YAAA,EAAe,MAAA,CAAO,QAAA,CAAS,MAAM,CAAA,aAAA;AAAA,KACvC;AAAA,EACF;AAEA,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,IAAA,EAAM,UAAA;AAAA,IACN,QAAA;AAAA,IACA,OAAA,EAAS;AAAA,MACP,eAAA,EAAiB,IAAA;AAAA,MACjB,kBAAA,EAAoB,IAAA;AAAA,MACpB,GAAI,MAAA,CAAO,GAAA,EAAK,IAAA,KAAS,WAAA,IAAe;AAAA,QACtC,YAAA,EAAc,IAAA;AAAA,QACd,cAAA,EAAgB;AAAA,OAClB;AAAA,MACA,GAAI,MAAA,CAAO,QAAA,CAAS,MAAA,IAAU;AAAA,QAC5B,iBAAA,EAAmB,IAAA;AAAA,QACnB,iBAAA,EAAmB,IAAA;AAAA,QACnB,aAAA,EAAe;AAAA;AACjB,KACF;AAAA,IACA,QAAA,EAAU;AAAA,MACR,kBAAA,EAAoB;AAAA,QAClB,MAAA,EAAQ;AAAA;AACV;AACF,GACF;AAEA,EAAA,OAAO,OAAO,OAAO,CAAA;AACvB;AAGA,SAAS,MAAA,CAAO,GAAA,EAAc,MAAA,GAAS,CAAA,EAAW;AAChD,EAAA,MAAM,GAAA,GAAM,GAAA,CAAI,MAAA,CAAO,MAAM,CAAA;AAE7B,EAAA,IAAI,GAAA,KAAQ,IAAA,IAAQ,GAAA,KAAQ,MAAA,EAAW,OAAO,EAAA;AAC9C,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,IAAA,IAAI,GAAA,CAAI,QAAA,CAAS,IAAI,CAAA,IAAK,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,IAAK,IAAI,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA,CAAI,SAAS,GAAG,CAAA,IAAK,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,IAAK,GAAA,CAAI,QAAA,CAAS,GAAG,CAAA,EAAG;AACzK,MAAA,OAAO,CAAA,CAAA,EAAI,GAAA,CAAI,OAAA,CAAQ,IAAA,EAAM,IAAI,CAAC,CAAA,CAAA,CAAA;AAAA,IACpC;AACA,IAAA,OAAO,GAAA;AAAA,EACT;AACA,EAAA,IAAI,OAAO,QAAQ,QAAA,IAAY,OAAO,QAAQ,SAAA,EAAW,OAAO,OAAO,GAAG,CAAA;AAE1E,EAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,GAAG,CAAA,EAAG;AACtB,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AAE7B,IAAA,MAAM,YAAY,GAAA,CAAI,KAAA;AAAA,MACpB,CAAC,SAAS,OAAO,IAAA,KAAS,YAAY,OAAO,IAAA,KAAS,QAAA,IAAY,OAAO,IAAA,KAAS;AAAA,KACpF;AACA,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,OAAO,GAAA,CACJ,GAAA,CAAI,CAAC,IAAA,KAAS;AAAA,EAAK,GAAG,CAAA,EAAA,EAAK,MAAA,CAAO,IAAA,EAAM,MAAA,GAAS,CAAC,CAAC,CAAA,CAAE,CAAA,CACrD,IAAA,CAAK,EAAE,CAAA;AAAA,IACZ;AACA,IAAA,OAAO,GAAA,CACJ,GAAA,CAAI,CAAC,IAAA,KAAS;AACb,MAAA,MAAM,GAAA,GAAM,MAAA,CAAO,IAAA,EAAM,MAAA,GAAS,CAAC,CAAA;AACnC,MAAA,IAAI,OAAO,SAAS,QAAA,IAAY,IAAA,KAAS,QAAQ,CAAC,KAAA,CAAM,OAAA,CAAQ,IAAI,CAAA,EAAG;AAErE,QAAA,MAAM,KAAA,GAAQ,GAAA,CAAI,KAAA,CAAM,IAAI,CAAA,CAAE,OAAO,CAAC,CAAA,KAAM,CAAA,CAAE,IAAA,EAAM,CAAA;AACpD,QAAA,IAAI,KAAA,CAAM,SAAS,CAAA,EAAG;AACpB,UAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,CAAC,CAAA,CAAE,SAAA,EAAU;AACjC,UAAA,MAAM,OAAO,KAAA,CAAM,KAAA,CAAM,CAAC,CAAA,CAAE,IAAI,CAAC,CAAA,KAAM,CAAA,EAAG,GAAG,KAAK,CAAA,CAAE,SAAA,EAAW,CAAA,CAAE,CAAA,CAAE,KAAK,IAAI,CAAA;AAC5E,UAAA,OAAO;AAAA,EAAK,GAAG,CAAA,EAAA,EAAK,KAAK,GAAG,IAAA,GAAO,IAAA,GAAO,OAAO,EAAE,CAAA,CAAA;AAAA,QACrD;AAAA,MACF;AACA,MAAA,OAAO;AAAA,EAAK,GAAG,KAAK,GAAG,CAAA,CAAA;AAAA,IACzB,CAAC,CAAA,CACA,IAAA,CAAK,EAAE,CAAA;AAAA,EACZ;AAEA,EAAA,IAAI,OAAO,QAAQ,QAAA,EAAU;AAC3B,IAAA,MAAM,OAAA,GAAU,MAAA,CAAO,OAAA,CAAQ,GAA8B,CAAA;AAC7D,IAAA,IAAI,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG,OAAO,IAAA;AACjC,IAAA,OAAO,QACJ,GAAA,CAAI,CAAC,CAAC,GAAA,EAAK,KAAK,CAAA,KAAM;AACrB,MAAA,IAAI,KAAA,KAAU,QAAQ,KAAA,KAAU,MAAA,SAAkB,CAAA,EAAG,GAAG,GAAG,GAAG,CAAA,CAAA,CAAA;AAC9D,MAAA,IAAI,OAAO,KAAA,KAAU,QAAA,IAAY,CAAC,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACtD,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,EAAO,MAAA,GAAS,CAAC,CAAA;AACvC,QAAA,OAAO,CAAA,EAAG,GAAG,CAAA,EAAG,GAAG,CAAA;AAAA,EAAM,MAAM,CAAA,CAAA;AAAA,MACjC;AACA,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,KAAK,CAAA,EAAG;AACxB,QAAA,MAAM,MAAA,GAAS,MAAA,CAAO,KAAA,EAAO,MAAA,GAAS,CAAC,CAAA;AACvC,QAAA,OAAO,CAAA,EAAG,GAAG,CAAA,EAAG,GAAG,IAAI,MAAM,CAAA,CAAA;AAAA,MAC/B;AACA,MAAA,OAAO,CAAA,EAAG,GAAG,CAAA,EAAG,GAAG,KAAK,MAAA,CAAO,KAAA,EAAO,MAAM,CAAC,CAAA,CAAA;AAAA,IAC/C,CAAC,CAAA,CACA,IAAA,CAAK,IAAI,CAAA;AAAA,EACd;AAEA,EAAA,OAAO,OAAO,GAAG,CAAA;AACnB;;;AC1eO,SAAS,kBAAkB,MAAA,EAAgC;AAChE,EAAA,MAAM,MAAA,GAAS,OAAO,QAAA,CAAS,MAAA;AAE/B,EAAA,MAAM,SAAA,GAAY;AAAA,IAChB,4CAAA;AAAA,IACA,kDAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,QAAA,EAAU,SAAA,CAAU,KAAK,2CAA2C,CAAA;AACxF,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,mBAAA,EAAqB,SAAA,CAAU,KAAK,mEAAmE,CAAA;AAC3H,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,eAAA,EAAiB,SAAA,CAAU,KAAK,2DAA2D,CAAA;AAC/G,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,SAAA,EAAW,SAAA,CAAU,KAAK,6CAA6C,CAAA;AAC3F,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,SAAA,EAAW,SAAA,CAAU,KAAK,+CAA+C,CAAA;AAC7F,EAAA,IAAI,MAAA,CAAO,SAAS,MAAA,EAAQ;AAC1B,IAAA,SAAA,CAAU,KAAK,2DAA2D,CAAA;AAC1E,IAAA,SAAA,CAAU,KAAK,6DAA6D,CAAA;AAAA,EAC9E;AAEA,EAAA,MAAM,KAAA,GAAQ,OAAO,QAAA,CAAS,QAAA;AAC9B,EAAA,MAAM,YAAA,GAAe;AAAA;AAAA;AAAA;AAAA,2CAAA,EAIsB,KAAK,CAAA,CAAA,CAAA;AAEhD,EAAA,MAAM,eAAyB,EAAC;AAGhC,EAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,oBAAA,EAGE,MAAM,CAAA;AAAA;AAAA,gCAAA,EAEM,YAAY;AAAA;AAAA,CAAA,CAE5C,CAAA;AAGA,EAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,4BAAA,EAGU,MAAM,CAAA;AAAA;AAAA,sCAAA,EAEI,YAAY;AAAA;AAAA,CAAA,CAElD,CAAA;AAGA,EAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,oBAAA,EAGE,MAAM,CAAA;AAAA;AAAA,8BAAA,EAEI,YAAY;AAAA;AAAA;AAAA;AAAA,8BAAA,EAIZ,YAAY;AAAA;AAAA,CAAA,CAE1C,CAAA;AAMA,EAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,gBAAA,EAGF,MAAM,CAAA;AAAA;AAAA,8BAAA,EAEQ,YAAY;AAAA;AAAA,CAAA,CAE1C,CAAA;AAGA,EAAA,IAAI,MAAA,CAAO,SAAS,QAAA,EAAU;AAC5B,IAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,yBAAA,EAGK,MAAM,CAAA;AAAA;AAAA,mCAAA,EAEI,YAAY;AAAA;AAAA,CAAA,CAE/C,CAAA;AAKE,IAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,kBAAA,EAGF,MAAM,CAAA;AAAA;AAAA,mCAAA,EAEW,YAAY;AAAA;AAAA,CAAA,CAE/C,CAAA;AAAA,EACA;AAGA,EAAA,IAAI,MAAA,CAAO,SAAS,mBAAA,EAAqB;AACvC,IAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,qCAAA,EAGiB,MAAM,CAAA;AAAA;AAAA,+CAAA,EAEI,YAAY;AAAA;AAAA,CAAA,CAE3D,CAAA;AAAA,EACA;AAGA,EAAA,IAAI,MAAA,CAAO,SAAS,eAAA,EAAiB;AACnC,IAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,iCAAA,EAGa,MAAM,CAAA;AAAA;AAAA,2CAAA,EAEI,YAAY;AAAA;AAAA,CAAA,CAEvD,CAAA;AAAA,EACA;AAGA,EAAA,IAAI,MAAA,CAAO,SAAS,SAAA,EAAW;AAC7B,IAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,0BAAA,EAGM,MAAM,CAAA;AAAA;AAAA,oCAAA,EAEI,YAAY;AAAA;AAAA,CAAA,CAEhD,CAAA;AAAA,EACA;AAGA,EAAA,IAAI,MAAA,CAAO,SAAS,SAAA,EAAW;AAC7B,IAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,2BAAA,EAGO,MAAM,CAAA;AAAA;AAAA,qCAAA,EAEI,YAAY;AAAA;AAAA,CAAA,CAEjD,CAAA;AAAA,EACA;AAGA,EAAA,IAAI,MAAA,CAAO,SAAS,MAAA,EAAQ;AAC1B,IAAA,YAAA,CAAa,IAAA,CAAK;AAAA;AAAA;AAAA,qBAAA,EAGC,MAAM,CAAA;AAAA;AAAA,uCAAA,EAEY,YAAY;AAAA;AAAA;AAAA,0CAAA,EAGT,YAAY;AAAA;AAAA;AAAA;AAAA,CAAA,CAItD,CAAA;AAAA,EACA;AAEA,EAAA,OAAO,CAAA;AAAA,8CAAA,EACuC,MAAM;AAAA;AAAA;;AAAA,EAIpD,SAAA,CAAU,IAAA,CAAK,IAAI,CAAC;;AAAA;AAAA,EAGpB,YAAA,CAAa,IAAA,CAAK,IAAI,CAAC;AAAA,CAAA;AAEzB;;;AC9KO,SAAS,sBAAsB,MAAA,EAAgC;AACpE,EAAA,MAAM,MAAA,GAAS,OAAO,QAAA,CAAS,MAAA;AAC/B,EAAA,MAAM,IAAA,GAAO,OAAO,KAAA,CAAM,QAAA;AAE1B,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,KAAA;AAAA,IACA,aAAA;AAAA,IACA;AAAA,GACF;AAEA,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,QAAA,EAAU,UAAA,CAAW,KAAK,UAAU,CAAA;AACxD,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,mBAAA,EAAqB,UAAA,CAAW,KAAK,sBAAsB,CAAA;AAC/E,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,eAAA,EAAiB,UAAA,CAAW,KAAK,kBAAkB,CAAA;AACvE,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,SAAA,EAAW,UAAA,CAAW,KAAK,WAAW,CAAA;AAC1D,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,SAAA,EAAW,UAAA,CAAW,KAAK,YAAY,CAAA;AAC3D,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,MAAA,EAAQ,UAAA,CAAW,KAAK,MAAM,CAAA;AAMlD,EAAA,MAAM,iBAAiB,MAAA,CAAO,QAAA,CAAS,QAAA,GAAW,CAAA,EAAA,EAAK,MAAM,CAAA,CAAA,GAAK,EAAA;AAClE,EAAA,MAAM,iBAAiB,CAAC,GAAG,WAAW,GAAA,CAAI,CAAC,MAAM,CAAA,EAAG,CAAC,IAAI,MAAM,CAAA,CAAE,GAAG,cAAc,CAAA,CAC/E,OAAO,OAAO,CAAA,CACd,KAAK,GAAG,CAAA;AAEX,EAAA,MAAM,YAAA,GAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,8CAAA,CAAA;AAUrB,EAAA,MAAM,MAAA,GAAS,CAAA;AAAA,8CAAA,EAC+B,MAAM;AAAA,oEAAA,EACgB,QAAA,CAAS,MAAM,CAAC;AAAA,4CAAA,CAAA;AAOpF,EAAA,IAAI,MAAA,CAAO,GAAA,EAAK,IAAA,KAAS,UAAA,EAAY;AACnC,IAAA,OAAO,GAAG,MAAM;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,gBAAA,EAOF,cAAc,CAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,gBAAA,EAQd,cAAc,CAAA;;AAAA,iDAAA,EAEmB,MAAM,CAAA;AAAA,iDAAA,EACN,MAAM,CAAA;;AAAA;;AAAA;AAAA,oCAAA,EAKnB,IAAI,IAAI,YAAY;AAAA;AAAA;AAAA,CAAA;AAAA,EAIxD;AAEA,EAAA,OAAO,GAAG,MAAM;AAAA;AAAA;;AAAA;AAAA;AAAA,gBAAA,EAMA,cAAc,CAAA;;AAAA;;AAAA;AAAA,oCAAA,EAKM,IAAI,IAAI,YAAY;AAAA;AAAA;AAAA,CAAA;AAI1D;AAEA,SAAS,SAAS,MAAA,EAAwB;AACxC,EAAA,OAAO,MAAA,CAAO,OAAA,CAAQ,iBAAA,EAAmB,GAAG,CAAA;AAC9C;;;AChFO,SAAS,kBAAkB,MAAA,EAAgC;AAChE,EAAA,MAAM,MAAA,GAAS,OAAO,QAAA,CAAS,MAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,EAAK,SAAA,IAAa,OAAO,QAAA,CAAS,UAAA;AACvD,EAAA,MAAM,MAAA,GAAS,OAAO,GAAA,EAAK,MAAA;AAE3B,EAAA,MAAM,UAAA,GAAa;AAAA,IACjB,UAAW,KAAK,CAAA,CAAA;AAAA,IAChB,MAAA,GAAS,CAAA,SAAA,EAAa,MAAM,CAAA,CAAA,GAAK,EAAA;AAAA;AAAA,IAEjC,CAAA,gBAAA,CAAA;AAAA,IACA,CAAA,2CAAA,CAAA;AAAA,IACA,CAAA,EAAA;AAAA,GACF,CACG,MAAA,CAAO,OAAO,CAAA,CACd,KAAK,IAAI,CAAA;AAEZ,EAAA,OAAO,CAAA;AAAA,8CAAA,EACuC,MAAM;AAAA,yEAAA,EACqB,MAAM,CAAA;AAAA;AAAA,+BAAA,EAEhD,MAAM,CAAA;;AAAA;AAAA,EAGrC,UAAU;AAAA;;AAAA;AAAA,EAIV,MAAM,OAAO,MAAM,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AASrB;;;AC1CO,SAAS,mBAAmB,MAAA,EAAgC;AACjE,EAAA,MAAM,MAAA,GAAS,OAAO,QAAA,CAAS,MAAA;AAC/B,EAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,GAAA,EAAK,SAAA,IAAa,OAAO,QAAA,CAAS,UAAA;AACvD,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,GAAA,EAAK,WAAA,IAAe,YAAA;AAC5C,EAAA,MAAM,MAAA,GAAS,OAAO,GAAA,EAAK,MAAA,GAAS,cAAc,MAAA,CAAO,GAAA,CAAI,MAAM,CAAA,CAAA,CAAA,GAAM,EAAA;AAEzE,EAAA,OAAO,CAAA;AAAA,kDAAA,EAC2C,MAAM,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,+CAAA,EAMT,MAAM,CAAA;AAAA;AAAA;AAAA,kFAAA,EAG6B,QAAQ,CAAA;AAAA;;AAAA,QAAA,EAGlF,MAAM,CAAA;AAAA,OAAA,EACP,KAAK,CAAA;AAAA,UAAA,EACF,QAAQ,CAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA,0CAAA,EAYwB,MAAM,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,EAM9C,qBAAqB,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAA,EAKP,MAAM,CAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAQxB;AC5DO,SAAS,UAAU,KAAA,EAAuB;AAC/C,EAAA,OAAO,MAAA,CAAO,WAAA,CAAY,KAAK,CAAA,CAAE,SAAS,KAAK,CAAA;AACjD;AAEO,SAAS,eAAA,GAAkB;AAChC,EAAA,OAAO;AAAA,IACL,eAAA,EAAiB,UAAU,EAAE,CAAA;AAAA,IAC7B,kBAAA,EAAoB,UAAU,EAAE,CAAA;AAAA,IAChC,aAAA,EAAe,UAAU,EAAE,CAAA;AAAA,IAC3B,iBAAA,EAAmB,UAAU,EAAE,CAAA;AAAA,IAC/B,kBAAA,EAAoB,UAAU,EAAE;AAAA,GAClC;AACF;ACVO,SAAS,gBAAgB,IAAA,EAA6B;AAC3D,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,GAAM,OAAA,GAAU,MAAA;AACtC,EAAA,MAAM,SAAS,IAAA,CAAK,MAAA;AACpB,EAAA,MAAM,UAAU,eAAA,EAAgB;AAChC,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,gBAAA,CAAiB,WAAA,EAAY,CAAE,OAAA,CAAQ,aAAA,EAAe,GAAG,CAAA,CAAE,OAAA,CAAQ,UAAA,EAAY,EAAE,CAAA,IAAK,UAAA;AAE9G,EAAA,OAAO,CAAA;AAAA,gCAAA,EAAA,iBACyB,IAAI,IAAA,EAAK,EAAE,WAAA,EAAa;;AAAA;AAAA;AAAA;AAAA,OAAA,EAKjD,MAAM;AAAA,SAAA,EACJ,QAAQ;;AAAA;AAAA;AAAA;AAAA,eAAA,EAKF,QAAQ,UAAU,MAAM;AAAA,qBAAA,EAClB,QAAQ,kBAAkB,MAAM;AAAA,aAAA,EACxC,QAAQ,eAAe,MAAM;AAAA,gBAAA,EAC1B,QAAQ,2BAA2B,MAAM;AAAA,qBAAA,EACpC,QAAQ,uBAAuB,MAAM;AAAA,cAAA,EAC5C,QAAQ,gBAAgB,MAAM;AAAA,eAAA,EAC7B,QAAQ,iBAAiB,MAAM;AAAA,gBAAA,EAC9B,QAAQ,UAAU,MAAM;AAAA,aAAA,EAC3B,QAAQ,CAAA,YAAA,EAAe,MAAM,IAAI,QAAQ,CAAA,wBAAA,EAA2B,MAAM,CAAA,CAAA,EAAI,QAAQ,CAAA,oBAAA,EAAuB,MAAM,IAAI,QAAQ,CAAA,aAAA,EAAgB,MAAM,CAAA,CAAA,EAAI,QAAQ,iBAAiB,MAAM;;AAAA;AAAA;AAAA;AAAA;AAAA,kBAAA,EAMnL,QAAQ,eAAe;AAAA;;AAAA;AAAA,qBAAA,EAIpB,QAAQ,kBAAkB;AAAA;;AAAA;AAAA;AAAA;AAAA,qBAAA,EAM1B,KAAK,UAAU;AAAA,qBAAA,EACf,KAAK,aAAa;;AAAA,eAAA,EAExB,QAAQ,UAAU,MAAM,CAAA;AAAA,aAAA,EAC1B,QAAQ,UAAU,MAAM,CAAA;AAAA,iBAAA,EACpB,QAAQ,UAAU,MAAM,CAAA;;AAAA,iBAAA,EAExBA,qBAAqB,GAAG;AAAA,qBAAA,EACpB,QAAQ,iBAAiB;;AAAA;AAAA;AAAA;AAAA,qBAAA,EAKzB,KAAK,UAAU;AAAA,wBAAA,EACZ,KAAK,aAAa;AAAA,kBAAA,EACxB,KAAK,gBAAgB;;AAAA;AAAA,wBAAA,EAGf,KAAK,gBAAgB;AAAA,wBAAA,EACrB,UAAU;AAAA,yBAAA,EACT,KAAK,UAAU;;AAAA;AAAA;AAAA;AAAA,eAAA,EAKzB,QAAQ,aAAa;;AAAA;AAAA;AAAA;AAAA,gBAAA,EAKpB,QAAQ,CAAA,eAAA,EAAkB,MAAM,IAAI,QAAQ,CAAA,YAAA,EAAe,MAAM,CAAA,CAAA,EAAI,QAAQ,CAAA,wBAAA,EAA2B,MAAM,IAAI,QAAQ,CAAA,oBAAA,EAAuB,MAAM,CAAA,CAAA,EAAI,QAAQ,gBAAgB,MAAM;AAAA,qBAAA,EACpL,QAAQ,CAAA,eAAA,EAAkB,MAAM,IAAI,QAAQ,CAAA,YAAA,EAAe,MAAM,CAAA,CAAA,EAAI,QAAQ,CAAA,wBAAA,EAA2B,MAAM,IAAI,QAAQ,CAAA,oBAAA,EAAuB,MAAM,CAAA,CAAA,EAAI,QAAQ,gBAAgB,MAAM;;AAAA;AAAA;AAAA;AAAA,WAAA,EAKnM,QAAQ,WAAW,MAAM;AAAA;AAAA,oBAAA,EAEhB,QAAQ,kBAAkB;AAAA,CAAA;AAEhD;ACpFA,IAAM,MAAA,GAAS,KAAA,CAAM,IAAA,CAAK,YAAY,CAAA;AAE/B,IAAM,MAAA,GAAS;AAAA,EACpB,IAAA,EAAM,CAAC,GAAA,KAAgB,OAAA,CAAQ,IAAI,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AAAA,EACrD,OAAA,EAAS,CAAC,GAAA,KAAgB,OAAA,CAAQ,IAAI,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,KAAA,CAAM,KAAA,CAAM,QAAG,CAAC,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AAAA,EAC5E,IAAA,EAAM,CAAC,GAAA,KAAgB,OAAA,CAAQ,IAAI,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,KAAA,CAAM,MAAA,CAAO,QAAG,CAAC,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AAAA,EAC1E,KAAA,EAAO,CAAC,GAAA,KAAgB,OAAA,CAAQ,MAAM,CAAA,EAAG,MAAM,CAAA,CAAA,EAAI,KAAA,CAAM,GAAA,CAAI,QAAG,CAAC,CAAA,CAAA,EAAI,GAAG,CAAA,CAAE,CAAA;AAAA,EAC1E,KAAA,EAAO,CAAC,GAAA,KAAgB;AACtB,IAAA,OAAA,CAAQ,IAAI,EAAE,CAAA;AACd,IAAA,OAAA,CAAQ,IAAI,KAAA,CAAM,IAAA,CAAK,SAAI,MAAA,CAAO,EAAE,CAAC,CAAC,CAAA;AACtC,IAAA,OAAA,CAAQ,IAAI,KAAA,CAAM,IAAA,CAAK,CAAA,EAAA,EAAK,GAAG,EAAE,CAAC,CAAA;AAClC,IAAA,OAAA,CAAQ,IAAI,KAAA,CAAM,IAAA,CAAK,SAAI,MAAA,CAAO,EAAE,CAAC,CAAC,CAAA;AACtC,IAAA,OAAA,CAAQ,IAAI,EAAE,CAAA;AAAA,EAChB,CAAA;AAAA,EACA,QAAQ,MAAM;AACZ,IAAA,OAAA,CAAQ,IAAI,EAAE,CAAA;AACd,IAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,kSAAkD,CAAC,CAAA;AAC1E,IAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,4DAAkD,CAAC,CAAA;AAC1E,IAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,4DAAkD,CAAC,CAAA;AAC1E,IAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,4DAAkD,CAAC,CAAA;AAC1E,IAAA,OAAA,CAAQ,GAAA,CAAI,KAAA,CAAM,IAAA,CAAK,kSAAkD,CAAC,CAAA;AAC1E,IAAA,OAAA,CAAQ,IAAI,EAAE,CAAA;AAAA,EAChB;AACF;ACtBA,eAAsB,WAAA,GAAgC;AACpD,EAAA,IAAI;AACF,IAAA,MAAM,EAAE,MAAA,EAAO,GAAI,MAAM,aAAa,kBAAkB,CAAA;AACxD,IAAA,MAAM,KAAA,GAAQ,MAAA,CAAO,KAAA,CAAM,sBAAsB,CAAA;AACjD,IAAA,IAAI,SAAS,QAAA,CAAS,KAAA,CAAM,CAAC,CAAA,EAAG,EAAE,KAAK,EAAA,EAAI;AACzC,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,MAAA,CAAO,KAAA,CAAM,CAAA,gCAAA,EAAmC,MAAA,CAAO,IAAA,EAAM,CAAA,CAAE,CAAA;AAC/D,IAAA,OAAO,KAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,MAAA,CAAO,MAAM,wCAAwC,CAAA;AACrD,IAAA,MAAA,CAAO,KAAK,qDAAqD,CAAA;AACjE,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,eAAsB,kBAAA,GAAuC;AAC3D,EAAA,IAAI;AACF,IAAA,MAAM,aAAa,wBAAwB,CAAA;AAC3C,IAAA,OAAO,IAAA;AAAA,EACT,CAAA,CAAA,MAAQ;AACN,IAAA,MAAA,CAAO,MAAM,oCAAoC,CAAA;AACjD,IAAA,MAAA,CAAO,KAAK,mDAAmD,CAAA;AAC/D,IAAA,OAAO,KAAA;AAAA,EACT;AACF;AAEA,eAAsB,kBAAA,GAAuC;AAC3D,EAAA,MAAM,MAAA,GAAS,MAAM,WAAA,EAAY;AACjC,EAAA,MAAM,OAAA,GAAU,MAAM,kBAAA,EAAmB;AACzC,EAAA,OAAO,MAAA,IAAU,OAAA;AACnB;AC7BO,SAAS,eAAA,CAAgB,QAAA,GAAmB,OAAA,CAAQ,GAAA,EAAI,EAAkB;AAC/E,EAAA,IAAI,GAAA,GAAM,QAAA;AACV,EAAA,OAAO,GAAA,KAAQ,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA,EAAG;AAChC,IAAA,IAAI,GAAG,UAAA,CAAW,IAAA,CAAK,KAAK,GAAA,EAAK,WAAW,CAAC,CAAA,EAAG;AAC9C,MAAA,OAAO,GAAA;AAAA,IACT;AACA,IAAA,GAAA,GAAM,IAAA,CAAK,QAAQ,GAAG,CAAA;AAAA,EACxB;AACA,EAAA,OAAO,IAAA;AACT;AAEO,SAAS,WAAW,UAAA,EAAqC;AAC9D,EAAA,MAAM,GAAA,GAAM,cAAc,eAAA,EAAgB;AAC1C,EAAA,IAAI,CAAC,GAAA,EAAK;AACR,IAAA,MAAM,IAAI,KAAA;AAAA,MACR,kBAAkB,WAAW,CAAA,8CAAA;AAAA,KAC/B;AAAA,EACF;AACA,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,IAAA,CAAK,GAAA,EAAK,WAAW,CAAA;AAC7C,EAAA,MAAM,GAAA,GAAM,EAAA,CAAG,YAAA,CAAa,UAAA,EAAY,OAAO,CAAA;AAC/C,EAAA,OAAO,IAAA,CAAK,MAAM,GAAG,CAAA;AACvB;AAEO,SAAS,UAAA,CAAW,QAAwB,UAAA,EAA0B;AAC3E,EAAA,MAAM,UAAA,GAAa,IAAA,CAAK,IAAA,CAAK,UAAA,EAAY,WAAW,CAAA;AACpD,EAAA,EAAA,CAAG,aAAA,CAAc,YAAY,IAAA,CAAK,SAAA,CAAU,QAAQ,IAAA,EAAM,CAAC,CAAA,GAAI,IAAA,EAAM,OAAO,CAAA;AAC9E;;;AC3BO,SAAS,kBAAA,GAA6B;AAC3C,EAAA,OAAO,CAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAgUT;;;AC/TO,SAAS,wBAAA,GAAmC;AACjD,EAAA,OAAO,CAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAuBT;AAQO,SAAS,2BAAA,GAAsC;AAEpD,EAAA,OAAO,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,CAAA;AAuDT;AAKO,SAAS,gCAAA,GAA2C;AACzD,EAAA,OAAO,CAAA;AAAA,CAAA;AAET","file":"index.mjs","sourcesContent":["export const CONFIG_FILE = 'habeetat.json';\nexport const ENV_FILE = '.env';\nexport const COMPOSE_FILE = 'docker-compose.yml';\n\nexport const DOCKER_REGISTRY = 'docker.io/capriisland';\n\nexport const IMAGES = {\n backend: 'capriisland/habeetat-backend',\n launcher: 'capriisland/habeetat-launcher',\n orgManager: 'capriisland/habeetat-org-manager',\n platformManager: 'capriisland/habeetat-platform-manager',\n analytics: 'capriisland/habeetat-analytics',\n sampleCrm: 'capriisland/habeetat-sample-crm',\n logtoConfig: 'capriisland/habeetat-logto-config',\n} as const;\n\nexport const THIRD_PARTY_IMAGES = {\n postgres: 'postgres:15-alpine',\n logto: 'svhd/logto:1.33',\n nginx: 'nginx:1.25-alpine',\n caddy: 'caddy:2-alpine',\n certbot: 'certbot/certbot',\n lego: 'goacme/lego:v4.21.0',\n zookeeper: 'zookeeper:3.7',\n clickhouse: 'clickhouse/clickhouse-server:24.1.2-alpine',\n signozSchemaMigrator: 'signoz/signoz-schema-migrator:0.88.22',\n signozOtelCollector: 'signoz/signoz-otel-collector:0.88.22',\n signozQuery: 'signoz/query-service:0.45.0',\n signozFrontend: 'signoz/frontend:0.45.0',\n} as const;\n\nexport const DEFAULT_PORTS = {\n http: 80,\n https: 443,\n hostNginx: 8080,\n} as const;\n\nexport const SERVICES = [\n 'logto-db',\n 'platform-db',\n 'logto-core',\n 'backend',\n 'launcher',\n 'organization-manager',\n 'platform-manager',\n 'analytics',\n 'sample-crm',\n 'nginx',\n 'zookeeper',\n 'clickhouse',\n 'otel-collector-migrator',\n 'otel-collector',\n 'signoz-query-service',\n 'signoz-frontend',\n] as const;\n\nexport type ServiceName = (typeof SERVICES)[number];\n","import type { HabeetatConfig } from '../types.js';\nimport { THIRD_PARTY_IMAGES } from '../constants.js';\nimport { SYSTEM_APP_LOGTO_IDS } from '@habeetat/sdk-core/constants';\n\nexport function generateDockerCompose(config: HabeetatConfig): string {\n const tag = config.docker.imageTag;\n const registry = config.docker.registry;\n\n const services: Record<string, unknown> = {\n 'logto-db': {\n image: THIRD_PARTY_IMAGES.postgres,\n environment: {\n POSTGRES_USER: '${LOGTO_DB_USER}',\n POSTGRES_PASSWORD: '${LOGTO_DB_PASSWORD}',\n POSTGRES_DB: '${LOGTO_DB_NAME}',\n },\n volumes: ['logto-db-data:/var/lib/postgresql/data'],\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'pg_isready -U ${LOGTO_DB_USER} -d ${LOGTO_DB_NAME}'],\n interval: '5s',\n timeout: '3s',\n retries: 10,\n },\n },\n\n 'platform-db': {\n image: THIRD_PARTY_IMAGES.postgres,\n environment: {\n POSTGRES_USER: '${PLATFORM_DB_USER}',\n POSTGRES_PASSWORD: '${PLATFORM_DB_PASSWORD}',\n POSTGRES_DB: '${PLATFORM_DB_NAME}',\n },\n volumes: ['platform-db-data:/var/lib/postgresql/data'],\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'pg_isready -U ${PLATFORM_DB_USER} -d ${PLATFORM_DB_NAME}'],\n interval: '5s',\n timeout: '3s',\n retries: 10,\n },\n },\n\n 'logto-core': {\n image: THIRD_PARTY_IMAGES.logto,\n entrypoint: ['sh', '-c'],\n command: ['npm run cli -- db seed -- --swe && npm run start || npm run start'],\n depends_on: {\n 'logto-db': { condition: 'service_healthy' },\n },\n environment: {\n DB_URL: 'postgres://${LOGTO_DB_USER}:${LOGTO_DB_PASSWORD}@logto-db:5432/${LOGTO_DB_NAME}',\n ENDPOINT: '${LOGTO_ENDPOINT}',\n ADMIN_ENDPOINT: '${LOGTO_ADMIN_ENDPOINT}',\n ADMIN_CONSOLE_URL: '${LOGTO_ADMIN_ENDPOINT}',\n ADMIN_PORT: '3002',\n TRUST_PROXY_HEADER: '1',\n COOKIE_KEYS: '${ENCRYPTION_KEY}',\n ALLOWED_ORIGINS: '${LOGTO_ENDPOINT},${LOGTO_ADMIN_ENDPOINT},${LAUNCHER_URL},${ORG_MANAGER_URL},${PLATFORM_MANAGER_URL},${ANALYTICS_URL},${SAMPLE_CRM_URL},${BACKEND_API_URL}',\n CORS_ALLOWED_ORIGINS: '${LOGTO_ENDPOINT},${LOGTO_ADMIN_ENDPOINT},${LAUNCHER_URL},${ORG_MANAGER_URL},${PLATFORM_MANAGER_URL},${ANALYTICS_URL},${SAMPLE_CRM_URL},${BACKEND_API_URL}',\n ADMIN_CONSOLE_ALLOWED_ORIGINS: '${LOGTO_ADMIN_ENDPOINT}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'wget -q --spider http://localhost:3001/oidc/.well-known/openid-configuration || exit 1'],\n interval: '10s',\n timeout: '5s',\n retries: 15,\n start_period: '150s',\n },\n },\n\n backend: {\n image: `${registry}/habeetat-backend:${tag}`,\n depends_on: {\n 'logto-core': { condition: 'service_healthy' },\n 'platform-db': { condition: 'service_healthy' },\n },\n environment: {\n NODE_ENV: 'production',\n DATABASE_URL: 'postgres://${PLATFORM_DB_USER}:${PLATFORM_DB_PASSWORD}@platform-db:5432/${PLATFORM_DB_NAME}',\n IAM_ISSUER_URL: '${LOGTO_ENDPOINT}/oidc',\n IAM_JWKS_URL: 'http://logto-core:3001',\n IAM_AUDIENCE: '${IAM_AUDIENCE}',\n LOGTO_ENDPOINT: 'http://logto-core:3001',\n LOGTO_EXTERNAL_ENDPOINT: '${LOGTO_ENDPOINT}',\n SDK_API_RESOURCE: '${IAM_AUDIENCE}',\n BACKEND_API_URL: '${BACKEND_API_URL}',\n LOGTO_M2M_APP_ID: SYSTEM_APP_LOGTO_IDS.m2m,\n LOGTO_M2M_APP_SECRET: '${LOGTO_M2M_APP_SECRET}',\n ENCRYPTION_KEY: '${ENCRYPTION_KEY}',\n LAUNCHER_URL: '${LAUNCHER_URL}',\n ORG_MANAGER_URL: '${ORG_MANAGER_URL}',\n PLATFORM_MANAGER_URL: '${PLATFORM_MANAGER_URL}',\n ANALYTICS_URL: '${ANALYTICS_URL}',\n SIGNOZ_URL: '${SIGNOZ_URL}',\n DOMAIN: '${DOMAIN}',\n NHP_DEFAULT_TENANT_NAME: '${NHP_DEFAULT_TENANT_NAME}',\n NHP_DEFAULT_TENANT_SLUG: '${NHP_DEFAULT_TENANT_SLUG}',\n NHP_PLATFORM_ADMIN_EMAIL: '${NHP_PLATFORM_ADMIN_EMAIL}',\n CORS_ORIGINS: '${CORS_ORIGINS}',\n ...(config.services.signoz && {\n OTEL_COLLECTOR_ENDPOINT: '${OTEL_COLLECTOR_ENDPOINT}',\n CLICKHOUSE_URL: 'http://clickhouse:8123',\n }),\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD', 'curl', '-f', 'http://localhost:3001/platform/status'],\n interval: '30s',\n timeout: '10s',\n retries: 3,\n start_period: '60s',\n },\n },\n };\n\n if (config.services.launcher) {\n services['launcher'] = {\n image: `${registry}/habeetat-launcher:${tag}`,\n depends_on: ['backend'],\n environment: {\n VITE_IAM_LOGTO_ENDPOINT: '${LOGTO_ENDPOINT}',\n VITE_IAM_AUDIENCE: '${IAM_AUDIENCE}',\n VITE_IAM_APP_ID: SYSTEM_APP_LOGTO_IDS.launcher,\n VITE_APP_BASE_URL: '${LAUNCHER_URL}',\n VITE_PLATFORM_API_URL: '${BACKEND_API_URL}',\n // Platform domain so the launcher can resolve the tenant slug from `<slug>.<domain>`\n // and build tenant subdomain origins (org-onboarding).\n VITE_PLATFORM_DOMAIN: '${DOMAIN}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n if (config.services.organizationManager) {\n services['organization-manager'] = {\n image: `${registry}/habeetat-org-manager:${tag}`,\n depends_on: ['backend'],\n environment: {\n VITE_LOGTO_ENDPOINT: '${LOGTO_ENDPOINT}',\n VITE_LOGTO_APP_ID: SYSTEM_APP_LOGTO_IDS.organizationManager,\n VITE_LOGTO_API_RESOURCE: '${IAM_AUDIENCE}',\n VITE_APP_BASE_URL: '${ORG_MANAGER_URL}',\n VITE_BACKEND_API_URL: '${BACKEND_API_URL}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n if (config.services.platformManager) {\n services['platform-manager'] = {\n image: `${registry}/habeetat-platform-manager:${tag}`,\n depends_on: ['backend'],\n environment: {\n VITE_LOGTO_ENDPOINT: '${LOGTO_ENDPOINT}',\n VITE_LOGTO_APP_ID: SYSTEM_APP_LOGTO_IDS.platformManager,\n VITE_LOGTO_API_RESOURCE: '${IAM_AUDIENCE}',\n VITE_APP_BASE_URL: '${PLATFORM_MANAGER_URL}',\n VITE_BACKEND_API_URL: '${BACKEND_API_URL}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n if (config.services.analytics) {\n services['analytics'] = {\n image: `${registry}/habeetat-analytics:${tag}`,\n depends_on: ['backend'],\n environment: {\n VITE_LOGTO_ENDPOINT: '${LOGTO_ENDPOINT}',\n VITE_LOGTO_APP_ID: SYSTEM_APP_LOGTO_IDS.analytics,\n VITE_LOGTO_API_RESOURCE: '${IAM_AUDIENCE}',\n VITE_APP_BASE_URL: '${ANALYTICS_URL}',\n VITE_BACKEND_API_URL: '${BACKEND_API_URL}',\n VITE_LAUNCHER_URL: '${LAUNCHER_URL}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n if (config.services.sampleCrm) {\n services['sample-crm'] = {\n image: `${registry}/habeetat-sample-crm:${tag}`,\n depends_on: ['backend'],\n environment: {\n VITE_LOGTO_ENDPOINT: '${LOGTO_ENDPOINT}',\n VITE_LOGTO_API_RESOURCE: '${IAM_AUDIENCE}',\n VITE_PLATFORM_API_URL: '${BACKEND_API_URL}',\n VITE_APP_BASE_URL: '${SAMPLE_CRM_URL}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n // SigNoz observability stack (ZooKeeper + ClickHouse + Schema Migrator + OTel Collector + Query Service + Frontend)\n if (config.services.signoz) {\n services['zookeeper'] = {\n image: THIRD_PARTY_IMAGES.zookeeper,\n environment: {\n ZOO_4LW_COMMANDS_WHITELIST: 'ruok,srvr,mntr',\n ZOO_AUTOPURGE_INTERVAL: '1',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'echo ruok | nc localhost 2181 | grep imok'],\n interval: '10s',\n timeout: '5s',\n retries: 10,\n },\n };\n\n services['clickhouse'] = {\n image: THIRD_PARTY_IMAGES.clickhouse,\n depends_on: {\n zookeeper: { condition: 'service_healthy' },\n },\n volumes: [\n 'clickhouse-data:/var/lib/clickhouse',\n 'clickhouse-logs:/var/log/clickhouse-server',\n './signoz/clickhouse-config.xml:/etc/clickhouse-server/config.d/habeetat-listen.xml:ro',\n ],\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'clickhouse-client --host=127.0.0.1 --query=\"SELECT 1\" || exit 1'],\n interval: '10s',\n timeout: '5s',\n retries: 15,\n start_period: '60s',\n },\n };\n\n services['otel-collector-migrator'] = {\n image: THIRD_PARTY_IMAGES.signozSchemaMigrator,\n command: ['--dsn=tcp://clickhouse:9000'],\n depends_on: {\n clickhouse: { condition: 'service_healthy' },\n },\n environment: {\n DOCKER_MULTI_NODE_CLUSTER: 'false',\n },\n networks: ['habeetat-network'],\n };\n\n services['otel-collector'] = {\n image: THIRD_PARTY_IMAGES.signozOtelCollector,\n command: [\n '--config=/etc/otel-collector-config.yaml',\n '--manager-config=/etc/manager-config.yaml',\n '--copy-path=/var/tmp/collector-config.yaml',\n '--feature-gates=-pkg.translator.prometheus.NormalizeName',\n ],\n user: 'root',\n depends_on: {\n clickhouse: { condition: 'service_healthy' },\n 'otel-collector-migrator': { condition: 'service_completed_successfully' },\n 'signoz-query-service': { condition: 'service_healthy' },\n },\n volumes: [\n './signoz/otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro',\n './signoz/otel-collector-opamp-config.yaml:/etc/manager-config.yaml:ro',\n ],\n environment: {\n OTEL_RESOURCE_ATTRIBUTES: 'host.name=signoz-host,os.type=linux',\n DOCKER_MULTI_NODE_CLUSTER: 'false',\n LOW_CARDINAL_EXCEPTION_GROUPING: 'false',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n\n services['signoz-query-service'] = {\n image: THIRD_PARTY_IMAGES.signozQuery,\n depends_on: {\n clickhouse: { condition: 'service_healthy' },\n },\n volumes: ['signoz-data:/var/lib/signoz'],\n environment: {\n ClickHouseUrl: 'tcp://clickhouse:9000',\n STORAGE: 'clickhouse',\n GODEBUG: 'netdns=go',\n SIGNOZ_LOCAL_DB_PATH: '/var/lib/signoz/signoz.db',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'wget -O- http://localhost:8080/api/v1/health 2>&1 | grep -q \"status\" || exit 1'],\n interval: '10s',\n timeout: '5s',\n retries: 15,\n start_period: '60s',\n },\n };\n\n services['signoz-frontend'] = {\n image: THIRD_PARTY_IMAGES.signozFrontend,\n depends_on: {\n 'signoz-query-service': { condition: 'service_healthy' },\n },\n environment: {\n FRONTEND_API_URL: 'http://signoz-query-service:8080',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n // Nginx reverse proxy (internal routing only — SSL handled by host nginx)\n const nginxDependsOn = ['logto-core', 'backend'];\n if (config.services.launcher) nginxDependsOn.push('launcher');\n if (config.services.organizationManager) nginxDependsOn.push('organization-manager');\n if (config.services.platformManager) nginxDependsOn.push('platform-manager');\n if (config.services.analytics) nginxDependsOn.push('analytics');\n if (config.services.sampleCrm) nginxDependsOn.push('sample-crm');\n if (config.services.signoz) {\n nginxDependsOn.push('signoz-frontend');\n nginxDependsOn.push('signoz-query-service');\n }\n\n const hostPort = config.nginx.hostPort;\n\n services['nginx'] = {\n image: THIRD_PARTY_IMAGES.nginx,\n depends_on: nginxDependsOn,\n volumes: ['./nginx/platform.conf:/etc/nginx/conf.d/default.conf:ro'],\n ports: [`127.0.0.1:${hostPort}:80`],\n // Network aliases so logto-core can resolve its own ENDPOINT / ADMIN_ENDPOINT\n // (iam.<domain> / iam-console.<domain>) to this reverse proxy from INSIDE the\n // docker network. Without this, Logto's Management API self-calls those URLs,\n // which resolve to 127.0.0.1:80 inside the container and fail — breaking M2M\n // auto-provisioning (vendor-app-onboarding §3). nginx then proxies them back to\n // logto-core (:3001 / :3002).\n // In on-demand TLS mode Caddy is the edge and owns the iam/iam-console aliases (for Logto's\n // HTTPS self-calls); otherwise nginx (the edge) owns them.\n networks:\n config.tls?.mode === 'on-demand'\n ? ['habeetat-network']\n : {\n 'habeetat-network': {\n aliases: [`iam.${config.platform.domain}`, `iam-console.${config.platform.domain}`],\n },\n },\n restart: 'unless-stopped',\n command: `/bin/sh -c 'while :; do sleep 6h & wait $\\${!}; nginx -s reload; done & nginx -g \"daemon off;\"'`,\n };\n\n // On-demand TLS (design D13): Caddy is the public edge terminator in front of the internal\n // nginx. It binds 80/443, serves the known service hosts with automatic HTTPS, and issues a\n // per-subdomain cert on demand for tenant subdomains (gated by /tenants/caddy-ask). Replaces\n // the host-nginx + certbot edge in this mode.\n if (config.tls?.mode === 'on-demand') {\n services['caddy'] = {\n image: THIRD_PARTY_IMAGES.caddy,\n // Wait for the backend to be healthy so the on-demand ask endpoint is ready before Caddy\n // accepts traffic (otherwise the first request for a new tenant SNI races startup).\n depends_on: {\n nginx: { condition: 'service_started' },\n backend: { condition: 'service_healthy' },\n },\n ports: ['80:80', '443:443', '443:443/udp'],\n volumes: [\n './caddy/Caddyfile:/etc/caddy/Caddyfile:ro',\n 'caddy-data:/data',\n 'caddy-config:/config',\n ],\n // Caddy is the TLS edge in this mode, so Logto's self-calls to its HTTPS ENDPOINT\n // (iam.<domain> / iam-console.<domain>) must resolve to Caddy from INSIDE the network.\n // (In other modes these aliases live on the nginx service.)\n networks: {\n 'habeetat-network': {\n aliases: [`iam.${config.platform.domain}`, `iam-console.${config.platform.domain}`],\n },\n },\n restart: 'unless-stopped',\n };\n }\n\n // Wildcard TLS mode (design D13): the host nginx is the 443 edge and lives OUTSIDE the docker\n // network, so the in-network nginx alias for iam./iam-console.<domain> (which listens only on\n // :80) cannot satisfy Logto's HTTPS self-calls to its own ENDPOINT/ADMIN_ENDPOINT. Those\n // self-calls happen on EVERY Management API request (getAdminTenantTokenValidationSet during\n // bearer-token auth) and need a 443 terminator — which the host nginx already is (lego cert).\n // Map those hostnames to the host gateway on logto-core so the self-calls reach the host nginx\n // instead of the :80-only container nginx. Without this, every /api/* request 500s with\n // `connect ECONNREFUSED <nginx-container>:443`, breaking platform-admin checks, vendor M2M\n // provisioning, org/role reads — anything that calls the Logto Management API.\n // (In on-demand mode Caddy is the in-network 443 edge and owns these aliases instead.)\n if (config.tls?.mode === 'wildcard') {\n (services['logto-core'] as { extra_hosts?: string[] }).extra_hosts = [\n `iam.${config.platform.domain}:host-gateway`,\n `iam-console.${config.platform.domain}:host-gateway`,\n ];\n }\n\n const compose = {\n name: 'habeetat',\n services,\n volumes: {\n 'logto-db-data': null,\n 'platform-db-data': null,\n ...(config.tls?.mode === 'on-demand' && {\n 'caddy-data': null,\n 'caddy-config': null,\n }),\n ...(config.services.signoz && {\n 'clickhouse-data': null,\n 'clickhouse-logs': null,\n 'signoz-data': null,\n }),\n },\n networks: {\n 'habeetat-network': {\n driver: 'bridge',\n },\n },\n };\n\n return toYaml(compose);\n}\n\n// Minimal YAML serializer — avoids adding a dependency for simple structure\nfunction toYaml(obj: unknown, indent = 0): string {\n const pad = ' '.repeat(indent);\n\n if (obj === null || obj === undefined) return '';\n if (typeof obj === 'string') {\n if (obj.includes('\\n') || obj.includes(\"'\") || obj.includes('\"') || obj.includes(':') || obj.includes('#') || obj.includes('{') || obj.includes('}') || obj.includes('$')) {\n return `'${obj.replace(/'/g, \"''\")}'`;\n }\n return obj;\n }\n if (typeof obj === 'number' || typeof obj === 'boolean') return String(obj);\n\n if (Array.isArray(obj)) {\n if (obj.length === 0) return '[]';\n // Check if all items are scalars\n const allScalar = obj.every(\n (item) => typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean',\n );\n if (allScalar) {\n return obj\n .map((item) => `\\n${pad}- ${toYaml(item, indent + 2)}`)\n .join('');\n }\n return obj\n .map((item) => {\n const val = toYaml(item, indent + 2);\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n // Object inside array — inline the first key after the dash\n const lines = val.split('\\n').filter((l) => l.trim());\n if (lines.length > 0) {\n const first = lines[0].trimStart();\n const rest = lines.slice(1).map((l) => `${pad} ${l.trimStart()}`).join('\\n');\n return `\\n${pad}- ${first}${rest ? '\\n' + rest : ''}`;\n }\n }\n return `\\n${pad}- ${val}`;\n })\n .join('');\n }\n\n if (typeof obj === 'object') {\n const entries = Object.entries(obj as Record<string, unknown>);\n if (entries.length === 0) return '{}';\n return entries\n .map(([key, value]) => {\n if (value === null || value === undefined) return `${pad}${key}:`;\n if (typeof value === 'object' && !Array.isArray(value)) {\n const nested = toYaml(value, indent + 2);\n return `${pad}${key}:\\n${nested}`;\n }\n if (Array.isArray(value)) {\n const nested = toYaml(value, indent + 2);\n return `${pad}${key}:${nested}`;\n }\n return `${pad}${key}: ${toYaml(value, indent)}`;\n })\n .join('\\n');\n }\n\n return String(obj);\n}\n","import type { HabeetatConfig } from '../types.js';\n\nexport function generateNginxConf(config: HabeetatConfig): string {\n const domain = config.platform.domain;\n\n const upstreams = [\n 'upstream logto { server logto-core:3001; }',\n 'upstream logto_admin { server logto-core:3002; }',\n 'upstream api { server backend:3001; }',\n ];\n\n if (config.services.launcher) upstreams.push('upstream launcher { server launcher:80; }');\n if (config.services.organizationManager) upstreams.push('upstream organization-manager { server organization-manager:80; }');\n if (config.services.platformManager) upstreams.push('upstream platform-manager { server platform-manager:80; }');\n if (config.services.analytics) upstreams.push('upstream analytics { server analytics:80; }');\n if (config.services.sampleCrm) upstreams.push('upstream sample-crm { server sample-crm:80; }');\n if (config.services.signoz) {\n upstreams.push('upstream signoz_frontend { server signoz-frontend:3301; }');\n upstreams.push('upstream signoz_query { server signoz-query-service:8080; }');\n }\n\n const proto = config.platform.protocol;\n const proxyHeaders = `\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto ${proto};`;\n\n const serverBlocks: string[] = [];\n\n // Logto IAM\n serverBlocks.push(`\nserver {\n listen 80;\n server_name iam.${domain};\n location / {\n proxy_pass http://logto;${proxyHeaders}\n }\n}`);\n\n // Logto Admin Console\n serverBlocks.push(`\nserver {\n listen 80;\n server_name iam-console.${domain};\n location / {\n proxy_pass http://logto_admin;${proxyHeaders}\n }\n}`);\n\n // Backend API\n serverBlocks.push(`\nserver {\n listen 80;\n server_name api.${domain};\n location /webhooks/ {\n proxy_pass http://api;${proxyHeaders}\n }\n location / {\n limit_req zone=api_limit burst=20 nodelay;\n proxy_pass http://api;${proxyHeaders}\n }\n}`);\n\n // Apex domain — public config-discovery for vendor apps (GET /.well-known/habeetat).\n // The api.${domain} block already proxies everything to the backend; this also\n // exposes discovery at the bare platform root so a vendor can self-configure from\n // `https://${domain}/.well-known/habeetat`.\n serverBlocks.push(`\nserver {\n listen 80;\n server_name ${domain};\n location /.well-known/ {\n proxy_pass http://api;${proxyHeaders}\n }\n}`);\n\n // Launcher\n if (config.services.launcher) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name launcher.${domain};\n location / {\n proxy_pass http://launcher;${proxyHeaders}\n }\n}`);\n\n // Tenant subdomains `<slug>.${domain}` are served by the launcher (org-onboarding).\n // nginx matches exact server_name (iam./api./launcher./… above) BEFORE this leading\n // wildcard, so the platform service hosts are never shadowed by a tenant slug.\n serverBlocks.push(`\nserver {\n listen 80;\n server_name *.${domain};\n location / {\n proxy_pass http://launcher;${proxyHeaders}\n }\n}`);\n }\n\n // Organization Manager\n if (config.services.organizationManager) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name organization-manager.${domain};\n location / {\n proxy_pass http://organization-manager;${proxyHeaders}\n }\n}`);\n }\n\n // Platform Manager\n if (config.services.platformManager) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name platform-manager.${domain};\n location / {\n proxy_pass http://platform-manager;${proxyHeaders}\n }\n}`);\n }\n\n // Analytics\n if (config.services.analytics) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name analytics.${domain};\n location / {\n proxy_pass http://analytics;${proxyHeaders}\n }\n}`);\n }\n\n // Sample CRM\n if (config.services.sampleCrm) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name sample-crm.${domain};\n location / {\n proxy_pass http://sample-crm;${proxyHeaders}\n }\n}`);\n }\n\n // SigNoz Dashboard (frontend serves UI, query-service serves API)\n if (config.services.signoz) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name logs.${domain};\n location /api {\n proxy_pass http://signoz_query;${proxyHeaders}\n }\n location / {\n proxy_pass http://signoz_frontend;${proxyHeaders}\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"upgrade\";\n }\n}`);\n }\n\n return `# Habeetat Platform - Container Nginx Configuration\n# Auto-generated by @habeetat/cli for domain: ${domain}\n# This handles internal routing between Docker services.\n# SSL is handled by the host nginx (see /etc/nginx/sites-enabled/).\n\n${upstreams.join('\\n')}\n\nlimit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;\n${serverBlocks.join('\\n')}\n`;\n}\n","import type { HabeetatConfig } from '../types.js';\n\nexport function generateHostNginxConf(config: HabeetatConfig): string {\n const domain = config.platform.domain;\n const port = config.nginx.hostPort;\n\n const subdomains = [\n 'iam',\n 'iam-console',\n 'api',\n ];\n\n if (config.services.launcher) subdomains.push('launcher');\n if (config.services.organizationManager) subdomains.push('organization-manager');\n if (config.services.platformManager) subdomains.push('platform-manager');\n if (config.services.analytics) subdomains.push('analytics');\n if (config.services.sampleCrm) subdomains.push('sample-crm');\n if (config.services.signoz) subdomains.push('logs');\n\n // Tenant subdomains `<slug>.${domain}` are served by the launcher (org-onboarding). nginx\n // matches the explicit service names before this leading wildcard, so service hosts are not\n // shadowed. TLS for `*.${domain}` needs a wildcard cert via Let's Encrypt DNS-01 (certbot\n // --nginx HTTP-01 cannot issue wildcards) — a documented install prerequisite.\n const tenantWildcard = config.services.launcher ? `*.${domain}` : '';\n const allServerNames = [...subdomains.map((s) => `${s}.${domain}`), tenantWildcard]\n .filter(Boolean)\n .join(' ');\n\n const proxyHeaders = `\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n proxy_set_header X-Forwarded-Host $host;\n proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"upgrade\";`;\n\n const header = `# Habeetat Platform - Host Nginx Configuration\n# Auto-generated by @habeetat/cli for domain: ${domain}\n# This file should be placed in /etc/nginx/sites-available/habeetat-${sanitize(domain)}\n# and symlinked to /etc/nginx/sites-enabled/`;\n\n // Wildcard TLS mode (design D13): a single `*.${domain}` cert from ACME DNS-01 (lego) covers\n // every service host AND every tenant subdomain. nginx terminates TLS here referencing the lego\n // cert; port 80 only redirects (DNS-01 needs no HTTP-01 challenge). Otherwise (on-demand/manual)\n // keep the plain `listen 80` block — certbot --nginx adds SSL, or Caddy fronts this entirely.\n if (config.tls?.mode === 'wildcard') {\n return `${header}\n#\n# TLS: wildcard cert via ACME DNS-01 (lego). Issue it with ./tls/issue-wildcard-cert.sh\n# before reloading nginx (the cert must exist at the paths below).\n\nserver {\n listen 80;\n server_name ${allServerNames};\n location / {\n return 301 https://$host$request_uri;\n }\n}\n\nserver {\n listen 443 ssl http2;\n server_name ${allServerNames};\n\n ssl_certificate /etc/lego/certificates/_.${domain}.crt;\n ssl_certificate_key /etc/lego/certificates/_.${domain}.key;\n\n client_max_body_size 50M;\n\n location / {\n proxy_pass http://127.0.0.1:${port};${proxyHeaders}\n }\n}\n`;\n }\n\n return `${header}\n#\n# SSL will be added automatically by certbot --nginx\n\nserver {\n listen 80;\n server_name ${allServerNames};\n\n client_max_body_size 50M;\n\n location / {\n proxy_pass http://127.0.0.1:${port};${proxyHeaders}\n }\n}\n`;\n}\n\nfunction sanitize(domain: string): string {\n return domain.replace(/[^a-zA-Z0-9.-]/g, '-');\n}\n","import type { HabeetatConfig } from '../types.js';\n\n/**\n * Caddyfile for the `on-demand` TLS mode (design D13). Caddy is the public edge terminator;\n * the internal nginx is the router. A single site matches the apex AND every subdomain\n * (`<domain>, *.<domain>`) and uses on-demand TLS so a certificate is issued the first time a\n * host connects — gated by the backend `/tenants/caddy-ask` endpoint, which approves the apex,\n * the platform service hosts (iam/api/launcher/…), and existing tenant subdomains, and denies\n * unknown names so Caddy never attempts ACME for arbitrary hosts (rate-limit abuse).\n *\n * NOTE: we deliberately do NOT also list the service hosts in a separate non-on-demand block.\n * A service host like `api.<domain>` is a single-label subdomain, so it matches `*.<domain>`;\n * a separate explicit policy (no on_demand) would shadow the wildcard's on-demand policy at the\n * handshake yet never get a proactively-issued cert (Caddy treats it as covered by the wildcard)\n * — a dead zone that yields \"no certificate available\". One on-demand site avoids that entirely.\n */\nexport function generateCaddyfile(config: HabeetatConfig): string {\n const domain = config.platform.domain;\n const email = config.tls?.acmeEmail || config.platform.adminEmail;\n const acmeCa = config.tls?.acmeCa;\n\n const globalOpts = [\n `\\temail ${email}`,\n acmeCa ? `\\tacme_ca ${acmeCa}` : '',\n // Caddy 2.10+ refuses bare on-demand TLS — the ask gate is mandatory.\n `\\ton_demand_tls {`,\n `\\t\\task http://backend:3001/tenants/caddy-ask`,\n `\\t}`,\n ]\n .filter(Boolean)\n .join('\\n');\n\n return `# Habeetat Platform - Caddy edge (on-demand TLS)\n# Auto-generated by @habeetat/cli for domain: ${domain}\n# The apex + every subdomain (service hosts and tenant subdomains <slug>.${domain}) get a\n# certificate issued on demand, gated by the backend /tenants/caddy-ask endpoint. Requires a\n# static wildcard DNS record *.${domain} -> server-ip and ports 80/443. No DNS-provider API.\n\n{\n${globalOpts}\n}\n\n# Apex + all subdomains — TLS on demand (ask-gated); internal nginx routes by Host header.\n${domain}, *.${domain} {\n\\ttls {\n\\t\\ton_demand\n\\t}\n\\treverse_proxy nginx:80 {\n\\t\\theader_up Host {host}\n\\t}\n}\n`;\n}\n","import type { HabeetatConfig } from '../types.js';\n\n/**\n * Shell script to issue/renew the wildcard TLS cert `*.<domain>` via ACME DNS-01 using lego\n * (design D13, 'wildcard' mode). A single wildcard cert + apex covers every service host AND\n * every tenant subdomain. Provider-agnostic: the operator puts their DNS-provider API creds in\n * `tls/dns-credentials.env` (see lego's per-provider env vars) and lego's `--dns <provider>`\n * picks the plugin. Writes the cert to `/etc/lego/certificates/_.<domain>.crt` (+ `.key`), the\n * paths the host nginx references.\n */\nexport function generateLegoScript(config: HabeetatConfig): string {\n const domain = config.platform.domain;\n const email = config.tls?.acmeEmail || config.platform.adminEmail;\n const provider = config.tls?.dnsProvider || 'cloudflare';\n const caFlag = config.tls?.acmeCa ? ` --server \"${config.tls.acmeCa}\"` : '';\n\n return `#!/usr/bin/env bash\n# Issue (or renew) the wildcard TLS certificate *.${domain} via ACME DNS-01 (lego).\n# Auto-generated by @habeetat/cli. Run from the project root:\n# ./tls/issue-wildcard-cert.sh # first issuance\n# ./tls/issue-wildcard-cert.sh renew # renewal (cron/systemd timer; then reload nginx)\n#\n# PREREQUISITES\n# 1) A static wildcard DNS A/AAAA record: *.${domain} -> <server-ip>\n# 2) Your DNS-provider API credentials in tls/dns-credentials.env. For Cloudflare:\n# CLOUDFLARE_DNS_API_TOKEN=<token scoped Zone:Read + DNS:Edit>\n# For other providers see the env vars at https://go-acme.github.io/lego/dns/${provider}/\nset -euo pipefail\n\nDOMAIN=\"${domain}\"\nEMAIL=\"${email}\"\nPROVIDER=\"${provider}\"\nACTION=\"\\${1:-run}\" # 'run' (issue) or 'renew'\nCREDS_FILE=\"\\$(dirname \"\\$0\")/dns-credentials.env\"\n\nif [ ! -f \"\\$CREDS_FILE\" ]; then\n echo \"Missing \\$CREDS_FILE — add your DNS-provider API credentials (see header).\" >&2\n exit 1\nfi\n\nEXTRA=\"\"\nif [ \"\\$ACTION\" = \"renew\" ]; then EXTRA=\"--days 30\"; fi\n\n# lego writes to /etc/lego/certificates/_.${domain}.crt (+ .key) — the paths the host nginx uses.\n# NOTE: we do NOT pass lego's --renew-hook 'nginx -s reload' — that would run INSIDE the lego\n# container, where nginx is absent. We reload the host nginx ourselves after the run below.\nsudo docker run --rm \\\\\n -v /etc/lego:/etc/lego \\\\\n --env-file \"\\$CREDS_FILE\" \\\\\n ${'goacme/lego:v4.21.0'} \\\\\n --email \"\\$EMAIL\" \\\\\n --dns \"\\$PROVIDER\" \\\\\n -d \"*.\\$DOMAIN\" -d \"\\$DOMAIN\" \\\\\n --path /etc/lego \\\\\n --accept-tos${caFlag} \\\\\n \\$ACTION \\$EXTRA\n\n# Reload the host nginx so it serves the new cert (idempotent; safe to run on issue + renew).\necho \"Reloading host nginx...\"\nsudo nginx -s reload || echo \"Could not reload nginx — do it manually: sudo nginx -s reload\"\necho \"Done: /etc/lego/certificates/_.\\${DOMAIN}.crt\"\n`;\n}\n","import crypto from 'node:crypto';\n\nexport function randomHex(bytes: number): string {\n return crypto.randomBytes(bytes).toString('hex');\n}\n\nexport function generateSecrets() {\n return {\n logtoDbPassword: randomHex(16),\n platformDbPassword: randomHex(16),\n encryptionKey: randomHex(32),\n logtoM2mAppSecret: randomHex(32),\n clickhousePassword: randomHex(16),\n };\n}\n","import type { CreateOptions } from '../types.js';\nimport { generateSecrets } from '../utils/crypto.js';\nimport { SYSTEM_APP_LOGTO_IDS } from '@habeetat/sdk-core/constants';\n\nexport function generateEnvFile(opts: CreateOptions): string {\n const protocol = opts.ssl ? 'https' : 'http';\n const domain = opts.domain;\n const secrets = generateSecrets();\n const tenantSlug = opts.organizationName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'platform';\n\n return `# Habeetat Platform - Environment Configuration\n# Generated by @habeetat/cli on ${new Date().toISOString()}\n\n# ============================================\n# Domain Configuration\n# ============================================\nDOMAIN=${domain}\nPROTOCOL=${protocol}\n\n# ============================================\n# Service URLs (External - Browser-facing)\n# ============================================\nLOGTO_ENDPOINT=${protocol}://iam.${domain}\nLOGTO_ADMIN_ENDPOINT=${protocol}://iam-console.${domain}\nLAUNCHER_URL=${protocol}://launcher.${domain}\nORG_MANAGER_URL=${protocol}://organization-manager.${domain}\nPLATFORM_MANAGER_URL=${protocol}://platform-manager.${domain}\nANALYTICS_URL=${protocol}://analytics.${domain}\nSAMPLE_CRM_URL=${protocol}://sample-crm.${domain}\nBACKEND_API_URL=${protocol}://api.${domain}\nCORS_ORIGINS=${protocol}://launcher.${domain},${protocol}://organization-manager.${domain},${protocol}://platform-manager.${domain},${protocol}://analytics.${domain},${protocol}://sample-crm.${domain}\n\n# ============================================\n# Database Configuration\n# ============================================\nLOGTO_DB_USER=logto\nLOGTO_DB_PASSWORD=${secrets.logtoDbPassword}\nLOGTO_DB_NAME=logto\n\nPLATFORM_DB_USER=habeetat\nPLATFORM_DB_PASSWORD=${secrets.platformDbPassword}\nPLATFORM_DB_NAME=habeetat_platform\n\n# ============================================\n# Logto IAM Configuration\n# ============================================\nLOGTO_ADMIN_USERNAME=${opts.adminEmail}\nLOGTO_ADMIN_PASSWORD=${opts.adminPassword}\n\nIAM_ISSUER_URL=${protocol}://iam.${domain}/oidc\nIAM_AUDIENCE=${protocol}://api.${domain}/api\nSDK_API_RESOURCE=${protocol}://api.${domain}/api\n\nLOGTO_M2M_APP_ID=${SYSTEM_APP_LOGTO_IDS.m2m}\nLOGTO_M2M_APP_SECRET=${secrets.logtoM2mAppSecret}\n\n# ============================================\n# Platform Configuration\n# ============================================\nPLATFORM_ADMIN_EMAIL=${opts.adminEmail}\nPLATFORM_ADMIN_PASSWORD=${opts.adminPassword}\nORGANIZATION_NAME=${opts.organizationName}\n\n# Seed inputs (consumed by prisma/seed.ts so the DB reflects the chosen org/admin)\nNHP_DEFAULT_TENANT_NAME=${opts.organizationName}\nNHP_DEFAULT_TENANT_SLUG=${tenantSlug}\nNHP_PLATFORM_ADMIN_EMAIL=${opts.adminEmail}\n\n# ============================================\n# Security\n# ============================================\nENCRYPTION_KEY=${secrets.encryptionKey}\n\n# ============================================\n# CORS Configuration\n# ============================================\nALLOWED_ORIGINS=${protocol}://iam-console.${domain},${protocol}://launcher.${domain},${protocol}://organization-manager.${domain},${protocol}://platform-manager.${domain},${protocol}://analytics.${domain}\nCORS_ALLOWED_ORIGINS=${protocol}://iam-console.${domain},${protocol}://launcher.${domain},${protocol}://organization-manager.${domain},${protocol}://platform-manager.${domain},${protocol}://analytics.${domain}\n\n# ============================================\n# SigNoz / OpenTelemetry (Observability)\n# ============================================\nSIGNOZ_URL=${protocol}://logs.${domain}\nOTEL_COLLECTOR_ENDPOINT=http://otel-collector:4317\nCLICKHOUSE_PASSWORD=${secrets.clickhousePassword}\n`;\n}\n","import chalk from 'chalk';\n\nconst prefix = chalk.cyan('[habeetat]');\n\nexport const logger = {\n info: (msg: string) => console.log(`${prefix} ${msg}`),\n success: (msg: string) => console.log(`${prefix} ${chalk.green('✓')} ${msg}`),\n warn: (msg: string) => console.log(`${prefix} ${chalk.yellow('⚠')} ${msg}`),\n error: (msg: string) => console.error(`${prefix} ${chalk.red('✗')} ${msg}`),\n phase: (msg: string) => {\n console.log('');\n console.log(chalk.cyan('═'.repeat(56)));\n console.log(chalk.cyan(` ${msg}`));\n console.log(chalk.cyan('═'.repeat(56)));\n console.log('');\n },\n banner: () => {\n console.log('');\n console.log(chalk.cyan('╔══════════════════════════════════════════════╗'));\n console.log(chalk.cyan('║ ║'));\n console.log(chalk.cyan('║ Habeetat Platform CLI ║'));\n console.log(chalk.cyan('║ ║'));\n console.log(chalk.cyan('╚══════════════════════════════════════════════╝'));\n console.log('');\n },\n};\n","import { execaCommand } from 'execa';\nimport { logger } from './logger.js';\n\nexport async function checkDocker(): Promise<boolean> {\n try {\n const { stdout } = await execaCommand('docker --version');\n const match = stdout.match(/Docker version (\\d+)/);\n if (match && parseInt(match[1], 10) >= 20) {\n return true;\n }\n logger.error(`Docker >= 20.0 required. Found: ${stdout.trim()}`);\n return false;\n } catch {\n logger.error('Docker is not installed or not in PATH');\n logger.info('Install Docker: https://docs.docker.com/get-docker/');\n return false;\n }\n}\n\nexport async function checkDockerCompose(): Promise<boolean> {\n try {\n await execaCommand('docker compose version');\n return true;\n } catch {\n logger.error('Docker Compose V2 is not available');\n logger.info('Docker Compose V2 is included with Docker Desktop');\n return false;\n }\n}\n\nexport async function checkPrerequisites(): Promise<boolean> {\n const docker = await checkDocker();\n const compose = await checkDockerCompose();\n return docker && compose;\n}\n\nexport interface ComposeExecOptions {\n cwd: string;\n composeFile?: string;\n silent?: boolean;\n}\n\nexport async function composeUp(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} up -d`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeDown(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} down`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeDestroy(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} down -v --remove-orphans`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composePs(opts: ComposeExecOptions): Promise<string> {\n const file = opts.composeFile || 'docker-compose.yml';\n const { stdout } = await execaCommand(`docker compose -f ${file} ps`, {\n cwd: opts.cwd,\n });\n return stdout;\n}\n\nexport async function composeLogs(\n opts: ComposeExecOptions & { service?: string; follow?: boolean; tail?: number },\n): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n const parts = ['docker', 'compose', '-f', file, 'logs'];\n if (opts.follow) parts.push('-f');\n if (opts.tail) parts.push('--tail', String(opts.tail));\n if (opts.service) parts.push(opts.service);\n\n await execaCommand(parts.join(' '), {\n cwd: opts.cwd,\n stdio: 'inherit',\n });\n}\n\nexport async function composeRestart(\n opts: ComposeExecOptions & { service?: string },\n): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n const cmd = opts.service\n ? `docker compose -f ${file} restart ${opts.service}`\n : `docker compose -f ${file} restart`;\n\n await execaCommand(cmd, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeExec(\n opts: ComposeExecOptions & { service: string; command: string },\n): Promise<string> {\n const file = opts.composeFile || 'docker-compose.yml';\n const { stdout } = await execaCommand(\n `docker compose -f ${file} exec -T ${opts.service} ${opts.command}`,\n { cwd: opts.cwd },\n );\n return stdout;\n}\n\nexport async function dockerPull(image: string): Promise<void> {\n await execaCommand(`docker pull ${image}`, { stdio: 'inherit' });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { CONFIG_FILE } from '../constants.js';\nimport type { HabeetatConfig } from '../types.js';\n\nexport function findProjectRoot(startDir: string = process.cwd()): string | null {\n let dir = startDir;\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, CONFIG_FILE))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n return null;\n}\n\nexport function loadConfig(projectDir?: string): HabeetatConfig {\n const dir = projectDir || findProjectRoot();\n if (!dir) {\n throw new Error(\n `Could not find ${CONFIG_FILE}. Are you inside a Habeetat project directory?`,\n );\n }\n const configPath = path.join(dir, CONFIG_FILE);\n const raw = fs.readFileSync(configPath, 'utf-8');\n return JSON.parse(raw) as HabeetatConfig;\n}\n\nexport function saveConfig(config: HabeetatConfig, projectDir: string): void {\n const configPath = path.join(projectDir, CONFIG_FILE);\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\nexport function getProjectDir(): string {\n const dir = findProjectRoot();\n if (!dir) {\n throw new Error(\n `Could not find ${CONFIG_FILE}. Are you inside a Habeetat project directory?`,\n );\n }\n return dir;\n}\n","// Logto IAM bootstrap seed script — embedded for scaffolding\n// This is the content of scripts/nhp-seed-logto-bootstrap.mjs\n// It runs inside a temporary Node container on the Docker network\n\nexport function getBootstrapScript(): string {\n return `#!/usr/bin/env node\nimport crypto from 'node:crypto';\n\nimport { argon2i } from 'hash-wasm';\nimport { customAlphabet } from 'nanoid';\nimport { Pool } from 'pg';\n\nconst alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\nconst shortId = customAlphabet(alphabet, 12);\nconst longId = customAlphabet(alphabet, 21);\n\nconst connectionString =\n process.env.NHP_LOGTO_DB_URL ?? 'postgres://logto:logto@localhost:5434/logto';\n\nconst pool = new Pool({ connectionString });\n\nconst log = (message) => console.log(\\`[NHP][iam-seed] \\${message}\\`);\nconst json = (value) => JSON.stringify(value ?? {});\n\nasync function hashPassword(password) {\n return argon2i({\n password,\n salt: crypto.randomBytes(16),\n iterations: 256,\n parallelism: 1,\n memorySize: 4096,\n hashLength: 32,\n outputType: 'encoded',\n });\n}\n\nasync function ensureOrganization({ tenantId, id, name, description, customData }) {\n const orgId = id ?? longId();\n const { rows } = await pool.query(\n \\`insert into organizations (tenant_id, id, name, description, custom_data)\n values ($1, $2, $3, $4, $5::jsonb)\n on conflict (id) do update\n set tenant_id = excluded.tenant_id,\n name = excluded.name,\n description = excluded.description,\n custom_data = excluded.custom_data\n returning id\\`,\n [tenantId, orgId, name, description ?? name, json(customData)]\n );\n return rows[0].id;\n}\n\nasync function ensureOrganizationMembership({ tenantId, organizationId, userId }) {\n await pool.query(\n \\`insert into organization_user_relations (tenant_id, organization_id, user_id)\n values ($1, $2, $3)\n on conflict (tenant_id, organization_id, user_id) do nothing\\`,\n [tenantId, organizationId, userId]\n );\n}\n\nasync function ensureOrganizationRole({ tenantId, id, name, description }) {\n const roleId = id ?? longId();\n const { rows } = await pool.query(\n \\`insert into organization_roles (tenant_id, id, name, description)\n values ($1, $2, $3, $4)\n on conflict (id) do update\n set tenant_id = excluded.tenant_id,\n name = excluded.name,\n description = excluded.description\n returning id\\`,\n [tenantId, roleId, name, description ?? name]\n );\n return rows[0].id;\n}\n\nasync function ensureOrganizationRoleAssignment({ tenantId, organizationId, organizationRoleId, userId }) {\n await pool.query(\n \\`insert into organization_role_user_relations (tenant_id, organization_id, organization_role_id, user_id)\n values ($1, $2, $3, $4)\n on conflict (tenant_id, organization_id, organization_role_id, user_id) do nothing\\`,\n [tenantId, organizationId, organizationRoleId, userId]\n );\n}\n\n// Grant a resource scope (resolved by name) to an organization role, so members with that\n// role receive the scope in their organization-scoped API token (refresh-grant). The platform\n// API token scope is coarse (nhp:all); fine-grained authorization stays in the platform DB.\nasync function ensureOrganizationRoleResourceScope({ tenantId, organizationRoleId, scopeName }) {\n await pool.query(\n \\`insert into organization_role_resource_scope_relations (tenant_id, organization_role_id, scope_id)\n select $1::text, $2::text, s.id from scopes s where s.tenant_id = $1::text and s.name = $3::text limit 1\n on conflict do nothing\\`,\n [tenantId, organizationRoleId, scopeName]\n );\n}\n\nasync function ensureUser({ tenantId, username, email, password, displayName, customData, preferredId }) {\n let existingId;\n\n if (preferredId) {\n const byId = await pool.query('select id from users where id = $1 limit 1', [preferredId]);\n if (byId.rows.length > 0) existingId = byId.rows[0].id;\n }\n\n if (!existingId) {\n const byTenant = await pool.query(\n 'select id from users where tenant_id = $1 and (username = $2 or primary_email = $3) limit 1',\n [tenantId, username, email]\n );\n if (byTenant.rows.length > 0) existingId = byTenant.rows[0].id;\n }\n\n const passwordEncrypted = await hashPassword(password);\n const targetId = existingId ?? preferredId ?? shortId();\n\n if (existingId) {\n await pool.query(\n \\`update users\n set tenant_id = $1, username = $3, primary_email = $4,\n password_encrypted = $5, password_encryption_method = 'Argon2i',\n name = $6, custom_data = $7::jsonb\n where id = $2\\`,\n [tenantId, targetId, username, email, passwordEncrypted, displayName ?? username, json(customData)]\n );\n return targetId;\n }\n\n await pool.query(\n \\`insert into users (\n tenant_id, id, username, primary_email, password_encrypted, password_encryption_method,\n name, is_suspended, custom_data, profile, identities, logto_config, mfa_verifications\n ) values (\n $1, $2, $3, $4, $5, 'Argon2i', $6, false,\n $7::jsonb, '{}'::jsonb, '{}'::jsonb, '{}'::jsonb, '[]'::jsonb\n )\\`,\n [tenantId, targetId, username, email, passwordEncrypted, displayName ?? username, json(customData)]\n );\n return targetId;\n}\n\nasync function ensureAdminConsoleInitialized(tenantId) {\n const payload = { organizationCreated: true, signInExperienceCustomized: true };\n await pool.query(\n \\`insert into logto_configs (tenant_id, key, value)\n values ($1, 'adminConsole', $2::jsonb)\n on conflict (tenant_id, key) do update set value = excluded.value\\`,\n [tenantId, json(payload)]\n );\n}\n\nasync function ensureAdminTenantSignInMode() {\n await pool.query(\\`update sign_in_experiences set sign_in_mode = 'SignIn' where tenant_id = 'admin'\\`);\n log('Configured admin tenant sign-in mode.');\n}\n\nasync function ensureDefaultTenantSignInExperience() {\n await pool.query(\n \\`update sign_in_experiences\n set sign_in_mode = 'SignInAndRegister',\n sign_in = jsonb_build_object(\n 'methods', jsonb_build_array(\n jsonb_build_object('identifier', 'username', 'password', true, 'verificationCode', false, 'isPasswordPrimary', true),\n jsonb_build_object('identifier', 'email', 'password', true, 'verificationCode', false, 'isPasswordPrimary', true)\n )\n ),\n sign_up = jsonb_build_object(\n 'identifiers', jsonb_build_array('username'),\n 'password', true,\n 'verify', false\n )\n where tenant_id = 'default'\\`\n );\n log('Configured default tenant sign-in experience.');\n}\n\nasync function ensureAdminAccountViaApi() {\n const username = process.env.NHP_PLATFORM_ADMIN_USERNAME ?? 'admin';\n const password = process.env.NHP_PLATFORM_ADMIN_PASSWORD ?? 'Habeetat_01';\n\n const { rows } = await pool.query(\n \\`select id from users where tenant_id = 'admin' and username = $1 limit 1\\`,\n [username]\n );\n\n const passwordEncrypted = await hashPassword(password);\n let adminUserId;\n\n if (rows.length === 0) {\n adminUserId = shortId();\n await pool.query(\n \\`INSERT INTO users (\n tenant_id, id, username, password_encrypted, password_encryption_method,\n name, is_suspended, custom_data, profile, identities, logto_config, mfa_verifications\n ) VALUES (\n 'admin', $1, $2, $3, 'Argon2i',\n $2, false, '{}'::jsonb, '{}'::jsonb, '{}'::jsonb, '{}'::jsonb, '[]'::jsonb\n )\\`,\n [adminUserId, username, passwordEncrypted]\n );\n log(\\`Created admin user via SQL (username: \\${username}, id: \\${adminUserId}).\\`);\n } else {\n adminUserId = rows[0].id;\n await pool.query(\n \\`UPDATE users SET password_encrypted = $1, password_encryption_method = 'Argon2i' WHERE id = $2\\`,\n [passwordEncrypted, adminUserId]\n );\n log(\\`Updated password for admin user \\${username} (id: \\${adminUserId}).\\`);\n }\n\n await pool.query(\n \\`INSERT INTO organization_user_relations (tenant_id, organization_id, user_id)\n VALUES ('admin', 't-default', $1) ON CONFLICT DO NOTHING\\`,\n [adminUserId]\n );\n\n await pool.query(\n \\`INSERT INTO organization_role_user_relations (tenant_id, organization_id, organization_role_id, user_id)\n VALUES ('admin', 't-default', 'admin', $1) ON CONFLICT DO NOTHING\\`,\n [adminUserId]\n );\n\n const { rows: allRoles } = await pool.query(\n \\`SELECT id FROM roles WHERE tenant_id = 'admin' AND type = 'User'\\`\n );\n\n for (const role of allRoles) {\n await pool.query(\n \\`INSERT INTO users_roles (tenant_id, id, user_id, role_id)\n VALUES ('admin', $1, $2, $3) ON CONFLICT (tenant_id, user_id, role_id) DO NOTHING\\`,\n [longId(), adminUserId, role.id]\n );\n }\n\n log('Admin account bootstrap via SQL completed.');\n}\n\nasync function main() {\n log('Starting IAM bootstrap seed...');\n\n const platformAdminUsername = process.env.NHP_PLATFORM_ADMIN_USERNAME ?? 'admin';\n const platformAdminEmail = process.env.NHP_PLATFORM_ADMIN_EMAIL ?? 'admin@habeetat.local';\n const platformAdminPassword = process.env.NHP_PLATFORM_ADMIN_PASSWORD ?? 'Habeetat_01';\n const platformAdminDisplayName = process.env.NHP_PLATFORM_ADMIN_DISPLAY_NAME ?? 'Platform Admin';\n const defaultTenantName = process.env.NHP_DEFAULT_TENANT_NAME ?? 'Default';\n const defaultTenantSlug = process.env.NHP_DEFAULT_TENANT_SLUG ?? 'default';\n\n const habeetatAdminOrgId = await ensureOrganization({\n tenantId: 'default',\n id: 'org_habeetat_admin',\n name: 'Habeetat Admin',\n description: 'Internal organization for Habeetat platform administrators',\n customData: { slug: 'habeetat-admin', type: 'internal' },\n });\n\n const defaultTenantOrgId = await ensureOrganization({\n tenantId: 'default',\n id: \\`org_\\${defaultTenantSlug}\\`,\n name: defaultTenantName,\n description: \\`Tenant organization: \\${defaultTenantName}\\`,\n customData: { slug: defaultTenantSlug, type: 'tenant' },\n });\n\n log(\\`Organizations ensured: Habeetat Admin (\\${habeetatAdminOrgId}), \\${defaultTenantName} (\\${defaultTenantOrgId})\\`);\n\n const orgTenantAdminRoleId = await ensureOrganizationRole({\n tenantId: 'default', id: 'org_role_tenant_admin', name: 'TENANT_ADMIN',\n description: 'Tenant administrator with full access to organization management',\n });\n\n const orgTenantUserRoleId = await ensureOrganizationRole({\n tenantId: 'default', id: 'org_role_tenant_user', name: 'TENANT_USER',\n description: 'Regular tenant user with launcher access',\n });\n\n const orgPlatformAdminRoleId = await ensureOrganizationRole({\n tenantId: 'default', id: 'org_role_plat_adm', name: 'PLATFORM_ADMIN',\n description: 'Platform administrator with access to Platform Manager',\n });\n\n log(\\`Organization roles ensured: TENANT_ADMIN=\\${orgTenantAdminRoleId}, TENANT_USER=\\${orgTenantUserRoleId}, PLATFORM_ADMIN=\\${orgPlatformAdminRoleId}\\`);\n\n // Organization-scoped API access: TENANT_ADMIN/TENANT_USER org roles carry the platform API\n // scope (nhp:all) so org-scoped tokens can call the API. Required for the org-scoped-identity\n // model — without it, refresh-grant org tokens would have no scope on the platform API.\n await ensureOrganizationRoleResourceScope({ tenantId: 'default', organizationRoleId: orgTenantAdminRoleId, scopeName: 'nhp:all' });\n await ensureOrganizationRoleResourceScope({ tenantId: 'default', organizationRoleId: orgTenantUserRoleId, scopeName: 'nhp:all' });\n log('Assigned nhp:all to TENANT_ADMIN/TENANT_USER organization roles (org-scoped API access)');\n\n await ensureAdminConsoleInitialized('default');\n await ensureAdminConsoleInitialized('admin');\n await ensureAdminTenantSignInMode();\n await ensureDefaultTenantSignInExperience();\n await ensureAdminAccountViaApi();\n\n const platformAdminUserId = await ensureUser({\n tenantId: 'default',\n preferredId: 'usr_admin01',\n username: platformAdminUsername,\n email: platformAdminEmail,\n password: platformAdminPassword,\n displayName: platformAdminDisplayName,\n customData: { tenantSlug: defaultTenantSlug },\n });\n\n await ensureOrganizationMembership({ tenantId: 'default', organizationId: habeetatAdminOrgId, userId: platformAdminUserId });\n await ensureOrganizationMembership({ tenantId: 'default', organizationId: defaultTenantOrgId, userId: platformAdminUserId });\n\n await ensureOrganizationRoleAssignment({ tenantId: 'default', organizationId: defaultTenantOrgId, organizationRoleId: orgTenantAdminRoleId, userId: platformAdminUserId });\n await ensureOrganizationRoleAssignment({ tenantId: 'default', organizationId: defaultTenantOrgId, organizationRoleId: orgTenantUserRoleId, userId: platformAdminUserId });\n await ensureOrganizationRoleAssignment({ tenantId: 'default', organizationId: habeetatAdminOrgId, organizationRoleId: orgPlatformAdminRoleId, userId: platformAdminUserId });\n\n log(\\`Ensured user \\${platformAdminUsername} (\\${platformAdminEmail}, id: \\${platformAdminUserId})\\`);\n log('IAM bootstrap seed completed successfully.');\n}\n\nmain()\n .catch((error) => {\n console.error('[NHP][iam-seed] Failed:', error);\n process.exitCode = 1;\n })\n .finally(async () => {\n await pool.end();\n });\n`;\n}\n","/**\n * Generates a ClickHouse config override for SigNoz compatibility.\n * - Forces IPv4-only listening (required on hosts with IPv6 disabled)\n * - Defines a single-node \"cluster\" (required by SigNoz schema migrator)\n * - Configures ZooKeeper connection (required for ON CLUSTER DDL)\n */\nexport function generateClickhouseConfig(): string {\n return `<!-- ClickHouse config override for Habeetat/SigNoz -->\n<clickhouse>\n <listen_host>0.0.0.0</listen_host>\n\n <remote_servers>\n <cluster>\n <shard>\n <replica>\n <host>clickhouse</host>\n <port>9000</port>\n </replica>\n </shard>\n </cluster>\n </remote_servers>\n\n <zookeeper>\n <node>\n <host>zookeeper</host>\n <port>2181</port>\n </node>\n </zookeeper>\n</clickhouse>\n`;\n}\n\n/**\n * Generates the OpenTelemetry Collector configuration for SigNoz.\n * DSN paths include database names (signoz_traces, signoz_logs, signoz_metrics).\n * docker_multi_node_cluster and low_cardinal_exception_grouping are read\n * from environment variables set on the otel-collector container.\n */\nexport function generateOtelCollectorConfig(): string {\n // Use literal $ so the YAML contains ${ENV_VAR} references (not JS interpolation)\n return `receivers:\n otlp:\n protocols:\n grpc:\n endpoint: 0.0.0.0:4317\n http:\n endpoint: 0.0.0.0:4318\n\nprocessors:\n batch:\n send_batch_size: 10000\n send_batch_max_size: 11000\n timeout: 10s\n resourcedetection:\n detectors: [env, system]\n timeout: 2s\n\nexporters:\n clickhousetraces:\n datasource: tcp://clickhouse:9000/signoz_traces\n docker_multi_node_cluster: \\${DOCKER_MULTI_NODE_CLUSTER}\n low_cardinal_exception_grouping: \\${LOW_CARDINAL_EXCEPTION_GROUPING}\n clickhousemetricswrite:\n endpoint: tcp://clickhouse:9000/signoz_metrics\n resource_to_telemetry_conversion:\n enabled: true\n clickhouselogsexporter:\n dsn: tcp://clickhouse:9000/signoz_logs\n docker_multi_node_cluster: \\${DOCKER_MULTI_NODE_CLUSTER}\n timeout: 10s\n\nextensions:\n health_check:\n endpoint: 0.0.0.0:13133\n\nservice:\n telemetry:\n metrics:\n address: 0.0.0.0:8888\n extensions:\n - health_check\n pipelines:\n traces:\n receivers: [otlp]\n processors: [batch]\n exporters: [clickhousetraces]\n metrics:\n receivers: [otlp]\n processors: [batch]\n exporters: [clickhousemetricswrite]\n logs:\n receivers: [otlp]\n processors: [batch]\n exporters: [clickhouselogsexporter]\n`;\n}\n\n/**\n * Generates the OpAMP manager configuration for the OTel collector.\n */\nexport function generateOtelCollectorOpampConfig(): string {\n return `server_endpoint: ws://signoz-query-service:4320/v1/opamp\n`;\n}\n"]}
1
+ {"version":3,"sources":["../src/constants.ts","../src/templates/docker-compose.ts","../src/templates/nginx.ts","../src/templates/host-nginx.ts","../src/templates/caddy.ts","../src/templates/lego-script.ts","../src/utils/crypto.ts","../src/templates/env.ts","../src/utils/logger.ts","../src/utils/docker.ts","../src/utils/config.ts","../src/templates/bootstrap-script.ts","../src/templates/otel-collector-config.ts"],"names":["SYSTEM_APP_LOGTO_IDS"],"mappings":"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","file":"index.mjs","sourcesContent":["export const CONFIG_FILE = 'habeetat.json';\nexport const ENV_FILE = '.env';\nexport const COMPOSE_FILE = 'docker-compose.yml';\n\nexport const DOCKER_REGISTRY = 'docker.io/capriisland';\n\nexport const IMAGES = {\n backend: 'capriisland/habeetat-backend',\n launcher: 'capriisland/habeetat-launcher',\n orgManager: 'capriisland/habeetat-org-manager',\n platformManager: 'capriisland/habeetat-platform-manager',\n analytics: 'capriisland/habeetat-analytics',\n sampleCrm: 'capriisland/habeetat-sample-crm',\n logtoConfig: 'capriisland/habeetat-logto-config',\n} as const;\n\nexport const THIRD_PARTY_IMAGES = {\n postgres: 'postgres:15-alpine',\n logto: 'svhd/logto:1.33',\n nginx: 'nginx:1.25-alpine',\n caddy: 'caddy:2-alpine',\n certbot: 'certbot/certbot',\n lego: 'goacme/lego:v4.21.0',\n zookeeper: 'zookeeper:3.7',\n clickhouse: 'clickhouse/clickhouse-server:24.1.2-alpine',\n signozSchemaMigrator: 'signoz/signoz-schema-migrator:0.88.22',\n signozOtelCollector: 'signoz/signoz-otel-collector:0.88.22',\n signozQuery: 'signoz/query-service:0.45.0',\n signozFrontend: 'signoz/frontend:0.45.0',\n} as const;\n\nexport const DEFAULT_PORTS = {\n http: 80,\n https: 443,\n hostNginx: 8080,\n} as const;\n\nexport const SERVICES = [\n 'logto-db',\n 'platform-db',\n 'logto-core',\n 'backend',\n 'launcher',\n 'organization-manager',\n 'platform-manager',\n 'analytics',\n 'sample-crm',\n 'nginx',\n 'zookeeper',\n 'clickhouse',\n 'otel-collector-migrator',\n 'otel-collector',\n 'signoz-query-service',\n 'signoz-frontend',\n] as const;\n\nexport type ServiceName = (typeof SERVICES)[number];\n","import type { HabeetatConfig } from '../types.js';\nimport { THIRD_PARTY_IMAGES } from '../constants.js';\nimport { SYSTEM_APP_LOGTO_IDS } from '@habeetat/sdk-core/constants';\n\nexport function generateDockerCompose(config: HabeetatConfig): string {\n const tag = config.docker.imageTag;\n const registry = config.docker.registry;\n\n const services: Record<string, unknown> = {\n 'logto-db': {\n image: THIRD_PARTY_IMAGES.postgres,\n environment: {\n POSTGRES_USER: '${LOGTO_DB_USER}',\n POSTGRES_PASSWORD: '${LOGTO_DB_PASSWORD}',\n POSTGRES_DB: '${LOGTO_DB_NAME}',\n },\n volumes: ['logto-db-data:/var/lib/postgresql/data'],\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'pg_isready -U ${LOGTO_DB_USER} -d ${LOGTO_DB_NAME}'],\n interval: '5s',\n timeout: '3s',\n retries: 10,\n },\n },\n\n 'platform-db': {\n image: THIRD_PARTY_IMAGES.postgres,\n environment: {\n POSTGRES_USER: '${PLATFORM_DB_USER}',\n POSTGRES_PASSWORD: '${PLATFORM_DB_PASSWORD}',\n POSTGRES_DB: '${PLATFORM_DB_NAME}',\n },\n volumes: ['platform-db-data:/var/lib/postgresql/data'],\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'pg_isready -U ${PLATFORM_DB_USER} -d ${PLATFORM_DB_NAME}'],\n interval: '5s',\n timeout: '3s',\n retries: 10,\n },\n },\n\n 'logto-core': {\n image: THIRD_PARTY_IMAGES.logto,\n entrypoint: ['sh', '-c'],\n command: ['npm run cli -- db seed -- --swe && npm run start || npm run start'],\n depends_on: {\n 'logto-db': { condition: 'service_healthy' },\n },\n environment: {\n DB_URL: 'postgres://${LOGTO_DB_USER}:${LOGTO_DB_PASSWORD}@logto-db:5432/${LOGTO_DB_NAME}',\n ENDPOINT: '${LOGTO_ENDPOINT}',\n ADMIN_ENDPOINT: '${LOGTO_ADMIN_ENDPOINT}',\n ADMIN_CONSOLE_URL: '${LOGTO_ADMIN_ENDPOINT}',\n ADMIN_PORT: '3002',\n TRUST_PROXY_HEADER: '1',\n COOKIE_KEYS: '${ENCRYPTION_KEY}',\n ALLOWED_ORIGINS: '${LOGTO_ENDPOINT},${LOGTO_ADMIN_ENDPOINT},${LAUNCHER_URL},${ORG_MANAGER_URL},${PLATFORM_MANAGER_URL},${ANALYTICS_URL},${SAMPLE_CRM_URL},${BACKEND_API_URL}',\n CORS_ALLOWED_ORIGINS: '${LOGTO_ENDPOINT},${LOGTO_ADMIN_ENDPOINT},${LAUNCHER_URL},${ORG_MANAGER_URL},${PLATFORM_MANAGER_URL},${ANALYTICS_URL},${SAMPLE_CRM_URL},${BACKEND_API_URL}',\n ADMIN_CONSOLE_ALLOWED_ORIGINS: '${LOGTO_ADMIN_ENDPOINT}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'wget -q --spider http://localhost:3001/oidc/.well-known/openid-configuration || exit 1'],\n interval: '10s',\n timeout: '5s',\n retries: 15,\n start_period: '150s',\n },\n },\n\n backend: {\n image: `${registry}/habeetat-backend:${tag}`,\n depends_on: {\n 'logto-core': { condition: 'service_healthy' },\n 'platform-db': { condition: 'service_healthy' },\n },\n environment: {\n NODE_ENV: 'production',\n DATABASE_URL: 'postgres://${PLATFORM_DB_USER}:${PLATFORM_DB_PASSWORD}@platform-db:5432/${PLATFORM_DB_NAME}',\n IAM_ISSUER_URL: '${LOGTO_ENDPOINT}/oidc',\n IAM_JWKS_URL: 'http://logto-core:3001',\n IAM_AUDIENCE: '${IAM_AUDIENCE}',\n LOGTO_ENDPOINT: 'http://logto-core:3001',\n LOGTO_EXTERNAL_ENDPOINT: '${LOGTO_ENDPOINT}',\n SDK_API_RESOURCE: '${IAM_AUDIENCE}',\n BACKEND_API_URL: '${BACKEND_API_URL}',\n LOGTO_M2M_APP_ID: SYSTEM_APP_LOGTO_IDS.m2m,\n LOGTO_M2M_APP_SECRET: '${LOGTO_M2M_APP_SECRET}',\n ENCRYPTION_KEY: '${ENCRYPTION_KEY}',\n LAUNCHER_URL: '${LAUNCHER_URL}',\n ORG_MANAGER_URL: '${ORG_MANAGER_URL}',\n PLATFORM_MANAGER_URL: '${PLATFORM_MANAGER_URL}',\n ANALYTICS_URL: '${ANALYTICS_URL}',\n SIGNOZ_URL: '${SIGNOZ_URL}',\n DOMAIN: '${DOMAIN}',\n NHP_DEFAULT_TENANT_NAME: '${NHP_DEFAULT_TENANT_NAME}',\n NHP_DEFAULT_TENANT_SLUG: '${NHP_DEFAULT_TENANT_SLUG}',\n NHP_PLATFORM_ADMIN_EMAIL: '${NHP_PLATFORM_ADMIN_EMAIL}',\n CORS_ORIGINS: '${CORS_ORIGINS}',\n ...(config.services.signoz && {\n OTEL_COLLECTOR_ENDPOINT: '${OTEL_COLLECTOR_ENDPOINT}',\n CLICKHOUSE_URL: 'http://clickhouse:8123',\n }),\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD', 'curl', '-f', 'http://localhost:3001/platform/status'],\n interval: '30s',\n timeout: '10s',\n retries: 3,\n start_period: '60s',\n },\n },\n };\n\n if (config.services.launcher) {\n services['launcher'] = {\n image: `${registry}/habeetat-launcher:${tag}`,\n depends_on: ['backend'],\n environment: {\n VITE_IAM_LOGTO_ENDPOINT: '${LOGTO_ENDPOINT}',\n VITE_IAM_AUDIENCE: '${IAM_AUDIENCE}',\n VITE_IAM_APP_ID: SYSTEM_APP_LOGTO_IDS.launcher,\n VITE_APP_BASE_URL: '${LAUNCHER_URL}',\n VITE_PLATFORM_API_URL: '${BACKEND_API_URL}',\n // Platform domain so the launcher can resolve the tenant slug from `<slug>.<domain>`\n // and build tenant subdomain origins (org-onboarding).\n VITE_PLATFORM_DOMAIN: '${DOMAIN}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n if (config.services.organizationManager) {\n services['organization-manager'] = {\n image: `${registry}/habeetat-org-manager:${tag}`,\n depends_on: ['backend'],\n environment: {\n VITE_LOGTO_ENDPOINT: '${LOGTO_ENDPOINT}',\n VITE_LOGTO_APP_ID: SYSTEM_APP_LOGTO_IDS.organizationManager,\n VITE_LOGTO_API_RESOURCE: '${IAM_AUDIENCE}',\n VITE_APP_BASE_URL: '${ORG_MANAGER_URL}',\n VITE_BACKEND_API_URL: '${BACKEND_API_URL}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n if (config.services.platformManager) {\n services['platform-manager'] = {\n image: `${registry}/habeetat-platform-manager:${tag}`,\n depends_on: ['backend'],\n environment: {\n VITE_LOGTO_ENDPOINT: '${LOGTO_ENDPOINT}',\n VITE_LOGTO_APP_ID: SYSTEM_APP_LOGTO_IDS.platformManager,\n VITE_LOGTO_API_RESOURCE: '${IAM_AUDIENCE}',\n VITE_APP_BASE_URL: '${PLATFORM_MANAGER_URL}',\n VITE_BACKEND_API_URL: '${BACKEND_API_URL}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n if (config.services.analytics) {\n services['analytics'] = {\n image: `${registry}/habeetat-analytics:${tag}`,\n depends_on: ['backend'],\n environment: {\n VITE_LOGTO_ENDPOINT: '${LOGTO_ENDPOINT}',\n VITE_LOGTO_APP_ID: SYSTEM_APP_LOGTO_IDS.analytics,\n VITE_LOGTO_API_RESOURCE: '${IAM_AUDIENCE}',\n VITE_APP_BASE_URL: '${ANALYTICS_URL}',\n VITE_BACKEND_API_URL: '${BACKEND_API_URL}',\n VITE_LAUNCHER_URL: '${LAUNCHER_URL}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n if (config.services.sampleCrm) {\n services['sample-crm'] = {\n image: `${registry}/habeetat-sample-crm:${tag}`,\n depends_on: ['backend'],\n environment: {\n VITE_LOGTO_ENDPOINT: '${LOGTO_ENDPOINT}',\n VITE_LOGTO_API_RESOURCE: '${IAM_AUDIENCE}',\n VITE_PLATFORM_API_URL: '${BACKEND_API_URL}',\n VITE_APP_BASE_URL: '${SAMPLE_CRM_URL}',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n // SigNoz observability stack (ZooKeeper + ClickHouse + Schema Migrator + OTel Collector + Query Service + Frontend)\n if (config.services.signoz) {\n services['zookeeper'] = {\n image: THIRD_PARTY_IMAGES.zookeeper,\n environment: {\n ZOO_4LW_COMMANDS_WHITELIST: 'ruok,srvr,mntr',\n ZOO_AUTOPURGE_INTERVAL: '1',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'echo ruok | nc localhost 2181 | grep imok'],\n interval: '10s',\n timeout: '5s',\n retries: 10,\n },\n };\n\n services['clickhouse'] = {\n image: THIRD_PARTY_IMAGES.clickhouse,\n depends_on: {\n zookeeper: { condition: 'service_healthy' },\n },\n volumes: [\n 'clickhouse-data:/var/lib/clickhouse',\n 'clickhouse-logs:/var/log/clickhouse-server',\n './signoz/clickhouse-config.xml:/etc/clickhouse-server/config.d/habeetat-listen.xml:ro',\n ],\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'clickhouse-client --host=127.0.0.1 --query=\"SELECT 1\" || exit 1'],\n interval: '10s',\n timeout: '5s',\n retries: 15,\n start_period: '60s',\n },\n };\n\n services['otel-collector-migrator'] = {\n image: THIRD_PARTY_IMAGES.signozSchemaMigrator,\n command: ['--dsn=tcp://clickhouse:9000'],\n depends_on: {\n clickhouse: { condition: 'service_healthy' },\n },\n environment: {\n DOCKER_MULTI_NODE_CLUSTER: 'false',\n },\n networks: ['habeetat-network'],\n };\n\n services['otel-collector'] = {\n image: THIRD_PARTY_IMAGES.signozOtelCollector,\n command: [\n '--config=/etc/otel-collector-config.yaml',\n '--manager-config=/etc/manager-config.yaml',\n '--copy-path=/var/tmp/collector-config.yaml',\n '--feature-gates=-pkg.translator.prometheus.NormalizeName',\n ],\n user: 'root',\n depends_on: {\n clickhouse: { condition: 'service_healthy' },\n 'otel-collector-migrator': { condition: 'service_completed_successfully' },\n 'signoz-query-service': { condition: 'service_healthy' },\n },\n volumes: [\n './signoz/otel-collector-config.yaml:/etc/otel-collector-config.yaml:ro',\n './signoz/otel-collector-opamp-config.yaml:/etc/manager-config.yaml:ro',\n ],\n environment: {\n OTEL_RESOURCE_ATTRIBUTES: 'host.name=signoz-host,os.type=linux',\n DOCKER_MULTI_NODE_CLUSTER: 'false',\n LOW_CARDINAL_EXCEPTION_GROUPING: 'false',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n\n services['signoz-query-service'] = {\n image: THIRD_PARTY_IMAGES.signozQuery,\n depends_on: {\n clickhouse: { condition: 'service_healthy' },\n },\n volumes: ['signoz-data:/var/lib/signoz'],\n environment: {\n ClickHouseUrl: 'tcp://clickhouse:9000',\n STORAGE: 'clickhouse',\n GODEBUG: 'netdns=go',\n SIGNOZ_LOCAL_DB_PATH: '/var/lib/signoz/signoz.db',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n healthcheck: {\n test: ['CMD-SHELL', 'wget -O- http://localhost:8080/api/v1/health 2>&1 | grep -q \"status\" || exit 1'],\n interval: '10s',\n timeout: '5s',\n retries: 15,\n start_period: '60s',\n },\n };\n\n services['signoz-frontend'] = {\n image: THIRD_PARTY_IMAGES.signozFrontend,\n depends_on: {\n 'signoz-query-service': { condition: 'service_healthy' },\n },\n environment: {\n FRONTEND_API_URL: 'http://signoz-query-service:8080',\n },\n networks: ['habeetat-network'],\n restart: 'unless-stopped',\n };\n }\n\n // Nginx reverse proxy (internal routing only — SSL handled by host nginx)\n const nginxDependsOn = ['logto-core', 'backend'];\n if (config.services.launcher) nginxDependsOn.push('launcher');\n if (config.services.organizationManager) nginxDependsOn.push('organization-manager');\n if (config.services.platformManager) nginxDependsOn.push('platform-manager');\n if (config.services.analytics) nginxDependsOn.push('analytics');\n if (config.services.sampleCrm) nginxDependsOn.push('sample-crm');\n if (config.services.signoz) {\n nginxDependsOn.push('signoz-frontend');\n nginxDependsOn.push('signoz-query-service');\n }\n\n const hostPort = config.nginx.hostPort;\n\n services['nginx'] = {\n image: THIRD_PARTY_IMAGES.nginx,\n depends_on: nginxDependsOn,\n volumes: ['./nginx/platform.conf:/etc/nginx/conf.d/default.conf:ro'],\n ports: [`127.0.0.1:${hostPort}:80`],\n // Network aliases so logto-core can resolve its own ENDPOINT / ADMIN_ENDPOINT\n // (iam.<domain> / iam-console.<domain>) to this reverse proxy from INSIDE the\n // docker network. Without this, Logto's Management API self-calls those URLs,\n // which resolve to 127.0.0.1:80 inside the container and fail — breaking M2M\n // auto-provisioning (vendor-app-onboarding §3). nginx then proxies them back to\n // logto-core (:3001 / :3002).\n // In on-demand TLS mode Caddy is the edge and owns the iam/iam-console aliases (for Logto's\n // HTTPS self-calls); otherwise nginx (the edge) owns them.\n networks:\n config.tls?.mode === 'on-demand'\n ? ['habeetat-network']\n : {\n 'habeetat-network': {\n aliases: [`iam.${config.platform.domain}`, `iam-console.${config.platform.domain}`],\n },\n },\n restart: 'unless-stopped',\n command: `/bin/sh -c 'while :; do sleep 6h & wait $\\${!}; nginx -s reload; done & nginx -g \"daemon off;\"'`,\n };\n\n // On-demand TLS (design D13): Caddy is the public edge terminator in front of the internal\n // nginx. It binds 80/443, serves the known service hosts with automatic HTTPS, and issues a\n // per-subdomain cert on demand for tenant subdomains (gated by /tenants/caddy-ask). Replaces\n // the host-nginx + certbot edge in this mode.\n if (config.tls?.mode === 'on-demand') {\n services['caddy'] = {\n image: THIRD_PARTY_IMAGES.caddy,\n // Wait for the backend to be healthy so the on-demand ask endpoint is ready before Caddy\n // accepts traffic (otherwise the first request for a new tenant SNI races startup).\n depends_on: {\n nginx: { condition: 'service_started' },\n backend: { condition: 'service_healthy' },\n },\n ports: ['80:80', '443:443', '443:443/udp'],\n volumes: [\n './caddy/Caddyfile:/etc/caddy/Caddyfile:ro',\n 'caddy-data:/data',\n 'caddy-config:/config',\n ],\n // Caddy is the TLS edge in this mode, so Logto's self-calls to its HTTPS ENDPOINT\n // (iam.<domain> / iam-console.<domain>) must resolve to Caddy from INSIDE the network.\n // (In other modes these aliases live on the nginx service.)\n networks: {\n 'habeetat-network': {\n aliases: [`iam.${config.platform.domain}`, `iam-console.${config.platform.domain}`],\n },\n },\n restart: 'unless-stopped',\n };\n }\n\n // Wildcard TLS mode (design D13): the host nginx is the 443 edge and lives OUTSIDE the docker\n // network, so the in-network nginx alias for iam./iam-console.<domain> (which listens only on\n // :80) cannot satisfy Logto's HTTPS self-calls to its own ENDPOINT/ADMIN_ENDPOINT. Those\n // self-calls happen on EVERY Management API request (getAdminTenantTokenValidationSet during\n // bearer-token auth) and need a 443 terminator — which the host nginx already is (lego cert).\n // Map those hostnames to the host gateway on logto-core so the self-calls reach the host nginx\n // instead of the :80-only container nginx. Without this, every /api/* request 500s with\n // `connect ECONNREFUSED <nginx-container>:443`, breaking platform-admin checks, vendor M2M\n // provisioning, org/role reads — anything that calls the Logto Management API.\n // (In on-demand mode Caddy is the in-network 443 edge and owns these aliases instead.)\n if (config.tls?.mode === 'wildcard') {\n (services['logto-core'] as { extra_hosts?: string[] }).extra_hosts = [\n `iam.${config.platform.domain}:host-gateway`,\n `iam-console.${config.platform.domain}:host-gateway`,\n ];\n }\n\n const compose = {\n name: 'habeetat',\n services,\n volumes: {\n 'logto-db-data': null,\n 'platform-db-data': null,\n ...(config.tls?.mode === 'on-demand' && {\n 'caddy-data': null,\n 'caddy-config': null,\n }),\n ...(config.services.signoz && {\n 'clickhouse-data': null,\n 'clickhouse-logs': null,\n 'signoz-data': null,\n }),\n },\n networks: {\n 'habeetat-network': {\n driver: 'bridge',\n },\n },\n };\n\n return toYaml(compose);\n}\n\n// Minimal YAML serializer — avoids adding a dependency for simple structure\nfunction toYaml(obj: unknown, indent = 0): string {\n const pad = ' '.repeat(indent);\n\n if (obj === null || obj === undefined) return '';\n if (typeof obj === 'string') {\n if (obj.includes('\\n') || obj.includes(\"'\") || obj.includes('\"') || obj.includes(':') || obj.includes('#') || obj.includes('{') || obj.includes('}') || obj.includes('$')) {\n return `'${obj.replace(/'/g, \"''\")}'`;\n }\n return obj;\n }\n if (typeof obj === 'number' || typeof obj === 'boolean') return String(obj);\n\n if (Array.isArray(obj)) {\n if (obj.length === 0) return '[]';\n // Check if all items are scalars\n const allScalar = obj.every(\n (item) => typeof item === 'string' || typeof item === 'number' || typeof item === 'boolean',\n );\n if (allScalar) {\n return obj\n .map((item) => `\\n${pad}- ${toYaml(item, indent + 2)}`)\n .join('');\n }\n return obj\n .map((item) => {\n const val = toYaml(item, indent + 2);\n if (typeof item === 'object' && item !== null && !Array.isArray(item)) {\n // Object inside array — inline the first key after the dash\n const lines = val.split('\\n').filter((l) => l.trim());\n if (lines.length > 0) {\n const first = lines[0].trimStart();\n const rest = lines.slice(1).map((l) => `${pad} ${l.trimStart()}`).join('\\n');\n return `\\n${pad}- ${first}${rest ? '\\n' + rest : ''}`;\n }\n }\n return `\\n${pad}- ${val}`;\n })\n .join('');\n }\n\n if (typeof obj === 'object') {\n const entries = Object.entries(obj as Record<string, unknown>);\n if (entries.length === 0) return '{}';\n return entries\n .map(([key, value]) => {\n if (value === null || value === undefined) return `${pad}${key}:`;\n if (typeof value === 'object' && !Array.isArray(value)) {\n const nested = toYaml(value, indent + 2);\n return `${pad}${key}:\\n${nested}`;\n }\n if (Array.isArray(value)) {\n const nested = toYaml(value, indent + 2);\n return `${pad}${key}:${nested}`;\n }\n return `${pad}${key}: ${toYaml(value, indent)}`;\n })\n .join('\\n');\n }\n\n return String(obj);\n}\n","import type { HabeetatConfig } from '../types.js';\n\nexport function generateNginxConf(config: HabeetatConfig): string {\n const domain = config.platform.domain;\n\n const upstreams = [\n 'upstream logto { server logto-core:3001; }',\n 'upstream logto_admin { server logto-core:3002; }',\n 'upstream api { server backend:3001; }',\n ];\n\n if (config.services.launcher) upstreams.push('upstream launcher { server launcher:80; }');\n if (config.services.organizationManager) upstreams.push('upstream organization-manager { server organization-manager:80; }');\n if (config.services.platformManager) upstreams.push('upstream platform-manager { server platform-manager:80; }');\n if (config.services.analytics) upstreams.push('upstream analytics { server analytics:80; }');\n if (config.services.sampleCrm) upstreams.push('upstream sample-crm { server sample-crm:80; }');\n if (config.services.signoz) {\n upstreams.push('upstream signoz_frontend { server signoz-frontend:3301; }');\n upstreams.push('upstream signoz_query { server signoz-query-service:8080; }');\n }\n\n const proto = config.platform.protocol;\n const proxyHeaders = `\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto ${proto};`;\n\n const serverBlocks: string[] = [];\n\n // Logto IAM\n serverBlocks.push(`\nserver {\n listen 80;\n server_name iam.${domain};\n location / {\n proxy_pass http://logto;${proxyHeaders}\n }\n}`);\n\n // Logto Admin Console\n serverBlocks.push(`\nserver {\n listen 80;\n server_name iam-console.${domain};\n location / {\n proxy_pass http://logto_admin;${proxyHeaders}\n }\n}`);\n\n // Backend API\n serverBlocks.push(`\nserver {\n listen 80;\n server_name api.${domain};\n location /webhooks/ {\n proxy_pass http://api;${proxyHeaders}\n }\n location / {\n limit_req zone=api_limit burst=20 nodelay;\n proxy_pass http://api;${proxyHeaders}\n }\n}`);\n\n // Apex domain. When the launcher is present, the apex is the public LANDING (org-onboarding\n // spec: \"public landing page on the main platform domain\") served at `/`. `/.well-known/` stays\n // on the backend for vendor config-discovery (GET /.well-known/habeetat); nginx matches the more\n // specific `/.well-known/` prefix before `/`, so discovery is never shadowed by the launcher.\n const apexLanding = config.services.launcher\n ? `\n location / {\n proxy_pass http://launcher;${proxyHeaders}\n }`\n : '';\n serverBlocks.push(`\nserver {\n listen 80;\n server_name ${domain};${apexLanding}\n location /.well-known/ {\n proxy_pass http://api;${proxyHeaders}\n }\n}`);\n\n // Launcher\n if (config.services.launcher) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name launcher.${domain};\n location / {\n proxy_pass http://launcher;${proxyHeaders}\n }\n}`);\n\n // Tenant subdomains `<slug>.${domain}` are served by the launcher (org-onboarding).\n // nginx matches exact server_name (iam./api./launcher./… above) BEFORE this leading\n // wildcard, so the platform service hosts are never shadowed by a tenant slug.\n serverBlocks.push(`\nserver {\n listen 80;\n server_name *.${domain};\n location / {\n proxy_pass http://launcher;${proxyHeaders}\n }\n}`);\n }\n\n // Organization Manager\n if (config.services.organizationManager) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name organization-manager.${domain};\n location / {\n proxy_pass http://organization-manager;${proxyHeaders}\n }\n}`);\n }\n\n // Platform Manager\n if (config.services.platformManager) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name platform-manager.${domain};\n location / {\n proxy_pass http://platform-manager;${proxyHeaders}\n }\n}`);\n }\n\n // Analytics\n if (config.services.analytics) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name analytics.${domain};\n location / {\n proxy_pass http://analytics;${proxyHeaders}\n }\n}`);\n }\n\n // Sample CRM\n if (config.services.sampleCrm) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name sample-crm.${domain};\n location / {\n proxy_pass http://sample-crm;${proxyHeaders}\n }\n}`);\n }\n\n // SigNoz Dashboard (frontend serves UI, query-service serves API)\n if (config.services.signoz) {\n serverBlocks.push(`\nserver {\n listen 80;\n server_name logs.${domain};\n location /api {\n proxy_pass http://signoz_query;${proxyHeaders}\n }\n location / {\n proxy_pass http://signoz_frontend;${proxyHeaders}\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"upgrade\";\n }\n}`);\n }\n\n return `# Habeetat Platform - Container Nginx Configuration\n# Auto-generated by @habeetat/cli for domain: ${domain}\n# This handles internal routing between Docker services.\n# SSL is handled by the host nginx (see /etc/nginx/sites-enabled/).\n\n${upstreams.join('\\n')}\n\nlimit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;\n${serverBlocks.join('\\n')}\n`;\n}\n","import type { HabeetatConfig } from '../types.js';\n\nexport function generateHostNginxConf(config: HabeetatConfig): string {\n const domain = config.platform.domain;\n const port = config.nginx.hostPort;\n\n const subdomains = [\n 'iam',\n 'iam-console',\n 'api',\n ];\n\n if (config.services.launcher) subdomains.push('launcher');\n if (config.services.organizationManager) subdomains.push('organization-manager');\n if (config.services.platformManager) subdomains.push('platform-manager');\n if (config.services.analytics) subdomains.push('analytics');\n if (config.services.sampleCrm) subdomains.push('sample-crm');\n if (config.services.signoz) subdomains.push('logs');\n\n // Tenant subdomains `<slug>.${domain}` are served by the launcher (org-onboarding). nginx\n // matches the explicit service names before this leading wildcard, so service hosts are not\n // shadowed. TLS for `*.${domain}` needs a wildcard cert via Let's Encrypt DNS-01 (certbot\n // --nginx HTTP-01 cannot issue wildcards) — a documented install prerequisite.\n const tenantWildcard = config.services.launcher ? `*.${domain}` : '';\n // The bare apex `${domain}` is the public landing host (org-onboarding) — it is NOT matched by\n // the `*.${domain}` wildcard, so it must be listed explicitly or the host nginx won't serve it.\n const allServerNames = [domain, ...subdomains.map((s) => `${s}.${domain}`), tenantWildcard]\n .filter(Boolean)\n .join(' ');\n\n const proxyHeaders = `\n proxy_set_header Host $host;\n proxy_set_header X-Real-IP $remote_addr;\n proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n proxy_set_header X-Forwarded-Proto $scheme;\n proxy_set_header X-Forwarded-Host $host;\n proxy_http_version 1.1;\n proxy_set_header Upgrade $http_upgrade;\n proxy_set_header Connection \"upgrade\";`;\n\n const header = `# Habeetat Platform - Host Nginx Configuration\n# Auto-generated by @habeetat/cli for domain: ${domain}\n# This file should be placed in /etc/nginx/sites-available/habeetat-${sanitize(domain)}\n# and symlinked to /etc/nginx/sites-enabled/`;\n\n // Wildcard TLS mode (design D13): a single `*.${domain}` cert from ACME DNS-01 (lego) covers\n // every service host AND every tenant subdomain. nginx terminates TLS here referencing the lego\n // cert; port 80 only redirects (DNS-01 needs no HTTP-01 challenge). Otherwise (on-demand/manual)\n // keep the plain `listen 80` block — certbot --nginx adds SSL, or Caddy fronts this entirely.\n if (config.tls?.mode === 'wildcard') {\n return `${header}\n#\n# TLS: wildcard cert via ACME DNS-01 (lego). Issue it with ./tls/issue-wildcard-cert.sh\n# before reloading nginx (the cert must exist at the paths below).\n\nserver {\n listen 80;\n server_name ${allServerNames};\n location / {\n return 301 https://$host$request_uri;\n }\n}\n\nserver {\n listen 443 ssl http2;\n server_name ${allServerNames};\n\n ssl_certificate /etc/lego/certificates/_.${domain}.crt;\n ssl_certificate_key /etc/lego/certificates/_.${domain}.key;\n\n client_max_body_size 50M;\n\n location / {\n proxy_pass http://127.0.0.1:${port};${proxyHeaders}\n }\n}\n`;\n }\n\n return `${header}\n#\n# SSL will be added automatically by certbot --nginx\n\nserver {\n listen 80;\n server_name ${allServerNames};\n\n client_max_body_size 50M;\n\n location / {\n proxy_pass http://127.0.0.1:${port};${proxyHeaders}\n }\n}\n`;\n}\n\nfunction sanitize(domain: string): string {\n return domain.replace(/[^a-zA-Z0-9.-]/g, '-');\n}\n","import type { HabeetatConfig } from '../types.js';\n\n/**\n * Caddyfile for the `on-demand` TLS mode (design D13). Caddy is the public edge terminator;\n * the internal nginx is the router. A single site matches the apex AND every subdomain\n * (`<domain>, *.<domain>`) and uses on-demand TLS so a certificate is issued the first time a\n * host connects — gated by the backend `/tenants/caddy-ask` endpoint, which approves the apex,\n * the platform service hosts (iam/api/launcher/…), and existing tenant subdomains, and denies\n * unknown names so Caddy never attempts ACME for arbitrary hosts (rate-limit abuse).\n *\n * NOTE: we deliberately do NOT also list the service hosts in a separate non-on-demand block.\n * A service host like `api.<domain>` is a single-label subdomain, so it matches `*.<domain>`;\n * a separate explicit policy (no on_demand) would shadow the wildcard's on-demand policy at the\n * handshake yet never get a proactively-issued cert (Caddy treats it as covered by the wildcard)\n * — a dead zone that yields \"no certificate available\". One on-demand site avoids that entirely.\n */\nexport function generateCaddyfile(config: HabeetatConfig): string {\n const domain = config.platform.domain;\n const email = config.tls?.acmeEmail || config.platform.adminEmail;\n const acmeCa = config.tls?.acmeCa;\n\n const globalOpts = [\n `\\temail ${email}`,\n acmeCa ? `\\tacme_ca ${acmeCa}` : '',\n // Caddy 2.10+ refuses bare on-demand TLS — the ask gate is mandatory.\n `\\ton_demand_tls {`,\n `\\t\\task http://backend:3001/tenants/caddy-ask`,\n `\\t}`,\n ]\n .filter(Boolean)\n .join('\\n');\n\n return `# Habeetat Platform - Caddy edge (on-demand TLS)\n# Auto-generated by @habeetat/cli for domain: ${domain}\n# The apex + every subdomain (service hosts and tenant subdomains <slug>.${domain}) get a\n# certificate issued on demand, gated by the backend /tenants/caddy-ask endpoint. Requires a\n# static wildcard DNS record *.${domain} -> server-ip and ports 80/443. No DNS-provider API.\n\n{\n${globalOpts}\n}\n\n# Apex + all subdomains — TLS on demand (ask-gated); internal nginx routes by Host header.\n${domain}, *.${domain} {\n\\ttls {\n\\t\\ton_demand\n\\t}\n\\treverse_proxy nginx:80 {\n\\t\\theader_up Host {host}\n\\t}\n}\n`;\n}\n","import type { HabeetatConfig } from '../types.js';\n\n/**\n * Shell script to issue/renew the wildcard TLS cert `*.<domain>` via ACME DNS-01 using lego\n * (design D13, 'wildcard' mode). A single wildcard cert + apex covers every service host AND\n * every tenant subdomain. Provider-agnostic: the operator puts their DNS-provider API creds in\n * `tls/dns-credentials.env` (see lego's per-provider env vars) and lego's `--dns <provider>`\n * picks the plugin. Writes the cert to `/etc/lego/certificates/_.<domain>.crt` (+ `.key`), the\n * paths the host nginx references.\n */\nexport function generateLegoScript(config: HabeetatConfig): string {\n const domain = config.platform.domain;\n const email = config.tls?.acmeEmail || config.platform.adminEmail;\n const provider = config.tls?.dnsProvider || 'cloudflare';\n const caFlag = config.tls?.acmeCa ? ` --server \"${config.tls.acmeCa}\"` : '';\n\n return `#!/usr/bin/env bash\n# Issue (or renew) the wildcard TLS certificate *.${domain} via ACME DNS-01 (lego).\n# Auto-generated by @habeetat/cli. Run from the project root:\n# ./tls/issue-wildcard-cert.sh # first issuance\n# ./tls/issue-wildcard-cert.sh renew # renewal (cron/systemd timer; then reload nginx)\n#\n# PREREQUISITES\n# 1) A static wildcard DNS A/AAAA record: *.${domain} -> <server-ip>\n# 2) Your DNS-provider API credentials in tls/dns-credentials.env. For Cloudflare:\n# CLOUDFLARE_DNS_API_TOKEN=<token scoped Zone:Read + DNS:Edit>\n# For other providers see the env vars at https://go-acme.github.io/lego/dns/${provider}/\nset -euo pipefail\n\nDOMAIN=\"${domain}\"\nEMAIL=\"${email}\"\nPROVIDER=\"${provider}\"\nACTION=\"\\${1:-run}\" # 'run' (issue) or 'renew'\nCREDS_FILE=\"\\$(dirname \"\\$0\")/dns-credentials.env\"\n\nif [ ! -f \"\\$CREDS_FILE\" ]; then\n echo \"Missing \\$CREDS_FILE — add your DNS-provider API credentials (see header).\" >&2\n exit 1\nfi\n\nEXTRA=\"\"\nif [ \"\\$ACTION\" = \"renew\" ]; then EXTRA=\"--days 30\"; fi\n\n# lego writes to /etc/lego/certificates/_.${domain}.crt (+ .key) — the paths the host nginx uses.\n# NOTE: we do NOT pass lego's --renew-hook 'nginx -s reload' — that would run INSIDE the lego\n# container, where nginx is absent. We reload the host nginx ourselves after the run below.\nsudo docker run --rm \\\\\n -v /etc/lego:/etc/lego \\\\\n --env-file \"\\$CREDS_FILE\" \\\\\n ${'goacme/lego:v4.21.0'} \\\\\n --email \"\\$EMAIL\" \\\\\n --dns \"\\$PROVIDER\" \\\\\n -d \"*.\\$DOMAIN\" -d \"\\$DOMAIN\" \\\\\n --path /etc/lego \\\\\n --accept-tos${caFlag} \\\\\n \\$ACTION \\$EXTRA\n\n# Reload the host nginx so it serves the new cert (idempotent; safe to run on issue + renew).\necho \"Reloading host nginx...\"\nsudo nginx -s reload || echo \"Could not reload nginx — do it manually: sudo nginx -s reload\"\necho \"Done: /etc/lego/certificates/_.\\${DOMAIN}.crt\"\n`;\n}\n","import crypto from 'node:crypto';\n\nexport function randomHex(bytes: number): string {\n return crypto.randomBytes(bytes).toString('hex');\n}\n\nexport function generateSecrets() {\n return {\n logtoDbPassword: randomHex(16),\n platformDbPassword: randomHex(16),\n encryptionKey: randomHex(32),\n logtoM2mAppSecret: randomHex(32),\n clickhousePassword: randomHex(16),\n };\n}\n","import type { CreateOptions } from '../types.js';\nimport { generateSecrets } from '../utils/crypto.js';\nimport { SYSTEM_APP_LOGTO_IDS } from '@habeetat/sdk-core/constants';\n\nexport function generateEnvFile(opts: CreateOptions): string {\n const protocol = opts.ssl ? 'https' : 'http';\n const domain = opts.domain;\n const secrets = generateSecrets();\n const tenantSlug = opts.organizationName.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '') || 'platform';\n\n return `# Habeetat Platform - Environment Configuration\n# Generated by @habeetat/cli on ${new Date().toISOString()}\n\n# ============================================\n# Domain Configuration\n# ============================================\nDOMAIN=${domain}\nPROTOCOL=${protocol}\n\n# ============================================\n# Service URLs (External - Browser-facing)\n# ============================================\nLOGTO_ENDPOINT=${protocol}://iam.${domain}\nLOGTO_ADMIN_ENDPOINT=${protocol}://iam-console.${domain}\nLAUNCHER_URL=${protocol}://launcher.${domain}\nORG_MANAGER_URL=${protocol}://organization-manager.${domain}\nPLATFORM_MANAGER_URL=${protocol}://platform-manager.${domain}\nANALYTICS_URL=${protocol}://analytics.${domain}\nSAMPLE_CRM_URL=${protocol}://sample-crm.${domain}\nBACKEND_API_URL=${protocol}://api.${domain}\nCORS_ORIGINS=${protocol}://launcher.${domain},${protocol}://organization-manager.${domain},${protocol}://platform-manager.${domain},${protocol}://analytics.${domain},${protocol}://sample-crm.${domain}\n\n# ============================================\n# Database Configuration\n# ============================================\nLOGTO_DB_USER=logto\nLOGTO_DB_PASSWORD=${secrets.logtoDbPassword}\nLOGTO_DB_NAME=logto\n\nPLATFORM_DB_USER=habeetat\nPLATFORM_DB_PASSWORD=${secrets.platformDbPassword}\nPLATFORM_DB_NAME=habeetat_platform\n\n# ============================================\n# Logto IAM Configuration\n# ============================================\nLOGTO_ADMIN_USERNAME=${opts.adminEmail}\nLOGTO_ADMIN_PASSWORD=${opts.adminPassword}\n\nIAM_ISSUER_URL=${protocol}://iam.${domain}/oidc\nIAM_AUDIENCE=${protocol}://api.${domain}/api\nSDK_API_RESOURCE=${protocol}://api.${domain}/api\n\nLOGTO_M2M_APP_ID=${SYSTEM_APP_LOGTO_IDS.m2m}\nLOGTO_M2M_APP_SECRET=${secrets.logtoM2mAppSecret}\n\n# ============================================\n# Platform Configuration\n# ============================================\nPLATFORM_ADMIN_EMAIL=${opts.adminEmail}\nPLATFORM_ADMIN_PASSWORD=${opts.adminPassword}\nORGANIZATION_NAME=${opts.organizationName}\n\n# Seed inputs (consumed by prisma/seed.ts so the DB reflects the chosen org/admin)\nNHP_DEFAULT_TENANT_NAME=${opts.organizationName}\nNHP_DEFAULT_TENANT_SLUG=${tenantSlug}\nNHP_PLATFORM_ADMIN_EMAIL=${opts.adminEmail}\n\n# ============================================\n# Security\n# ============================================\nENCRYPTION_KEY=${secrets.encryptionKey}\n\n# ============================================\n# CORS Configuration\n# ============================================\nALLOWED_ORIGINS=${protocol}://iam-console.${domain},${protocol}://launcher.${domain},${protocol}://organization-manager.${domain},${protocol}://platform-manager.${domain},${protocol}://analytics.${domain}\nCORS_ALLOWED_ORIGINS=${protocol}://iam-console.${domain},${protocol}://launcher.${domain},${protocol}://organization-manager.${domain},${protocol}://platform-manager.${domain},${protocol}://analytics.${domain}\n\n# ============================================\n# SigNoz / OpenTelemetry (Observability)\n# ============================================\nSIGNOZ_URL=${protocol}://logs.${domain}\nOTEL_COLLECTOR_ENDPOINT=http://otel-collector:4317\nCLICKHOUSE_PASSWORD=${secrets.clickhousePassword}\n`;\n}\n","import chalk from 'chalk';\n\nconst prefix = chalk.cyan('[habeetat]');\n\nexport const logger = {\n info: (msg: string) => console.log(`${prefix} ${msg}`),\n success: (msg: string) => console.log(`${prefix} ${chalk.green('✓')} ${msg}`),\n warn: (msg: string) => console.log(`${prefix} ${chalk.yellow('⚠')} ${msg}`),\n error: (msg: string) => console.error(`${prefix} ${chalk.red('✗')} ${msg}`),\n phase: (msg: string) => {\n console.log('');\n console.log(chalk.cyan('═'.repeat(56)));\n console.log(chalk.cyan(` ${msg}`));\n console.log(chalk.cyan('═'.repeat(56)));\n console.log('');\n },\n banner: () => {\n console.log('');\n console.log(chalk.cyan('╔══════════════════════════════════════════════╗'));\n console.log(chalk.cyan('║ ║'));\n console.log(chalk.cyan('║ Habeetat Platform CLI ║'));\n console.log(chalk.cyan('║ ║'));\n console.log(chalk.cyan('╚══════════════════════════════════════════════╝'));\n console.log('');\n },\n};\n","import { execaCommand } from 'execa';\nimport { logger } from './logger.js';\n\nexport async function checkDocker(): Promise<boolean> {\n try {\n const { stdout } = await execaCommand('docker --version');\n const match = stdout.match(/Docker version (\\d+)/);\n if (match && parseInt(match[1], 10) >= 20) {\n return true;\n }\n logger.error(`Docker >= 20.0 required. Found: ${stdout.trim()}`);\n return false;\n } catch {\n logger.error('Docker is not installed or not in PATH');\n logger.info('Install Docker: https://docs.docker.com/get-docker/');\n return false;\n }\n}\n\nexport async function checkDockerCompose(): Promise<boolean> {\n try {\n await execaCommand('docker compose version');\n return true;\n } catch {\n logger.error('Docker Compose V2 is not available');\n logger.info('Docker Compose V2 is included with Docker Desktop');\n return false;\n }\n}\n\nexport async function checkPrerequisites(): Promise<boolean> {\n const docker = await checkDocker();\n const compose = await checkDockerCompose();\n return docker && compose;\n}\n\nexport interface ComposeExecOptions {\n cwd: string;\n composeFile?: string;\n silent?: boolean;\n}\n\nexport async function composeUp(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} up -d`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeDown(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} down`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeDestroy(opts: ComposeExecOptions): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n await execaCommand(`docker compose -f ${file} down -v --remove-orphans`, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composePs(opts: ComposeExecOptions): Promise<string> {\n const file = opts.composeFile || 'docker-compose.yml';\n const { stdout } = await execaCommand(`docker compose -f ${file} ps`, {\n cwd: opts.cwd,\n });\n return stdout;\n}\n\nexport async function composeLogs(\n opts: ComposeExecOptions & { service?: string; follow?: boolean; tail?: number },\n): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n const parts = ['docker', 'compose', '-f', file, 'logs'];\n if (opts.follow) parts.push('-f');\n if (opts.tail) parts.push('--tail', String(opts.tail));\n if (opts.service) parts.push(opts.service);\n\n await execaCommand(parts.join(' '), {\n cwd: opts.cwd,\n stdio: 'inherit',\n });\n}\n\nexport async function composeRestart(\n opts: ComposeExecOptions & { service?: string },\n): Promise<void> {\n const file = opts.composeFile || 'docker-compose.yml';\n const cmd = opts.service\n ? `docker compose -f ${file} restart ${opts.service}`\n : `docker compose -f ${file} restart`;\n\n await execaCommand(cmd, {\n cwd: opts.cwd,\n stdio: opts.silent ? 'pipe' : 'inherit',\n });\n}\n\nexport async function composeExec(\n opts: ComposeExecOptions & { service: string; command: string },\n): Promise<string> {\n const file = opts.composeFile || 'docker-compose.yml';\n const { stdout } = await execaCommand(\n `docker compose -f ${file} exec -T ${opts.service} ${opts.command}`,\n { cwd: opts.cwd },\n );\n return stdout;\n}\n\nexport async function dockerPull(image: string): Promise<void> {\n await execaCommand(`docker pull ${image}`, { stdio: 'inherit' });\n}\n","import fs from 'node:fs';\nimport path from 'node:path';\nimport { CONFIG_FILE } from '../constants.js';\nimport type { HabeetatConfig } from '../types.js';\n\nexport function findProjectRoot(startDir: string = process.cwd()): string | null {\n let dir = startDir;\n while (dir !== path.dirname(dir)) {\n if (fs.existsSync(path.join(dir, CONFIG_FILE))) {\n return dir;\n }\n dir = path.dirname(dir);\n }\n return null;\n}\n\nexport function loadConfig(projectDir?: string): HabeetatConfig {\n const dir = projectDir || findProjectRoot();\n if (!dir) {\n throw new Error(\n `Could not find ${CONFIG_FILE}. Are you inside a Habeetat project directory?`,\n );\n }\n const configPath = path.join(dir, CONFIG_FILE);\n const raw = fs.readFileSync(configPath, 'utf-8');\n return JSON.parse(raw) as HabeetatConfig;\n}\n\nexport function saveConfig(config: HabeetatConfig, projectDir: string): void {\n const configPath = path.join(projectDir, CONFIG_FILE);\n fs.writeFileSync(configPath, JSON.stringify(config, null, 2) + '\\n', 'utf-8');\n}\n\nexport function getProjectDir(): string {\n const dir = findProjectRoot();\n if (!dir) {\n throw new Error(\n `Could not find ${CONFIG_FILE}. Are you inside a Habeetat project directory?`,\n );\n }\n return dir;\n}\n","// Logto IAM bootstrap seed script — embedded for scaffolding\n// This is the content of scripts/nhp-seed-logto-bootstrap.mjs\n// It runs inside a temporary Node container on the Docker network\n\nexport function getBootstrapScript(): string {\n return `#!/usr/bin/env node\nimport crypto from 'node:crypto';\n\nimport { argon2i } from 'hash-wasm';\nimport { customAlphabet } from 'nanoid';\nimport { Pool } from 'pg';\n\nconst alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';\nconst shortId = customAlphabet(alphabet, 12);\nconst longId = customAlphabet(alphabet, 21);\n\nconst connectionString =\n process.env.NHP_LOGTO_DB_URL ?? 'postgres://logto:logto@localhost:5434/logto';\n\nconst pool = new Pool({ connectionString });\n\nconst log = (message) => console.log(\\`[NHP][iam-seed] \\${message}\\`);\nconst json = (value) => JSON.stringify(value ?? {});\n\nasync function hashPassword(password) {\n return argon2i({\n password,\n salt: crypto.randomBytes(16),\n iterations: 256,\n parallelism: 1,\n memorySize: 4096,\n hashLength: 32,\n outputType: 'encoded',\n });\n}\n\nasync function ensureOrganization({ tenantId, id, name, description, customData }) {\n const orgId = id ?? longId();\n const { rows } = await pool.query(\n \\`insert into organizations (tenant_id, id, name, description, custom_data)\n values ($1, $2, $3, $4, $5::jsonb)\n on conflict (id) do update\n set tenant_id = excluded.tenant_id,\n name = excluded.name,\n description = excluded.description,\n custom_data = excluded.custom_data\n returning id\\`,\n [tenantId, orgId, name, description ?? name, json(customData)]\n );\n return rows[0].id;\n}\n\nasync function ensureOrganizationMembership({ tenantId, organizationId, userId }) {\n await pool.query(\n \\`insert into organization_user_relations (tenant_id, organization_id, user_id)\n values ($1, $2, $3)\n on conflict (tenant_id, organization_id, user_id) do nothing\\`,\n [tenantId, organizationId, userId]\n );\n}\n\nasync function ensureOrganizationRole({ tenantId, id, name, description }) {\n const roleId = id ?? longId();\n const { rows } = await pool.query(\n \\`insert into organization_roles (tenant_id, id, name, description)\n values ($1, $2, $3, $4)\n on conflict (id) do update\n set tenant_id = excluded.tenant_id,\n name = excluded.name,\n description = excluded.description\n returning id\\`,\n [tenantId, roleId, name, description ?? name]\n );\n return rows[0].id;\n}\n\nasync function ensureOrganizationRoleAssignment({ tenantId, organizationId, organizationRoleId, userId }) {\n await pool.query(\n \\`insert into organization_role_user_relations (tenant_id, organization_id, organization_role_id, user_id)\n values ($1, $2, $3, $4)\n on conflict (tenant_id, organization_id, organization_role_id, user_id) do nothing\\`,\n [tenantId, organizationId, organizationRoleId, userId]\n );\n}\n\n// Grant a resource scope (resolved by name) to an organization role, so members with that\n// role receive the scope in their organization-scoped API token (refresh-grant). The platform\n// API token scope is coarse (nhp:all); fine-grained authorization stays in the platform DB.\nasync function ensureOrganizationRoleResourceScope({ tenantId, organizationRoleId, scopeName }) {\n await pool.query(\n \\`insert into organization_role_resource_scope_relations (tenant_id, organization_role_id, scope_id)\n select $1::text, $2::text, s.id from scopes s where s.tenant_id = $1::text and s.name = $3::text limit 1\n on conflict do nothing\\`,\n [tenantId, organizationRoleId, scopeName]\n );\n}\n\nasync function ensureUser({ tenantId, username, email, password, displayName, customData, preferredId }) {\n let existingId;\n\n if (preferredId) {\n const byId = await pool.query('select id from users where id = $1 limit 1', [preferredId]);\n if (byId.rows.length > 0) existingId = byId.rows[0].id;\n }\n\n if (!existingId) {\n const byTenant = await pool.query(\n 'select id from users where tenant_id = $1 and (username = $2 or primary_email = $3) limit 1',\n [tenantId, username, email]\n );\n if (byTenant.rows.length > 0) existingId = byTenant.rows[0].id;\n }\n\n const passwordEncrypted = await hashPassword(password);\n const targetId = existingId ?? preferredId ?? shortId();\n\n if (existingId) {\n await pool.query(\n \\`update users\n set tenant_id = $1, username = $3, primary_email = $4,\n password_encrypted = $5, password_encryption_method = 'Argon2i',\n name = $6, custom_data = $7::jsonb\n where id = $2\\`,\n [tenantId, targetId, username, email, passwordEncrypted, displayName ?? username, json(customData)]\n );\n return targetId;\n }\n\n await pool.query(\n \\`insert into users (\n tenant_id, id, username, primary_email, password_encrypted, password_encryption_method,\n name, is_suspended, custom_data, profile, identities, logto_config, mfa_verifications\n ) values (\n $1, $2, $3, $4, $5, 'Argon2i', $6, false,\n $7::jsonb, '{}'::jsonb, '{}'::jsonb, '{}'::jsonb, '[]'::jsonb\n )\\`,\n [tenantId, targetId, username, email, passwordEncrypted, displayName ?? username, json(customData)]\n );\n return targetId;\n}\n\nasync function ensureAdminConsoleInitialized(tenantId) {\n const payload = { organizationCreated: true, signInExperienceCustomized: true };\n await pool.query(\n \\`insert into logto_configs (tenant_id, key, value)\n values ($1, 'adminConsole', $2::jsonb)\n on conflict (tenant_id, key) do update set value = excluded.value\\`,\n [tenantId, json(payload)]\n );\n}\n\nasync function ensureAdminTenantSignInMode() {\n await pool.query(\\`update sign_in_experiences set sign_in_mode = 'SignIn' where tenant_id = 'admin'\\`);\n log('Configured admin tenant sign-in mode.');\n}\n\nasync function ensureDefaultTenantSignInExperience() {\n await pool.query(\n \\`update sign_in_experiences\n set sign_in_mode = 'SignInAndRegister',\n sign_in = jsonb_build_object(\n 'methods', jsonb_build_array(\n jsonb_build_object('identifier', 'username', 'password', true, 'verificationCode', false, 'isPasswordPrimary', true),\n jsonb_build_object('identifier', 'email', 'password', true, 'verificationCode', false, 'isPasswordPrimary', true)\n )\n ),\n sign_up = jsonb_build_object(\n 'identifiers', jsonb_build_array('username'),\n 'password', true,\n 'verify', false\n )\n where tenant_id = 'default'\\`\n );\n log('Configured default tenant sign-in experience.');\n}\n\nasync function ensureAdminAccountViaApi() {\n const username = process.env.NHP_PLATFORM_ADMIN_USERNAME ?? 'admin';\n const password = process.env.NHP_PLATFORM_ADMIN_PASSWORD ?? 'Habeetat_01';\n\n const { rows } = await pool.query(\n \\`select id from users where tenant_id = 'admin' and username = $1 limit 1\\`,\n [username]\n );\n\n const passwordEncrypted = await hashPassword(password);\n let adminUserId;\n\n if (rows.length === 0) {\n adminUserId = shortId();\n await pool.query(\n \\`INSERT INTO users (\n tenant_id, id, username, password_encrypted, password_encryption_method,\n name, is_suspended, custom_data, profile, identities, logto_config, mfa_verifications\n ) VALUES (\n 'admin', $1, $2, $3, 'Argon2i',\n $2, false, '{}'::jsonb, '{}'::jsonb, '{}'::jsonb, '{}'::jsonb, '[]'::jsonb\n )\\`,\n [adminUserId, username, passwordEncrypted]\n );\n log(\\`Created admin user via SQL (username: \\${username}, id: \\${adminUserId}).\\`);\n } else {\n adminUserId = rows[0].id;\n await pool.query(\n \\`UPDATE users SET password_encrypted = $1, password_encryption_method = 'Argon2i' WHERE id = $2\\`,\n [passwordEncrypted, adminUserId]\n );\n log(\\`Updated password for admin user \\${username} (id: \\${adminUserId}).\\`);\n }\n\n await pool.query(\n \\`INSERT INTO organization_user_relations (tenant_id, organization_id, user_id)\n VALUES ('admin', 't-default', $1) ON CONFLICT DO NOTHING\\`,\n [adminUserId]\n );\n\n await pool.query(\n \\`INSERT INTO organization_role_user_relations (tenant_id, organization_id, organization_role_id, user_id)\n VALUES ('admin', 't-default', 'admin', $1) ON CONFLICT DO NOTHING\\`,\n [adminUserId]\n );\n\n const { rows: allRoles } = await pool.query(\n \\`SELECT id FROM roles WHERE tenant_id = 'admin' AND type = 'User'\\`\n );\n\n for (const role of allRoles) {\n await pool.query(\n \\`INSERT INTO users_roles (tenant_id, id, user_id, role_id)\n VALUES ('admin', $1, $2, $3) ON CONFLICT (tenant_id, user_id, role_id) DO NOTHING\\`,\n [longId(), adminUserId, role.id]\n );\n }\n\n log('Admin account bootstrap via SQL completed.');\n}\n\nasync function main() {\n log('Starting IAM bootstrap seed...');\n\n const platformAdminUsername = process.env.NHP_PLATFORM_ADMIN_USERNAME ?? 'admin';\n const platformAdminEmail = process.env.NHP_PLATFORM_ADMIN_EMAIL ?? 'admin@habeetat.local';\n const platformAdminPassword = process.env.NHP_PLATFORM_ADMIN_PASSWORD ?? 'Habeetat_01';\n const platformAdminDisplayName = process.env.NHP_PLATFORM_ADMIN_DISPLAY_NAME ?? 'Platform Admin';\n const defaultTenantName = process.env.NHP_DEFAULT_TENANT_NAME ?? 'Default';\n const defaultTenantSlug = process.env.NHP_DEFAULT_TENANT_SLUG ?? 'default';\n\n const habeetatAdminOrgId = await ensureOrganization({\n tenantId: 'default',\n id: 'org_habeetat_admin',\n name: 'Habeetat Admin',\n description: 'Internal organization for Habeetat platform administrators',\n customData: { slug: 'habeetat-admin', type: 'internal' },\n });\n\n const defaultTenantOrgId = await ensureOrganization({\n tenantId: 'default',\n id: \\`org_\\${defaultTenantSlug}\\`,\n name: defaultTenantName,\n description: \\`Tenant organization: \\${defaultTenantName}\\`,\n customData: { slug: defaultTenantSlug, type: 'tenant' },\n });\n\n log(\\`Organizations ensured: Habeetat Admin (\\${habeetatAdminOrgId}), \\${defaultTenantName} (\\${defaultTenantOrgId})\\`);\n\n const orgTenantAdminRoleId = await ensureOrganizationRole({\n tenantId: 'default', id: 'org_role_tenant_admin', name: 'TENANT_ADMIN',\n description: 'Tenant administrator with full access to organization management',\n });\n\n const orgTenantUserRoleId = await ensureOrganizationRole({\n tenantId: 'default', id: 'org_role_tenant_user', name: 'TENANT_USER',\n description: 'Regular tenant user with launcher access',\n });\n\n const orgPlatformAdminRoleId = await ensureOrganizationRole({\n tenantId: 'default', id: 'org_role_plat_adm', name: 'PLATFORM_ADMIN',\n description: 'Platform administrator with access to Platform Manager',\n });\n\n log(\\`Organization roles ensured: TENANT_ADMIN=\\${orgTenantAdminRoleId}, TENANT_USER=\\${orgTenantUserRoleId}, PLATFORM_ADMIN=\\${orgPlatformAdminRoleId}\\`);\n\n // Organization-scoped API access: TENANT_ADMIN/TENANT_USER org roles carry the platform API\n // scope (nhp:all) so org-scoped tokens can call the API. Required for the org-scoped-identity\n // model — without it, refresh-grant org tokens would have no scope on the platform API.\n await ensureOrganizationRoleResourceScope({ tenantId: 'default', organizationRoleId: orgTenantAdminRoleId, scopeName: 'nhp:all' });\n await ensureOrganizationRoleResourceScope({ tenantId: 'default', organizationRoleId: orgTenantUserRoleId, scopeName: 'nhp:all' });\n log('Assigned nhp:all to TENANT_ADMIN/TENANT_USER organization roles (org-scoped API access)');\n\n await ensureAdminConsoleInitialized('default');\n await ensureAdminConsoleInitialized('admin');\n await ensureAdminTenantSignInMode();\n await ensureDefaultTenantSignInExperience();\n await ensureAdminAccountViaApi();\n\n const platformAdminUserId = await ensureUser({\n tenantId: 'default',\n preferredId: 'usr_admin01',\n username: platformAdminUsername,\n email: platformAdminEmail,\n password: platformAdminPassword,\n displayName: platformAdminDisplayName,\n customData: { tenantSlug: defaultTenantSlug },\n });\n\n await ensureOrganizationMembership({ tenantId: 'default', organizationId: habeetatAdminOrgId, userId: platformAdminUserId });\n await ensureOrganizationMembership({ tenantId: 'default', organizationId: defaultTenantOrgId, userId: platformAdminUserId });\n\n await ensureOrganizationRoleAssignment({ tenantId: 'default', organizationId: defaultTenantOrgId, organizationRoleId: orgTenantAdminRoleId, userId: platformAdminUserId });\n await ensureOrganizationRoleAssignment({ tenantId: 'default', organizationId: defaultTenantOrgId, organizationRoleId: orgTenantUserRoleId, userId: platformAdminUserId });\n await ensureOrganizationRoleAssignment({ tenantId: 'default', organizationId: habeetatAdminOrgId, organizationRoleId: orgPlatformAdminRoleId, userId: platformAdminUserId });\n\n log(\\`Ensured user \\${platformAdminUsername} (\\${platformAdminEmail}, id: \\${platformAdminUserId})\\`);\n log('IAM bootstrap seed completed successfully.');\n}\n\nmain()\n .catch((error) => {\n console.error('[NHP][iam-seed] Failed:', error);\n process.exitCode = 1;\n })\n .finally(async () => {\n await pool.end();\n });\n`;\n}\n","/**\n * Generates a ClickHouse config override for SigNoz compatibility.\n * - Forces IPv4-only listening (required on hosts with IPv6 disabled)\n * - Defines a single-node \"cluster\" (required by SigNoz schema migrator)\n * - Configures ZooKeeper connection (required for ON CLUSTER DDL)\n */\nexport function generateClickhouseConfig(): string {\n return `<!-- ClickHouse config override for Habeetat/SigNoz -->\n<clickhouse>\n <listen_host>0.0.0.0</listen_host>\n\n <remote_servers>\n <cluster>\n <shard>\n <replica>\n <host>clickhouse</host>\n <port>9000</port>\n </replica>\n </shard>\n </cluster>\n </remote_servers>\n\n <zookeeper>\n <node>\n <host>zookeeper</host>\n <port>2181</port>\n </node>\n </zookeeper>\n</clickhouse>\n`;\n}\n\n/**\n * Generates the OpenTelemetry Collector configuration for SigNoz.\n * DSN paths include database names (signoz_traces, signoz_logs, signoz_metrics).\n * docker_multi_node_cluster and low_cardinal_exception_grouping are read\n * from environment variables set on the otel-collector container.\n */\nexport function generateOtelCollectorConfig(): string {\n // Use literal $ so the YAML contains ${ENV_VAR} references (not JS interpolation)\n return `receivers:\n otlp:\n protocols:\n grpc:\n endpoint: 0.0.0.0:4317\n http:\n endpoint: 0.0.0.0:4318\n\nprocessors:\n batch:\n send_batch_size: 10000\n send_batch_max_size: 11000\n timeout: 10s\n resourcedetection:\n detectors: [env, system]\n timeout: 2s\n\nexporters:\n clickhousetraces:\n datasource: tcp://clickhouse:9000/signoz_traces\n docker_multi_node_cluster: \\${DOCKER_MULTI_NODE_CLUSTER}\n low_cardinal_exception_grouping: \\${LOW_CARDINAL_EXCEPTION_GROUPING}\n clickhousemetricswrite:\n endpoint: tcp://clickhouse:9000/signoz_metrics\n resource_to_telemetry_conversion:\n enabled: true\n clickhouselogsexporter:\n dsn: tcp://clickhouse:9000/signoz_logs\n docker_multi_node_cluster: \\${DOCKER_MULTI_NODE_CLUSTER}\n timeout: 10s\n\nextensions:\n health_check:\n endpoint: 0.0.0.0:13133\n\nservice:\n telemetry:\n metrics:\n address: 0.0.0.0:8888\n extensions:\n - health_check\n pipelines:\n traces:\n receivers: [otlp]\n processors: [batch]\n exporters: [clickhousetraces]\n metrics:\n receivers: [otlp]\n processors: [batch]\n exporters: [clickhousemetricswrite]\n logs:\n receivers: [otlp]\n processors: [batch]\n exporters: [clickhouselogsexporter]\n`;\n}\n\n/**\n * Generates the OpAMP manager configuration for the OTel collector.\n */\nexport function generateOtelCollectorOpampConfig(): string {\n return `server_endpoint: ws://signoz-query-service:4320/v1/opamp\n`;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@habeetat/cli",
3
- "version": "0.1.0-dev.20260624145259.c5f7eb0",
3
+ "version": "0.1.0",
4
4
  "description": "Habeetat Platform CLI — manage your platform instances",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -26,7 +26,7 @@
26
26
  "clean": "rm -rf dist"
27
27
  },
28
28
  "dependencies": {
29
- "@habeetat/sdk-core": "dev",
29
+ "@habeetat/sdk-core": "latest",
30
30
  "chalk": "^5.3.0",
31
31
  "commander": "^12.1.0",
32
32
  "execa": "^9.3.0",