@astralyn/sash 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (339) hide show
  1. package/CHANGELOG.md +184 -0
  2. package/LICENSE +21 -0
  3. package/README.md +71 -0
  4. package/THIRD_PARTY_NOTICES.md +54 -0
  5. package/dist/api.js +103 -0
  6. package/dist/browser.js +25 -0
  7. package/dist/cli-errors.js +15 -0
  8. package/dist/cli.js +122 -0
  9. package/dist/commands/lifecycle.js +50 -0
  10. package/dist/commands/logs.js +54 -0
  11. package/dist/commands/shared.js +8 -0
  12. package/dist/commands/status.js +39 -0
  13. package/dist/commands/update.js +5 -0
  14. package/dist/commands/upgrade.js +43 -0
  15. package/dist/commands/web.js +33 -0
  16. package/dist/contracts.js +412 -0
  17. package/dist/core-config-validation.js +72 -0
  18. package/dist/core-install-record.js +55 -0
  19. package/dist/core-install-transaction.js +114 -0
  20. package/dist/core-update-coordination.js +105 -0
  21. package/dist/core-update-service.js +245 -0
  22. package/dist/core-update.js +804 -0
  23. package/dist/core-version.js +18 -0
  24. package/dist/core.js +206 -0
  25. package/dist/daemon/app.js +157 -0
  26. package/dist/daemon/context.js +40 -0
  27. package/dist/daemon/entry.js +67 -0
  28. package/dist/daemon/errors.js +47 -0
  29. package/dist/daemon/handlers/core.js +17 -0
  30. package/dist/daemon/handlers/daemon.js +66 -0
  31. package/dist/daemon/handlers/profiles.js +57 -0
  32. package/dist/daemon/handlers/proxy.js +12 -0
  33. package/dist/daemon/handlers/settings.js +48 -0
  34. package/dist/daemon/router.js +312 -0
  35. package/dist/daemon/scheduler.js +33 -0
  36. package/dist/daemon/server.js +121 -0
  37. package/dist/daemon-auth.js +71 -0
  38. package/dist/daemon-client.js +55 -0
  39. package/dist/daemon-entry.js +13 -0
  40. package/dist/daemon-http.js +93 -0
  41. package/dist/daemon-lifecycle.js +378 -0
  42. package/dist/daemon-proxy.js +176 -0
  43. package/dist/daemon-static.js +106 -0
  44. package/dist/daemon.js +3 -0
  45. package/dist/error-utils.js +14 -0
  46. package/dist/fs-atomic.js +123 -0
  47. package/dist/github.js +187 -0
  48. package/dist/http.js +282 -0
  49. package/dist/json-shape.js +17 -0
  50. package/dist/log-follow.js +280 -0
  51. package/dist/log.js +17 -0
  52. package/dist/managed-state-transaction.js +377 -0
  53. package/dist/mihomo-config.js +334 -0
  54. package/dist/node-version-guard.js +8 -0
  55. package/dist/offline-mutation.js +58 -0
  56. package/dist/paths.js +57 -0
  57. package/dist/process.js +572 -0
  58. package/dist/profile-migration.js +101 -0
  59. package/dist/profile-service.js +667 -0
  60. package/dist/profiles.js +182 -0
  61. package/dist/runtime-lifecycle.js +205 -0
  62. package/dist/runtime-owner.js +87 -0
  63. package/dist/runtime-recovery.js +31 -0
  64. package/dist/sash-client.js +163 -0
  65. package/dist/settings-service.js +242 -0
  66. package/dist/settings.js +314 -0
  67. package/dist/state-lock.js +331 -0
  68. package/dist/status.js +279 -0
  69. package/dist/supervisor.js +301 -0
  70. package/dist/sysproxy/common.js +99 -0
  71. package/dist/sysproxy/darwin.js +287 -0
  72. package/dist/sysproxy/factory.js +71 -0
  73. package/dist/sysproxy/gnome.js +181 -0
  74. package/dist/sysproxy/legacy.js +58 -0
  75. package/dist/sysproxy/snapshot.js +284 -0
  76. package/dist/sysproxy/types.js +24 -0
  77. package/dist/sysproxy/windows.js +216 -0
  78. package/dist/sysproxy.js +8 -0
  79. package/dist/system-proxy-manager.js +460 -0
  80. package/dist/tun-guidance.js +11 -0
  81. package/dist/ui/assets/05129d5ad91a6181d272cc3d031363d6-DJkDXMrK.woff2 +0 -0
  82. package/dist/ui/assets/0526ebf94418638dfd5b6cd9b06c07d4-BzWe4Lji.woff2 +0 -0
  83. package/dist/ui/assets/053f2647a78f659f6f8a3ae8436bd265-BocXYDl5.woff2 +0 -0
  84. package/dist/ui/assets/078f666863424d3fd2d98e3ea528704c-DQ_QCvOt.woff2 +0 -0
  85. package/dist/ui/assets/07f3ff379663ffa0222c12f241421dd9-Cma7oDlr.woff2 +0 -0
  86. package/dist/ui/assets/08427b8d865853bbd7c439321b26495f-CJmC8fWx.woff2 +0 -0
  87. package/dist/ui/assets/095224e4db29d40c54098da02b266b0a-DjsP0nQn.woff2 +0 -0
  88. package/dist/ui/assets/0ada18ca45940b08accde5c61ee871e3-E1BZD3RX.woff2 +0 -0
  89. package/dist/ui/assets/0be242294f7d791af850c6df38ac78a0-2cL6Ntwf.woff2 +0 -0
  90. package/dist/ui/assets/0bf18c938d0c27cce06c39f855405fdb-CruLZZZJ.woff2 +0 -0
  91. package/dist/ui/assets/0cfb3e9f4edf60839c37dc83e6f75ea3-DzAtRHvi.woff2 +0 -0
  92. package/dist/ui/assets/0fbbd340d0467dfe3101d58846f30cb0-gtFcO250.woff2 +0 -0
  93. package/dist/ui/assets/1063fa2dc7334d1f383e30824e016eae-B7U-kD-0.woff2 +0 -0
  94. package/dist/ui/assets/109e26e62ddc85d946e699464afbece7-BLnUjAEV.woff2 +0 -0
  95. package/dist/ui/assets/12a443b0ae9748a993b5395f8fad412b-Btjff2Lz.woff2 +0 -0
  96. package/dist/ui/assets/135c4621de7a4d85d852e03d416f13ee-DdSuW36e.woff2 +0 -0
  97. package/dist/ui/assets/13aa415469ee761c968749b1c0c56ec6-Dwe-Wa_w.woff2 +0 -0
  98. package/dist/ui/assets/1435b1ad447bd9c0e8bc52035c9dcfa8-C05ldXtw.woff2 +0 -0
  99. package/dist/ui/assets/175e0915aa874e7446b79b6bc9b00721-Dp0-l77L.woff2 +0 -0
  100. package/dist/ui/assets/1876e7d02187f006e2b7f769391c3089-CNjpRdap.woff2 +0 -0
  101. package/dist/ui/assets/1886dc284b3b845e3b5fe04aa2107276-Bh_wHwL1.woff2 +0 -0
  102. package/dist/ui/assets/19a3dda6611aaf5d787403bd1159fe15-zoEBvdpA.woff2 +0 -0
  103. package/dist/ui/assets/1afa74e14da193125e45d4783d358a4f-BgjSTENX.woff2 +0 -0
  104. package/dist/ui/assets/1cd26a6a6d784720b4a43053e9058bcf-TAP3dvNi.woff2 +0 -0
  105. package/dist/ui/assets/1ce19bddc3beab385a863b1e05685678-BCdXitZw.woff2 +0 -0
  106. package/dist/ui/assets/1d3459ac6578c80502bdb876a4824a93-CSwdnEGP.woff2 +0 -0
  107. package/dist/ui/assets/1d479e364dab4af01c539f0a6a7ac036-ZFI-djGt.woff2 +0 -0
  108. package/dist/ui/assets/1dcea2408d17fcec4197adce50f8b32d-CnK2xXR-.woff2 +0 -0
  109. package/dist/ui/assets/1e855385699999e24a33f7df8aed0489-DGFHkDVQ.woff2 +0 -0
  110. package/dist/ui/assets/1f55944b8f7972580e3029694462a6b0-CB7ogVJ9.woff2 +0 -0
  111. package/dist/ui/assets/1f96eda70929089762dc3c4feb33f9c8-DtSQ6YOf.woff2 +0 -0
  112. package/dist/ui/assets/1fb275532caadc746455881b31da27c4-BHFTsg74.woff2 +0 -0
  113. package/dist/ui/assets/20e679bdc00d06f802ea71fd9154b284-D9gRjq_v.woff2 +0 -0
  114. package/dist/ui/assets/25aff66c4a9f8cb801cbd525f4a923e4-Dgi87hP7.woff2 +0 -0
  115. package/dist/ui/assets/28e6700380b023b23e77f2d75aee624f-b19D855Q.woff2 +0 -0
  116. package/dist/ui/assets/2a1c50aa9cd99ce3a0197f5d49948e63-DrztdXCB.woff2 +0 -0
  117. package/dist/ui/assets/2b4e0ae0bf3af610b97717dfd66a012d-CBoapvha.woff2 +0 -0
  118. package/dist/ui/assets/2be2b7a672b616bc2f07059a67bfaad8-BUR0aNML.woff2 +0 -0
  119. package/dist/ui/assets/2e0a358ada78ea98ec8ba86002a27eac-DvgbSr9v.woff2 +0 -0
  120. package/dist/ui/assets/2e1cf63a2a22a50516c49b1dc521ea8a-CmltIxig.woff2 +0 -0
  121. package/dist/ui/assets/2e4481801925fcb6573c4337c73f15d7-DYOoCk-m.woff2 +0 -0
  122. package/dist/ui/assets/2fe5e634c568cd874f94d24b8f02bfd1-DcEHY35G.woff2 +0 -0
  123. package/dist/ui/assets/309c33f63f29887fb557115aa24d4bb5-CUgqrXIj.woff2 +0 -0
  124. package/dist/ui/assets/3158f45c959e1b346b0bbd6f3193dbf0-kimcClqp.woff2 +0 -0
  125. package/dist/ui/assets/316adbc8037a36f8d804637b053bbe5e-CjbZmJf9.woff2 +0 -0
  126. package/dist/ui/assets/319e9631bc29fc7235b70fc9aac43cd9-IV6yZuHZ.woff2 +0 -0
  127. package/dist/ui/assets/32054f9bb88d9431b1cdf023f770e614-CYrpCgqK.woff2 +0 -0
  128. package/dist/ui/assets/3245fa1aac6338c1d9d04befb7c346f8-CzvPhVPA.woff2 +0 -0
  129. package/dist/ui/assets/326c730f98afa476057957f2743c81e2-GPHJ3Fpu.woff2 +0 -0
  130. package/dist/ui/assets/33885558dc783bf9bae6c5d4668fef07-D33us0yR.woff2 +0 -0
  131. package/dist/ui/assets/33cd11f5e61556e4618801c8231f2744-CoR_Tv3X.woff2 +0 -0
  132. package/dist/ui/assets/34a170749cb7e6c5851acc510882af6b-BCZwsihk.woff2 +0 -0
  133. package/dist/ui/assets/3538de2d387591258d7e9908aad803b9-CewOkERZ.woff2 +0 -0
  134. package/dist/ui/assets/38d7b029c036080067a2e94211098171-CettR5Qv.woff2 +0 -0
  135. package/dist/ui/assets/393f47efeefc9f9e9cca83eb10a82c69-Brhz4z1y.woff2 +0 -0
  136. package/dist/ui/assets/396a51f2b274d01f6ba606a94f3e5fe2-DgRk-jtI.woff2 +0 -0
  137. package/dist/ui/assets/3991bf955d4c925e84b4a6542760d4d5-II4HtRkQ.woff2 +0 -0
  138. package/dist/ui/assets/39b6cb6ae8d1ea0e9832b88d2c21ef99-CbJm-q6b.woff2 +0 -0
  139. package/dist/ui/assets/3a1133157fbd259f1a51aaa9f8418a26-3FmUjjvi.woff2 +0 -0
  140. package/dist/ui/assets/3a34cff07dca7a65ed2486be19229290-B7ml2yBN.woff2 +0 -0
  141. package/dist/ui/assets/3c339dd7c27e6b8a06eea431733e076f-dGQqXaEj.woff2 +0 -0
  142. package/dist/ui/assets/3d074ea67f60953b816ce7cf5d87a980-B5VkPOmg.woff2 +0 -0
  143. package/dist/ui/assets/3d38f54dcf4a9f4a50165d5849becf71-CVDtFSZn.woff2 +0 -0
  144. package/dist/ui/assets/3e3fc9a19a27f94e4ff1b815b55b2671-Ci736GLi.woff2 +0 -0
  145. package/dist/ui/assets/3e8abb1f606f29e2f0a8a8a6b702d263-C5sOSf5L.woff2 +0 -0
  146. package/dist/ui/assets/3f0ab4e1cd99bdbfdf9acbc8f4bcb9ce-0DcdTLxV.woff2 +0 -0
  147. package/dist/ui/assets/3f30c0482650345c981d66920f56ab61-CTD2CsZI.woff2 +0 -0
  148. package/dist/ui/assets/41a9aa12ad9a60758b304c1a998fb781-BTQUDLf1.woff2 +0 -0
  149. package/dist/ui/assets/424010b2bc5cee540b92b28da49b61bf-DT8upW2M.woff2 +0 -0
  150. package/dist/ui/assets/42fbdafff2d44b76c6665d51bb2cee9d-_UrojhXD.woff2 +0 -0
  151. package/dist/ui/assets/4341db13c311b3cb0eaaf6b4c71b89e5-CzjA7MzG.woff2 +0 -0
  152. package/dist/ui/assets/434db5a796128131fde78d4389d14b71-AeNdWKua.woff2 +0 -0
  153. package/dist/ui/assets/43cb51fc70a15274d49e2d956c5ec3b4-BQbufd96.woff2 +0 -0
  154. package/dist/ui/assets/43e79de1c7815f21efbc966ff96fcbd6-DlCQvOsQ.woff2 +0 -0
  155. package/dist/ui/assets/43faf6a8a3cde1088bd5f7c830890a89-SvDzF3nA.woff2 +0 -0
  156. package/dist/ui/assets/44731ae21d7690ce538d0f8242755833-CEmu9Z88.woff2 +0 -0
  157. package/dist/ui/assets/45324b2a64cc0c0db797d5c09e239d34-BuFudtvM.woff2 +0 -0
  158. package/dist/ui/assets/4584df05d00aa75ae6e1f850fdc9df1d-GNHt6xwM.woff2 +0 -0
  159. package/dist/ui/assets/48d539539e98481fb511a761031c59fd-Cd9gdi8B.woff2 +0 -0
  160. package/dist/ui/assets/49a1fb9fc6a35796b2e0d3539088ede8-CD1cRDOy.woff2 +0 -0
  161. package/dist/ui/assets/4bec02eb0c2371e59bfb7d41a141ea1e-CmBnNPo0.woff2 +0 -0
  162. package/dist/ui/assets/4c5a81ef5683f6fbf9935e640de804e7-B4wQxzVs.woff2 +0 -0
  163. package/dist/ui/assets/4f11c9c75e86214b7f69ddee3a9f8076-DHsQ2xpE.woff2 +0 -0
  164. package/dist/ui/assets/50434b8ff88e27101d1c67ba953ee873-PH_hIqxu.woff2 +0 -0
  165. package/dist/ui/assets/5107fd5153d52c6a3f8d43ff214dd6c2-ls3eo5Qd.woff2 +0 -0
  166. package/dist/ui/assets/520cb7d3683dee99e767650efc0aa5b1-Lkd4z-9S.woff2 +0 -0
  167. package/dist/ui/assets/5455087df2f091b7bf3d38c5a102a2e7-QNkiOxwe.woff2 +0 -0
  168. package/dist/ui/assets/556450fdf0978d329cf8277e3b71dcdb-CtypGAPw.woff2 +0 -0
  169. package/dist/ui/assets/5a1b5c1b71cad50c51a79a7f4825e6e6-DQA407Ec.woff2 +0 -0
  170. package/dist/ui/assets/5ba02e809d2ef4f7639178e7a7d654c0-Dty0omtl.woff2 +0 -0
  171. package/dist/ui/assets/5bd654afe48e094f95e5142e4eaadc75-D9pUq71R.woff2 +0 -0
  172. package/dist/ui/assets/5c4c3ca0a3f4115879a61a96d02e3efc-RcVLBj31.woff2 +0 -0
  173. package/dist/ui/assets/5c737d740638e8d764f12c1e5c1cd144-D2Npjq-N.woff2 +0 -0
  174. package/dist/ui/assets/5e78019102102aa5741aa591313fd5b5-V7Azrw-2.woff2 +0 -0
  175. package/dist/ui/assets/6287cacac64e1849941f7b7d7e6316c5-DzkbPOID.woff2 +0 -0
  176. package/dist/ui/assets/643df7194160d54edc48d16d76e5ba74-BKmmIRjw.woff2 +0 -0
  177. package/dist/ui/assets/65d3b214c69ff6786fd1cab06f8394b7-B0cRUJAr.woff2 +0 -0
  178. package/dist/ui/assets/6698103c11bfe260d44fcf00c6d8b623-DVWYOeyb.woff2 +0 -0
  179. package/dist/ui/assets/692e07b3a609a8f1a21c15c45631f348-DJW5LcZH.woff2 +0 -0
  180. package/dist/ui/assets/694e87456af181279c2bfd551aa3c6e3-Cu7kRuJB.woff2 +0 -0
  181. package/dist/ui/assets/6b88066bdc7a6e8bc823128dbd0f6f3b-BG38UZSq.woff2 +0 -0
  182. package/dist/ui/assets/6d6f36f15381826d113832bfdd41b021-Bgh7YPiq.woff2 +0 -0
  183. package/dist/ui/assets/6e22361162bd0a5cd189ca3c98d23d52-DqnptHqF.woff2 +0 -0
  184. package/dist/ui/assets/6e884dd501b8da24ecd37425a9b3d51d-BVNqra8s.woff2 +0 -0
  185. package/dist/ui/assets/71200dbc7497fbafa28db5cfeae74acb-B6xMqoC6.woff2 +0 -0
  186. package/dist/ui/assets/72a85441a9757146440e3985f3b02075-CzTSlCPZ.woff2 +0 -0
  187. package/dist/ui/assets/7472d7e02045dea3ff288eac850e38eb-CboJEy4X.woff2 +0 -0
  188. package/dist/ui/assets/795ffa953bea666763ae79ac88aa7e5a-C6UsoDmi.woff2 +0 -0
  189. package/dist/ui/assets/7aa8647d6c52d249169b73417aa8e444-kJejhQ0-.woff2 +0 -0
  190. package/dist/ui/assets/7be6b794fc233ccd8b5769496301313a-Ba2iZC0a.woff2 +0 -0
  191. package/dist/ui/assets/7c0748f04d52086809c9f551c5aaded7-DSzO_ybF.woff2 +0 -0
  192. package/dist/ui/assets/7c858bb53a7652227fab8cf9753d3e1f-Bi9fbvIF.woff2 +0 -0
  193. package/dist/ui/assets/7e7026091b4e6061b05963bdb3a7f944-CrmRDJpc.woff2 +0 -0
  194. package/dist/ui/assets/7f80369a7479d568ab8bf492000282bd-CqcI5ZOp.woff2 +0 -0
  195. package/dist/ui/assets/834ce2f2571aaa26e47a618c4ad55e58-DZfWJrxo.woff2 +0 -0
  196. package/dist/ui/assets/834faab602d9c795341bc7dfd6578fe5-B1VeBVWh.woff2 +0 -0
  197. package/dist/ui/assets/8513a8eea35b460a047a16a87c36f8bb-H259w_6b.woff2 +0 -0
  198. package/dist/ui/assets/8699e8a36465bf46671dc28ce24e188c-YlkPpQ6h.woff2 +0 -0
  199. package/dist/ui/assets/86ae8881eae9eac7e9c0182c8ce6c627-Ch2r3LNs.woff2 +0 -0
  200. package/dist/ui/assets/86b3ae1be58d76f7147793f09264451b-CpgTfcn-.woff2 +0 -0
  201. package/dist/ui/assets/8769f8d7d45adcfcbd3f80460d22720d-DV_yqcTo.woff2 +0 -0
  202. package/dist/ui/assets/87bb0ceea9f5515490c832bdf6ebf641-CJpxd8e6.woff2 +0 -0
  203. package/dist/ui/assets/8928b9a50b5efbaaafa039674a3c7301-C-42WRD6.woff2 +0 -0
  204. package/dist/ui/assets/899f2c2a36cbeac473a7caeeaabc46b1-xrIcXJXU.woff2 +0 -0
  205. package/dist/ui/assets/8a075d4043e6bf66740808b492186438-Dq0346Qm.woff2 +0 -0
  206. package/dist/ui/assets/8b86676936792154c53205ab5d90b797-BGH_CGsg.woff2 +0 -0
  207. package/dist/ui/assets/8c63ca479653200a0e12f428242e1171-CsBTcPwY.woff2 +0 -0
  208. package/dist/ui/assets/8c9c7ff8342f5fed60e73c4a7ad67325-CGSYpt52.woff2 +0 -0
  209. package/dist/ui/assets/8ca655fcc5d9cf33d49815e231f3f356-b8PyEeZg.woff2 +0 -0
  210. package/dist/ui/assets/8e96f0f9385ef826f900587d0fc18b3d-D7GIG6Uq.woff2 +0 -0
  211. package/dist/ui/assets/8ea917252cf2c1e664f06ee5badffeea-CDZ1AFr0.woff2 +0 -0
  212. package/dist/ui/assets/8f42f890fc37e292017446af85af2745-Qx6oGI0z.woff2 +0 -0
  213. package/dist/ui/assets/8f9589e71c53bb753749a9c412f15c01-BVR5mPJl.woff2 +0 -0
  214. package/dist/ui/assets/90e70b52a3cc2491bbb2b4c0caf0ae7e-BdwPu67j.woff2 +0 -0
  215. package/dist/ui/assets/92ac4ca42fe050c1e680c585551abd9c-CXLyuj7l.woff2 +0 -0
  216. package/dist/ui/assets/92c12bb794c491930fd06f3f97299807-u_0ognJ0.woff2 +0 -0
  217. package/dist/ui/assets/92f0b4d2bb274a801aac10fc34c1e0cc-DFHB6dyu.woff2 +0 -0
  218. package/dist/ui/assets/93247aebd628367f5518eafdb2770ce9-o1N4zvTO.woff2 +0 -0
  219. package/dist/ui/assets/940446ea160995af66a9ee223cc3d4d1-C-_7aPYO.woff2 +0 -0
  220. package/dist/ui/assets/94be430de618453b6ae27bd366827ba2-1YYf1n5N.woff2 +0 -0
  221. package/dist/ui/assets/98cd7d62095e466e55885b34f63c86f1-z33YCk0X.woff2 +0 -0
  222. package/dist/ui/assets/99049fd5cec5894cafe2a1e5e13d1e03-DNrg8nIk.woff2 +0 -0
  223. package/dist/ui/assets/99e2752b7351aaa7681b4d91db80e89a-b3hi7miY.woff2 +0 -0
  224. package/dist/ui/assets/9d1b670cbfd64716ac685dea26237d95-DAZ9U6es.woff2 +0 -0
  225. package/dist/ui/assets/CodeEditorModal-6m0TJWyF.css +1 -0
  226. package/dist/ui/assets/CodeEditorModal-CFEnWsyh.js +14 -0
  227. package/dist/ui/assets/ConnectionsView-DHo6yvU6.css +1 -0
  228. package/dist/ui/assets/ConnectionsView-DNGmZBSU.js +1 -0
  229. package/dist/ui/assets/LogsView-BoeE92VF.css +1 -0
  230. package/dist/ui/assets/LogsView-fSiaxQ13.js +1 -0
  231. package/dist/ui/assets/PaginationFooter-B3kHzRfB.js +1 -0
  232. package/dist/ui/assets/PaginationFooter-BNkpcNoB.css +1 -0
  233. package/dist/ui/assets/ProfileEditorDialog-BydoZthX.js +1 -0
  234. package/dist/ui/assets/ProfilesView-Btc1DOxE.js +2 -0
  235. package/dist/ui/assets/ProfilesView-ByqdFNHN.css +1 -0
  236. package/dist/ui/assets/RulesView-CHyynVqA.css +1 -0
  237. package/dist/ui/assets/RulesView-D9vZBiJ1.js +1 -0
  238. package/dist/ui/assets/SettingsFileDialog-CNFEAVs4.js +1 -0
  239. package/dist/ui/assets/SettingsView-BlDhZkXQ.js +2 -0
  240. package/dist/ui/assets/SettingsView-CngS3vBM.css +1 -0
  241. package/dist/ui/assets/a0f2d41645a113d821e7ff0891daad1e-XK0rDAci.woff2 +0 -0
  242. package/dist/ui/assets/a1d1345d8407dd6169f39c28ff6b1708-Bn7hMmv8.woff2 +0 -0
  243. package/dist/ui/assets/a29f51b4ebb6776e43e7492a036be28e-CrAKKz8u.woff2 +0 -0
  244. package/dist/ui/assets/a3252ac86b2c4e88bfb9baecabcad817-qnA_3LNE.woff2 +0 -0
  245. package/dist/ui/assets/a3d63a61e7eb2bb497dbc2da65bd0873-BRMJAm0m.woff2 +0 -0
  246. package/dist/ui/assets/a45eea933252dbe3529f30a0323c2661-D4kBOrXR.woff2 +0 -0
  247. package/dist/ui/assets/a4886c4ebed8c8b1f8a87b5b491a39aa-CBQdRqpF.woff2 +0 -0
  248. package/dist/ui/assets/a50b4ab745c7676d9d3ceb3c0a023a3d-CW990pgI.woff2 +0 -0
  249. package/dist/ui/assets/a5851ae4d7e58996d8bd681f80d4727c-BBytdb0t.woff2 +0 -0
  250. package/dist/ui/assets/a5cdaa96bf7d1db6c671432f9ab7bccb-slKJjgfX.woff2 +0 -0
  251. package/dist/ui/assets/a640dd2e962cf72c7fcf76234c973303-CUCWUDBY.woff2 +0 -0
  252. package/dist/ui/assets/a67e457bbd366aef5104ce743a2cf6d4-DkE8fLlE.woff2 +0 -0
  253. package/dist/ui/assets/a6c3f2257315d45aa212bd2e86a02852-CxDbXnZV.woff2 +0 -0
  254. package/dist/ui/assets/a73399a40a5f81fb7314b8b9a10cd221-DRAvJPKI.woff2 +0 -0
  255. package/dist/ui/assets/a73a64b0941803d9d807b9ec082df641-BbPpPyy5.woff2 +0 -0
  256. package/dist/ui/assets/a73d1a0a1dfd4f4234f7a0649ece4da4-BHeqktY9.woff2 +0 -0
  257. package/dist/ui/assets/a740044e77a400a450e71fcdea55523f-Co5hpBNK.woff2 +0 -0
  258. package/dist/ui/assets/a7669b29f404662c179c71b87e67c8d2-CVnuBgHy.woff2 +0 -0
  259. package/dist/ui/assets/a964a4def15811e91b05a91740a1cf37-CzcDfCRn.woff2 +0 -0
  260. package/dist/ui/assets/aac3f69132da164921fda75d2d90bfb7-B6rUZQ4_.woff2 +0 -0
  261. package/dist/ui/assets/aacd263c3bb4ba163a4d5079c159680a-DtrDLFlk.woff2 +0 -0
  262. package/dist/ui/assets/ac62ec881ded2cdb450e542b396e24d0-CRlVJvPa.woff2 +0 -0
  263. package/dist/ui/assets/aebcb9b7d4b174ab5a4b911206f24036-BuleSpgP.woff2 +0 -0
  264. package/dist/ui/assets/af70712dadc05c7b18d248996a5ab0a9-gCZSZGzb.woff2 +0 -0
  265. package/dist/ui/assets/afbd3a8a4cfaa4561b7848c28bc6c4f8-DgnqceEw.woff2 +0 -0
  266. package/dist/ui/assets/b02d3867e6e2ea921d2845b44c4a5a31-C9v4FrqD.woff2 +0 -0
  267. package/dist/ui/assets/b1b22825b930688403337d4fd7bbba62-vmMs2pJf.woff2 +0 -0
  268. package/dist/ui/assets/b3206c979bfb28d12d7ad6df58e74b9f-X1PqLaCR.woff2 +0 -0
  269. package/dist/ui/assets/b6280e42d4f11dcab70594f9d6774936-CtezImLG.woff2 +0 -0
  270. package/dist/ui/assets/b71b8cd1a70405c3dbc0e7a44055ca9a-Cd6cIOEr.woff2 +0 -0
  271. package/dist/ui/assets/b9198c4f220a4ca075f8daa4db529e50-Bgc7zlEt.woff2 +0 -0
  272. package/dist/ui/assets/baad304a58d7d42d0af29235c5e9490b-BQZYwARB.woff2 +0 -0
  273. package/dist/ui/assets/bb99e34f8784cc44f0eeadbe735dd238-UHFYI827.woff2 +0 -0
  274. package/dist/ui/assets/bc1cb0f523c8a2ff566a047aeddf90fd-BSlXQn97.woff2 +0 -0
  275. package/dist/ui/assets/bd3171e975d62612e50148bf38b2158f-CtZKzCzQ.woff2 +0 -0
  276. package/dist/ui/assets/be10640c403263dd5917ad65c4d453a6-B-rbuuja.woff2 +0 -0
  277. package/dist/ui/assets/be764e101e78b50b749aa1414d4810a7-yIPaQQih.woff2 +0 -0
  278. package/dist/ui/assets/bfa682a7f5f12945b41230c35eb859f6-CzagcI5f.woff2 +0 -0
  279. package/dist/ui/assets/bfa9753ed26f2e1f81ab7020167bd1a0-C6ZNQQ2p.woff2 +0 -0
  280. package/dist/ui/assets/branding/sash-cat.png +0 -0
  281. package/dist/ui/assets/c0e78c6ad709b19ce437677c91033489-BtwtlApg.woff2 +0 -0
  282. package/dist/ui/assets/c5a59409c610cc8c265d1691eb3f71eb-DmI_ky2X.woff2 +0 -0
  283. package/dist/ui/assets/c5ff66a1a57f2a29424e8de5d4ef3756-C9pOsaV1.woff2 +0 -0
  284. package/dist/ui/assets/c607bdee84a0e5b69721367ccc0c9c31-eoHbdXeg.woff2 +0 -0
  285. package/dist/ui/assets/c8095033941d18db730496eb4c863757-DoexTYks.woff2 +0 -0
  286. package/dist/ui/assets/c8295519e16f4cf3a350e9729f07653a-C8bAtIO_.woff2 +0 -0
  287. package/dist/ui/assets/c91f9c9f4db81afeba37c8e73afb0bfd-BGIl2iKW.woff2 +0 -0
  288. package/dist/ui/assets/c9ad9caa4afdd40766add91d321b0350-HfuiRq1k.woff2 +0 -0
  289. package/dist/ui/assets/cc4f271c90f9ea5157db9c0a4edc976b-MAjuDvHE.woff2 +0 -0
  290. package/dist/ui/assets/cdf7c3d96ba172214d7e1e9fe5e6ba8b-CUx4fWQE.woff2 +0 -0
  291. package/dist/ui/assets/cf70d5821ea7c3ca34653169ac763606-CE0T0Svc.woff2 +0 -0
  292. package/dist/ui/assets/d0d5efe92496b1ceea38e180b0ac97d3-7G71Z6v3.woff2 +0 -0
  293. package/dist/ui/assets/d1977142eceb878b06440375e64c4372-mr-7LWm-.woff2 +0 -0
  294. package/dist/ui/assets/d42feb13392b4dd9214c61b61a6e5ae8-DjnKADf_.woff2 +0 -0
  295. package/dist/ui/assets/d46a696ec6a077c6873fc39043c3c082-C62E-13k.woff2 +0 -0
  296. package/dist/ui/assets/d4c0bbf1605a8a9c36fff5a2ead81bb5-C2F6tzOj.woff2 +0 -0
  297. package/dist/ui/assets/d918d4e47697b7c752ea223e0d0d4c81-twovU2ty.woff2 +0 -0
  298. package/dist/ui/assets/d988c05da0b5624267dd825fedd133d1-Bgbc9SVH.woff2 +0 -0
  299. package/dist/ui/assets/da3a071df79531f4f033b7c8499651d0-0tgZJL_N.woff2 +0 -0
  300. package/dist/ui/assets/da8eba4acbf93048645043006de1c5f0-Ce0dmHn_.woff2 +0 -0
  301. package/dist/ui/assets/dc3f16892e20a85a8fcad2d3097e622b-8PRrFPJt.woff2 +0 -0
  302. package/dist/ui/assets/dd5f808ec691f911483a2eb60b5049bd-BhVupSbT.woff2 +0 -0
  303. package/dist/ui/assets/e2b04534cc697a76afd70e885119cb8c-DO303iCb.woff2 +0 -0
  304. package/dist/ui/assets/e307280eb2fb7809adee14ff0d247d32-DHMLXvSs.woff2 +0 -0
  305. package/dist/ui/assets/e3b484bec850c669094f713570870b3a-BI_9kRw8.woff2 +0 -0
  306. package/dist/ui/assets/e7b1d196949b7530cbda0ad956fbb2cc-i2m2Id0q.woff2 +0 -0
  307. package/dist/ui/assets/e7c2e5fb387880508811cadc2926e13a-BfROXX4U.woff2 +0 -0
  308. package/dist/ui/assets/e8a5fe283c8b9e173097bee0b5757ab6-BvfjDjYP.woff2 +0 -0
  309. package/dist/ui/assets/e8e3465d48435612e9c3509be3984188-BeUPU5-9.woff2 +0 -0
  310. package/dist/ui/assets/e93903f4604b007fc1b7134a74f5c534-B1M4h46T.woff2 +0 -0
  311. package/dist/ui/assets/eb0994906efd969102d522b6d8b3aff2-i9SHU5CJ.woff2 +0 -0
  312. package/dist/ui/assets/eb32eee23ceadd3fc4eb5763d3573f57-B3h9kgf3.woff2 +0 -0
  313. package/dist/ui/assets/ebadbc005027fb3e2b1c2d15be38c66b-qVQSBwBu.woff2 +0 -0
  314. package/dist/ui/assets/ecbbb464ff6934b5012cf33c80c7a907-CBEPqZfS.woff2 +0 -0
  315. package/dist/ui/assets/ed79ac25c014b6434f22fe1e2549bc26-mWhz7hkU.woff2 +0 -0
  316. package/dist/ui/assets/eed64f40443554cb9f65edaca176abb0-Cqw29XTm.woff2 +0 -0
  317. package/dist/ui/assets/efc749471476cce09e12e7038c757950-BhSWPf1Q.woff2 +0 -0
  318. package/dist/ui/assets/f2a7c2cb375662aa93d8f31116d39c20-D1zsMYCW.woff2 +0 -0
  319. package/dist/ui/assets/f5ba0fb4332ccceadc481e47134023d3-CAKMPiu5.woff2 +0 -0
  320. package/dist/ui/assets/f6326eb5031e18478aa4588598f96965-Dj3uu55n.woff2 +0 -0
  321. package/dist/ui/assets/f8678cbaab9caef95e1986731dcbd92f-CnIuR3EN.woff2 +0 -0
  322. package/dist/ui/assets/f8d9d55e2a811e9839c9af5f8f2d62ac-DIUQRBsH.woff2 +0 -0
  323. package/dist/ui/assets/f98b117e363eb51f4d7c7d1056da7688-O9MtqjIW.woff2 +0 -0
  324. package/dist/ui/assets/f9ab5d9163148ceb211e5b4f15a3d8e0-Dtqse-AT.woff2 +0 -0
  325. package/dist/ui/assets/fa69ce224ff0a6c0ff97b10a829779c2-pX45dCNY.woff2 +0 -0
  326. package/dist/ui/assets/fc38d1da3930d39dd8e286f708105765-DmbOHwTI.woff2 +0 -0
  327. package/dist/ui/assets/fe03c1dfaffc1cad3521fe55f1541d6b-BW8aEqCj.woff2 +0 -0
  328. package/dist/ui/assets/fe0b2421eb4d1f4f8949c602871a317c-BsBLV6jH.woff2 +0 -0
  329. package/dist/ui/assets/fe9c75d0cb3d808023412d26dfc9d388-eXjcgUPI.woff2 +0 -0
  330. package/dist/ui/assets/index-B61V60w_.js +19 -0
  331. package/dist/ui/assets/index-bkyxJG8J.css +1 -0
  332. package/dist/ui/assets/theme-BNq4FkXS.js +1 -0
  333. package/dist/ui/index.html +52 -0
  334. package/dist/webui.js +21 -0
  335. package/docs/backend.md +260 -0
  336. package/docs/frontend.md +125 -0
  337. package/docs/remix-icon-license.txt +186 -0
  338. package/docs/usage.md +227 -0
  339. package/package.json +82 -0
@@ -0,0 +1,50 @@
1
+ import { log } from "../log.js";
2
+ import { ensureRunning, restartRuntime, stopRuntime } from "../runtime-owner.js";
3
+ import { tunPrivilegeGuidance } from "../tun-guidance.js";
4
+ import { runtimeContext } from "./shared.js";
5
+ export async function runStart() {
6
+ const ctx = runtimeContext();
7
+ const { owner, result } = await ensureRunning(ctx);
8
+ log.ok(`core started (PID=${result.pid}${result.version ? `, version ${result.version}` : ""})`);
9
+ printEndpoints(ctx, owner.daemon.port);
10
+ reportTunState(ctx, result);
11
+ if (ctx.settings.systemProxy)
12
+ log.ok("system proxy enabled");
13
+ }
14
+ export async function runStop() {
15
+ const ctx = runtimeContext();
16
+ const { wasRunning } = await stopRuntime(ctx);
17
+ if (wasRunning) {
18
+ log.ok("sash stopped; system proxy restored to its pre-Sash state");
19
+ }
20
+ else {
21
+ log.info("sash is not running; stale runtime state was reconciled");
22
+ }
23
+ }
24
+ export async function runRestart(deps = {}) {
25
+ const ctx = runtimeContext();
26
+ const { owner, result, daemonPid, daemonWasRunning } = await restartRuntime(ctx, deps);
27
+ const verb = daemonWasRunning ? "restarted" : "started";
28
+ log.ok(`sashd ${verb} (PID=${daemonPid})`);
29
+ log.ok(`core ${verb} (PID=${result.pid}${result.version ? `, version ${result.version}` : ""})`);
30
+ printEndpoints(ctx, owner.daemon.port);
31
+ reportTunState(ctx, result);
32
+ }
33
+ function reportTunState(ctx, result) {
34
+ if (!ctx.settings.tun)
35
+ return;
36
+ if (result.tunActive === true) {
37
+ log.ok("TUN active");
38
+ }
39
+ else if (result.tunActive === false) {
40
+ log.warn(`TUN was requested but is inactive; the core remains available without TUN. ${tunPrivilegeGuidance("runtime-inactive", { root: ctx.layout.root })}`);
41
+ }
42
+ else {
43
+ log.warn(`TUN was requested, but its runtime state could not be verified. ${tunPrivilegeGuidance("runtime-inactive", { root: ctx.layout.root })}`);
44
+ }
45
+ }
46
+ export function printEndpoints(ctx, daemonPort) {
47
+ log.kv("mixed port", `127.0.0.1:${ctx.settings.mixedPort}`);
48
+ log.kv("sash api", `http://127.0.0.1:${daemonPort}`);
49
+ log.kv("dashboard", `http://127.0.0.1:${daemonPort}/ui/ (sash web to open)`);
50
+ }
@@ -0,0 +1,54 @@
1
+ import fs from "node:fs";
2
+ import { log } from "../log.js";
3
+ import { followLogFile, logCursorAtEnd, normalizeLines } from "../log-follow.js";
4
+ import { tailFile } from "../process.js";
5
+ import { runtimeContext } from "./shared.js";
6
+ export async function runLogs(opts = {}) {
7
+ const ctx = runtimeContext();
8
+ let file;
9
+ if (opts.daemon) {
10
+ file = opts.errors ? ctx.layout.daemonErrLogFile : ctx.layout.daemonLogFile;
11
+ }
12
+ else {
13
+ file = opts.errors ? ctx.layout.coreErrLogFile : ctx.layout.coreLogFile;
14
+ }
15
+ const lines = normalizeLines(opts.lines);
16
+ const cursor = logCursorAtEnd(file);
17
+ if (cursor.identity === null) {
18
+ log.info(`${opts.follow ? "waiting for" : "no"} log file at ${file}`);
19
+ if (!opts.follow)
20
+ return;
21
+ }
22
+ else {
23
+ printTail(file, lines);
24
+ }
25
+ if (!opts.follow)
26
+ return;
27
+ const controller = new AbortController();
28
+ const stop = () => controller.abort();
29
+ process.once("SIGINT", stop);
30
+ process.once("SIGTERM", stop);
31
+ try {
32
+ await followLogFile(file, {
33
+ cursor,
34
+ signal: controller.signal,
35
+ onChunk: async (chunk) => {
36
+ if (process.stdout.write(chunk))
37
+ return;
38
+ await new Promise((resolve) => process.stdout.once("drain", resolve));
39
+ },
40
+ });
41
+ }
42
+ finally {
43
+ process.removeListener("SIGINT", stop);
44
+ process.removeListener("SIGTERM", stop);
45
+ }
46
+ }
47
+ function printTail(file, lines) {
48
+ if (!fs.existsSync(file))
49
+ return;
50
+ const tail = tailFile(file, lines);
51
+ if (!tail)
52
+ return;
53
+ process.stdout.write(`${tail}\n`);
54
+ }
@@ -0,0 +1,8 @@
1
+ import { sashLayout } from "../paths.js";
2
+ import { loadSettings } from "../settings.js";
3
+ export { runOfflineMutation } from "../offline-mutation.js";
4
+ export function runtimeContext() {
5
+ const layout = sashLayout();
6
+ const settings = loadSettings(layout);
7
+ return { layout, settings };
8
+ }
@@ -0,0 +1,39 @@
1
+ import { log } from "../log.js";
2
+ import { collectRuntimeStatus, formatObservedProxy, formatTunObservation, markIncompleteObservation, runtimeStatusHeadline, shouldShowTunGuidance, } from "../status.js";
3
+ import { tunPrivilegeGuidance } from "../tun-guidance.js";
4
+ import { runtimeContext } from "./shared.js";
5
+ export async function runStatus(opts = {}, collect = () => collectRuntimeStatus(runtimeContext())) {
6
+ const status = await collect();
7
+ if (opts.json) {
8
+ console.log(JSON.stringify(status, null, 2));
9
+ markIncompleteObservation(status.complete);
10
+ return;
11
+ }
12
+ const headline = runtimeStatusHeadline(status);
13
+ log[headline.level](headline.text);
14
+ if (status.queryError)
15
+ log.warn(`status incomplete: ${status.queryError}`);
16
+ log.kv("root", status.paths.root);
17
+ log.kv("config", status.paths.config);
18
+ log.kv("mixed port", status.endpoints.mixedProxy);
19
+ log.kv("proxy desired", status.systemProxy.desired ? "on" : "off");
20
+ log.kv("daemon applied", status.systemProxy.daemonApplied === null
21
+ ? status.daemon.state === "stopped"
22
+ ? "n/a (stopped)"
23
+ : "unknown"
24
+ : status.systemProxy.daemonApplied
25
+ ? "yes"
26
+ : "no");
27
+ log.kv("os proxy", formatObservedProxy(status.systemProxy.osObserved));
28
+ log.kv("sash api", status.endpoints.daemonApi);
29
+ log.kv("dashboard", status.endpoints.dashboard);
30
+ log.kv("active profile", status.activeProfile
31
+ ? `${status.activeProfile.name} (${status.activeProfile.url || "local file"})`
32
+ : "(none)");
33
+ log.kv("tun", formatTunObservation(status));
34
+ log.kv("core version", status.core.installedVersion || "(not installed)");
35
+ if (shouldShowTunGuidance(status)) {
36
+ log.warn(tunPrivilegeGuidance("runtime-inactive", { root: status.paths.root }));
37
+ }
38
+ markIncompleteObservation(status.complete);
39
+ }
@@ -0,0 +1,5 @@
1
+ import { runCoreUpdate } from "../core-update-service.js";
2
+ import { runtimeContext } from "./shared.js";
3
+ export async function runUpdate(opts = {}, deps = {}) {
4
+ await runCoreUpdate(runtimeContext(), opts, deps);
5
+ }
@@ -0,0 +1,43 @@
1
+ import spawn from "cross-spawn";
2
+ import { log } from "../log.js";
3
+ import { buildSanitizedEnv } from "../process.js";
4
+ import { resolveRuntimeOwner } from "../runtime-owner.js";
5
+ import { runtimeContext } from "./shared.js";
6
+ const PACKAGE_NAME = "@astralyn/sash";
7
+ const STRICT_SEMVER = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|\d*[A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
8
+ const SAFE_DIST_TAG = /^[A-Za-z][A-Za-z0-9._-]{0,63}$/;
9
+ export function validateUpgradeVersion(value) {
10
+ if (value !== value.trim() || !value) {
11
+ throw new Error(`Invalid Sash package version or dist-tag: ${JSON.stringify(value)}`);
12
+ }
13
+ if (STRICT_SEMVER.test(value))
14
+ return value;
15
+ if (SAFE_DIST_TAG.test(value) && !/^v?\d+(?:\.|$)/i.test(value))
16
+ return value;
17
+ throw new Error(`Invalid Sash package version or dist-tag: ${JSON.stringify(value)}`);
18
+ }
19
+ export function buildUpgradeSpawnOptions(sourceEnv = process.env) {
20
+ return { stdio: "inherit", env: buildSanitizedEnv(sourceEnv) };
21
+ }
22
+ export async function runUpgrade(opts = {}) {
23
+ const ctx = runtimeContext();
24
+ const owner = await resolveRuntimeOwner(ctx);
25
+ if (owner.kind !== "offline") {
26
+ throw new Error("stop Sash with `sash stop` before upgrading the package");
27
+ }
28
+ const version = validateUpgradeVersion(opts.version ?? "latest");
29
+ const target = `${PACKAGE_NAME}@${version}`;
30
+ log.info(`upgrading Sash via npm: ${target}`);
31
+ const code = await new Promise((resolve) => {
32
+ const child = spawn("npm", ["install", "-g", target], buildUpgradeSpawnOptions());
33
+ child.on("error", (err) => {
34
+ log.error(`failed to launch npm: ${err.message}`);
35
+ resolve(1);
36
+ });
37
+ child.on("close", (exitCode) => resolve(exitCode ?? 1));
38
+ });
39
+ if (code !== 0) {
40
+ throw new Error(`npm exited with code ${code}. Try running the command manually: npm install -g ${target}`);
41
+ }
42
+ log.ok("Sash upgraded. Run `sash version` to verify, then start it normally.");
43
+ }
@@ -0,0 +1,33 @@
1
+ import { openInBrowser } from "../browser.js";
2
+ import { log } from "../log.js";
3
+ import { resolveRuntimeOwner } from "../runtime-owner.js";
4
+ import { runStart } from "./lifecycle.js";
5
+ import { runtimeContext } from "./shared.js";
6
+ export function dashboardUrl(daemonPort) {
7
+ return `http://127.0.0.1:${daemonPort}/ui/`;
8
+ }
9
+ export async function runWeb(opts = {}) {
10
+ const ctx = runtimeContext();
11
+ let owner = await resolveRuntimeOwner(ctx);
12
+ let coreRunning = false;
13
+ if (owner.kind === "daemon") {
14
+ try {
15
+ coreRunning = (await owner.client.status()).core.running;
16
+ }
17
+ catch {
18
+ coreRunning = false;
19
+ }
20
+ }
21
+ if (!coreRunning) {
22
+ log.info("sash is not running; starting it first...");
23
+ await runStart();
24
+ owner = await resolveRuntimeOwner(ctx);
25
+ }
26
+ if (owner.kind !== "daemon") {
27
+ throw new Error("sashd did not become healthy before opening the dashboard");
28
+ }
29
+ const url = dashboardUrl(owner.daemon.port);
30
+ log.ok(`dashboard: ${url}`);
31
+ if (!opts.noOpen)
32
+ openInBrowser(url);
33
+ }
@@ -0,0 +1,412 @@
1
+ import { isCanonicalIsoTimestamp, isPlainObject } from "./json-shape.js";
2
+ export const WEB_SOCKET_AUTH_PROTOCOL = "sash";
3
+ export const WEB_SOCKET_TOKEN_PROTOCOL_PREFIX = "sash-token.";
4
+ export function apiErrorBody(code, message) {
5
+ return { error: { code, message } };
6
+ }
7
+ export function parseApiErrorBody(value) {
8
+ if (!isPlainObject(value) || !isPlainObject(value.error))
9
+ return undefined;
10
+ const { code, message } = value.error;
11
+ if (typeof code !== "string" || typeof message !== "string")
12
+ return undefined;
13
+ return { code, message };
14
+ }
15
+ function invalid(contract, path, expected) {
16
+ throw new TypeError(`${contract} response is invalid: ${path} must be ${expected}`);
17
+ }
18
+ function objectValue(value, contract, path) {
19
+ if (!isPlainObject(value))
20
+ invalid(contract, path, "a plain object");
21
+ return value;
22
+ }
23
+ function required(source, key, contract, path) {
24
+ if (!Object.hasOwn(source, key))
25
+ invalid(contract, path, "present");
26
+ return source[key];
27
+ }
28
+ function booleanValue(value, contract, path) {
29
+ if (typeof value !== "boolean")
30
+ invalid(contract, path, "a boolean");
31
+ return value;
32
+ }
33
+ function stringValue(value, contract, path, nonEmpty = false) {
34
+ if (typeof value !== "string" || (nonEmpty && !value.trim())) {
35
+ invalid(contract, path, nonEmpty ? "a non-empty string" : "a string");
36
+ }
37
+ return value;
38
+ }
39
+ function finiteNumber(value, contract, path) {
40
+ if (typeof value !== "number" || !Number.isFinite(value)) {
41
+ invalid(contract, path, "a finite number");
42
+ }
43
+ return value;
44
+ }
45
+ function positiveSafeInteger(value, contract, path) {
46
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value <= 0) {
47
+ invalid(contract, path, "a positive safe integer");
48
+ }
49
+ return value;
50
+ }
51
+ function nonNegativeSafeInteger(value, contract, path) {
52
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 0) {
53
+ invalid(contract, path, "a non-negative safe integer");
54
+ }
55
+ return value;
56
+ }
57
+ function portValue(value, contract, path) {
58
+ if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > 65_535) {
59
+ invalid(contract, path, "an integer port from 1 to 65535");
60
+ }
61
+ return value;
62
+ }
63
+ function timestampValue(value, contract, path) {
64
+ if (!isCanonicalIsoTimestamp(value))
65
+ invalid(contract, path, "a canonical ISO timestamp");
66
+ return value;
67
+ }
68
+ function optionalString(source, key, contract, path) {
69
+ return Object.hasOwn(source, key) ? stringValue(source[key], contract, path) : undefined;
70
+ }
71
+ function knownFlag(source, key, contract, path) {
72
+ return Object.hasOwn(source, key) ? booleanValue(source[key], contract, path) : false;
73
+ }
74
+ function parseSystemProxyState(value, contract, path) {
75
+ const source = objectValue(value, contract, path);
76
+ const server = optionalString(source, "server", contract, `${path}.server`);
77
+ const details = optionalString(source, "details", contract, `${path}.details`);
78
+ return {
79
+ supported: booleanValue(required(source, "supported", contract, `${path}.supported`), contract, `${path}.supported`),
80
+ enabled: booleanValue(required(source, "enabled", contract, `${path}.enabled`), contract, `${path}.enabled`),
81
+ ...(server !== undefined ? { server } : {}),
82
+ ...(details !== undefined ? { details } : {}),
83
+ };
84
+ }
85
+ function parseCoreState(value, contract) {
86
+ const source = objectValue(value, contract, "core");
87
+ const pid = Object.hasOwn(source, "pid")
88
+ ? positiveSafeInteger(source.pid, contract, "core.pid")
89
+ : undefined;
90
+ const startedAt = Object.hasOwn(source, "startedAt")
91
+ ? timestampValue(source.startedAt, contract, "core.startedAt")
92
+ : undefined;
93
+ const healthy = Object.hasOwn(source, "healthy")
94
+ ? booleanValue(source.healthy, contract, "core.healthy")
95
+ : undefined;
96
+ const version = optionalString(source, "version", contract, "core.version");
97
+ const tunActive = Object.hasOwn(source, "tunActive")
98
+ ? booleanValue(source.tunActive, contract, "core.tunActive")
99
+ : undefined;
100
+ return {
101
+ running: booleanValue(required(source, "running", contract, "core.running"), contract, "core.running"),
102
+ ...(pid !== undefined ? { pid } : {}),
103
+ ...(startedAt !== undefined ? { startedAt } : {}),
104
+ ...(healthy !== undefined ? { healthy } : {}),
105
+ ...(version !== undefined ? { version } : {}),
106
+ ...(tunActive !== undefined ? { tunActive } : {}),
107
+ };
108
+ }
109
+ export function parsePublicSettings(value) {
110
+ const contract = "sashd settings";
111
+ const source = objectValue(value, contract, "settings");
112
+ return {
113
+ mixedPort: portValue(required(source, "mixedPort", contract, "settings.mixedPort"), contract, "settings.mixedPort"),
114
+ controller: stringValue(required(source, "controller", contract, "settings.controller"), contract, "settings.controller", true),
115
+ tun: booleanValue(required(source, "tun", contract, "settings.tun"), contract, "settings.tun"),
116
+ allowLan: booleanValue(required(source, "allowLan", contract, "settings.allowLan"), contract, "settings.allowLan"),
117
+ daemonPort: portValue(required(source, "daemonPort", contract, "settings.daemonPort"), contract, "settings.daemonPort"),
118
+ systemProxy: booleanValue(required(source, "systemProxy", contract, "settings.systemProxy"), contract, "settings.systemProxy"),
119
+ };
120
+ }
121
+ function parseProfileMeta(value, contract, path) {
122
+ const source = objectValue(value, contract, path);
123
+ const subInfoValue = Object.hasOwn(source, "subInfo")
124
+ ? objectValue(source.subInfo, contract, `${path}.subInfo`)
125
+ : undefined;
126
+ const subInfo = subInfoValue
127
+ ? {
128
+ upload: finiteNumber(required(subInfoValue, "upload", contract, `${path}.subInfo.upload`), contract, `${path}.subInfo.upload`),
129
+ download: finiteNumber(required(subInfoValue, "download", contract, `${path}.subInfo.download`), contract, `${path}.subInfo.download`),
130
+ total: finiteNumber(required(subInfoValue, "total", contract, `${path}.subInfo.total`), contract, `${path}.subInfo.total`),
131
+ ...(Object.hasOwn(subInfoValue, "expire")
132
+ ? {
133
+ expire: finiteNumber(subInfoValue.expire, contract, `${path}.subInfo.expire`),
134
+ }
135
+ : {}),
136
+ }
137
+ : undefined;
138
+ const homePage = optionalString(source, "homePage", contract, `${path}.homePage`);
139
+ const lastError = optionalString(source, "lastError", contract, `${path}.lastError`);
140
+ return {
141
+ id: stringValue(required(source, "id", contract, `${path}.id`), contract, `${path}.id`, true),
142
+ name: stringValue(required(source, "name", contract, `${path}.name`), contract, `${path}.name`),
143
+ url: stringValue(required(source, "url", contract, `${path}.url`), contract, `${path}.url`),
144
+ intervalHours: nonNegativeSafeInteger(required(source, "intervalHours", contract, `${path}.intervalHours`), contract, `${path}.intervalHours`),
145
+ createdAt: timestampValue(required(source, "createdAt", contract, `${path}.createdAt`), contract, `${path}.createdAt`),
146
+ updatedAt: timestampValue(required(source, "updatedAt", contract, `${path}.updatedAt`), contract, `${path}.updatedAt`),
147
+ ...(subInfo !== undefined ? { subInfo } : {}),
148
+ ...(homePage !== undefined ? { homePage } : {}),
149
+ ...(lastError !== undefined ? { lastError } : {}),
150
+ };
151
+ }
152
+ function optionalProxyCount(source, contract, path) {
153
+ return Object.hasOwn(source, "proxyCount")
154
+ ? { proxyCount: nonNegativeSafeInteger(source.proxyCount, contract, `${path}.proxyCount`) }
155
+ : {};
156
+ }
157
+ export function parseHealthInfo(value) {
158
+ const contract = "sashd health";
159
+ const source = objectValue(value, contract, "response");
160
+ return {
161
+ token: stringValue(required(source, "token", contract, "token"), contract, "token", true),
162
+ pid: positiveSafeInteger(required(source, "pid", contract, "pid"), contract, "pid"),
163
+ startedAt: timestampValue(required(source, "startedAt", contract, "startedAt"), contract, "startedAt"),
164
+ };
165
+ }
166
+ export function parseCoreStartResult(value) {
167
+ const contract = "sashd core start";
168
+ const source = objectValue(value, contract, "response");
169
+ const version = optionalString(source, "version", contract, "version");
170
+ const tunActive = Object.hasOwn(source, "tunActive")
171
+ ? booleanValue(source.tunActive, contract, "tunActive")
172
+ : undefined;
173
+ return {
174
+ pid: positiveSafeInteger(required(source, "pid", contract, "pid"), contract, "pid"),
175
+ ...(version !== undefined ? { version } : {}),
176
+ ...(tunActive !== undefined ? { tunActive } : {}),
177
+ };
178
+ }
179
+ export function parseCoreReloadResult(value) {
180
+ const contract = "sashd core reload";
181
+ const source = objectValue(value, contract, "response");
182
+ const sourceKind = stringValue(required(source, "source", contract, "source"), contract, "source");
183
+ if (sourceKind !== "subscription" && sourceKind !== "default") {
184
+ invalid(contract, "source", `"subscription" or "default"`);
185
+ }
186
+ return {
187
+ proxyCount: nonNegativeSafeInteger(required(source, "proxyCount", contract, "proxyCount"), contract, "proxyCount"),
188
+ source: sourceKind,
189
+ };
190
+ }
191
+ export function parseShutdownResult(value) {
192
+ const contract = "sashd shutdown";
193
+ const source = objectValue(value, contract, "response");
194
+ return {
195
+ coreWasRunning: booleanValue(required(source, "coreWasRunning", contract, "coreWasRunning"), contract, "coreWasRunning"),
196
+ };
197
+ }
198
+ export function parseSystemProxyStatusResponse(value) {
199
+ const contract = "sashd system proxy";
200
+ const source = objectValue(value, contract, "response");
201
+ const state = parseSystemProxyState(source, contract, "response");
202
+ const queryError = optionalString(source, "queryError", contract, "queryError");
203
+ return {
204
+ desired: booleanValue(required(source, "desired", contract, "desired"), contract, "desired"),
205
+ applied: booleanValue(required(source, "applied", contract, "applied"), contract, "applied"),
206
+ ...state,
207
+ appliedKnown: knownFlag(source, "appliedKnown", contract, "appliedKnown"),
208
+ stateKnown: knownFlag(source, "stateKnown", contract, "stateKnown"),
209
+ ...(queryError !== undefined ? { queryError } : {}),
210
+ };
211
+ }
212
+ export function parseSettingsPatch(value, direction = "response") {
213
+ const subject = `sashd settings patch ${direction}`;
214
+ const fail = (path, expected) => {
215
+ throw new TypeError(`${subject} is invalid: ${path} must be ${expected}`);
216
+ };
217
+ if (!isPlainObject(value))
218
+ fail("body", "a plain object");
219
+ const source = value;
220
+ const allowed = new Set([
221
+ "mixedPort",
222
+ "allowLan",
223
+ "tun",
224
+ "systemProxy",
225
+ "daemonPort",
226
+ "daemonSecret",
227
+ ]);
228
+ for (const key of Object.keys(source)) {
229
+ if (!allowed.has(key))
230
+ fail(key, "a known settings patch field");
231
+ }
232
+ const portField = (key) => {
233
+ if (!Object.hasOwn(source, key))
234
+ return undefined;
235
+ const field = source[key];
236
+ if (typeof field !== "number" || !Number.isInteger(field) || field < 1 || field > 65_535) {
237
+ return fail(key, "an integer port from 1 to 65535");
238
+ }
239
+ return field;
240
+ };
241
+ const boolField = (key) => {
242
+ if (!Object.hasOwn(source, key))
243
+ return undefined;
244
+ const field = source[key];
245
+ if (typeof field !== "boolean")
246
+ return fail(key, "a boolean");
247
+ return field;
248
+ };
249
+ const patch = {};
250
+ const mixedPort = portField("mixedPort");
251
+ if (mixedPort !== undefined)
252
+ patch.mixedPort = mixedPort;
253
+ const daemonPort = portField("daemonPort");
254
+ if (daemonPort !== undefined)
255
+ patch.daemonPort = daemonPort;
256
+ const allowLan = boolField("allowLan");
257
+ if (allowLan !== undefined)
258
+ patch.allowLan = allowLan;
259
+ const tun = boolField("tun");
260
+ if (tun !== undefined)
261
+ patch.tun = tun;
262
+ const systemProxy = boolField("systemProxy");
263
+ if (systemProxy !== undefined)
264
+ patch.systemProxy = systemProxy;
265
+ if (Object.hasOwn(source, "daemonSecret")) {
266
+ const secret = source.daemonSecret;
267
+ if (typeof secret !== "string" || !secret.trim()) {
268
+ fail("daemonSecret", "a non-empty string");
269
+ }
270
+ patch.daemonSecret = secret;
271
+ }
272
+ return patch;
273
+ }
274
+ export function parseSettingsWriteResult(value) {
275
+ const contract = "sashd settings write";
276
+ const source = objectValue(value, contract, "response");
277
+ return {
278
+ restartRequired: booleanValue(required(source, "restartRequired", contract, "restartRequired"), contract, "restartRequired"),
279
+ settings: parsePublicSettings(required(source, "settings", contract, "settings")),
280
+ };
281
+ }
282
+ export function parseSettingsFileContent(value) {
283
+ const contract = "sashd settings file";
284
+ const source = objectValue(value, contract, "response");
285
+ return {
286
+ content: stringValue(required(source, "content", contract, "content"), contract, "content"),
287
+ };
288
+ }
289
+ export function parseProfilesIndex(value) {
290
+ const contract = "sashd profiles";
291
+ const source = objectValue(value, contract, "response");
292
+ const activeValue = required(source, "activeId", contract, "activeId");
293
+ const profilesValue = required(source, "profiles", contract, "profiles");
294
+ if (!Array.isArray(profilesValue))
295
+ invalid(contract, "profiles", "an array");
296
+ return {
297
+ activeId: activeValue === null ? null : stringValue(activeValue, contract, "activeId", true),
298
+ profiles: profilesValue.map((entry, index) => parseProfileMeta(entry, contract, `profiles[${index}]`)),
299
+ };
300
+ }
301
+ export function parseProfileActionResponse(value) {
302
+ const contract = "sashd profile action";
303
+ const source = objectValue(value, contract, "response");
304
+ return {
305
+ profile: parseProfileMeta(required(source, "profile", contract, "profile"), contract, "profile"),
306
+ activated: booleanValue(required(source, "activated", contract, "activated"), contract, "activated"),
307
+ ...optionalProxyCount(source, contract, "response"),
308
+ };
309
+ }
310
+ export function parseProfileUpdateResponse(value) {
311
+ const contract = "sashd profile update";
312
+ const source = objectValue(value, contract, "response");
313
+ return {
314
+ profile: parseProfileMeta(required(source, "profile", contract, "profile"), contract, "profile"),
315
+ ...optionalProxyCount(source, contract, "response"),
316
+ };
317
+ }
318
+ export function parseProfilesUpdateAllResponse(value) {
319
+ const contract = "sashd profiles update-all";
320
+ const source = objectValue(value, contract, "response");
321
+ const failedValue = required(source, "failed", contract, "failed");
322
+ if (!Array.isArray(failedValue))
323
+ invalid(contract, "failed", "an array");
324
+ return {
325
+ updated: nonNegativeSafeInteger(required(source, "updated", contract, "updated"), contract, "updated"),
326
+ failed: failedValue.map((entry, index) => {
327
+ const path = `failed[${index}]`;
328
+ const failure = objectValue(entry, contract, path);
329
+ return {
330
+ id: stringValue(required(failure, "id", contract, `${path}.id`), contract, `${path}.id`),
331
+ name: stringValue(required(failure, "name", contract, `${path}.name`), contract, `${path}.name`),
332
+ error: stringValue(required(failure, "error", contract, `${path}.error`), contract, `${path}.error`),
333
+ };
334
+ }),
335
+ ...optionalProxyCount(source, contract, "response"),
336
+ };
337
+ }
338
+ export function parseProfileContentResponse(value) {
339
+ const contract = "sashd profile content";
340
+ const source = objectValue(value, contract, "response");
341
+ return {
342
+ name: stringValue(required(source, "name", contract, "name"), contract, "name"),
343
+ content: stringValue(required(source, "content", contract, "content"), contract, "content"),
344
+ };
345
+ }
346
+ export function parseProfileActivateResponse(value) {
347
+ const contract = "sashd profile activate";
348
+ const source = objectValue(value, contract, "response");
349
+ const activeValue = required(source, "activeId", contract, "activeId");
350
+ return {
351
+ activeId: activeValue === null ? null : stringValue(activeValue, contract, "activeId", true),
352
+ proxyCount: nonNegativeSafeInteger(required(source, "proxyCount", contract, "proxyCount"), contract, "proxyCount"),
353
+ };
354
+ }
355
+ export function parseProfileRemoveResponse(value) {
356
+ const contract = "sashd profile remove";
357
+ const source = objectValue(value, contract, "response");
358
+ return {
359
+ wasActive: booleanValue(required(source, "wasActive", contract, "wasActive"), contract, "wasActive"),
360
+ ...optionalProxyCount(source, contract, "response"),
361
+ };
362
+ }
363
+ export function parseProfileRenameResponse(value) {
364
+ const contract = "sashd profile rename";
365
+ const source = objectValue(value, contract, "response");
366
+ return {
367
+ profile: parseProfileMeta(required(source, "profile", contract, "profile"), contract, "profile"),
368
+ };
369
+ }
370
+ export function parseDaemonStatus(value) {
371
+ const contract = "sashd status";
372
+ const source = objectValue(value, contract, "response");
373
+ const daemonSource = objectValue(required(source, "daemon", contract, "daemon"), contract, "daemon");
374
+ const revisionsSource = objectValue(required(source, "revisions", contract, "revisions"), contract, "revisions");
375
+ const proxySource = objectValue(required(source, "systemProxy", contract, "systemProxy"), contract, "systemProxy");
376
+ const actual = Object.hasOwn(proxySource, "actual")
377
+ ? parseSystemProxyState(proxySource.actual, contract, "systemProxy.actual")
378
+ : undefined;
379
+ const queryError = optionalString(proxySource, "queryError", contract, "systemProxy.queryError");
380
+ const activeValue = required(source, "activeProfile", contract, "activeProfile");
381
+ const activeProfile = activeValue === null
382
+ ? null
383
+ : (() => {
384
+ const active = objectValue(activeValue, contract, "activeProfile");
385
+ return {
386
+ id: stringValue(required(active, "id", contract, "activeProfile.id"), contract, "activeProfile.id", true),
387
+ name: stringValue(required(active, "name", contract, "activeProfile.name"), contract, "activeProfile.name"),
388
+ url: stringValue(required(active, "url", contract, "activeProfile.url"), contract, "activeProfile.url"),
389
+ };
390
+ })();
391
+ return {
392
+ daemon: {
393
+ pid: positiveSafeInteger(required(daemonSource, "pid", contract, "daemon.pid"), contract, "daemon.pid"),
394
+ startedAt: timestampValue(required(daemonSource, "startedAt", contract, "daemon.startedAt"), contract, "daemon.startedAt"),
395
+ port: portValue(required(daemonSource, "port", contract, "daemon.port"), contract, "daemon.port"),
396
+ },
397
+ revisions: {
398
+ profiles: nonNegativeSafeInteger(required(revisionsSource, "profiles", contract, "revisions.profiles"), contract, "revisions.profiles"),
399
+ },
400
+ core: parseCoreState(required(source, "core", contract, "core"), contract),
401
+ systemProxy: {
402
+ desired: booleanValue(required(proxySource, "desired", contract, "systemProxy.desired"), contract, "systemProxy.desired"),
403
+ applied: booleanValue(required(proxySource, "applied", contract, "systemProxy.applied"), contract, "systemProxy.applied"),
404
+ ...(actual !== undefined ? { actual } : {}),
405
+ appliedKnown: knownFlag(proxySource, "appliedKnown", contract, "systemProxy.appliedKnown"),
406
+ stateKnown: knownFlag(proxySource, "stateKnown", contract, "systemProxy.stateKnown"),
407
+ ...(queryError !== undefined ? { queryError } : {}),
408
+ },
409
+ settings: parsePublicSettings(required(source, "settings", contract, "settings")),
410
+ activeProfile,
411
+ };
412
+ }