@saluzi/saluzi-edu 0.2.20 → 0.2.21

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 (185) hide show
  1. package/dist/cli.js +106 -83
  2. package/dist/rcs-web/assets/AdminPanel-B0hhIa7W.js +1 -0
  3. package/dist/rcs-web/assets/Claim-BTx12YJw.js +1 -0
  4. package/dist/rcs-web/assets/Dashboard-C_qeuXGp.js +1 -0
  5. package/dist/rcs-web/assets/Join-DDMaEXX-.js +1 -0
  6. package/dist/rcs-web/assets/Login-eCEGVdjw.js +1 -0
  7. package/dist/rcs-web/assets/Register-gqlt4O0J.js +1 -0
  8. package/dist/rcs-web/assets/{SessionDetail-B5C0o1YT.js → SessionDetail-BfrG6lOA.js} +10 -10
  9. package/dist/rcs-web/assets/SessionVisibilityBadge-CN3bz2gb.js +11 -0
  10. package/dist/rcs-web/assets/Setup-yO-c5mfy.js +1 -0
  11. package/dist/rcs-web/assets/{ShareLanding-DBC9gbJo.js → ShareLanding-S3XUdrDL.js} +1 -1
  12. package/dist/rcs-web/assets/TeamCreate-DGUK4ghi.js +1 -0
  13. package/dist/rcs-web/assets/TeamDetail-Ct07DirR.js +6 -0
  14. package/dist/rcs-web/assets/TeamList-CJTYa2Ah.js +1 -0
  15. package/dist/rcs-web/assets/TeamSettings-DXb0w8GG.js +1 -0
  16. package/dist/rcs-web/assets/UserSettings-DzreS8Mi.js +1 -0
  17. package/dist/rcs-web/assets/{arc-DBPKxYzS.js → arc-wiB_u0W8.js} +1 -1
  18. package/dist/rcs-web/assets/{architectureDiagram-3BPJPVTR-D88rj_js.js → architectureDiagram-3BPJPVTR-70tgIgZq.js} +1 -1
  19. package/{packages/remote-control-server/web/dist/assets/blockDiagram-GPEHLZMM-xzgUpRMn.js → dist/rcs-web/assets/blockDiagram-GPEHLZMM-Drz4LSdp.js} +1 -1
  20. package/dist/rcs-web/assets/{c4Diagram-AAUBKEIU-vpg_EoPb.js → c4Diagram-AAUBKEIU-BM7C7SEx.js} +1 -1
  21. package/dist/rcs-web/assets/channel-D-a_TNjA.js +1 -0
  22. package/dist/rcs-web/assets/{chunk-2J33WTMH-DXWsXvhS.js → chunk-2J33WTMH-BSqxyVTy.js} +1 -1
  23. package/dist/rcs-web/assets/{chunk-4BX2VUAB-BtTxwj9K.js → chunk-4BX2VUAB-HFKHN20V.js} +1 -1
  24. package/dist/rcs-web/assets/{chunk-55IACEB6-D2-Q95qg.js → chunk-55IACEB6-DOBdvIv4.js} +1 -1
  25. package/{packages/remote-control-server/web/dist/assets/chunk-727SXJPM-Ce3e5x8u.js → dist/rcs-web/assets/chunk-727SXJPM-B2qn-WmZ.js} +1 -1
  26. package/dist/rcs-web/assets/{chunk-AQP2D5EJ-C0UbKVtd.js → chunk-AQP2D5EJ-DFC3ivzL.js} +1 -1
  27. package/dist/rcs-web/assets/{chunk-FMBD7UC4-BCwppVqh.js → chunk-FMBD7UC4-CkVr3MVW.js} +1 -1
  28. package/dist/rcs-web/assets/{chunk-ND2GUHAM-CnOBwWrm.js → chunk-ND2GUHAM-B2WO2xxD.js} +1 -1
  29. package/dist/rcs-web/assets/{chunk-QZHKN3VN-CDdzB71P.js → chunk-QZHKN3VN-YpZyVA2c.js} +1 -1
  30. package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-Dl3V5TVw.js +1 -0
  31. package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-Dl3V5TVw.js +1 -0
  32. package/dist/rcs-web/assets/{code-block-IT6T5CEO-C1_H_ztH.js → code-block-IT6T5CEO-Bmds1dKk.js} +1 -1
  33. package/dist/rcs-web/assets/{copy-DXU1lQqc.js → copy-DdSkINCW.js} +1 -1
  34. package/dist/rcs-web/assets/{cose-bilkent-S5V4N54A-BC6nfjTF.js → cose-bilkent-S5V4N54A-CTtGg7Fx.js} +1 -1
  35. package/dist/rcs-web/assets/{dagre-BM42HDAG-CEPR_pRx.js → dagre-BM42HDAG-CFX48pZZ.js} +1 -1
  36. package/dist/rcs-web/assets/{diagram-2AECGRRQ-fVMGnSYa.js → diagram-2AECGRRQ-BwZE2jAF.js} +1 -1
  37. package/dist/rcs-web/assets/{diagram-5GNKFQAL-BPzN2rbK.js → diagram-5GNKFQAL-BuHnggju.js} +1 -1
  38. package/dist/rcs-web/assets/{diagram-KO2AKTUF-Boneg9n-.js → diagram-KO2AKTUF-Dmd3MO7f.js} +1 -1
  39. package/{packages/remote-control-server/web/dist/assets/diagram-LMA3HP47-B8AtvjO9.js → dist/rcs-web/assets/diagram-LMA3HP47-34ZNfvQd.js} +1 -1
  40. package/dist/rcs-web/assets/{diagram-OG6HWLK6-DjY7A8jK.js → diagram-OG6HWLK6-CjZvlFxO.js} +1 -1
  41. package/{packages/remote-control-server/web/dist/assets/erDiagram-TEJ5UH35-C1BEfKxk.js → dist/rcs-web/assets/erDiagram-TEJ5UH35-BWR0WD_N.js} +1 -1
  42. package/dist/rcs-web/assets/{flowDiagram-I6XJVG4X-7TbI9MLV.js → flowDiagram-I6XJVG4X-DjZ7uFyw.js} +1 -1
  43. package/{packages/remote-control-server/web/dist/assets/ganttDiagram-6RSMTGT7-CMAV0A01.js → dist/rcs-web/assets/ganttDiagram-6RSMTGT7-BuAM7awZ.js} +1 -1
  44. package/dist/rcs-web/assets/{gitGraphDiagram-PVQCEYII-DAlR8G81.js → gitGraphDiagram-PVQCEYII-B_6bqpod.js} +1 -1
  45. package/dist/rcs-web/assets/{infoDiagram-5YYISTIA-0T0DAV4W.js → infoDiagram-5YYISTIA-BbhCTAn2.js} +1 -1
  46. package/{packages/remote-control-server/web/dist/assets/ishikawaDiagram-YF4QCWOH-BAw8txlx.js → dist/rcs-web/assets/ishikawaDiagram-YF4QCWOH-1VPCYnPS.js} +1 -1
  47. package/{packages/remote-control-server/web/dist/assets/journeyDiagram-JHISSGLW-DWvYKwz-.js → dist/rcs-web/assets/journeyDiagram-JHISSGLW-Dzl0f8Im.js} +1 -1
  48. package/dist/rcs-web/assets/{kanban-definition-UN3LZRKU-Qzqw1H5B.js → kanban-definition-UN3LZRKU-BGoVgBze.js} +1 -1
  49. package/{packages/remote-control-server/web/dist/assets/linear-D2KIJoCI.js → dist/rcs-web/assets/linear-DF7ChHtW.js} +1 -1
  50. package/dist/rcs-web/assets/main-B_OE0doJ.css +1 -0
  51. package/dist/rcs-web/assets/main-CEsvX5rj.js +253 -0
  52. package/dist/rcs-web/assets/{mermaid-VLURNSYL-CxWk1wHz.js → mermaid-VLURNSYL-3EqupjjN.js} +4 -4
  53. package/dist/rcs-web/assets/{mermaid.core-C48YvKu4.js → mermaid.core-BnVRH5R_.js} +5 -5
  54. package/dist/rcs-web/assets/{mindmap-definition-RKZ34NQL-BfmcTuCA.js → mindmap-definition-RKZ34NQL-R3usKqMg.js} +1 -1
  55. package/dist/rcs-web/assets/{pieDiagram-4H26LBE5-DVNZpnfb.js → pieDiagram-4H26LBE5-U1XXn3t9.js} +1 -1
  56. package/{packages/remote-control-server/web/dist/assets/quadrantDiagram-W4KKPZXB-COL55Z3i.js → dist/rcs-web/assets/quadrantDiagram-W4KKPZXB-CocIpolQ.js} +1 -1
  57. package/dist/rcs-web/assets/{requirementDiagram-4Y6WPE33-CFczYQ0a.js → requirementDiagram-4Y6WPE33-DX7pHOr5.js} +1 -1
  58. package/{packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-BrQEv3WQ.js → dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-TD6XCrii.js} +1 -1
  59. package/{packages/remote-control-server/web/dist/assets/sequenceDiagram-3UESZ5HK-CMxtYmQu.js → dist/rcs-web/assets/sequenceDiagram-3UESZ5HK-EyZvfcbT.js} +1 -1
  60. package/dist/rcs-web/assets/{stateDiagram-AJRCARHV-Dw9xJZ-A.js → stateDiagram-AJRCARHV-B_SU6QSv.js} +1 -1
  61. package/dist/rcs-web/assets/{stateDiagram-v2-BHNVJYJU-Br0D-weX.js → stateDiagram-v2-BHNVJYJU-C8vEqOLP.js} +1 -1
  62. package/{packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-DuWDwYBt.js → dist/rcs-web/assets/timeline-definition-PNZ67QCA-C2XHcj96.js} +1 -1
  63. package/dist/rcs-web/assets/{vennDiagram-CIIHVFJN--7IV65HQ.js → vennDiagram-CIIHVFJN-aAmhPOm3.js} +1 -1
  64. package/dist/rcs-web/assets/{wardleyDiagram-YWT4CUSO-CVTgWbvT.js → wardleyDiagram-YWT4CUSO-Db_mMfd6.js} +1 -1
  65. package/dist/rcs-web/assets/workerType-Bd-zteMi.js +1 -0
  66. package/{packages/remote-control-server/web/dist/assets/xychartDiagram-2RQKCTM6-B9om4xAF.js → dist/rcs-web/assets/xychartDiagram-2RQKCTM6-DPjdOqDe.js} +1 -1
  67. package/dist/rcs-web/index.html +2 -2
  68. package/package.json +1 -1
  69. package/packages/remote-control-server/src/__tests__/bind-replacement.test.ts +5 -5
  70. package/packages/remote-control-server/src/__tests__/phase4-integration.test.ts +2 -2
  71. package/packages/remote-control-server/src/__tests__/route-mounting.test.ts +2 -2
  72. package/packages/remote-control-server/src/__tests__/routes.test.ts +21 -5
  73. package/packages/remote-control-server/src/__tests__/shares.test.ts +21 -20
  74. package/packages/remote-control-server/src/__tests__/teams.test.ts +119 -0
  75. package/packages/remote-control-server/src/config.ts +3 -0
  76. package/packages/remote-control-server/src/db/schema.sql +6 -1
  77. package/packages/remote-control-server/src/db/sqlite.ts +46 -1
  78. package/packages/remote-control-server/src/registerRoutes.ts +17 -1
  79. package/packages/remote-control-server/src/routes/v1/environments.ts +35 -1
  80. package/packages/remote-control-server/src/routes/v1/sessions.ts +48 -2
  81. package/packages/remote-control-server/src/routes/web/auth-routes.ts +64 -0
  82. package/packages/remote-control-server/src/routes/web/environments.ts +7 -3
  83. package/packages/remote-control-server/src/routes/web/shares.ts +17 -26
  84. package/packages/remote-control-server/src/routes/web/teams.ts +241 -4
  85. package/packages/remote-control-server/src/services/environment.ts +12 -1
  86. package/packages/remote-control-server/src/store.ts +87 -4
  87. package/packages/remote-control-server/src/types/api.ts +1 -0
  88. package/packages/remote-control-server/web/dist/assets/AdminPanel-B0hhIa7W.js +1 -0
  89. package/packages/remote-control-server/web/dist/assets/Claim-BTx12YJw.js +1 -0
  90. package/packages/remote-control-server/web/dist/assets/Dashboard-C_qeuXGp.js +1 -0
  91. package/packages/remote-control-server/web/dist/assets/Join-DDMaEXX-.js +1 -0
  92. package/packages/remote-control-server/web/dist/assets/Login-eCEGVdjw.js +1 -0
  93. package/packages/remote-control-server/web/dist/assets/Register-gqlt4O0J.js +1 -0
  94. package/packages/remote-control-server/web/dist/assets/{SessionDetail-B5C0o1YT.js → SessionDetail-BfrG6lOA.js} +10 -10
  95. package/packages/remote-control-server/web/dist/assets/SessionVisibilityBadge-CN3bz2gb.js +11 -0
  96. package/packages/remote-control-server/web/dist/assets/Setup-yO-c5mfy.js +1 -0
  97. package/packages/remote-control-server/web/dist/assets/{ShareLanding-DBC9gbJo.js → ShareLanding-S3XUdrDL.js} +1 -1
  98. package/packages/remote-control-server/web/dist/assets/TeamCreate-DGUK4ghi.js +1 -0
  99. package/packages/remote-control-server/web/dist/assets/TeamDetail-Ct07DirR.js +6 -0
  100. package/packages/remote-control-server/web/dist/assets/TeamList-CJTYa2Ah.js +1 -0
  101. package/packages/remote-control-server/web/dist/assets/TeamSettings-DXb0w8GG.js +1 -0
  102. package/packages/remote-control-server/web/dist/assets/UserSettings-DzreS8Mi.js +1 -0
  103. package/packages/remote-control-server/web/dist/assets/{arc-DBPKxYzS.js → arc-wiB_u0W8.js} +1 -1
  104. package/packages/remote-control-server/web/dist/assets/{architectureDiagram-3BPJPVTR-D88rj_js.js → architectureDiagram-3BPJPVTR-70tgIgZq.js} +1 -1
  105. package/{dist/rcs-web/assets/blockDiagram-GPEHLZMM-xzgUpRMn.js → packages/remote-control-server/web/dist/assets/blockDiagram-GPEHLZMM-Drz4LSdp.js} +1 -1
  106. package/packages/remote-control-server/web/dist/assets/{c4Diagram-AAUBKEIU-vpg_EoPb.js → c4Diagram-AAUBKEIU-BM7C7SEx.js} +1 -1
  107. package/packages/remote-control-server/web/dist/assets/channel-D-a_TNjA.js +1 -0
  108. package/packages/remote-control-server/web/dist/assets/{chunk-2J33WTMH-DXWsXvhS.js → chunk-2J33WTMH-BSqxyVTy.js} +1 -1
  109. package/packages/remote-control-server/web/dist/assets/{chunk-4BX2VUAB-BtTxwj9K.js → chunk-4BX2VUAB-HFKHN20V.js} +1 -1
  110. package/packages/remote-control-server/web/dist/assets/{chunk-55IACEB6-D2-Q95qg.js → chunk-55IACEB6-DOBdvIv4.js} +1 -1
  111. package/{dist/rcs-web/assets/chunk-727SXJPM-Ce3e5x8u.js → packages/remote-control-server/web/dist/assets/chunk-727SXJPM-B2qn-WmZ.js} +1 -1
  112. package/packages/remote-control-server/web/dist/assets/{chunk-AQP2D5EJ-C0UbKVtd.js → chunk-AQP2D5EJ-DFC3ivzL.js} +1 -1
  113. package/packages/remote-control-server/web/dist/assets/{chunk-FMBD7UC4-BCwppVqh.js → chunk-FMBD7UC4-CkVr3MVW.js} +1 -1
  114. package/packages/remote-control-server/web/dist/assets/{chunk-ND2GUHAM-CnOBwWrm.js → chunk-ND2GUHAM-B2WO2xxD.js} +1 -1
  115. package/packages/remote-control-server/web/dist/assets/{chunk-QZHKN3VN-CDdzB71P.js → chunk-QZHKN3VN-YpZyVA2c.js} +1 -1
  116. package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-Dl3V5TVw.js +1 -0
  117. package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-Dl3V5TVw.js +1 -0
  118. package/packages/remote-control-server/web/dist/assets/{code-block-IT6T5CEO-C1_H_ztH.js → code-block-IT6T5CEO-Bmds1dKk.js} +1 -1
  119. package/packages/remote-control-server/web/dist/assets/{copy-DXU1lQqc.js → copy-DdSkINCW.js} +1 -1
  120. package/packages/remote-control-server/web/dist/assets/{cose-bilkent-S5V4N54A-BC6nfjTF.js → cose-bilkent-S5V4N54A-CTtGg7Fx.js} +1 -1
  121. package/packages/remote-control-server/web/dist/assets/{dagre-BM42HDAG-CEPR_pRx.js → dagre-BM42HDAG-CFX48pZZ.js} +1 -1
  122. package/packages/remote-control-server/web/dist/assets/{diagram-2AECGRRQ-fVMGnSYa.js → diagram-2AECGRRQ-BwZE2jAF.js} +1 -1
  123. package/packages/remote-control-server/web/dist/assets/{diagram-5GNKFQAL-BPzN2rbK.js → diagram-5GNKFQAL-BuHnggju.js} +1 -1
  124. package/packages/remote-control-server/web/dist/assets/{diagram-KO2AKTUF-Boneg9n-.js → diagram-KO2AKTUF-Dmd3MO7f.js} +1 -1
  125. package/{dist/rcs-web/assets/diagram-LMA3HP47-B8AtvjO9.js → packages/remote-control-server/web/dist/assets/diagram-LMA3HP47-34ZNfvQd.js} +1 -1
  126. package/packages/remote-control-server/web/dist/assets/{diagram-OG6HWLK6-DjY7A8jK.js → diagram-OG6HWLK6-CjZvlFxO.js} +1 -1
  127. package/{dist/rcs-web/assets/erDiagram-TEJ5UH35-C1BEfKxk.js → packages/remote-control-server/web/dist/assets/erDiagram-TEJ5UH35-BWR0WD_N.js} +1 -1
  128. package/packages/remote-control-server/web/dist/assets/{flowDiagram-I6XJVG4X-7TbI9MLV.js → flowDiagram-I6XJVG4X-DjZ7uFyw.js} +1 -1
  129. package/{dist/rcs-web/assets/ganttDiagram-6RSMTGT7-CMAV0A01.js → packages/remote-control-server/web/dist/assets/ganttDiagram-6RSMTGT7-BuAM7awZ.js} +1 -1
  130. package/packages/remote-control-server/web/dist/assets/{gitGraphDiagram-PVQCEYII-DAlR8G81.js → gitGraphDiagram-PVQCEYII-B_6bqpod.js} +1 -1
  131. package/packages/remote-control-server/web/dist/assets/{infoDiagram-5YYISTIA-0T0DAV4W.js → infoDiagram-5YYISTIA-BbhCTAn2.js} +1 -1
  132. package/{dist/rcs-web/assets/ishikawaDiagram-YF4QCWOH-BAw8txlx.js → packages/remote-control-server/web/dist/assets/ishikawaDiagram-YF4QCWOH-1VPCYnPS.js} +1 -1
  133. package/{dist/rcs-web/assets/journeyDiagram-JHISSGLW-DWvYKwz-.js → packages/remote-control-server/web/dist/assets/journeyDiagram-JHISSGLW-Dzl0f8Im.js} +1 -1
  134. package/packages/remote-control-server/web/dist/assets/{kanban-definition-UN3LZRKU-Qzqw1H5B.js → kanban-definition-UN3LZRKU-BGoVgBze.js} +1 -1
  135. package/{dist/rcs-web/assets/linear-D2KIJoCI.js → packages/remote-control-server/web/dist/assets/linear-DF7ChHtW.js} +1 -1
  136. package/packages/remote-control-server/web/dist/assets/main-B_OE0doJ.css +1 -0
  137. package/packages/remote-control-server/web/dist/assets/main-CEsvX5rj.js +253 -0
  138. package/packages/remote-control-server/web/dist/assets/{mermaid-VLURNSYL-CxWk1wHz.js → mermaid-VLURNSYL-3EqupjjN.js} +4 -4
  139. package/packages/remote-control-server/web/dist/assets/{mermaid.core-C48YvKu4.js → mermaid.core-BnVRH5R_.js} +5 -5
  140. package/packages/remote-control-server/web/dist/assets/{mindmap-definition-RKZ34NQL-BfmcTuCA.js → mindmap-definition-RKZ34NQL-R3usKqMg.js} +1 -1
  141. package/packages/remote-control-server/web/dist/assets/{pieDiagram-4H26LBE5-DVNZpnfb.js → pieDiagram-4H26LBE5-U1XXn3t9.js} +1 -1
  142. package/{dist/rcs-web/assets/quadrantDiagram-W4KKPZXB-COL55Z3i.js → packages/remote-control-server/web/dist/assets/quadrantDiagram-W4KKPZXB-CocIpolQ.js} +1 -1
  143. package/packages/remote-control-server/web/dist/assets/{requirementDiagram-4Y6WPE33-CFczYQ0a.js → requirementDiagram-4Y6WPE33-DX7pHOr5.js} +1 -1
  144. package/{dist/rcs-web/assets/sankeyDiagram-5OEKKPKP-BrQEv3WQ.js → packages/remote-control-server/web/dist/assets/sankeyDiagram-5OEKKPKP-TD6XCrii.js} +1 -1
  145. package/{dist/rcs-web/assets/sequenceDiagram-3UESZ5HK-CMxtYmQu.js → packages/remote-control-server/web/dist/assets/sequenceDiagram-3UESZ5HK-EyZvfcbT.js} +1 -1
  146. package/packages/remote-control-server/web/dist/assets/{stateDiagram-AJRCARHV-Dw9xJZ-A.js → stateDiagram-AJRCARHV-B_SU6QSv.js} +1 -1
  147. package/packages/remote-control-server/web/dist/assets/{stateDiagram-v2-BHNVJYJU-Br0D-weX.js → stateDiagram-v2-BHNVJYJU-C8vEqOLP.js} +1 -1
  148. package/{dist/rcs-web/assets/timeline-definition-PNZ67QCA-DuWDwYBt.js → packages/remote-control-server/web/dist/assets/timeline-definition-PNZ67QCA-C2XHcj96.js} +1 -1
  149. package/packages/remote-control-server/web/dist/assets/{vennDiagram-CIIHVFJN--7IV65HQ.js → vennDiagram-CIIHVFJN-aAmhPOm3.js} +1 -1
  150. package/packages/remote-control-server/web/dist/assets/{wardleyDiagram-YWT4CUSO-CVTgWbvT.js → wardleyDiagram-YWT4CUSO-Db_mMfd6.js} +1 -1
  151. package/packages/remote-control-server/web/dist/assets/workerType-Bd-zteMi.js +1 -0
  152. package/{dist/rcs-web/assets/xychartDiagram-2RQKCTM6-B9om4xAF.js → packages/remote-control-server/web/dist/assets/xychartDiagram-2RQKCTM6-DPjdOqDe.js} +1 -1
  153. package/packages/remote-control-server/web/dist/index.html +2 -2
  154. package/dist/rcs-web/assets/AdminPanel-CQU763nr.js +0 -1
  155. package/dist/rcs-web/assets/Dashboard-B1hQfqI9.js +0 -1
  156. package/dist/rcs-web/assets/Join-7hMl360t.js +0 -1
  157. package/dist/rcs-web/assets/Login-BE8mNc0U.js +0 -1
  158. package/dist/rcs-web/assets/SessionVisibilityBadge-CQN3bJW4.js +0 -11
  159. package/dist/rcs-web/assets/Setup-CqZ5gEBQ.js +0 -1
  160. package/dist/rcs-web/assets/TeamCreate-DSYdTaPe.js +0 -1
  161. package/dist/rcs-web/assets/TeamDetail-CmJGsgOP.js +0 -1
  162. package/dist/rcs-web/assets/TeamList-BMS_Qq8U.js +0 -1
  163. package/dist/rcs-web/assets/TeamSettings-C0sYgCFT.js +0 -1
  164. package/dist/rcs-web/assets/UserSettings-CqzeJ5cc.js +0 -1
  165. package/dist/rcs-web/assets/channel-Daz3yMSu.js +0 -1
  166. package/dist/rcs-web/assets/classDiagram-4FO5ZUOK-DufdcV1P.js +0 -1
  167. package/dist/rcs-web/assets/classDiagram-v2-Q7XG4LA2-DufdcV1P.js +0 -1
  168. package/dist/rcs-web/assets/main-EP6Lac2m.css +0 -1
  169. package/dist/rcs-web/assets/main-J6cPs2y8.js +0 -253
  170. package/packages/remote-control-server/web/dist/assets/AdminPanel-CQU763nr.js +0 -1
  171. package/packages/remote-control-server/web/dist/assets/Dashboard-B1hQfqI9.js +0 -1
  172. package/packages/remote-control-server/web/dist/assets/Join-7hMl360t.js +0 -1
  173. package/packages/remote-control-server/web/dist/assets/Login-BE8mNc0U.js +0 -1
  174. package/packages/remote-control-server/web/dist/assets/SessionVisibilityBadge-CQN3bJW4.js +0 -11
  175. package/packages/remote-control-server/web/dist/assets/Setup-CqZ5gEBQ.js +0 -1
  176. package/packages/remote-control-server/web/dist/assets/TeamCreate-DSYdTaPe.js +0 -1
  177. package/packages/remote-control-server/web/dist/assets/TeamDetail-CmJGsgOP.js +0 -1
  178. package/packages/remote-control-server/web/dist/assets/TeamList-BMS_Qq8U.js +0 -1
  179. package/packages/remote-control-server/web/dist/assets/TeamSettings-C0sYgCFT.js +0 -1
  180. package/packages/remote-control-server/web/dist/assets/UserSettings-CqzeJ5cc.js +0 -1
  181. package/packages/remote-control-server/web/dist/assets/channel-Daz3yMSu.js +0 -1
  182. package/packages/remote-control-server/web/dist/assets/classDiagram-4FO5ZUOK-DufdcV1P.js +0 -1
  183. package/packages/remote-control-server/web/dist/assets/classDiagram-v2-Q7XG4LA2-DufdcV1P.js +0 -1
  184. package/packages/remote-control-server/web/dist/assets/main-EP6Lac2m.css +0 -1
  185. package/packages/remote-control-server/web/dist/assets/main-J6cPs2y8.js +0 -253
@@ -1587,6 +1587,125 @@ describe('POST /web/environments/:id/transfer', () => {
1587
1587
  expect([200, 201]).toContain(res.status)
1588
1588
  // Detailed session visibility is tested in session-visibility.test.ts
1589
1589
  })
1590
+
1591
+ test('personal env (no source team) → target team admin can claim → 200', async () => {
1592
+ // Use a fresh env id that's not in any team
1593
+ const personalEnvId = `env_${randomUUID().replace(/-/g, '')}`
1594
+ const res = await app.request(
1595
+ `/web/environments/${personalEnvId}/transfer`,
1596
+ {
1597
+ method: 'POST',
1598
+ headers: {
1599
+ ...authHeader(owner.accessToken),
1600
+ 'Content-Type': 'application/json',
1601
+ },
1602
+ body: JSON.stringify({ toTeamId: targetTeam.id }),
1603
+ },
1604
+ )
1605
+ expect(res.status).toBe(200)
1606
+ // Verify the link exists
1607
+ const linkRow = db
1608
+ .query(
1609
+ 'SELECT team_id FROM team_environments WHERE environment_id = $envId',
1610
+ )
1611
+ .get({ $envId: personalEnvId }) as { team_id: string } | null
1612
+ expect(linkRow?.team_id).toBe(targetTeam.id)
1613
+ })
1614
+
1615
+ test('personal env → target team member (non-admin) → 403', async () => {
1616
+ const personalEnvId = `env_${randomUUID().replace(/-/g, '')}`
1617
+ // teamMember is only a 'member' of sourceTeam, not targetTeam at all
1618
+ const res = await app.request(
1619
+ `/web/environments/${personalEnvId}/transfer`,
1620
+ {
1621
+ method: 'POST',
1622
+ headers: {
1623
+ ...authHeader(teamMember.accessToken),
1624
+ 'Content-Type': 'application/json',
1625
+ },
1626
+ body: JSON.stringify({ toTeamId: targetTeam.id }),
1627
+ },
1628
+ )
1629
+ expect(res.status).toBe(403)
1630
+ })
1631
+ })
1632
+
1633
+ describe('DELETE /web/teams/:id/environments/:envId', () => {
1634
+ let app: Hono
1635
+ let db: Database
1636
+ let admin: TestUser
1637
+ let owner: TestUser
1638
+ let teamMember: TestUser
1639
+ let team: { id: string }
1640
+ let envId: string
1641
+
1642
+ beforeEach(async () => {
1643
+ db = freshDb()
1644
+ app = createApp()
1645
+ admin = await setupAdmin(app)
1646
+ owner = await createAndLoginUser(db, app, {
1647
+ username: 'owner2',
1648
+ role: 'member',
1649
+ })
1650
+ teamMember = await createAndLoginUser(db, app, {
1651
+ username: 'tmember2',
1652
+ role: 'member',
1653
+ })
1654
+ team = createTeamDirectly(db, {
1655
+ name: 'Team2',
1656
+ slug: 'team2',
1657
+ createdBy: owner.id,
1658
+ })
1659
+ addTeamMember(db, {
1660
+ teamId: team.id,
1661
+ userId: teamMember.id,
1662
+ role: 'member',
1663
+ addedBy: owner.id,
1664
+ })
1665
+ envId = `env_${randomUUID().replace(/-/g, '')}`
1666
+ db.query(
1667
+ `INSERT INTO team_environments (team_id, environment_id) VALUES ($teamId, $envId)`,
1668
+ ).run({ $teamId: team.id, $envId: envId })
1669
+ })
1670
+
1671
+ test('team owner → 200, link removed', async () => {
1672
+ const res = await app.request(
1673
+ `/web/teams/${team.id}/environments/${envId}`,
1674
+ {
1675
+ method: 'DELETE',
1676
+ headers: authHeader(owner.accessToken),
1677
+ },
1678
+ )
1679
+ expect(res.status).toBe(200)
1680
+ const row = db
1681
+ .query(
1682
+ 'SELECT team_id FROM team_environments WHERE environment_id = $envId',
1683
+ )
1684
+ .get({ $envId: envId })
1685
+ expect(row).toBeNull()
1686
+ })
1687
+
1688
+ test('team member (non-admin) → 403', async () => {
1689
+ const res = await app.request(
1690
+ `/web/teams/${team.id}/environments/${envId}`,
1691
+ {
1692
+ method: 'DELETE',
1693
+ headers: authHeader(teamMember.accessToken),
1694
+ },
1695
+ )
1696
+ expect(res.status).toBe(403)
1697
+ })
1698
+
1699
+ test('system admin → 200', async () => {
1700
+ const res = await app.request(
1701
+ `/web/teams/${team.id}/environments/${envId}`,
1702
+ {
1703
+ method: 'DELETE',
1704
+ headers: authHeader(admin.accessToken),
1705
+ },
1706
+ )
1707
+ expect(res.status).toBe(200)
1708
+ })
1590
1709
  })
1591
1710
 
1592
1711
  // ===========================================================================
@@ -12,6 +12,9 @@ export const config = {
12
12
  .split(',')
13
13
  .map(origin => origin.trim())
14
14
  .filter(Boolean),
15
+ /** Whether the web UI allows open user self-registration (POST /web/auth/register).
16
+ * When false, only admin invitation (/join) can create new users. Default true. */
17
+ allowRegistration: process.env.RCS_ALLOW_REGISTRATION !== 'false',
15
18
  /** Bun WebSocket idle timeout (seconds). Bun sends protocol-level pings after
16
19
  * this many seconds of no received data. Must be shorter than any reverse
17
20
  * proxy's idle timeout (nginx default 60s, Cloudflare 100s). Default 30s. */
@@ -87,7 +87,10 @@ CREATE TABLE IF NOT EXISTS environments (
87
87
  worker_type TEXT NOT NULL DEFAULT 'claude_code',
88
88
  status TEXT NOT NULL DEFAULT 'active',
89
89
  last_poll_at TEXT,
90
- created_at TEXT NOT NULL
90
+ created_at TEXT NOT NULL,
91
+ owner_user_id TEXT,
92
+ claim_token TEXT,
93
+ claim_expires_at TEXT
91
94
  );
92
95
 
93
96
  CREATE TABLE IF NOT EXISTS sessions (
@@ -114,3 +117,5 @@ CREATE INDEX IF NOT EXISTS idx_sessions_visibility ON sessions(visibility);
114
117
  CREATE INDEX IF NOT EXISTS idx_sessions_environment ON sessions(environment_id);
115
118
  CREATE INDEX IF NOT EXISTS idx_session_tokens_user ON session_tokens(user_id);
116
119
  CREATE INDEX IF NOT EXISTS idx_environments_team ON environments(team_id);
120
+ CREATE INDEX IF NOT EXISTS idx_environments_owner_user ON environments(owner_user_id);
121
+ CREATE INDEX IF NOT EXISTS idx_environments_claim_token ON environments(claim_token);
@@ -11,7 +11,9 @@ let _dbPath: string | null = null
11
11
 
12
12
  /**
13
13
  * Run all schema migrations on the given database.
14
- * Idempotent — uses CREATE TABLE IF NOT EXISTS.
14
+ * Idempotent — uses CREATE TABLE IF NOT EXISTS for new tables, plus
15
+ * ALTER TABLE ADD COLUMN for columns added to existing tables (gated by
16
+ * PRAGMA table_info so re-running on an already-migrated DB is a no-op).
15
17
  * Reads schema.sql and executes as a single db.exec() call,
16
18
  * which correctly handles semicolons inside CHECK constraints.
17
19
  */
@@ -20,9 +22,52 @@ export function migrateDatabase(db: Database): void {
20
22
  const schema = readFileSync(schemaPath, 'utf8')
21
23
 
22
24
  db.exec('PRAGMA foreign_keys = ON')
25
+ // Run ALTER TABLE migrations BEFORE db.exec(schema) — schema.sql's
26
+ // CREATE INDEX statements reference the new columns, so the columns
27
+ // must exist before the indexes can be created. CREATE TABLE IF NOT
28
+ // EXISTS skips existing tables (so the ALTER adds the missing columns
29
+ // to pre-existing tables); on a fresh DB the ALTER is a no-op because
30
+ // the table doesn't exist yet, then db.exec(schema) creates it with
31
+ // all columns.
32
+ migrateEnvironmentsColumns(db)
23
33
  db.exec(schema)
24
34
  }
25
35
 
36
+ /**
37
+ * Add columns to pre-existing `environments` tables that were created
38
+ * before owner_user_id / claim_token / claim_expires_at existed.
39
+ * CREATE TABLE IF NOT EXISTS skips existing tables entirely, so without
40
+ * this the new columns would never appear on upgraded DBs. Must run
41
+ * BEFORE db.exec(schema) because schema.sql's CREATE INDEX statements
42
+ * reference the new columns. On a fresh DB (table doesn't exist yet),
43
+ * skip entirely — db.exec(schema) will create the table with all columns.
44
+ */
45
+ function migrateEnvironmentsColumns(db: Database): void {
46
+ // Check if environments table exists at all. On a fresh DB it won't,
47
+ // and ALTER TABLE on a non-existent table throws. PRAGMA table_info
48
+ // returns empty for non-existent tables, but ALTER still errors — so
49
+ // gate on table existence via sqlite_master.
50
+ const tableExists = db
51
+ .query(
52
+ "SELECT 1 FROM sqlite_master WHERE type='table' AND name='environments'",
53
+ )
54
+ .get() as { 1: number } | undefined
55
+ if (!tableExists) return
56
+
57
+ const cols = db.query('PRAGMA table_info(environments)').all() as Array<{
58
+ name: string
59
+ }>
60
+ const names = new Set(cols.map(c => c.name))
61
+ const addIfMissing = (name: string, defn: string): void => {
62
+ if (!names.has(name)) {
63
+ db.exec(`ALTER TABLE environments ADD COLUMN ${name} ${defn}`)
64
+ }
65
+ }
66
+ addIfMissing('owner_user_id', 'TEXT')
67
+ addIfMissing('claim_token', 'TEXT')
68
+ addIfMissing('claim_expires_at', 'TEXT')
69
+ }
70
+
26
71
  /**
27
72
  * Resolve the default database path.
28
73
  * - Uses RCS_DB_PATH env var if set
@@ -56,6 +56,10 @@ export function registerRoutes(
56
56
  app.get('/code', ss({ root: webDir, path: 'index.html' }))
57
57
  app.get('/code/', ss({ root: webDir, path: 'index.html' }))
58
58
  app.get('/code/:sessionId', ss({ root: webDir, path: 'index.html' }))
59
+ // /code/s/:shareToken — share landing page (two-segment path, not matched by /code/:sessionId)
60
+ app.get('/code/s/:shareToken', ss({ root: webDir, path: 'index.html' }))
61
+ // /code/claim/:claimToken — environment claim landing page
62
+ app.get('/code/claim/:claimToken', ss({ root: webDir, path: 'index.html' }))
59
63
 
60
64
  // v1 Environment routes
61
65
  app.route('/v1/environments', v1Environments)
@@ -107,9 +111,21 @@ export function registerRoutes(
107
111
 
108
112
  // SPA fallback — serve index.html for frontend routes handled by React Router.
109
113
  // Must be registered AFTER all API routes to avoid intercepting /web/*, /v1/*, /acp/* etc.
110
- const spaPaths = ['/login', '/setup', '/join', '/settings', '/teams']
114
+ const spaPaths = [
115
+ '/login',
116
+ '/register',
117
+ '/setup',
118
+ '/join',
119
+ '/settings',
120
+ '/teams',
121
+ '/admin',
122
+ '/share',
123
+ ]
111
124
  for (const p of spaPaths) {
112
125
  app.get(p, ss({ root: webDir, path: 'index.html' }))
113
126
  app.get(`${p}/*`, ss({ root: webDir, path: 'index.html' }))
114
127
  }
128
+
129
+ // Root redirect → /code/ (main dashboard entry point)
130
+ app.get('/', c => c.redirect('/code/'))
115
131
  }
@@ -1,5 +1,6 @@
1
1
  import { Hono } from 'hono'
2
2
  import type { Context, Next } from 'hono'
3
+ import { randomUUID } from 'node:crypto'
3
4
  import {
4
5
  registerEnvironment,
5
6
  deregisterEnvironment,
@@ -62,6 +63,18 @@ app.post('/bridge', acceptCliHeaders, bridgeAuth, async c => {
62
63
  const userId = c.get('userId') as string | undefined
63
64
  const username = userId
64
65
  const teamId = c.req.header('X-Team-Id')
66
+ const headerUserId = c.req.header('X-User-Id')
67
+
68
+ // X-User-Id explicitly sets env.owner_user_id. If both X-User-Id and
69
+ // X-Team-Id are absent, the env is "unowned" — a claim_token is generated
70
+ // and returned so the worker can print a /code/claim/<token> URL for the
71
+ // first logged-in user to claim ownership.
72
+ const ownerUserId = headerUserId || null
73
+ const needsClaim = !ownerUserId && !teamId
74
+ const claimToken = needsClaim ? `clm_${randomUUID().replace(/-/g, '')}` : null
75
+ const claimExpiresAt = claimToken
76
+ ? new Date(Date.now() + 24 * 60 * 60 * 1000)
77
+ : null
65
78
 
66
79
  // Validate team if X-Team-Id is provided
67
80
  if (teamId && userId) {
@@ -109,7 +122,13 @@ app.post('/bridge', acceptCliHeaders, bridgeAuth, async c => {
109
122
  }
110
123
  }
111
124
 
112
- const result = registerEnvironment({ ...body, username })
125
+ const result = registerEnvironment({
126
+ ...body,
127
+ username,
128
+ ownerUserId,
129
+ claimToken,
130
+ claimExpiresAt,
131
+ })
113
132
 
114
133
  // Link environment to team if X-Team-Id was provided
115
134
  if (teamId) {
@@ -124,6 +143,21 @@ app.post('/bridge', acceptCliHeaders, bridgeAuth, async c => {
124
143
  }
125
144
  }
126
145
 
146
+ // Append claim info to response so worker can print the claim URL.
147
+ // Worker reads `claim_url` and prints it to terminal; first logged-in
148
+ // user to visit claims the env.
149
+ if (claimToken) {
150
+ const host = c.req.header('host') || ''
151
+ const proto = c.req.header('x-forwarded-proto') || 'http'
152
+ const claimUrl = host
153
+ ? `${proto}://${host}/code/claim/${claimToken}`
154
+ : `/code/claim/${claimToken}`
155
+ return c.json(
156
+ { ...result, claim_token: claimToken, claim_url: claimUrl },
157
+ 200,
158
+ )
159
+ }
160
+
127
161
  return c.json(result, 200)
128
162
  })
129
163
 
@@ -10,14 +10,60 @@ import {
10
10
  import { createWorkItem } from '../../services/work-dispatch'
11
11
  import { apiKeyAuth, acceptCliHeaders } from '../../auth/middleware'
12
12
  import { publishSessionEvent } from '../../services/transport'
13
+ import { storeBindSession, storeGetEnvironmentOwnership } from '../../store'
13
14
 
14
15
  const app = new Hono()
15
16
 
16
- /** POST /v1/sessions — Create session */
17
+ /** POST /v1/sessions — Create session.
18
+ * Used by replBridge/ACP workers to auto-create their initial session.
19
+ * Session ownership: user owner = env.owner_user_id, team owner = env.team_id
20
+ * (auto-inherited). If env has no owner_user_id yet (claim flow pending),
21
+ * returns 409 so the worker can retry after claim completes. */
17
22
  app.post('/', acceptCliHeaders, apiKeyAuth, async c => {
18
23
  const body = await c.req.json()
19
24
  const username = c.get('userId')
20
- const session = createSession({ ...body, username })
25
+
26
+ // Resolve env ownership to bind session_owners.
27
+ let envOwnerUserId: string | null = null
28
+ let envTeamId: string | null = null
29
+ if (body.environment_id) {
30
+ const ownership = storeGetEnvironmentOwnership(body.environment_id)
31
+ if (ownership) {
32
+ envOwnerUserId = ownership.ownerUserId
33
+ envTeamId = ownership.teamId
34
+ // Claim flow pending: env exists but has no user owner yet. Worker
35
+ // should retry after claim completes (Q4 = option A).
36
+ if (!ownership.ownerUserId) {
37
+ return c.json(
38
+ {
39
+ error: {
40
+ type: 'environment_unowned',
41
+ message:
42
+ 'Environment has no owner yet; claim it via the printed URL before creating sessions',
43
+ },
44
+ },
45
+ 409,
46
+ )
47
+ }
48
+ }
49
+ }
50
+
51
+ const session = createSession({
52
+ ...body,
53
+ username,
54
+ visibility: envTeamId ? 'team' : 'private',
55
+ })
56
+
57
+ // Write session_owners: team owner inherited from env, user owner = env owner.
58
+ // This is the key fix for the "not your sessions" bug — previously /v1/sessions
59
+ // only set sessions.username, never wrote session_owners, so the Web UI list
60
+ // (which filters by session_owners) never showed these sessions.
61
+ if (envTeamId) {
62
+ storeBindSession(session.id, envTeamId, 'team')
63
+ }
64
+ if (envOwnerUserId) {
65
+ storeBindSession(session.id, envOwnerUserId, 'user')
66
+ }
21
67
 
22
68
  // Create work item if environment is specified
23
69
  if (body.environment_id) {
@@ -377,6 +377,70 @@ app.post('/logout', async c => {
377
377
  return c.json({ ok: true })
378
378
  })
379
379
 
380
+ // GET /register-status — Whether self-registration is open
381
+ app.get('/register-status', c => {
382
+ return c.json({ allowed: config.allowRegistration })
383
+ })
384
+
385
+ // POST /register — Self-register a new member account (no team association).
386
+ // Only available when RCS_ALLOW_REGISTRATION !== 'false'.
387
+ app.post('/register', async c => {
388
+ if (!config.allowRegistration) {
389
+ return c.json({ error: 'Registration is disabled' }, 403)
390
+ }
391
+
392
+ let body: Record<string, unknown>
393
+ try {
394
+ body = await c.req.json()
395
+ } catch {
396
+ return c.json({ error: 'Invalid JSON' }, 400)
397
+ }
398
+
399
+ const { username, password } = body as {
400
+ username?: string
401
+ password?: string
402
+ }
403
+
404
+ if (!username || typeof username !== 'string') {
405
+ return c.json({ error: 'Username is required' }, 400)
406
+ }
407
+ if (!password || typeof password !== 'string') {
408
+ return c.json({ error: 'Password is required' }, 400)
409
+ }
410
+ if (password.length < 8) {
411
+ return c.json({ error: 'Password must be at least 8 characters' }, 400)
412
+ }
413
+
414
+ const db = getDb()
415
+ const userId = `usr_${randomUUID().replace(/-/g, '')}`
416
+ const passwordHash = await hashPasswordAsync(password)
417
+ const now = new Date().toISOString()
418
+
419
+ try {
420
+ const result = db
421
+ .query(
422
+ `INSERT OR IGNORE INTO users (id, username, password_hash, role, created_at)
423
+ VALUES ($id, $username, $passwordHash, 'member', $now)`,
424
+ )
425
+ .run({
426
+ $id: userId,
427
+ $username: username,
428
+ $passwordHash: passwordHash,
429
+ $now: now,
430
+ })
431
+
432
+ if (result.changes === 0) {
433
+ return c.json({ error: 'Username already taken' }, 409)
434
+ }
435
+ } catch (err) {
436
+ console.warn('[/register] insert failed:', err)
437
+ return c.json({ error: 'Registration failed' }, 500)
438
+ }
439
+
440
+ const isHttps = isSecureRequest(c)
441
+ return issueAndRespond(c, userId, isHttps)
442
+ })
443
+
380
444
  // POST /join — Join via invitation token
381
445
  app.post('/join', async c => {
382
446
  let body: Record<string, unknown>
@@ -9,8 +9,9 @@ import { getDb } from '../../db/sqlite'
9
9
  const app = new Hono()
10
10
 
11
11
  /** GET /web/environments — List active environments.
12
- * Admin sees all. Non-admin sees only environments linked to teams they
13
- * belong to, plus environments with no team association (personal space). */
12
+ * Admin sees all. Non-admin sees only environments they own (owner_user_id = me)
13
+ * OR environments linked to teams they belong to. Unowned personal envs (no
14
+ * owner, no team) are invisible — they're in claim flow pending state. */
14
15
  app.get('/environments', sessionAuth, async c => {
15
16
  const userId = c.get('userId') as string
16
17
  const isAdmin = c.get('isAdmin') as boolean
@@ -28,8 +29,11 @@ app.get('/environments', sessionAuth, async c => {
28
29
  .all({ $userId: userId }) as Array<{ team_id: string }>
29
30
  const teamIds = new Set(teamRows.map(r => r.team_id))
30
31
 
32
+ // Visible if: env.owner_user_id is me OR env.team_id is one of my teams.
31
33
  const filtered = allEnvs.filter(
32
- env => !env.team_id || teamIds.has(env.team_id),
34
+ env =>
35
+ env.owner_user_id === userId ||
36
+ (env.team_id !== null && teamIds.has(env.team_id)),
33
37
  )
34
38
  return c.json(filtered, 200)
35
39
  })
@@ -27,17 +27,6 @@ function isTeamMember(
27
27
  return !!row
28
28
  }
29
29
 
30
- interface ShareRow {
31
- id: string
32
- session_id: string
33
- granted_to_user: string | null
34
- granted_to_team: string | null
35
- permission: string
36
- expires_at: string | null
37
- granted_by: string
38
- granted_at: string
39
- }
40
-
41
30
  /**
42
31
  * Helper: check if the current user is the session owner.
43
32
  * Returns the userId on success, or a Response on failure.
@@ -112,10 +101,10 @@ function checkSessionOwnership(
112
101
  }
113
102
 
114
103
  /**
115
- * POST /sessions/:id/share — Create a share for a session.
104
+ * POST /sessions/:id/shares — Create a share for a session.
116
105
  */
117
106
  app.post(
118
- '/sessions/:id/share',
107
+ '/sessions/:id/shares',
119
108
  async (c, next) => {
120
109
  const result = await sessionAuth(c, next)
121
110
  if (result) return result
@@ -228,17 +217,18 @@ app.post(
228
217
  $now: now,
229
218
  })
230
219
 
231
- return c.json(
232
- {
233
- id: shareId,
234
- shareToken: shareId,
235
- share_token: shareId,
236
- permission,
237
- expiresAt: expiresAt || null,
238
- expires_at: expiresAt || null,
239
- },
240
- 201,
241
- )
220
+ // Return { share, shareToken } to match frontend CreateShareResponse type.
221
+ const share = {
222
+ id: shareId,
223
+ session_id: sessionId,
224
+ granted_to_user: grantedTo.userId || null,
225
+ granted_to_team: grantedTo.teamId || null,
226
+ permission,
227
+ expires_at: expiresAt || null,
228
+ created_at: now,
229
+ created_by: userId,
230
+ }
231
+ return c.json({ share, shareToken: shareId }, 201)
242
232
  },
243
233
  )
244
234
 
@@ -260,11 +250,12 @@ app.get(
260
250
  const shares = db
261
251
  .query(
262
252
  `SELECT id, session_id, granted_to_user, granted_to_team,
263
- permission, expires_at, granted_by, granted_at
253
+ permission, expires_at,
254
+ granted_by AS created_by, granted_at AS created_at
264
255
  FROM session_shares
265
256
  WHERE session_id = $sid`,
266
257
  )
267
- .all({ $sid: sessionId }) as ShareRow[]
258
+ .all({ $sid: sessionId })
268
259
 
269
260
  return c.json(shares, 200)
270
261
  },