@undefineds.co/xpod 0.3.56 → 0.3.57

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.
Files changed (57) hide show
  1. package/dist/api/container/index.js +3 -0
  2. package/dist/api/container/index.js.map +1 -1
  3. package/dist/api/container/local.js +53 -13
  4. package/dist/api/container/local.js.map +1 -1
  5. package/dist/api/container/types.d.ts +6 -0
  6. package/dist/api/container/types.js.map +1 -1
  7. package/dist/api/handlers/AdminHandler.d.ts +15 -0
  8. package/dist/api/handlers/AdminHandler.js +128 -7
  9. package/dist/api/handlers/AdminHandler.js.map +1 -1
  10. package/dist/cli/commands/obj.d.ts +36 -0
  11. package/dist/cli/commands/obj.js +235 -30
  12. package/dist/cli/commands/obj.js.map +1 -1
  13. package/dist/components/components.jsonld +1 -0
  14. package/dist/components/context.jsonld +36 -0
  15. package/dist/edge/DdnsManager.d.ts +1 -1
  16. package/dist/edge/DdnsManager.js.map +1 -1
  17. package/dist/edge/reachability/P2PRealnetAcceptance.js +4 -3
  18. package/dist/edge/reachability/P2PRealnetAcceptance.js.map +1 -1
  19. package/dist/edge/reachability/TcpP2PSignalingSession.js +26 -17
  20. package/dist/edge/reachability/TcpP2PSignalingSession.js.map +1 -1
  21. package/dist/index.d.ts +2 -1
  22. package/dist/index.js +3 -1
  23. package/dist/index.js.map +1 -1
  24. package/dist/tunnel/NgrokTunnelProvider.d.ts +46 -0
  25. package/dist/tunnel/NgrokTunnelProvider.js +344 -0
  26. package/dist/tunnel/NgrokTunnelProvider.js.map +1 -0
  27. package/dist/tunnel/NgrokTunnelProvider.jsonld +215 -0
  28. package/dist/tunnel/TunnelProvider.d.ts +2 -2
  29. package/dist/tunnel/TunnelProvider.js.map +1 -1
  30. package/dist/tunnel/index.d.ts +1 -0
  31. package/dist/tunnel/index.js +3 -1
  32. package/dist/tunnel/index.js.map +1 -1
  33. package/node_modules/@undefineds.co/drizzle-solid/dist/core/pod-database.d.ts +62 -0
  34. package/node_modules/@undefineds.co/drizzle-solid/dist/core/pod-database.d.ts.map +1 -1
  35. package/node_modules/@undefineds.co/drizzle-solid/dist/core/pod-database.js +197 -0
  36. package/node_modules/@undefineds.co/drizzle-solid/dist/core/pod-database.js.map +1 -1
  37. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/pod-database.d.ts +62 -0
  38. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/pod-database.d.ts.map +1 -1
  39. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/pod-database.js +197 -0
  40. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/core/pod-database.js.map +1 -1
  41. package/node_modules/@undefineds.co/drizzle-solid/dist/esm/pod.d.ts.map +1 -1
  42. package/node_modules/@undefineds.co/drizzle-solid/dist/pod.d.ts.map +1 -1
  43. package/node_modules/@undefineds.co/drizzle-solid/package.json +1 -1
  44. package/package.json +10 -6
  45. package/static/app/assets/{index-AaQ1qxhy.js → index-C1yksyT4.js} +28 -28
  46. package/static/app/assets/inrupt-smoke.js +2 -2
  47. package/static/app/assets/main.css +1 -1
  48. package/static/app/assets/main.js +10 -50
  49. package/static/dashboard/assets/dashboard-BssaVKTn.css +1 -0
  50. package/static/dashboard/assets/dashboard-Ckuadl3C.js +54 -0
  51. package/static/dashboard/dashboard.html +2 -2
  52. package/static/dashboard/reachability.html +221 -0
  53. package/static/dashboard/reachability.svg +7 -0
  54. package/static/dashboard/reachability.webmanifest +18 -0
  55. package/static/dashboard/signal-pod.html +293 -0
  56. package/static/dashboard/assets/dashboard-CTk9cn1-.js +0 -52
  57. package/static/dashboard/assets/dashboard-VQRsvXx9.css +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"AdminHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/AdminHandler.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;AAqKH,kDA6XC;AA7hBD,4CAAoB;AACpB,gDAAwB;AACxB,2BAAgD;AAChD,uCAA2C;AAC3C,2CAA6C;AAE7C,MAAM,UAAU,GAAG,cAAI,CAAC,OAAO,CAAC,sBAAY,EAAE,QAAQ,CAAC,CAAC;AAExD,SAAS,cAAc;IACrB,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;IAC1C,IAAI,OAAO,IAAI,OAAO,CAAC,IAAI,EAAE,EAAE,CAAC;QAC9B,OAAO,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC/B,CAAC;IACD,OAAO,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,YAAY,CAAC,CAAC;AACnD,CAAC;AAYD;;GAEG;AACH,SAAS,WAAW,CAAC,QAAgB;IACnC,MAAM,MAAM,GAAc,EAAE,CAAC;IAC7B,IAAI,CAAC,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC7B,OAAO,MAAM,CAAC;IAChB,CAAC;IACD,MAAM,OAAO,GAAG,YAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IACnD,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QAClD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;QACrC,IAAI,OAAO,KAAK,CAAC,CAAC;YAAE,SAAS;QAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;QAC7C,IAAI,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;QAC9C,gBAAgB;QAChB,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC;YAC9C,CAAC,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC;YACnD,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC7B,CAAC;QACD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;IACtB,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;GAEG;AACH,SAAS,YAAY,CAAC,QAAgB,EAAE,MAAiB;IACvD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,yDAAyD;QACzD,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC1C,MAAM,WAAW,GAAG,WAAW,CAAC,CAAC,CAAC,IAAI,KAAK,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC;QACvD,KAAK,CAAC,IAAI,CAAC,GAAG,GAAG,IAAI,WAAW,EAAE,CAAC,CAAC;IACtC,CAAC;IACD,YAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AACtD,CAAC;AAED;;GAEG;AACH,SAAS,eAAe;IACtB,MAAM,KAAK,GAAiB,EAAE,CAAC;IAC/B,MAAM,WAAW,GAAG,CAAC,YAAY,EAAE,YAAY,EAAE,WAAW,EAAE,gBAAgB,CAAC,CAAC;IAEhF,KAAK,MAAM,IAAI,IAAI,WAAW,EAAE,CAAC;QAC/B,MAAM,QAAQ,GAAG,cAAI,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;QAC7C,KAAK,CAAC,IAAI,CAAC;YACT,IAAI;YACJ,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,YAAE,CAAC,UAAU,CAAC,QAAQ,CAAC;SAChC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;GAEG;AAEH,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IACxD,IAAI,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IAC7C,MAAM,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;IACtC,IAAI,CAAC,EAAE,CAAC;QACN,MAAM,MAAM,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC5B,IAAI,MAAM,IAAI,EAAE,IAAI,MAAM,IAAI,EAAE;YAAE,OAAO,IAAI,CAAC;IAChD,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,KAAK,UAAU,aAAa;IAC1B,MAAM,SAAS,GAAG;QAChB,mCAAmC;QACnC,wBAAwB;KACzB,CAAC;IAEF,KAAK,MAAM,GAAG,IAAI,SAAS,EAAE,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;YACpE,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,SAAS;YACX,CAAC;YACD,MAAM,WAAW,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC;YAC1D,IAAI,WAAW,CAAC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,CAAC;gBAC7C,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAqB,CAAC;gBACjD,MAAM,EAAE,GAAG,IAAI,CAAC,EAAE,EAAE,IAAI,EAAE,CAAC;gBAC3B,IAAI,EAAE,EAAE,CAAC;oBACP,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;iBAAM,CAAC;gBACN,MAAM,EAAE,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;gBACrC,IAAI,EAAE,EAAE,CAAC;oBACP,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,+BAA+B;QACjC,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,QAAQ,CAAC,GAAmB,EAAE,MAAc,EAAE,IAAa;IAClE,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC;IACxB,GAAG,CAAC,SAAS,CAAC,cAAc,EAAE,kBAAkB,CAAC,CAAC;IAClD,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;AAChC,CAAC;AAED;;GAEG;AACH,SAAS,aAAa,CAAC,GAAyB;IAC9C,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,IAAI,IAAI,GAAG,EAAE,CAAC;QACd,GAAG,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YAC/B,IAAI,IAAI,KAAK,CAAC,QAAQ,EAAE,CAAC;QAC3B,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;YACjB,IAAI,CAAC;gBACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACxC,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,MAAM,CAAC,GAAG,CAAC,CAAC;YACd,CAAC;QACH,CAAC,CAAC,CAAC;QACH,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,SAAgB,mBAAmB,CAAC,MAAiB;IACnD,MAAM,MAAM,GAAG,OAAO,CAAC;IAEvB,0CAA0C;IAC1C,MAAM,aAAa,GAAiB,KAAK,EACvC,IAA0B,EAC1B,GAAmB,EACnB,EAAE;QACF,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;YACrC,MAAM,OAAO,GAAG,eAAe,EAAE,CAAC;YAElC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;gBACjB,MAAM,EAAE,SAAS;gBACjB,GAAG,EAAE,OAAO,CAAC,GAAG;gBAChB,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE;gBACxB,GAAG,EAAE;oBACH,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY;oBAC1D,YAAY,EAAE,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY;oBAC1D,QAAQ,EAAE,GAAG,CAAC,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ;iBAC/C;gBACD,OAAO;aACR,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;YAC7C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,sBAAsB,EAAE,CAAC,CAAC;QACxD,CAAC;IACH,CAAC,CAAC;IAEF,oDAAoD;IACpD,MAAM,gBAAgB,GAAiB,KAAK,EAC1C,IAA0B,EAC1B,GAAmB,EACnB,EAAE;QACF,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;YACrC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;gBACjB,GAAG;gBACH,WAAW,EAAE,eAAe,EAAE;aAC/B,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,2BAA2B,EAAE,KAAK,CAAC,CAAC;YACjD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,8BAA8B,EAAE,CAAC,CAAC;QAChE,CAAC;IACH,CAAC,CAAC;IAEF,+CAA+C;IAC/C,MAAM,mBAAmB,GAAiB,KAAK,EAC7C,GAAyB,EACzB,GAAmB,EACnB,EAAE;QACF,IAAI,CAAC;YACH,8BAA8B;YAC9B,MAAM,IAAI,GAAG,MAAM,aAAa,CAAC,GAAG,CAAC,CAAC;YAEtC,IAAI,IAAI,CAAC,GAAG,EAAE,CAAC;gBACb,6BAA6B;gBAC7B,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;gBACrC,MAAM,UAAU,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,EAAE,GAAG,UAAU,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAE9C,0CAA0C;gBAC1C,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;oBAClD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;wBACnC,OAAO,MAAM,CAAC,GAAG,CAAC,CAAC;oBACrB,CAAC;gBACH,CAAC;gBAED,YAAY,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;gBAClC,MAAM,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;YAC9C,CAAC;YAED,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;gBACjB,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,qEAAqE;aAC/E,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,KAAK,CAAC,CAAC;YACpD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,gCAAgC,EAAE,CAAC,CAAC;QAClE,CAAC;IACH,CAAC,CAAC;IAEF,iDAAiD;IACjD,MAAM,cAAc,GAAiB,KAAK,EACxC,IAA0B,EAC1B,GAAmB,EACnB,EAAE;QACF,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC;YAE1B,IAAI,CAAC,IAAI,EAAE,CAAC;gBACV,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,iCAAiC,EAAE,CAAC,CAAC;gBACjE,OAAO;YACT,CAAC;YAED,MAAM,CAAC,GAAG,CAAC,mDAAmD,IAAI,GAAG,CAAC,CAAC;YAEvE,0CAA0C;YAC1C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;gBACjB,OAAO,EAAE,IAAI;gBACb,OAAO,EAAE,mDAAmD;aAC7D,CAAC,CAAC;YAEH,wDAAwD;YACxD,UAAU,CAAC,GAAG,EAAE;gBACd,IAAI,CAAC;oBACH,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;gBAChC,CAAC;gBAAC,OAAO,GAAG,EAAE,CAAC;oBACb,MAAM,CAAC,KAAK,CAAC,wCAAwC,EAAE,GAAG,CAAC,CAAC;gBAC9D,CAAC;YACH,CAAC,EAAE,GAAG,CAAC,CAAC;QACV,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE,KAAK,CAAC,CAAC;YAC9C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,2BAA2B,EAAE,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC,CAAC;IAEF,yCAAyC;IACzC,MAAM,SAAS,GAKV,EAAE,CAAC;IACR,MAAM,cAAc,GAAG,IAAI,CAAC;IAE5B,6BAA6B;IAC7B,MAAM,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACtE,MAAM,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IAEtE,SAAS,MAAM,CAAC,KAAa,EAAE,MAAc,EAAE,OAAe;QAC5D,MAAM,KAAK,GAAG;YACZ,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;YACnC,KAAK;YACL,MAAM;YACN,OAAO,EAAE,OAAO,CAAC,IAAI,EAAE;SACxB,CAAC;QACF,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QACtB,IAAI,SAAS,CAAC,MAAM,GAAG,cAAc,EAAE,CAAC;YACtC,SAAS,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;IACH,CAAC;IAED,mBAAmB;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,KAAU,EAAE,GAAG,IAAW,EAAW,EAAE;QAC7D,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjC,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAChC,OAAO,mBAAmB,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;IAC7C,CAAC,CAAC;IAEF,mBAAmB;IACnB,OAAO,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,KAAU,EAAE,GAAG,IAAW,EAAW,EAAE;QAC7D,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;QACjC,MAAM,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QACjC,OAAO,mBAAmB,CAAC,KAAK,EAAE,GAAG,IAAI,CAAC,CAAC;IAC7C,CAAC,CAAC;IAEF,wCAAwC;IACxC,MAAM,cAAc,GAAiB,KAAK,EACxC,GAAyB,EACzB,GAAmB,EACnB,EAAE;QACF,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACjE,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC,CAAC;YACnE,MAAM,KAAK,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YAC5C,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;YAE9C,IAAI,IAAI,GAAG,CAAC,GAAG,SAAS,CAAC,CAAC;YAE1B,gBAAgB;YAChB,IAAI,KAAK,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;gBAC7B,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,KAAK,KAAK,CAAC,CAAC;YACjD,CAAC;YACD,IAAI,MAAM,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;gBAC/B,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,MAAM,CAAC,CAAC;YACnD,CAAC;YAED,qBAAqB;YACrB,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;YAE1B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;QAC/B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;YAC/C,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,oBAAoB,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC,CAAC;IAEF,mDAAmD;IACnD,MAAM,iBAAiB,GAAiB,KAAK,EAC3C,IAA0B,EAC1B,GAAmB,EACnB,EAAE;QACF,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE;YACjB,cAAc,EAAE,mBAAmB;YACnC,eAAe,EAAE,UAAU;YAC3B,YAAY,EAAE,YAAY;SAC3B,CAAC,CAAC;QAEH,oBAAoB;QACpB,MAAM,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC;QACnC,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;QAExF,6BAA6B;QAC7B,IAAI,YAAY,GAAG,SAAS,CAAC;QAC7B,MAAM,QAAQ,GAAG,WAAW,CAAC,GAAG,EAAE;YAChC,IAAI,SAAS,CAAC,MAAM,GAAG,YAAY,EAAE,CAAC;gBACpC,MAAM,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,YAAY,CAAC,CAAC;gBAC9C,GAAG,CAAC,KAAK,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,MAAM,CAAC,CAAC;gBAC5E,YAAY,GAAG,SAAS,CAAC,MAAM,CAAC;YAClC,CAAC;QACH,CAAC,EAAE,IAAI,CAAC,CAAC;QAET,oBAAoB;QACpB,GAAG,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;YACnB,aAAa,CAAC,QAAQ,CAAC,CAAC;QAC1B,CAAC,CAAC,CAAC;IACL,CAAC,CAAC;IAEF,qDAAqD;IACrD,MAAM,iBAAiB,GAAiB,KAAK,EAC3C,GAAyB,EACzB,GAAmB,EACnB,EAAE;QACF,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,EAAE,UAAU,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YACjE,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,EAAE,EAAE,CAAC,CAAC;YAEnE,gCAAgC;YAChC,MAAM,QAAQ,GAAG;gBACf,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,cAAc,CAAC;gBACnD,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,EAAE,WAAW,CAAC;gBAChD,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,UAAU,CAAC;gBACvC,cAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,cAAc,CAAC;aAC5C,CAAC;YAEF,IAAI,OAAO,GAAkB,IAAI,CAAC;YAClC,KAAK,MAAM,CAAC,IAAI,QAAQ,EAAE,CAAC;gBACzB,IAAI,YAAE,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,CAAC;oBACrB,OAAO,GAAG,CAAC,CAAC;oBACZ,MAAM;gBACR,CAAC;YACH,CAAC;YAED,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,mBAAmB,EAAE,CAAC,CAAC;gBACnD,OAAO;YACT,CAAC;YAED,oBAAoB;YACpB,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,MAAM,KAAK,GAAG,IAAA,aAAQ,EAAC,OAAO,CAAC,CAAC;YAChC,MAAM,MAAM,GAAG,IAAA,qBAAgB,EAAC,OAAO,EAAE;gBACvC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,IAAI,GAAG,IAAI,GAAG,GAAG,CAAC,EAAE,aAAa;gBAC1D,GAAG,EAAE,KAAK,CAAC,IAAI;aAChB,CAAC,CAAC;YAEH,MAAM,EAAE,GAAG,IAAA,0BAAe,EAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;YAC9C,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC;gBAC5B,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACtB,CAAC;YAED,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC;YACzC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;gBACjB,IAAI,EAAE,OAAO;gBACb,KAAK,EAAE,SAAS;aACjB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,6BAA6B,EAAE,KAAK,CAAC,CAAC;YACnD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,yBAAyB,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC,CAAC;IAGF,qFAAqF;IACrF,MAAM,WAAW,GAAiB,KAAK,EACrC,GAAyB,EACzB,GAAmB,EACnB,EAAE;QACF,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,cAAc,EAAE,CAAC;YACrC,MAAM,GAAG,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;YACrC,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,IAAI,GAAG,EAAE,kBAAkB,CAAC,CAAC;YAC9D,MAAM,OAAO,GAAG,SAAS,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;YAE5G,MAAM,EAAE,GAAG,MAAM,aAAa,EAAE,CAAC;YAEjC,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;oBACjB,MAAM,EAAE,SAAS;oBACjB,IAAI,EAAE,EAAE;oBACR,OAAO;oBACP,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAC,0BAA0B;iBACpE,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,IAAI,QAAQ,GAAG,EAAE,CAAC;YAClB,IAAI,CAAC;gBACH,QAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;oBACjB,MAAM,EAAE,SAAS;oBACjB,IAAI,EAAE,EAAE;oBACR,OAAO;oBACP,MAAM,EAAE,sBAAsB;iBAC/B,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;oBACjB,MAAM,EAAE,MAAM;oBACd,IAAI,EAAE,EAAE;oBACR,OAAO;oBACP,MAAM,EAAE,2BAA2B;iBACpC,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,0CAA0C;YAC1C,MAAM,WAAW,GAAG,yBAAyB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAC7D,IAAI,WAAW,EAAE,CAAC;gBAChB,IAAI,CAAC,EAAE,EAAE,CAAC;oBACR,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;wBACjB,MAAM,EAAE,SAAS;wBACjB,IAAI,EAAE,IAAI;wBACV,OAAO;wBACP,MAAM,EAAE,mBAAmB;qBAC5B,CAAC,CAAC;oBACH,OAAO;gBACT,CAAC;gBACD,MAAM,EAAE,GAAG,QAAQ,KAAK,EAAE,CAAC;gBAC3B,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;oBACjB,MAAM,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM;oBAC5B,IAAI,EAAE,EAAE;oBACR,OAAO;oBACP,MAAM,EAAE,EAAE;wBACR,CAAC,CAAC,gCAAgC;wBAClC,CAAC,CAAC,kCAAkC;iBACvC,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,2CAA2C;YAC3C,IAAI,CAAC,EAAE,EAAE,CAAC;gBACR,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;oBACjB,MAAM,EAAE,SAAS;oBACjB,IAAI,EAAE,IAAI;oBACV,OAAO;oBACP,MAAM,EAAE,6BAA6B;iBACtC,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YAED,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE;gBACjB,MAAM,EAAE,MAAM;gBACd,IAAI,EAAE,EAAE;gBACR,OAAO;gBACP,MAAM,EAAE,8BAA8B;aACvC,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,CAAC,KAAK,CAAC,gCAAgC,EAAE,KAAK,CAAC,CAAC;YACtD,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,KAAK,EAAE,4BAA4B,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CAAC;IAEF,mEAAmE;IACnE,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,aAAa,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACjE,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,gBAAgB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,CAAC,GAAG,CAAC,sBAAsB,EAAE,WAAW,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAClE,MAAM,CAAC,GAAG,CAAC,mBAAmB,EAAE,mBAAmB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACvE,MAAM,CAAC,IAAI,CAAC,oBAAoB,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IACpE,MAAM,CAAC,GAAG,CAAC,iBAAiB,EAAE,cAAc,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAChE,MAAM,CAAC,GAAG,CAAC,wBAAwB,EAAE,iBAAiB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAC1E,MAAM,CAAC,GAAG,CAAC,sBAAsB,EAAE,iBAAiB,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC;IAExE,MAAM,CAAC,GAAG,CAAC,qCAAqC,CAAC,CAAC;AACpD,CAAC","sourcesContent":["/**\n * Admin API Handler\n * Provides configuration management, restart functionality, and log streaming\n */\n\nimport type { ServerResponse } from 'node:http';\nimport type { ApiServer, RouteHandler } from '../ApiServer';\nimport type { AuthenticatedRequest } from '../middleware/AuthMiddleware';\nimport fs from 'fs';\nimport path from 'path';\nimport { createReadStream, statSync } from 'fs';\nimport { createInterface } from 'readline';\nimport { PACKAGE_ROOT } from '../../runtime';\n\nconst CONFIG_DIR = path.resolve(PACKAGE_ROOT, 'config');\n\nfunction getEnvFilePath(): string {\n const envPath = process.env.XPOD_ENV_PATH;\n if (envPath && envPath.trim()) {\n return path.resolve(envPath);\n }\n return path.resolve(process.cwd(), '.env.local');\n}\n\ninterface ConfigFile {\n name: string;\n path: string;\n exists: boolean;\n}\n\ninterface EnvConfig {\n [key: string]: string;\n}\n\n/**\n * Read .env.local file and parse it\n */\nfunction readEnvFile(filePath: string): EnvConfig {\n const config: EnvConfig = {};\n if (!fs.existsSync(filePath)) {\n return config;\n }\n const content = fs.readFileSync(filePath, 'utf-8');\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIndex = trimmed.indexOf('=');\n if (eqIndex === -1) continue;\n const key = trimmed.slice(0, eqIndex).trim();\n let value = trimmed.slice(eqIndex + 1).trim();\n // Remove quotes\n if ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n config[key] = value;\n }\n return config;\n}\n\n/**\n * Write .env.local file\n */\nfunction writeEnvFile(filePath: string, config: EnvConfig): void {\n const lines: string[] = [];\n for (const [key, value] of Object.entries(config)) {\n // Quote values that contain spaces or special characters\n const needsQuotes = /[\\s\"'=]/.test(value);\n const quotedValue = needsQuotes ? `\"${value}\"` : value;\n lines.push(`${key}=${quotedValue}`);\n }\n fs.writeFileSync(filePath, lines.join('\\n') + '\\n');\n}\n\n/**\n * List available config files\n */\nfunction listConfigFiles(): ConfigFile[] {\n const files: ConfigFile[] = [];\n const configFiles = ['local.json', 'cloud.json', 'main.json', 'xpod.base.json'];\n\n for (const name of configFiles) {\n const filePath = path.join(CONFIG_DIR, name);\n files.push({\n name,\n path: filePath,\n exists: fs.existsSync(filePath),\n });\n }\n return files;\n}\n\n/**\n * Send JSON response helper\n */\n\nfunction isPrivateIp(host: string): boolean {\n if (host === 'localhost' || host === '::1') return true;\n if (host.startsWith('127.')) return true;\n if (host.startsWith('10.')) return true;\n if (host.startsWith('192.168.')) return true;\n const m = host.match(/^172\\.(\\d+)\\./);\n if (m) {\n const second = Number(m[1]);\n if (second >= 16 && second <= 31) return true;\n }\n return false;\n}\n\nasync function fetchPublicIp(): Promise<string | null> {\n const endpoints = [\n 'https://api.ipify.org?format=json',\n 'https://ifconfig.me/ip',\n ];\n\n for (const url of endpoints) {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(3000) });\n if (!res.ok) {\n continue;\n }\n const contentType = res.headers.get('content-type') || '';\n if (contentType.includes('application/json')) {\n const json = await res.json() as { ip?: string };\n const ip = json.ip?.trim();\n if (ip) {\n return ip;\n }\n } else {\n const ip = (await res.text()).trim();\n if (ip) {\n return ip;\n }\n }\n } catch {\n // ignore and try next endpoint\n }\n }\n\n return null;\n}\n\nfunction sendJson(res: ServerResponse, status: number, data: unknown): void {\n res.statusCode = status;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(data));\n}\n\n/**\n * Parse JSON body from request\n */\nfunction parseJsonBody(req: AuthenticatedRequest): Promise<{ env?: EnvConfig }> {\n return new Promise((resolve, reject) => {\n let body = '';\n req.on('data', (chunk: Buffer) => {\n body += chunk.toString();\n });\n req.on('end', () => {\n try {\n resolve(body ? JSON.parse(body) : {});\n } catch (err) {\n reject(err);\n }\n });\n req.on('error', reject);\n });\n}\n\nexport function registerAdminRoutes(server: ApiServer): void {\n const logger = console;\n\n // GET /api/admin/status - Get xpod status\n const statusHandler: RouteHandler = async (\n _req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const envFilePath = getEnvFilePath();\n const env = readEnvFile(envFilePath);\n const configs = listConfigFiles();\n\n sendJson(res, 200, {\n status: 'running',\n pid: process.pid,\n ppid: process.ppid,\n uptime: process.uptime(),\n env: {\n CSS_BASE_URL: env.CSS_BASE_URL || process.env.CSS_BASE_URL,\n XPOD_EDITION: env.XPOD_EDITION || process.env.XPOD_EDITION,\n CSS_PORT: env.CSS_PORT || process.env.CSS_PORT,\n },\n configs,\n });\n } catch (error) {\n logger.error('[Admin] Status error:', error);\n sendJson(res, 500, { error: 'Failed to get status' });\n }\n };\n\n // GET /api/admin/config - Get current configuration\n const getConfigHandler: RouteHandler = async (\n _req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const envFilePath = getEnvFilePath();\n const env = readEnvFile(envFilePath);\n sendJson(res, 200, {\n env,\n configFiles: listConfigFiles(),\n });\n } catch (error) {\n logger.error('[Admin] Get config error:', error);\n sendJson(res, 500, { error: 'Failed to read configuration' });\n }\n };\n\n // PUT /api/admin/config - Update configuration\n const updateConfigHandler: RouteHandler = async (\n req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n // Parse body from raw request\n const body = await parseJsonBody(req);\n\n if (body.env) {\n // Merge with existing config\n const envFilePath = getEnvFilePath();\n const currentEnv = readEnvFile(envFilePath);\n const newEnv = { ...currentEnv, ...body.env };\n\n // Remove keys set to null or empty string\n for (const [key, value] of Object.entries(newEnv)) {\n if (value === null || value === '') {\n delete newEnv[key];\n }\n }\n\n writeEnvFile(envFilePath, newEnv);\n logger.log('[Admin] Configuration updated');\n }\n\n sendJson(res, 200, {\n success: true,\n message: 'Configuration updated. Restart required for changes to take effect.',\n });\n } catch (error) {\n logger.error('[Admin] Update config error:', error);\n sendJson(res, 500, { error: 'Failed to update configuration' });\n }\n };\n\n // POST /api/admin/restart - Trigger xpod restart\n const restartHandler: RouteHandler = async (\n _req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const ppid = process.ppid;\n\n if (!ppid) {\n sendJson(res, 500, { error: 'Cannot determine parent process' });\n return;\n }\n\n logger.log(`[Admin] Sending SIGUSR1 to parent process (pid: ${ppid})`);\n\n // Send response before triggering restart\n sendJson(res, 200, {\n success: true,\n message: 'Restart signal sent. Server will restart shortly.',\n });\n\n // Give time for response to be sent, then signal parent\n setTimeout(() => {\n try {\n process.kill(ppid, 'SIGUSR1');\n } catch (err) {\n logger.error('[Admin] Failed to send restart signal:', err);\n }\n }, 100);\n } catch (error) {\n logger.error('[Admin] Restart error:', error);\n sendJson(res, 500, { error: 'Failed to trigger restart' });\n }\n };\n\n // Log buffer for recent logs (in-memory)\n const logBuffer: Array<{\n timestamp: string;\n level: string;\n source: string;\n message: string;\n }> = [];\n const MAX_LOG_BUFFER = 1000;\n\n // Capture stdout/stderr logs\n const originalStdoutWrite = process.stdout.write.bind(process.stdout);\n const originalStderrWrite = process.stderr.write.bind(process.stderr);\n\n function addLog(level: string, source: string, message: string): void {\n const entry = {\n timestamp: new Date().toISOString(),\n level,\n source,\n message: message.trim(),\n };\n logBuffer.push(entry);\n if (logBuffer.length > MAX_LOG_BUFFER) {\n logBuffer.shift();\n }\n }\n\n // Intercept stdout\n process.stdout.write = (chunk: any, ...args: any[]): boolean => {\n const message = chunk.toString();\n addLog('info', 'xpod', message);\n return originalStdoutWrite(chunk, ...args);\n };\n\n // Intercept stderr\n process.stderr.write = (chunk: any, ...args: any[]): boolean => {\n const message = chunk.toString();\n addLog('error', 'xpod', message);\n return originalStderrWrite(chunk, ...args);\n };\n\n // GET /api/admin/logs - Get recent logs\n const getLogsHandler: RouteHandler = async (\n req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const url = new URL(req.url || '', `http://${req.headers.host}`);\n const limit = parseInt(url.searchParams.get('limit') || '100', 10);\n const level = url.searchParams.get('level');\n const source = url.searchParams.get('source');\n\n let logs = [...logBuffer];\n\n // Apply filters\n if (level && level !== 'all') {\n logs = logs.filter(log => log.level === level);\n }\n if (source && source !== 'all') {\n logs = logs.filter(log => log.source === source);\n }\n\n // Return last N logs\n logs = logs.slice(-limit);\n\n sendJson(res, 200, { logs });\n } catch (error) {\n logger.error('[Admin] Get logs error:', error);\n sendJson(res, 500, { error: 'Failed to get logs' });\n }\n };\n\n // GET /api/admin/logs/stream - Stream logs via SSE\n const streamLogsHandler: RouteHandler = async (\n _req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n });\n\n // Send initial logs\n const lastIndex = logBuffer.length;\n res.write(`data: ${JSON.stringify({ type: 'init', logs: logBuffer.slice(-100) })}\\n\\n`);\n\n // Send new logs every second\n let currentIndex = lastIndex;\n const interval = setInterval(() => {\n if (logBuffer.length > currentIndex) {\n const newLogs = logBuffer.slice(currentIndex);\n res.write(`data: ${JSON.stringify({ type: 'update', logs: newLogs })}\\n\\n`);\n currentIndex = logBuffer.length;\n }\n }, 1000);\n\n // Clean up on close\n res.on('close', () => {\n clearInterval(interval);\n });\n };\n\n // GET /api/admin/logs/file - Read log file from disk\n const getLogFileHandler: RouteHandler = async (\n req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const url = new URL(req.url || '', `http://${req.headers.host}`);\n const lines = parseInt(url.searchParams.get('lines') || '100', 10);\n\n // Try common log file locations\n const logPaths = [\n path.resolve(process.cwd(), 'logs', 'combined.log'),\n path.resolve(process.cwd(), 'logs', 'error.log'),\n path.resolve(process.cwd(), 'xpod.log'),\n path.resolve(process.cwd(), 'combined.log'),\n ];\n\n let logPath: string | null = null;\n for (const p of logPaths) {\n if (fs.existsSync(p)) {\n logPath = p;\n break;\n }\n }\n\n if (!logPath) {\n sendJson(res, 404, { error: 'No log file found' });\n return;\n }\n\n // Read last N lines\n const fileLogs: string[] = [];\n const stats = statSync(logPath);\n const stream = createReadStream(logPath, {\n start: Math.max(0, stats.size - 1024 * 100), // Last 100KB\n end: stats.size,\n });\n\n const rl = createInterface({ input: stream });\n for await (const line of rl) {\n fileLogs.push(line);\n }\n\n const lastLines = fileLogs.slice(-lines);\n sendJson(res, 200, {\n file: logPath,\n lines: lastLines,\n });\n } catch (error) {\n logger.error('[Admin] Get log file error:', error);\n sendJson(res, 500, { error: 'Failed to read log file' });\n }\n };\n\n\n // GET /api/admin/public-ip - Detect outbound public IP and compare with CSS_BASE_URL\n const ipv4Handler: RouteHandler = async (\n req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const envFilePath = getEnvFilePath();\n const env = readEnvFile(envFilePath);\n const parsedUrl = new URL(req.url ?? '/', 'http://localhost');\n const baseUrl = parsedUrl.searchParams.get('baseUrl') || env.CSS_BASE_URL || process.env.CSS_BASE_URL || '';\n\n const ip = await fetchPublicIp();\n\n if (!baseUrl) {\n sendJson(res, 200, {\n status: 'unknown',\n ipv4: ip,\n baseUrl,\n detail: ip ? '未配置 Base URL,无法判断是否可直连。' : '未配置 Base URL,且无法获取公网 IP。',\n });\n return;\n }\n\n let hostname = '';\n try {\n hostname = new URL(baseUrl).hostname;\n } catch {\n sendJson(res, 200, {\n status: 'unknown',\n ipv4: ip,\n baseUrl,\n detail: 'Base URL 格式不合法,无法判断。',\n });\n return;\n }\n\n if (isPrivateIp(hostname)) {\n sendJson(res, 200, {\n status: 'fail',\n ipv4: ip,\n baseUrl,\n detail: 'Base URL 为本地/内网地址,默认不可直连。',\n });\n return;\n }\n\n // If hostname is an IP, compare directly.\n const isIpLiteral = /^\\d{1,3}(\\.\\d{1,3}){3}$/.test(hostname);\n if (isIpLiteral) {\n if (!ip) {\n sendJson(res, 200, {\n status: 'unknown',\n ipv4: null,\n baseUrl,\n detail: '无法获取公网出口 IP,无法比对。',\n });\n return;\n }\n const ok = hostname === ip;\n sendJson(res, 200, {\n status: ok ? 'pass' : 'fail',\n ipv4: ip,\n baseUrl,\n detail: ok\n ? 'Base URL IP 与公网出口 IP 一致,默认可直连。'\n : 'Base URL IP 与公网出口 IP 不一致,默认不可直连。',\n });\n return;\n }\n\n // Domain name: we can only do best-effort.\n if (!ip) {\n sendJson(res, 200, {\n status: 'unknown',\n ipv4: null,\n baseUrl,\n detail: '已配置域名,但无法获取公网出口 IP,无法进一步判断。',\n });\n return;\n }\n\n sendJson(res, 200, {\n status: 'pass',\n ipv4: ip,\n baseUrl,\n detail: '已配置域名,默认可直连(仍需确保端口映射/防火墙放行)。',\n });\n } catch (error) {\n logger.error('[Admin] Public IP check error:', error);\n sendJson(res, 500, { error: 'Failed to detect public ip' });\n }\n };\n\n // Register routes - public for now (TODO: add auth for production)\n server.get('/api/admin/status', statusHandler, { public: true });\n server.get('/api/admin/config', getConfigHandler, { public: true });\n server.get('/api/admin/public-ip', ipv4Handler, { public: true });\n server.put('/api/admin/config', updateConfigHandler, { public: true });\n server.post('/api/admin/restart', restartHandler, { public: true });\n server.get('/api/admin/logs', getLogsHandler, { public: true });\n server.get('/api/admin/logs/stream', streamLogsHandler, { public: true });\n server.get('/api/admin/logs/file', getLogFileHandler, { public: true });\n\n logger.log('[Admin] Admin API routes registered');\n}\n"]}
1
+ {"version":3,"file":"AdminHandler.js","sourceRoot":"","sources":["../../../src/api/handlers/AdminHandler.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Admin API Handler\n * Provides configuration management, restart functionality, and log streaming\n */\n\nimport type { ServerResponse } from 'node:http';\nimport type { ApiServer, RouteHandler } from '../ApiServer';\nimport type { AuthenticatedRequest } from '../middleware/AuthMiddleware';\nimport fs from 'fs';\nimport path from 'path';\nimport { createReadStream, statSync } from 'fs';\nimport { createInterface } from 'readline';\nimport { PACKAGE_ROOT } from '../../runtime';\n\nconst CONFIG_DIR = path.resolve(PACKAGE_ROOT, 'config');\n\nfunction getEnvFilePath(): string {\n const envPath = process.env.XPOD_ENV_PATH;\n if (envPath && envPath.trim()) {\n return path.resolve(envPath);\n }\n return path.resolve(process.cwd(), '.env.local');\n}\n\ninterface ConfigFile {\n name: string;\n path: string;\n exists: boolean;\n}\n\ninterface EnvConfig {\n [key: string]: string;\n}\n\ninterface LogEntry {\n timestamp: string;\n level: string;\n source: string;\n message: string;\n}\n\nexport interface SanitizedEnvRead {\n env: EnvConfig;\n secrets: Record<string, { configured: boolean }>;\n}\n\nexport const ALLOWED_ADMIN_CONFIG_KEYS = [\n 'XPOD_DEPLOY_MODE',\n 'CSS_ROOT_FILE_PATH',\n 'CSS_BASE_URL',\n 'XPOD_TUNNEL_PROVIDER',\n 'XPOD_TUNNEL_PUBLIC_URL',\n 'CLOUDFLARE_TUNNEL_TOKEN',\n 'SAKURA_TUNNEL_TOKEN',\n 'NGROK_AUTHTOKEN',\n 'NGROK_URL',\n 'FRP_TUNNEL_TOKEN',\n 'FRP_TUNNEL_URL',\n 'XPOD_HTTPS_MODE',\n 'XPOD_HTTPS_CERT_PATH',\n 'XPOD_HTTPS_KEY_PATH',\n 'XPOD_CLOUD_API_ENDPOINT',\n 'XPOD_NODE_ID',\n 'XPOD_SP_DOMAIN',\n 'XPOD_NODE_TOKEN',\n 'XPOD_SERVICE_TOKEN',\n 'CSS_PORT',\n 'CSS_SPARQL_ENDPOINT',\n 'CSS_IDENTITY_DB_URL',\n 'CSS_LOGGING_LEVEL',\n 'CSS_SHOW_STACK_TRACE',\n] as const;\n\nconst ALLOWED_ADMIN_CONFIG_KEY_SET = new Set<string>(ALLOWED_ADMIN_CONFIG_KEYS);\n\nexport function isAdminSecretEnvKey(key: string): boolean {\n const normalized = key.toUpperCase();\n if (normalized.endsWith('_KEY_PATH') || normalized.endsWith('_CERT_PATH')) {\n return false;\n }\n return (\n normalized.includes('AUTHTOKEN') ||\n normalized.endsWith('_TOKEN') ||\n normalized.endsWith('_SECRET') ||\n normalized.endsWith('_API_KEY') ||\n normalized.includes('PASSWORD') ||\n normalized.includes('CLIENT_SECRET') ||\n normalized.endsWith('_DB_URL') ||\n normalized.includes('DATABASE_URL')\n );\n}\n\nexport function sanitizeEnvForRead(env: EnvConfig): SanitizedEnvRead {\n const sanitized: EnvConfig = {};\n const secrets: Record<string, { configured: boolean }> = {};\n\n for (const [key, value] of Object.entries(env)) {\n if (isAdminSecretEnvKey(key)) {\n secrets[key] = { configured: Boolean(value) };\n continue;\n }\n sanitized[key] = value;\n }\n\n return { env: sanitized, secrets };\n}\n\nexport function createAllowedAdminConfigPatch(input: EnvConfig): EnvConfig {\n const patch: EnvConfig = {};\n for (const [key, value] of Object.entries(input)) {\n if (!ALLOWED_ADMIN_CONFIG_KEY_SET.has(key)) {\n continue;\n }\n if (isAdminSecretEnvKey(key) && !value) {\n continue;\n }\n patch[key] = value;\n }\n return patch;\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nexport function sanitizeLogMessage(message: string, env: EnvConfig): string {\n let sanitized = message;\n const secretEntries = Object.entries(env)\n .filter(([key, value]) => isAdminSecretEnvKey(key) && value.length >= 6)\n .sort((a, b) => b[1].length - a[1].length);\n\n for (const [key, value] of secretEntries) {\n sanitized = sanitized.replace(new RegExp(escapeRegExp(value), 'g'), `[redacted:${key}]`);\n }\n return sanitized;\n}\n\nfunction sanitizeLogEntry(entry: LogEntry, env: EnvConfig): LogEntry {\n return {\n ...entry,\n message: sanitizeLogMessage(entry.message, env),\n };\n}\n\nfunction isLocalAdminHost(req: AuthenticatedRequest): boolean {\n const configuredToken = process.env.XPOD_ADMIN_TOKEN;\n const providedToken = req.headers['x-xpod-admin-token'] ??\n req.headers.authorization?.replace(/^Bearer\\s+/i, '');\n if (configuredToken && providedToken === configuredToken) {\n return true;\n }\n\n const host = String(req.headers.host ?? '').split(':')[0].toLowerCase();\n return host === 'localhost' || host === '127.0.0.1' || host === '[::1]' || host === '::1';\n}\n\nfunction assertAdminMutationAllowed(req: AuthenticatedRequest, res: ServerResponse): boolean {\n if (isLocalAdminHost(req)) {\n return true;\n }\n sendJson(res, 403, {\n error: 'Forbidden',\n detail: 'Runtime config writes and restart are allowed only from loopback or with XPOD_ADMIN_TOKEN.',\n });\n return false;\n}\n\n/**\n * Read .env.local file and parse it\n */\nfunction readEnvFile(filePath: string): EnvConfig {\n const config: EnvConfig = {};\n if (!fs.existsSync(filePath)) {\n return config;\n }\n const content = fs.readFileSync(filePath, 'utf-8');\n for (const line of content.split('\\n')) {\n const trimmed = line.trim();\n if (!trimmed || trimmed.startsWith('#')) continue;\n const eqIndex = trimmed.indexOf('=');\n if (eqIndex === -1) continue;\n const key = trimmed.slice(0, eqIndex).trim();\n let value = trimmed.slice(eqIndex + 1).trim();\n // Remove quotes\n if ((value.startsWith('\"') && value.endsWith('\"')) ||\n (value.startsWith(\"'\") && value.endsWith(\"'\"))) {\n value = value.slice(1, -1);\n }\n config[key] = value;\n }\n return config;\n}\n\n/**\n * Write .env.local file\n */\nfunction writeEnvFile(filePath: string, config: EnvConfig): void {\n const lines: string[] = [];\n for (const [key, value] of Object.entries(config)) {\n // Quote values that contain spaces or special characters\n const needsQuotes = /[\\s\"'=]/.test(value);\n const quotedValue = needsQuotes ? `\"${value}\"` : value;\n lines.push(`${key}=${quotedValue}`);\n }\n fs.writeFileSync(filePath, lines.join('\\n') + '\\n');\n}\n\n/**\n * List available config files\n */\nfunction listConfigFiles(): ConfigFile[] {\n const files: ConfigFile[] = [];\n const configFiles = ['local.json', 'cloud.json', 'main.json', 'xpod.base.json'];\n\n for (const name of configFiles) {\n const filePath = path.join(CONFIG_DIR, name);\n files.push({\n name,\n path: filePath,\n exists: fs.existsSync(filePath),\n });\n }\n return files;\n}\n\n/**\n * Send JSON response helper\n */\n\nfunction isPrivateIp(host: string): boolean {\n if (host === 'localhost' || host === '::1') return true;\n if (host.startsWith('127.')) return true;\n if (host.startsWith('10.')) return true;\n if (host.startsWith('192.168.')) return true;\n const m = host.match(/^172\\.(\\d+)\\./);\n if (m) {\n const second = Number(m[1]);\n if (second >= 16 && second <= 31) return true;\n }\n return false;\n}\n\nasync function fetchPublicIp(): Promise<string | null> {\n const endpoints = [\n 'https://api.ipify.org?format=json',\n 'https://ifconfig.me/ip',\n ];\n\n for (const url of endpoints) {\n try {\n const res = await fetch(url, { signal: AbortSignal.timeout(3000) });\n if (!res.ok) {\n continue;\n }\n const contentType = res.headers.get('content-type') || '';\n if (contentType.includes('application/json')) {\n const json = await res.json() as { ip?: string };\n const ip = json.ip?.trim();\n if (ip) {\n return ip;\n }\n } else {\n const ip = (await res.text()).trim();\n if (ip) {\n return ip;\n }\n }\n } catch {\n // ignore and try next endpoint\n }\n }\n\n return null;\n}\n\nfunction sendJson(res: ServerResponse, status: number, data: unknown): void {\n res.statusCode = status;\n res.setHeader('Content-Type', 'application/json');\n res.end(JSON.stringify(data));\n}\n\n/**\n * Parse JSON body from request\n */\nfunction parseJsonBody(req: AuthenticatedRequest): Promise<{ env?: EnvConfig }> {\n return new Promise((resolve, reject) => {\n let body = '';\n req.on('data', (chunk: Buffer) => {\n body += chunk.toString();\n });\n req.on('end', () => {\n try {\n resolve(body ? JSON.parse(body) : {});\n } catch (err) {\n reject(err);\n }\n });\n req.on('error', reject);\n });\n}\n\nexport function registerAdminRoutes(server: ApiServer): void {\n const logger = console;\n\n // GET /api/admin/status - Get xpod status\n const statusHandler: RouteHandler = async (\n _req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const envFilePath = getEnvFilePath();\n const env = readEnvFile(envFilePath);\n const configs = listConfigFiles();\n\n sendJson(res, 200, {\n status: 'running',\n pid: process.pid,\n ppid: process.ppid,\n uptime: process.uptime(),\n env: {\n CSS_BASE_URL: env.CSS_BASE_URL || process.env.CSS_BASE_URL,\n XPOD_EDITION: env.XPOD_EDITION || process.env.XPOD_EDITION,\n CSS_PORT: env.CSS_PORT || process.env.CSS_PORT,\n },\n configs,\n });\n } catch (error) {\n logger.error('[Admin] Status error:', error);\n sendJson(res, 500, { error: 'Failed to get status' });\n }\n };\n\n // GET /api/admin/config - Get current configuration\n const getConfigHandler: RouteHandler = async (\n _req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const envFilePath = getEnvFilePath();\n const env = readEnvFile(envFilePath);\n sendJson(res, 200, {\n ...sanitizeEnvForRead(env),\n configFiles: listConfigFiles(),\n });\n } catch (error) {\n logger.error('[Admin] Get config error:', error);\n sendJson(res, 500, { error: 'Failed to read configuration' });\n }\n };\n\n // PUT /api/admin/config - Update configuration\n const updateConfigHandler: RouteHandler = async (\n req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n if (!assertAdminMutationAllowed(req, res)) {\n return;\n }\n // Parse body from raw request\n const body = await parseJsonBody(req);\n\n if (body.env) {\n // Merge with existing config\n const envFilePath = getEnvFilePath();\n const currentEnv = readEnvFile(envFilePath);\n const patch = createAllowedAdminConfigPatch(body.env);\n const newEnv = { ...currentEnv, ...patch };\n\n // Remove keys set to null or empty string\n for (const [key, value] of Object.entries(newEnv)) {\n if (value === null || value === '') {\n delete newEnv[key];\n }\n }\n\n writeEnvFile(envFilePath, newEnv);\n logger.log('[Admin] Configuration updated');\n }\n\n sendJson(res, 200, {\n success: true,\n message: 'Configuration updated. Restart required for changes to take effect.',\n });\n } catch (error) {\n logger.error('[Admin] Update config error:', error);\n sendJson(res, 500, { error: 'Failed to update configuration' });\n }\n };\n\n // POST /api/admin/restart - Trigger xpod restart\n const restartHandler: RouteHandler = async (\n req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n if (!assertAdminMutationAllowed(req, res)) {\n return;\n }\n const ppid = process.ppid;\n\n if (!ppid) {\n sendJson(res, 500, { error: 'Cannot determine parent process' });\n return;\n }\n\n logger.log(`[Admin] Sending SIGUSR1 to parent process (pid: ${ppid})`);\n\n // Send response before triggering restart\n sendJson(res, 200, {\n success: true,\n message: 'Restart signal sent. Server will restart shortly.',\n });\n\n // Give time for response to be sent, then signal parent\n setTimeout(() => {\n try {\n process.kill(ppid, 'SIGUSR1');\n } catch (err) {\n logger.error('[Admin] Failed to send restart signal:', err);\n }\n }, 100);\n } catch (error) {\n logger.error('[Admin] Restart error:', error);\n sendJson(res, 500, { error: 'Failed to trigger restart' });\n }\n };\n\n // Log buffer for recent logs (in-memory)\n const logBuffer: LogEntry[] = [];\n const MAX_LOG_BUFFER = 1000;\n\n // Capture stdout/stderr logs\n const originalStdoutWrite = process.stdout.write.bind(process.stdout);\n const originalStderrWrite = process.stderr.write.bind(process.stderr);\n\n function addLog(level: string, source: string, message: string): void {\n const entry = {\n timestamp: new Date().toISOString(),\n level,\n source,\n message: message.trim(),\n };\n logBuffer.push(entry);\n if (logBuffer.length > MAX_LOG_BUFFER) {\n logBuffer.shift();\n }\n }\n\n // Intercept stdout\n process.stdout.write = (chunk: any, ...args: any[]): boolean => {\n const message = chunk.toString();\n addLog('info', 'xpod', message);\n return originalStdoutWrite(chunk, ...args);\n };\n\n // Intercept stderr\n process.stderr.write = (chunk: any, ...args: any[]): boolean => {\n const message = chunk.toString();\n addLog('error', 'xpod', message);\n return originalStderrWrite(chunk, ...args);\n };\n\n // GET /api/admin/logs - Get recent logs\n const getLogsHandler: RouteHandler = async (\n req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const url = new URL(req.url || '', `http://${req.headers.host}`);\n const limit = parseInt(url.searchParams.get('limit') || '100', 10);\n const level = url.searchParams.get('level');\n const source = url.searchParams.get('source');\n const env = readEnvFile(getEnvFilePath());\n\n let logs = [...logBuffer];\n\n // Apply filters\n if (level && level !== 'all') {\n logs = logs.filter(log => log.level === level);\n }\n if (source && source !== 'all') {\n logs = logs.filter(log => log.source === source);\n }\n\n // Return last N logs\n logs = logs.slice(-limit).map((log) => sanitizeLogEntry(log, env));\n\n sendJson(res, 200, { logs });\n } catch (error) {\n logger.error('[Admin] Get logs error:', error);\n sendJson(res, 500, { error: 'Failed to get logs' });\n }\n };\n\n // GET /api/admin/logs/stream - Stream logs via SSE\n const streamLogsHandler: RouteHandler = async (\n _req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n res.writeHead(200, {\n 'Content-Type': 'text/event-stream',\n 'Cache-Control': 'no-cache',\n 'Connection': 'keep-alive',\n });\n\n // Send initial logs\n const lastIndex = logBuffer.length;\n let env = readEnvFile(getEnvFilePath());\n res.write(`data: ${JSON.stringify({ type: 'init', logs: logBuffer.slice(-100).map((log) => sanitizeLogEntry(log, env)) })}\\n\\n`);\n\n // Send new logs every second\n let currentIndex = lastIndex;\n const interval = setInterval(() => {\n if (logBuffer.length > currentIndex) {\n env = readEnvFile(getEnvFilePath());\n const newLogs = logBuffer.slice(currentIndex).map((log) => sanitizeLogEntry(log, env));\n res.write(`data: ${JSON.stringify({ type: 'update', logs: newLogs })}\\n\\n`);\n currentIndex = logBuffer.length;\n }\n }, 1000);\n\n // Clean up on close\n res.on('close', () => {\n clearInterval(interval);\n });\n };\n\n // GET /api/admin/logs/file - Read log file from disk\n const getLogFileHandler: RouteHandler = async (\n req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const url = new URL(req.url || '', `http://${req.headers.host}`);\n const lines = parseInt(url.searchParams.get('lines') || '100', 10);\n const env = readEnvFile(getEnvFilePath());\n\n // Try common log file locations\n const logPaths = [\n path.resolve(process.cwd(), 'logs', 'combined.log'),\n path.resolve(process.cwd(), 'logs', 'error.log'),\n path.resolve(process.cwd(), 'xpod.log'),\n path.resolve(process.cwd(), 'combined.log'),\n ];\n\n let logPath: string | null = null;\n for (const p of logPaths) {\n if (fs.existsSync(p)) {\n logPath = p;\n break;\n }\n }\n\n if (!logPath) {\n sendJson(res, 404, { error: 'No log file found' });\n return;\n }\n\n // Read last N lines\n const fileLogs: string[] = [];\n const stats = statSync(logPath);\n const stream = createReadStream(logPath, {\n start: Math.max(0, stats.size - 1024 * 100), // Last 100KB\n end: stats.size,\n });\n\n const rl = createInterface({ input: stream });\n for await (const line of rl) {\n fileLogs.push(line);\n }\n\n const lastLines = fileLogs.slice(-lines);\n sendJson(res, 200, {\n file: logPath,\n lines: lastLines.map((line) => sanitizeLogMessage(line, env)),\n });\n } catch (error) {\n logger.error('[Admin] Get log file error:', error);\n sendJson(res, 500, { error: 'Failed to read log file' });\n }\n };\n\n\n // GET /api/admin/public-ip - Detect outbound public IP and compare with CSS_BASE_URL\n const ipv4Handler: RouteHandler = async (\n req: AuthenticatedRequest,\n res: ServerResponse,\n ) => {\n try {\n const envFilePath = getEnvFilePath();\n const env = readEnvFile(envFilePath);\n const parsedUrl = new URL(req.url ?? '/', 'http://localhost');\n const baseUrl = parsedUrl.searchParams.get('baseUrl') || env.CSS_BASE_URL || process.env.CSS_BASE_URL || '';\n\n const ip = await fetchPublicIp();\n\n if (!baseUrl) {\n sendJson(res, 200, {\n status: 'unknown',\n ipv4: ip,\n baseUrl,\n detail: ip ? '未配置 Base URL,无法判断是否可直连。' : '未配置 Base URL,且无法获取公网 IP。',\n });\n return;\n }\n\n let hostname = '';\n try {\n hostname = new URL(baseUrl).hostname;\n } catch {\n sendJson(res, 200, {\n status: 'unknown',\n ipv4: ip,\n baseUrl,\n detail: 'Base URL 格式不合法,无法判断。',\n });\n return;\n }\n\n if (isPrivateIp(hostname)) {\n sendJson(res, 200, {\n status: 'fail',\n ipv4: ip,\n baseUrl,\n detail: 'Base URL 为本地/内网地址,默认不可直连。',\n });\n return;\n }\n\n // If hostname is an IP, compare directly.\n const isIpLiteral = /^\\d{1,3}(\\.\\d{1,3}){3}$/.test(hostname);\n if (isIpLiteral) {\n if (!ip) {\n sendJson(res, 200, {\n status: 'unknown',\n ipv4: null,\n baseUrl,\n detail: '无法获取公网出口 IP,无法比对。',\n });\n return;\n }\n const ok = hostname === ip;\n sendJson(res, 200, {\n status: ok ? 'pass' : 'fail',\n ipv4: ip,\n baseUrl,\n detail: ok\n ? 'Base URL IP 与公网出口 IP 一致,默认可直连。'\n : 'Base URL IP 与公网出口 IP 不一致,默认不可直连。',\n });\n return;\n }\n\n // Domain name: we can only do best-effort.\n if (!ip) {\n sendJson(res, 200, {\n status: 'unknown',\n ipv4: null,\n baseUrl,\n detail: '已配置域名,但无法获取公网出口 IP,无法进一步判断。',\n });\n return;\n }\n\n sendJson(res, 200, {\n status: 'pass',\n ipv4: ip,\n baseUrl,\n detail: '已配置域名,默认可直连(仍需确保端口映射/防火墙放行)。',\n });\n } catch (error) {\n logger.error('[Admin] Public IP check error:', error);\n sendJson(res, 500, { error: 'Failed to detect public ip' });\n }\n };\n\n // Register routes - public for now (TODO: add auth for production)\n server.get('/api/admin/status', statusHandler, { public: true });\n server.get('/api/admin/config', getConfigHandler, { public: true });\n server.get('/api/admin/public-ip', ipv4Handler, { public: true });\n server.put('/api/admin/config', updateConfigHandler, { public: true });\n server.post('/api/admin/restart', restartHandler, { public: true });\n server.get('/api/admin/logs', getLogsHandler, { public: true });\n server.get('/api/admin/logs/stream', streamLogsHandler, { public: true });\n server.get('/api/admin/logs/file', getLogFileHandler, { public: true });\n\n logger.log('[Admin] Admin API routes registered');\n}\n"]}
@@ -1,5 +1,6 @@
1
1
  import type { CommandModule } from 'yargs';
2
2
  import { type PodModelDescriptor } from '@undefineds.co/models';
3
+ import { type CliAuthContext } from '../lib/auth-context';
3
4
  interface ObjArgs {
4
5
  url?: string;
5
6
  json: boolean;
@@ -28,7 +29,28 @@ interface ResolvedObjSelector {
28
29
  limit: number;
29
30
  includeMetadata: boolean;
30
31
  }
32
+ type ItemResult = {
33
+ index: number;
34
+ ok: boolean;
35
+ code: string;
36
+ message?: string;
37
+ [key: string]: unknown;
38
+ };
39
+ type ObjMutationContext = CliAuthContext & {
40
+ planningOnly?: boolean;
41
+ planningWarning?: string;
42
+ pendingOnly?: boolean;
43
+ pendingWarning?: string;
44
+ outboxPath?: string;
45
+ };
46
+ export declare function resolveObjMutationContext(argv: ObjArgs, commit: boolean): Promise<ObjMutationContext>;
47
+ export declare function getObjLocalOutboxPath(): string;
31
48
  export declare function redactDescriptorObject(descriptor: PodModelDescriptor, value: Record<string, unknown>): Record<string, unknown>;
49
+ export declare function serializeSchemaDescriptor(descriptor: PodModelDescriptor): Record<string, unknown>;
50
+ export declare function listSchemaDescriptors(input?: {
51
+ domain?: string;
52
+ }, descriptors?: readonly PodModelDescriptor[]): Record<string, unknown>[];
53
+ export declare function describeSchemaDescriptor(schemaOrAlias: string, descriptors?: readonly PodModelDescriptor[]): Record<string, unknown> | null;
32
54
  export declare function buildDescriptorUpsertSparql(descriptor: PodModelDescriptor, subject: string, row: ObjMutationRow): string;
33
55
  export declare function buildDescriptorPatchSparql(descriptor: PodModelDescriptor, subject: string, set: Record<string, unknown>): string;
34
56
  export declare function buildDescriptorLinkSparql(subject: string, predicate: string, object: string): string;
@@ -40,5 +62,19 @@ export declare function extractReservedWhereSelectors(where: Record<string, unkn
40
62
  path?: string;
41
63
  };
42
64
  export declare function buildDescriptorObjectQuery(selector: ResolvedObjSelector): string;
65
+ export declare function descriptorUpsertPlanItem(input: {
66
+ descriptor: PodModelDescriptor;
67
+ index: number;
68
+ commit: boolean;
69
+ podRoot: string;
70
+ row: ObjMutationRow;
71
+ }): ItemResult;
72
+ export declare function executeRows(input: {
73
+ argv: ObjArgs;
74
+ rows: ObjMutationRow[];
75
+ defaultSchema?: string;
76
+ commit: boolean;
77
+ }): Promise<ItemResult[]>;
78
+ export declare function mutationItemsResultCode(items: ItemResult[], commit: boolean): 'plan_ready' | 'committed' | 'pending_local' | 'partial_failure';
43
79
  export declare const objCommand: CommandModule<object, ObjArgs>;
44
80
  export {};
@@ -1,16 +1,26 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.objCommand = void 0;
4
+ exports.resolveObjMutationContext = resolveObjMutationContext;
5
+ exports.getObjLocalOutboxPath = getObjLocalOutboxPath;
4
6
  exports.redactDescriptorObject = redactDescriptorObject;
7
+ exports.serializeSchemaDescriptor = serializeSchemaDescriptor;
8
+ exports.listSchemaDescriptors = listSchemaDescriptors;
9
+ exports.describeSchemaDescriptor = describeSchemaDescriptor;
5
10
  exports.buildDescriptorUpsertSparql = buildDescriptorUpsertSparql;
6
11
  exports.buildDescriptorPatchSparql = buildDescriptorPatchSparql;
7
12
  exports.buildDescriptorLinkSparql = buildDescriptorLinkSparql;
8
13
  exports.buildDescriptorDeleteSparql = buildDescriptorDeleteSparql;
9
14
  exports.extractReservedWhereSelectors = extractReservedWhereSelectors;
10
15
  exports.buildDescriptorObjectQuery = buildDescriptorObjectQuery;
16
+ exports.descriptorUpsertPlanItem = descriptorUpsertPlanItem;
17
+ exports.executeRows = executeRows;
18
+ exports.mutationItemsResultCode = mutationItemsResultCode;
11
19
  const fs_1 = require("fs");
20
+ const path_1 = require("path");
12
21
  const models_1 = require("@undefineds.co/models");
13
22
  const auth_context_1 = require("../lib/auth-context");
23
+ const credentials_store_1 = require("../lib/credentials-store");
14
24
  const output_1 = require("../lib/output");
15
25
  const resource_1 = require("../lib/resource");
16
26
  const rdf_1 = require("./rdf");
@@ -93,14 +103,28 @@ async function readJsonl(input) {
93
103
  function descriptorLocalName(value) {
94
104
  return value.split(/[\/#]/u).filter(Boolean).pop() ?? value;
95
105
  }
106
+ function normalizeDescriptorAlias(value) {
107
+ return value.toLowerCase().replace(/[^a-z0-9]+/gu, '');
108
+ }
109
+ function descriptorAliases(descriptor) {
110
+ const discovery = descriptor;
111
+ return discovery.aliases?.length ? discovery.aliases : [descriptorLocalName(descriptor.class)];
112
+ }
113
+ function descriptorMatchesRef(descriptor, ref) {
114
+ const normalized = normalizeDescriptorAlias(ref);
115
+ return descriptor.uri === ref ||
116
+ descriptor.class === ref ||
117
+ descriptor.resourceKind.toLowerCase() === ref.trim().toLowerCase() ||
118
+ normalizeDescriptorAlias(descriptorLocalName(descriptor.uri)) === normalized ||
119
+ normalizeDescriptorAlias(descriptorLocalName(descriptor.class)) === normalized ||
120
+ descriptorAliases(descriptor).some((alias) => normalizeDescriptorAlias(alias) === normalized);
121
+ }
96
122
  function resolveDescriptorOrNull(schema) {
97
- const exact = models_1.podSchema.describe({ schemaUri: schema });
123
+ const exact = models_1.podSchema.describe({ schemaUri: schema }) ??
124
+ models_1.podSchema.describe?.({ alias: schema });
98
125
  if (exact)
99
126
  return exact;
100
- const normalized = schema.trim().toLowerCase();
101
- return models_1.podSchema.list().find((descriptor) => descriptor.resourceKind.toLowerCase() === normalized ||
102
- descriptorLocalName(descriptor.uri).toLowerCase() === normalized ||
103
- descriptorLocalName(descriptor.class).toLowerCase() === normalized) ?? null;
127
+ return models_1.podSchema.list().find((descriptor) => descriptorMatchesRef(descriptor, schema)) ?? null;
104
128
  }
105
129
  function resolveDescriptor(schema) {
106
130
  const descriptor = resolveDescriptorOrNull(schema);
@@ -112,6 +136,48 @@ function resolveDescriptor(schema) {
112
136
  function resourceUrlFromPlan(podRoot, plan) {
113
137
  return new URL(plan.resourceUri.replace(/^\/+/, ''), podRoot).toString();
114
138
  }
139
+ async function resolveObjMutationContext(argv, commit) {
140
+ try {
141
+ return await (0, auth_context_1.requireAuthContext)(argv);
142
+ }
143
+ catch (error) {
144
+ const podRoot = (0, auth_context_1.normalizeBaseUrl)(argv.url ?? 'https://pod.local/');
145
+ const outboxPath = getObjLocalOutboxPath();
146
+ return {
147
+ baseUrl: podRoot,
148
+ webId: 'urn:xpod:unauthenticated',
149
+ podRoot,
150
+ baseIri: podRoot,
151
+ accessToken: '',
152
+ credentials: {
153
+ url: podRoot,
154
+ webId: 'urn:xpod:unauthenticated',
155
+ authType: 'client_credentials',
156
+ secrets: {
157
+ clientId: '',
158
+ clientSecret: '',
159
+ },
160
+ },
161
+ ...(commit
162
+ ? {
163
+ pendingOnly: true,
164
+ outboxPath,
165
+ pendingWarning: `No Solid credentials found; mutation was written to local xpod outbox at ${outboxPath} and was not saved to a Pod.`,
166
+ }
167
+ : {
168
+ planningOnly: true,
169
+ planningWarning: 'No Solid credentials found; this is an offline dry-run plan and was not saved to a Pod.',
170
+ }),
171
+ };
172
+ }
173
+ }
174
+ function getObjLocalOutboxPath() {
175
+ return (0, path_1.join)((0, credentials_store_1.getSolidHomeDir)(), 'apps', 'xpod', 'outbox', 'obj-mutations.jsonl');
176
+ }
177
+ function appendObjLocalOutbox(entry, outboxPath = getObjLocalOutboxPath()) {
178
+ (0, fs_1.mkdirSync)((0, path_1.dirname)(outboxPath), { recursive: true });
179
+ (0, fs_1.appendFileSync)(outboxPath, `${JSON.stringify(entry)}\n`, 'utf-8');
180
+ }
115
181
  function varName(field) {
116
182
  return `v_${field.replace(/[^A-Za-z0-9_]/gu, '_')}`;
117
183
  }
@@ -159,6 +225,47 @@ function redactDescriptorObject(descriptor, value) {
159
225
  }
160
226
  return redacted;
161
227
  }
228
+ function serializeSchemaDescriptor(descriptor) {
229
+ const discovery = descriptor;
230
+ return {
231
+ schema: descriptor.uri,
232
+ uri: descriptor.uri,
233
+ alias: descriptorAliases(descriptor)[0] ?? descriptor.resourceKind,
234
+ aliases: descriptorAliases(descriptor),
235
+ domains: discovery.domains ?? [],
236
+ version: descriptor.version,
237
+ source: descriptor.source,
238
+ trustLevel: descriptor.trustLevel,
239
+ namespace: descriptor.namespace,
240
+ class: descriptor.class,
241
+ resourceKind: descriptor.resourceKind,
242
+ description: descriptor.description,
243
+ storage: descriptor.storage,
244
+ idSemantics: discovery.idSemantics ?? null,
245
+ relationFields: discovery.relationFields ?? Object.entries(descriptor.fields)
246
+ .filter(([, field]) => field.type === 'uri')
247
+ .map(([field]) => field),
248
+ documentPathPolicy: discovery.documentPathPolicy ?? null,
249
+ fields: descriptor.fields,
250
+ requiredFields: Object.entries(descriptor.fields)
251
+ .filter(([, field]) => field.required)
252
+ .map(([field]) => field),
253
+ uniqueBy: descriptor.uniqueBy,
254
+ writableFields: descriptor.writableFields,
255
+ mergePolicy: descriptor.mergePolicy,
256
+ exampleInput: discovery.exampleInput ?? descriptor.examples[0] ?? null,
257
+ examples: descriptor.examples,
258
+ };
259
+ }
260
+ function listSchemaDescriptors(input = {}, descriptors = models_1.podSchema.list()) {
261
+ return descriptors
262
+ .filter((descriptor) => !input.domain || (descriptor.domains ?? []).includes(input.domain))
263
+ .map(serializeSchemaDescriptor);
264
+ }
265
+ function describeSchemaDescriptor(schemaOrAlias, descriptors = models_1.podSchema.list()) {
266
+ const descriptor = descriptors.find((item) => descriptorMatchesRef(item, schemaOrAlias));
267
+ return descriptor ? serializeSchemaDescriptor(descriptor) : null;
268
+ }
162
269
  function buildDescriptorUpsertSparql(descriptor, subject, row) {
163
270
  const fields = descriptor.fields;
164
271
  const match = row.match ?? {};
@@ -701,36 +808,51 @@ async function executeDescriptorRow(context, row, index, commit) {
701
808
  }
702
809
  throw new output_1.CliCommandError('unsupported_operation', `Unsupported object operation: ${op}`, 2);
703
810
  }
704
- const storage = (0, models_1.createPodStorage)();
811
+ const item = descriptorUpsertPlanItem({
812
+ descriptor,
813
+ index,
814
+ commit,
815
+ podRoot: context.podRoot,
816
+ row,
817
+ });
818
+ const subject = String(item.subject);
819
+ if (commit) {
820
+ const sparql = buildDescriptorUpsertSparql(descriptor, subject, row);
821
+ await patchSubject({ context, subject, sparql, ifMatch: row.ifMatch, errorCode: 'obj_commit_failed' });
822
+ }
823
+ return item;
824
+ }
825
+ function descriptorUpsertPlanItem(input) {
826
+ const storage = (0, models_1.createPodStorage)((0, models_1.createPodModelDescriptorRegistry)([input.descriptor]));
705
827
  const validation = storage.validate({
706
- schemaUri: descriptor.uri,
828
+ schemaUri: input.descriptor.uri,
707
829
  operation: 'upsert',
708
- match: row.match ?? {},
709
- set: row.set ?? {},
830
+ match: input.row.match ?? {},
831
+ set: input.row.set ?? {},
710
832
  });
711
833
  if (!validation.ok) {
712
834
  throw new output_1.CliCommandError(validation.error.code, validation.error.message, 2);
713
835
  }
714
- const subject = resourceUrlFromPlan(context.podRoot, validation.plan);
715
- if (commit) {
716
- const sparql = buildDescriptorUpsertSparql(descriptor, subject, row);
717
- await patchSubject({ context, subject, sparql, ifMatch: row.ifMatch, errorCode: 'obj_commit_failed' });
718
- }
836
+ const discovery = input.descriptor;
837
+ const subject = resourceUrlFromPlan(input.podRoot, validation.plan);
719
838
  return {
720
- index,
839
+ index: input.index,
721
840
  ok: true,
722
- code: commit ? 'committed' : 'plan_ready',
723
- operation: op,
724
- schema: descriptor.uri,
841
+ code: input.commit ? 'committed' : 'plan_ready',
842
+ operation: input.row.op ?? 'upsert',
843
+ schema: input.descriptor.uri,
725
844
  subject,
726
845
  resourceUrl: (0, rdf_1.documentResourceInput)(subject),
727
846
  planId: validation.plan.id,
728
- match: redactDescriptorObject(descriptor, row.match ?? {}),
729
- set: redactDescriptorObject(descriptor, row.set ?? {}),
847
+ resourceId: validation.plan.resourceId,
848
+ resourceUri: validation.plan.resourceUri,
849
+ documentPathPolicy: discovery.documentPathPolicy ?? null,
850
+ match: redactDescriptorObject(input.descriptor, input.row.match ?? {}),
851
+ set: redactDescriptorObject(input.descriptor, input.row.set ?? {}),
730
852
  };
731
853
  }
732
854
  async function executeRows(input) {
733
- const context = await (0, auth_context_1.requireAuthContext)(input.argv);
855
+ const context = await resolveObjMutationContext(input.argv, input.commit);
734
856
  const items = [];
735
857
  for (const [index, originalRow] of input.rows.entries()) {
736
858
  const row = {
@@ -738,10 +860,44 @@ async function executeRows(input) {
738
860
  schema: originalRow.schema ?? input.defaultSchema,
739
861
  };
740
862
  try {
863
+ const shouldCommitToPod = input.commit && !context.pendingOnly;
741
864
  const item = row.schema
742
- ? await executeDescriptorRow(context, row, index, input.commit)
743
- : await executeRawRow(context, row, index, input.commit);
744
- items.push(item);
865
+ ? await executeDescriptorRow(context, row, index, shouldCommitToPod)
866
+ : await executeRawRow(context, row, index, shouldCommitToPod);
867
+ if (context.pendingOnly && input.commit) {
868
+ const outboxPath = context.outboxPath ?? getObjLocalOutboxPath();
869
+ appendObjLocalOutbox({
870
+ kind: 'xpod.obj.mutation',
871
+ version: 1,
872
+ status: 'pending',
873
+ createdAt: new Date().toISOString(),
874
+ webId: context.webId,
875
+ podRoot: context.podRoot,
876
+ row,
877
+ item,
878
+ }, outboxPath);
879
+ items.push({
880
+ ...item,
881
+ code: 'pending_local',
882
+ pendingLocal: true,
883
+ outboxPath,
884
+ warnings: [
885
+ ...(Array.isArray(item.warnings) ? item.warnings : []),
886
+ context.pendingWarning,
887
+ ],
888
+ });
889
+ continue;
890
+ }
891
+ items.push(context.planningOnly
892
+ ? {
893
+ ...item,
894
+ planningOnly: true,
895
+ warnings: [
896
+ ...(Array.isArray(item.warnings) ? item.warnings : []),
897
+ context.planningWarning,
898
+ ],
899
+ }
900
+ : item);
745
901
  }
746
902
  catch (error) {
747
903
  const err = error instanceof output_1.CliCommandError
@@ -752,11 +908,61 @@ async function executeRows(input) {
752
908
  }
753
909
  return items;
754
910
  }
911
+ function mutationItemsResultCode(items, commit) {
912
+ if (!items.every((item) => item.ok))
913
+ return 'partial_failure';
914
+ if (items.some((item) => item.code === 'pending_local'))
915
+ return 'pending_local';
916
+ return commit ? 'committed' : 'plan_ready';
917
+ }
755
918
  function printItems(items) {
756
919
  for (const item of items) {
757
920
  console.log(`${item.index}\t${item.ok ? item.code : `ERROR ${item.code}`}\t${String(item.subject ?? item.resourceUrl ?? item.message ?? '')}`);
758
921
  }
759
922
  }
923
+ const schemasCommand = {
924
+ command: 'schemas',
925
+ describe: 'List model-backed object schemas available to AI tools',
926
+ builder: (yargs) => objOptions(yargs)
927
+ .option('domain', { type: 'string', description: 'Filter schemas by domain such as capture or symphony' }),
928
+ handler: async (argv) => {
929
+ try {
930
+ const schemas = listSchemaDescriptors({ domain: argv.domain });
931
+ if (argv.json) {
932
+ (0, output_1.writeJsonResult)({ schemas }, 'schemas');
933
+ return;
934
+ }
935
+ for (const descriptor of schemas) {
936
+ console.log(`${String(descriptor.alias)}\t${String(descriptor.schema)}\t${String(descriptor.resourceKind)}`);
937
+ }
938
+ }
939
+ catch (error) {
940
+ (0, output_1.handleCliError)(error, argv.json);
941
+ }
942
+ },
943
+ };
944
+ const describeCommand = {
945
+ command: 'describe <schema>',
946
+ describe: 'Describe one model-backed object schema by URI or alias',
947
+ builder: (yargs) => objOptions(yargs)
948
+ .positional('schema', { type: 'string', demandOption: true, description: 'Schema URI or descriptor alias' }),
949
+ handler: async (argv) => {
950
+ try {
951
+ const descriptor = describeSchemaDescriptor(argv.schema);
952
+ if (!descriptor) {
953
+ throw new output_1.CliCommandError('schema_unknown', `Schema is not known by @undefineds.co/models: ${argv.schema}`, 2);
954
+ }
955
+ if (argv.json) {
956
+ (0, output_1.writeJsonResult)({ descriptor }, 'schema');
957
+ return;
958
+ }
959
+ console.log(JSON.stringify(descriptor, null, 2));
960
+ }
961
+ catch (error) {
962
+ (0, output_1.handleCliError)(error, argv.json);
963
+ }
964
+ },
965
+ };
760
966
  const importCommand = {
761
967
  command: 'import <file>',
762
968
  describe: 'Import descriptor-backed or explicit raw JSONL rows',
@@ -772,9 +978,7 @@ const importCommand = {
772
978
  rows: await readJsonl(argv.file),
773
979
  commit: argv.commit === true,
774
980
  });
775
- const code = items.every((item) => item.ok)
776
- ? (argv.commit ? 'committed' : 'plan_ready')
777
- : 'partial_failure';
981
+ const code = mutationItemsResultCode(items, argv.commit === true);
778
982
  if (argv.json) {
779
983
  (0, output_1.writeJsonItems)(items, code);
780
984
  return;
@@ -794,6 +998,7 @@ const upsertCommand = {
794
998
  builder: (yargs) => objOptions(yargs)
795
999
  .option('schema', { type: 'string', demandOption: true, description: 'Schema URI or descriptor alias' })
796
1000
  .option('from', { type: 'string', demandOption: true, description: 'JSONL file to read, or - for stdin' })
1001
+ .nargs('from', 1)
797
1002
  .option('dry-run', { type: 'boolean', description: 'Validate and print a plan without writing' })
798
1003
  .option('commit', { type: 'boolean', description: 'Commit the validated mutations' })
799
1004
  .check(mutationModeCheck),
@@ -805,9 +1010,7 @@ const upsertCommand = {
805
1010
  defaultSchema: resolveDescriptor(argv.schema).uri,
806
1011
  commit: argv.commit === true,
807
1012
  });
808
- const code = items.every((item) => item.ok)
809
- ? (argv.commit ? 'committed' : 'plan_ready')
810
- : 'partial_failure';
1013
+ const code = mutationItemsResultCode(items, argv.commit === true);
811
1014
  if (argv.json) {
812
1015
  (0, output_1.writeJsonItems)(items, code);
813
1016
  return;
@@ -1044,6 +1247,8 @@ exports.objCommand = {
1044
1247
  command: 'obj',
1045
1248
  describe: 'Descriptor-backed object transport',
1046
1249
  builder: (yargs) => yargs
1250
+ .command(schemasCommand)
1251
+ .command(describeCommand)
1047
1252
  .command(exportCommand)
1048
1253
  .command(importCommand)
1049
1254
  .command(getCommand)