@quenty/studio-bridge 0.21.1 → 0.22.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 (482) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +109 -17
  3. package/build-scripts/transform-add-session-attribute.lua +1 -0
  4. package/deploy.nevermore.json +10 -0
  5. package/dist/src/bridge/bridge-connection.d.ts +26 -2
  6. package/dist/src/bridge/bridge-connection.d.ts.map +1 -1
  7. package/dist/src/bridge/bridge-connection.js +159 -14
  8. package/dist/src/bridge/bridge-connection.js.map +1 -1
  9. package/dist/src/bridge/bridge-connection.test.js +81 -0
  10. package/dist/src/bridge/bridge-connection.test.js.map +1 -1
  11. package/dist/src/bridge/bridge-session.d.ts +35 -2
  12. package/dist/src/bridge/bridge-session.d.ts.map +1 -1
  13. package/dist/src/bridge/bridge-session.js +185 -28
  14. package/dist/src/bridge/bridge-session.js.map +1 -1
  15. package/dist/src/bridge/bridge-session.test.js +6 -4
  16. package/dist/src/bridge/bridge-session.test.js.map +1 -1
  17. package/dist/src/bridge/index.d.ts +1 -1
  18. package/dist/src/bridge/index.d.ts.map +1 -1
  19. package/dist/src/bridge/index.js.map +1 -1
  20. package/dist/src/bridge/internal/bridge-client.d.ts +4 -0
  21. package/dist/src/bridge/internal/bridge-client.d.ts.map +1 -1
  22. package/dist/src/bridge/internal/bridge-client.js +20 -7
  23. package/dist/src/bridge/internal/bridge-client.js.map +1 -1
  24. package/dist/src/bridge/internal/bridge-client.test.js +18 -0
  25. package/dist/src/bridge/internal/bridge-client.test.js.map +1 -1
  26. package/dist/src/bridge/internal/bridge-host.d.ts +13 -1
  27. package/dist/src/bridge/internal/bridge-host.d.ts.map +1 -1
  28. package/dist/src/bridge/internal/bridge-host.js +35 -0
  29. package/dist/src/bridge/internal/bridge-host.js.map +1 -1
  30. package/dist/src/bridge/internal/bridge-host.test.js +31 -0
  31. package/dist/src/bridge/internal/bridge-host.test.js.map +1 -1
  32. package/dist/src/bridge/internal/hand-off.d.ts.map +1 -1
  33. package/dist/src/bridge/internal/hand-off.js +4 -1
  34. package/dist/src/bridge/internal/hand-off.js.map +1 -1
  35. package/dist/src/bridge/internal/host-protocol.d.ts +8 -0
  36. package/dist/src/bridge/internal/host-protocol.d.ts.map +1 -1
  37. package/dist/src/bridge/internal/host-protocol.js +120 -13
  38. package/dist/src/bridge/internal/host-protocol.js.map +1 -1
  39. package/dist/src/bridge/internal/host-protocol.test.js +13 -0
  40. package/dist/src/bridge/internal/host-protocol.test.js.map +1 -1
  41. package/dist/src/bridge/internal/instance-state.d.ts +9 -0
  42. package/dist/src/bridge/internal/instance-state.d.ts.map +1 -0
  43. package/dist/src/bridge/internal/instance-state.js +28 -0
  44. package/dist/src/bridge/internal/instance-state.js.map +1 -0
  45. package/dist/src/bridge/internal/transport-client.d.ts.map +1 -1
  46. package/dist/src/bridge/internal/transport-client.js +2 -1
  47. package/dist/src/bridge/internal/transport-client.js.map +1 -1
  48. package/dist/src/bridge/internal/transport-server.d.ts.map +1 -1
  49. package/dist/src/bridge/internal/transport-server.js +5 -1
  50. package/dist/src/bridge/internal/transport-server.js.map +1 -1
  51. package/dist/src/bridge/types.d.ts +43 -4
  52. package/dist/src/bridge/types.d.ts.map +1 -1
  53. package/dist/src/bridge/types.js.map +1 -1
  54. package/dist/src/cli/adapters/cli-command-adapter-handler.test.js +24 -0
  55. package/dist/src/cli/adapters/cli-command-adapter-handler.test.js.map +1 -1
  56. package/dist/src/cli/adapters/cli-command-adapter.d.ts +6 -0
  57. package/dist/src/cli/adapters/cli-command-adapter.d.ts.map +1 -1
  58. package/dist/src/cli/adapters/cli-command-adapter.js +107 -11
  59. package/dist/src/cli/adapters/cli-command-adapter.js.map +1 -1
  60. package/dist/src/cli/adapters/group-builder.d.ts +3 -0
  61. package/dist/src/cli/adapters/group-builder.d.ts.map +1 -1
  62. package/dist/src/cli/adapters/group-builder.js +34 -15
  63. package/dist/src/cli/adapters/group-builder.js.map +1 -1
  64. package/dist/src/cli/adapters/group-builder.test.js +26 -2
  65. package/dist/src/cli/adapters/group-builder.test.js.map +1 -1
  66. package/dist/src/cli/adapters/help-formatter.d.ts.map +1 -1
  67. package/dist/src/cli/adapters/help-formatter.js +4 -3
  68. package/dist/src/cli/adapters/help-formatter.js.map +1 -1
  69. package/dist/src/cli/adapters/help-formatter.test.js +1 -1
  70. package/dist/src/cli/adapters/help-formatter.test.js.map +1 -1
  71. package/dist/src/cli/adapters/playtest-edit-guard.test.d.ts +2 -0
  72. package/dist/src/cli/adapters/playtest-edit-guard.test.d.ts.map +1 -0
  73. package/dist/src/cli/adapters/playtest-edit-guard.test.js +28 -0
  74. package/dist/src/cli/adapters/playtest-edit-guard.test.js.map +1 -0
  75. package/dist/src/cli/args/global-args.d.ts +1 -1
  76. package/dist/src/cli/args/global-args.d.ts.map +1 -1
  77. package/dist/src/cli/cli-output-context.d.ts +14 -0
  78. package/dist/src/cli/cli-output-context.d.ts.map +1 -0
  79. package/dist/src/cli/cli-output-context.js +39 -0
  80. package/dist/src/cli/cli-output-context.js.map +1 -0
  81. package/dist/src/cli/cli-output-context.test.d.ts +2 -0
  82. package/dist/src/cli/cli-output-context.test.d.ts.map +1 -0
  83. package/dist/src/cli/cli-output-context.test.js +38 -0
  84. package/dist/src/cli/cli-output-context.test.js.map +1 -0
  85. package/dist/src/cli/cli.js +40 -17
  86. package/dist/src/cli/cli.js.map +1 -1
  87. package/dist/src/cli/managed-studio-run.d.ts +21 -0
  88. package/dist/src/cli/managed-studio-run.d.ts.map +1 -0
  89. package/dist/src/cli/managed-studio-run.js +75 -0
  90. package/dist/src/cli/managed-studio-run.js.map +1 -0
  91. package/dist/src/cli/managed-studio-run.test.d.ts +2 -0
  92. package/dist/src/cli/managed-studio-run.test.d.ts.map +1 -0
  93. package/dist/src/cli/managed-studio-run.test.js +52 -0
  94. package/dist/src/cli/managed-studio-run.test.js.map +1 -0
  95. package/dist/src/cli/resolve-session.js +1 -1
  96. package/dist/src/cli/resolve-session.js.map +1 -1
  97. package/dist/src/cli/resolve-session.test.js +1 -1
  98. package/dist/src/cli/resolve-session.test.js.map +1 -1
  99. package/dist/src/cli/script-executor.d.ts +13 -1
  100. package/dist/src/cli/script-executor.d.ts.map +1 -1
  101. package/dist/src/cli/script-executor.js +77 -47
  102. package/dist/src/cli/script-executor.js.map +1 -1
  103. package/dist/src/commands/console/exec/exec.d.ts +17 -0
  104. package/dist/src/commands/console/exec/exec.d.ts.map +1 -1
  105. package/dist/src/commands/console/exec/exec.js +39 -7
  106. package/dist/src/commands/console/exec/exec.js.map +1 -1
  107. package/dist/src/commands/console/exec/exec.test.js +62 -3
  108. package/dist/src/commands/console/exec/exec.test.js.map +1 -1
  109. package/dist/src/commands/console/logs/logs.d.ts +30 -2
  110. package/dist/src/commands/console/logs/logs.d.ts.map +1 -1
  111. package/dist/src/commands/console/logs/logs.js +82 -7
  112. package/dist/src/commands/console/logs/logs.js.map +1 -1
  113. package/dist/src/commands/console/logs/logs.test.js +63 -4
  114. package/dist/src/commands/console/logs/logs.test.js.map +1 -1
  115. package/dist/src/commands/explorer/export/export.d.ts +19 -0
  116. package/dist/src/commands/explorer/export/export.d.ts.map +1 -0
  117. package/dist/src/commands/explorer/export/export.js +37 -0
  118. package/dist/src/commands/explorer/export/export.js.map +1 -0
  119. package/dist/src/commands/explorer/export/export.test.d.ts +2 -0
  120. package/dist/src/commands/explorer/export/export.test.d.ts.map +1 -0
  121. package/dist/src/commands/explorer/export/export.test.js +25 -0
  122. package/dist/src/commands/explorer/export/export.test.js.map +1 -0
  123. package/dist/src/commands/explorer/find/find.d.ts +28 -0
  124. package/dist/src/commands/explorer/find/find.d.ts.map +1 -0
  125. package/dist/src/commands/explorer/find/find.js +75 -0
  126. package/dist/src/commands/explorer/find/find.js.map +1 -0
  127. package/dist/src/commands/explorer/find/find.test.d.ts +2 -0
  128. package/dist/src/commands/explorer/find/find.test.d.ts.map +1 -0
  129. package/dist/src/commands/explorer/find/find.test.js +44 -0
  130. package/dist/src/commands/explorer/find/find.test.js.map +1 -0
  131. package/dist/src/commands/explorer/grep/grep.d.ts +24 -0
  132. package/dist/src/commands/explorer/grep/grep.d.ts.map +1 -0
  133. package/dist/src/commands/explorer/grep/grep.js +63 -0
  134. package/dist/src/commands/explorer/grep/grep.js.map +1 -0
  135. package/dist/src/commands/explorer/grep/grep.test.d.ts +2 -0
  136. package/dist/src/commands/explorer/grep/grep.test.d.ts.map +1 -0
  137. package/dist/src/commands/explorer/grep/grep.test.js +42 -0
  138. package/dist/src/commands/explorer/grep/grep.test.js.map +1 -0
  139. package/dist/src/commands/explorer/import/import.d.ts +21 -0
  140. package/dist/src/commands/explorer/import/import.d.ts.map +1 -0
  141. package/dist/src/commands/explorer/import/import.js +37 -0
  142. package/dist/src/commands/explorer/import/import.js.map +1 -0
  143. package/dist/src/commands/explorer/import/import.test.d.ts +2 -0
  144. package/dist/src/commands/explorer/import/import.test.d.ts.map +1 -0
  145. package/dist/src/commands/explorer/import/import.test.js +45 -0
  146. package/dist/src/commands/explorer/import/import.test.js.map +1 -0
  147. package/dist/src/commands/formatters.test.js +7 -1
  148. package/dist/src/commands/formatters.test.js.map +1 -1
  149. package/dist/src/commands/framework/action-loader.d.ts +5 -1
  150. package/dist/src/commands/framework/action-loader.d.ts.map +1 -1
  151. package/dist/src/commands/framework/action-loader.js +9 -2
  152. package/dist/src/commands/framework/action-loader.js.map +1 -1
  153. package/dist/src/commands/framework/action-loader.test.js +23 -0
  154. package/dist/src/commands/framework/action-loader.test.js.map +1 -1
  155. package/dist/src/commands/framework/arg-builder.d.ts +15 -2
  156. package/dist/src/commands/framework/arg-builder.d.ts.map +1 -1
  157. package/dist/src/commands/framework/arg-builder.js +22 -2
  158. package/dist/src/commands/framework/arg-builder.js.map +1 -1
  159. package/dist/src/commands/framework/define-command.d.ts +19 -3
  160. package/dist/src/commands/framework/define-command.d.ts.map +1 -1
  161. package/dist/src/commands/framework/define-command.js.map +1 -1
  162. package/dist/src/commands/framework/index.d.ts +1 -1
  163. package/dist/src/commands/framework/index.d.ts.map +1 -1
  164. package/dist/src/commands/framework/index.js.map +1 -1
  165. package/dist/src/commands/index.d.ts +11 -0
  166. package/dist/src/commands/index.d.ts.map +1 -1
  167. package/dist/src/commands/index.js +11 -0
  168. package/dist/src/commands/index.js.map +1 -1
  169. package/dist/src/commands/linux/inject-credentials/inject-credentials.d.ts.map +1 -1
  170. package/dist/src/commands/linux/inject-credentials/inject-credentials.js +1 -3
  171. package/dist/src/commands/linux/inject-credentials/inject-credentials.js.map +1 -1
  172. package/dist/src/commands/linux/setup/setup.d.ts.map +1 -1
  173. package/dist/src/commands/linux/setup/setup.js +1 -3
  174. package/dist/src/commands/linux/setup/setup.js.map +1 -1
  175. package/dist/src/commands/linux/status/status.d.ts +9 -1
  176. package/dist/src/commands/linux/status/status.d.ts.map +1 -1
  177. package/dist/src/commands/linux/status/status.js +66 -86
  178. package/dist/src/commands/linux/status/status.js.map +1 -1
  179. package/dist/src/commands/playtest/player/add/add.d.ts +17 -0
  180. package/dist/src/commands/playtest/player/add/add.d.ts.map +1 -0
  181. package/dist/src/commands/playtest/player/add/add.js +45 -0
  182. package/dist/src/commands/playtest/player/add/add.js.map +1 -0
  183. package/dist/src/commands/playtest/player/list/list.d.ts +13 -0
  184. package/dist/src/commands/playtest/player/list/list.d.ts.map +1 -0
  185. package/dist/src/commands/playtest/player/list/list.js +33 -0
  186. package/dist/src/commands/playtest/player/list/list.js.map +1 -0
  187. package/dist/src/commands/playtest/player/playtest-players.d.ts +36 -0
  188. package/dist/src/commands/playtest/player/playtest-players.d.ts.map +1 -0
  189. package/dist/src/commands/playtest/player/playtest-players.js +187 -0
  190. package/dist/src/commands/playtest/player/playtest-players.js.map +1 -0
  191. package/dist/src/commands/playtest/player/playtest-players.test.d.ts +2 -0
  192. package/dist/src/commands/playtest/player/playtest-players.test.d.ts.map +1 -0
  193. package/dist/src/commands/playtest/player/playtest-players.test.js +89 -0
  194. package/dist/src/commands/playtest/player/playtest-players.test.js.map +1 -0
  195. package/dist/src/commands/playtest/player/remove/remove.d.ts +17 -0
  196. package/dist/src/commands/playtest/player/remove/remove.d.ts.map +1 -0
  197. package/dist/src/commands/playtest/player/remove/remove.js +42 -0
  198. package/dist/src/commands/playtest/player/remove/remove.js.map +1 -0
  199. package/dist/src/commands/playtest/playtest-sessions.d.ts +49 -0
  200. package/dist/src/commands/playtest/playtest-sessions.d.ts.map +1 -0
  201. package/dist/src/commands/playtest/playtest-sessions.js +283 -0
  202. package/dist/src/commands/playtest/playtest-sessions.js.map +1 -0
  203. package/dist/src/commands/playtest/playtest-sessions.test.d.ts +2 -0
  204. package/dist/src/commands/playtest/playtest-sessions.test.d.ts.map +1 -0
  205. package/dist/src/commands/playtest/playtest-sessions.test.js +87 -0
  206. package/dist/src/commands/playtest/playtest-sessions.test.js.map +1 -0
  207. package/dist/src/commands/playtest/restart/restart.d.ts +23 -0
  208. package/dist/src/commands/playtest/restart/restart.d.ts.map +1 -0
  209. package/dist/src/commands/playtest/restart/restart.js +105 -0
  210. package/dist/src/commands/playtest/restart/restart.js.map +1 -0
  211. package/dist/src/commands/playtest/run/run.d.ts +47 -0
  212. package/dist/src/commands/playtest/run/run.d.ts.map +1 -0
  213. package/dist/src/commands/playtest/run/run.js +137 -0
  214. package/dist/src/commands/playtest/run/run.js.map +1 -0
  215. package/dist/src/commands/playtest/start/start.d.ts +42 -0
  216. package/dist/src/commands/playtest/start/start.d.ts.map +1 -0
  217. package/dist/src/commands/playtest/start/start.js +70 -0
  218. package/dist/src/commands/playtest/start/start.js.map +1 -0
  219. package/dist/src/commands/playtest/stop/stop.d.ts +15 -0
  220. package/dist/src/commands/playtest/stop/stop.d.ts.map +1 -0
  221. package/dist/src/commands/playtest/stop/stop.js +24 -0
  222. package/dist/src/commands/playtest/stop/stop.js.map +1 -0
  223. package/dist/src/commands/process/close/close.d.ts +19 -10
  224. package/dist/src/commands/process/close/close.d.ts.map +1 -1
  225. package/dist/src/commands/process/close/close.js +118 -15
  226. package/dist/src/commands/process/close/close.js.map +1 -1
  227. package/dist/src/commands/process/close/close.test.d.ts +2 -0
  228. package/dist/src/commands/process/close/close.test.d.ts.map +1 -0
  229. package/dist/src/commands/process/close/close.test.js +190 -0
  230. package/dist/src/commands/process/close/close.test.js.map +1 -0
  231. package/dist/src/commands/process/info/info.d.ts +45 -5
  232. package/dist/src/commands/process/info/info.d.ts.map +1 -1
  233. package/dist/src/commands/process/info/info.js +117 -13
  234. package/dist/src/commands/process/info/info.js.map +1 -1
  235. package/dist/src/commands/process/info/info.test.js +140 -38
  236. package/dist/src/commands/process/info/info.test.js.map +1 -1
  237. package/dist/src/commands/process/launch/launch.d.ts +11 -1
  238. package/dist/src/commands/process/launch/launch.d.ts.map +1 -1
  239. package/dist/src/commands/process/launch/launch.js +37 -7
  240. package/dist/src/commands/process/launch/launch.js.map +1 -1
  241. package/dist/src/commands/process/launch/launch.test.js +99 -20
  242. package/dist/src/commands/process/launch/launch.test.js.map +1 -1
  243. package/dist/src/commands/process/list/list.d.ts +2 -1
  244. package/dist/src/commands/process/list/list.d.ts.map +1 -1
  245. package/dist/src/commands/process/list/list.js +9 -6
  246. package/dist/src/commands/process/list/list.js.map +1 -1
  247. package/dist/src/commands/process/list/list.test.js +1 -0
  248. package/dist/src/commands/process/list/list.test.js.map +1 -1
  249. package/dist/src/commands/process/run/run.d.ts +9 -0
  250. package/dist/src/commands/process/run/run.d.ts.map +1 -1
  251. package/dist/src/commands/process/run/run.js +15 -5
  252. package/dist/src/commands/process/run/run.js.map +1 -1
  253. package/dist/src/commands/serve/serve.d.ts +2 -0
  254. package/dist/src/commands/serve/serve.d.ts.map +1 -1
  255. package/dist/src/commands/serve/serve.js +17 -4
  256. package/dist/src/commands/serve/serve.js.map +1 -1
  257. package/dist/src/commands/serve/serve.test.js +9 -2
  258. package/dist/src/commands/serve/serve.test.js.map +1 -1
  259. package/dist/src/commands/viewport/screenshot/screenshot.d.ts.map +1 -1
  260. package/dist/src/commands/viewport/screenshot/screenshot.js +4 -1
  261. package/dist/src/commands/viewport/screenshot/screenshot.js.map +1 -1
  262. package/dist/src/commands/viewport/screenshot/screenshot.test.js +5 -9
  263. package/dist/src/commands/viewport/screenshot/screenshot.test.js.map +1 -1
  264. package/dist/src/deploy/deploy-places.d.ts +39 -0
  265. package/dist/src/deploy/deploy-places.d.ts.map +1 -0
  266. package/dist/src/deploy/deploy-places.js +162 -0
  267. package/dist/src/deploy/deploy-places.js.map +1 -0
  268. package/dist/src/deploy/deploy-places.test.d.ts +2 -0
  269. package/dist/src/deploy/deploy-places.test.d.ts.map +1 -0
  270. package/dist/src/deploy/deploy-places.test.js +96 -0
  271. package/dist/src/deploy/deploy-places.test.js.map +1 -0
  272. package/dist/src/index.d.ts +2 -2
  273. package/dist/src/index.d.ts.map +1 -1
  274. package/dist/src/index.js +1 -1
  275. package/dist/src/index.js.map +1 -1
  276. package/dist/src/plugin/persistent-plugin-installer.d.ts.map +1 -1
  277. package/dist/src/plugin/persistent-plugin-installer.js +2 -1
  278. package/dist/src/plugin/persistent-plugin-installer.js.map +1 -1
  279. package/dist/src/plugin/persistent-plugin-installer.test.js +3 -0
  280. package/dist/src/plugin/persistent-plugin-installer.test.js.map +1 -1
  281. package/dist/src/plugin/plugin-build-version.d.ts +7 -0
  282. package/dist/src/plugin/plugin-build-version.d.ts.map +1 -0
  283. package/dist/src/plugin/plugin-build-version.js +42 -0
  284. package/dist/src/plugin/plugin-build-version.js.map +1 -0
  285. package/dist/src/plugin/plugin-build-version.test.d.ts +2 -0
  286. package/dist/src/plugin/plugin-build-version.test.d.ts.map +1 -0
  287. package/dist/src/plugin/plugin-build-version.test.js +41 -0
  288. package/dist/src/plugin/plugin-build-version.test.js.map +1 -0
  289. package/dist/src/plugin/plugin-injector.d.ts.map +1 -1
  290. package/dist/src/plugin/plugin-injector.js +7 -1
  291. package/dist/src/plugin/plugin-injector.js.map +1 -1
  292. package/dist/src/process/studio-process-closer.d.ts +35 -0
  293. package/dist/src/process/studio-process-closer.d.ts.map +1 -0
  294. package/dist/src/process/studio-process-closer.js +129 -0
  295. package/dist/src/process/studio-process-closer.js.map +1 -0
  296. package/dist/src/process/studio-process-closer.test.d.ts +2 -0
  297. package/dist/src/process/studio-process-closer.test.d.ts.map +1 -0
  298. package/dist/src/process/studio-process-closer.test.js +80 -0
  299. package/dist/src/process/studio-process-closer.test.js.map +1 -0
  300. package/dist/src/process/studio-settings.d.ts +14 -0
  301. package/dist/src/process/studio-settings.d.ts.map +1 -0
  302. package/dist/src/process/studio-settings.js +50 -0
  303. package/dist/src/process/studio-settings.js.map +1 -0
  304. package/dist/src/process/studio-settings.test.d.ts +2 -0
  305. package/dist/src/process/studio-settings.test.d.ts.map +1 -0
  306. package/dist/src/process/studio-settings.test.js +16 -0
  307. package/dist/src/process/studio-settings.test.js.map +1 -0
  308. package/dist/src/process/studio-window-state.d.ts +13 -0
  309. package/dist/src/process/studio-window-state.d.ts.map +1 -0
  310. package/dist/src/process/studio-window-state.js +48 -0
  311. package/dist/src/process/studio-window-state.js.map +1 -0
  312. package/dist/src/server/studio-bridge-server.d.ts +3 -1
  313. package/dist/src/server/studio-bridge-server.d.ts.map +1 -1
  314. package/dist/src/server/studio-bridge-server.js +12 -4
  315. package/dist/src/server/studio-bridge-server.js.map +1 -1
  316. package/dist/src/server/web-socket-protocol.d.ts +173 -6
  317. package/dist/src/server/web-socket-protocol.d.ts.map +1 -1
  318. package/dist/src/server/web-socket-protocol.js +244 -1
  319. package/dist/src/server/web-socket-protocol.js.map +1 -1
  320. package/dist/src/server/web-socket-protocol.test.js +48 -0
  321. package/dist/src/server/web-socket-protocol.test.js.map +1 -1
  322. package/dist/src/test/e2e/persistent-session.test.js +121 -0
  323. package/dist/src/test/e2e/persistent-session.test.js.map +1 -1
  324. package/dist/src/test/e2e/split-server.test.d.ts +3 -5
  325. package/dist/src/test/e2e/split-server.test.d.ts.map +1 -1
  326. package/dist/src/test/e2e/split-server.test.js +3 -5
  327. package/dist/src/test/e2e/split-server.test.js.map +1 -1
  328. package/dist/tsconfig.tsbuildinfo +1 -1
  329. package/docker/Dockerfile +3 -0
  330. package/package.json +8 -6
  331. package/src/bridge/bridge-connection.test.ts +126 -0
  332. package/src/bridge/bridge-connection.ts +217 -22
  333. package/src/bridge/bridge-session.test.ts +6 -4
  334. package/src/bridge/bridge-session.ts +273 -28
  335. package/src/bridge/index.ts +3 -0
  336. package/src/bridge/internal/bridge-client.test.ts +23 -0
  337. package/src/bridge/internal/bridge-client.ts +25 -7
  338. package/src/bridge/internal/bridge-host.test.ts +38 -0
  339. package/src/bridge/internal/bridge-host.ts +47 -0
  340. package/src/bridge/internal/hand-off.ts +4 -1
  341. package/src/bridge/internal/host-protocol.test.ts +15 -0
  342. package/src/bridge/internal/host-protocol.ts +148 -37
  343. package/src/bridge/internal/instance-state.ts +34 -0
  344. package/src/bridge/internal/transport-client.ts +2 -1
  345. package/src/bridge/internal/transport-server.ts +5 -1
  346. package/src/bridge/types.ts +47 -2
  347. package/src/cli/adapters/cli-command-adapter-handler.test.ts +28 -0
  348. package/src/cli/adapters/cli-command-adapter.ts +150 -18
  349. package/src/cli/adapters/group-builder.test.ts +34 -2
  350. package/src/cli/adapters/group-builder.ts +52 -20
  351. package/src/cli/adapters/help-formatter.test.ts +1 -1
  352. package/src/cli/adapters/help-formatter.ts +4 -3
  353. package/src/cli/adapters/playtest-edit-guard.test.ts +54 -0
  354. package/src/cli/args/global-args.ts +1 -1
  355. package/src/cli/cli-output-context.test.ts +55 -0
  356. package/src/cli/cli-output-context.ts +50 -0
  357. package/src/cli/cli.ts +49 -17
  358. package/src/cli/managed-studio-run.test.ts +71 -0
  359. package/src/cli/managed-studio-run.ts +135 -0
  360. package/src/cli/resolve-session.test.ts +1 -1
  361. package/src/cli/resolve-session.ts +1 -1
  362. package/src/cli/script-executor.ts +99 -51
  363. package/src/commands/console/exec/exec.test.ts +96 -3
  364. package/src/commands/console/exec/exec.ts +59 -6
  365. package/src/commands/console/exec/execute.lua +356 -240
  366. package/src/commands/console/exec/execute.spec.lua +286 -0
  367. package/src/commands/console/logs/logs.test.ts +76 -4
  368. package/src/commands/console/logs/logs.ts +132 -17
  369. package/src/commands/console/logs/query-logs.lua +85 -52
  370. package/src/commands/console/logs/query-logs.spec.lua +132 -0
  371. package/src/commands/explorer/export/export-instances.lua +108 -0
  372. package/src/commands/explorer/export/export-instances.spec.lua +87 -0
  373. package/src/commands/explorer/export/export.test.ts +27 -0
  374. package/src/commands/explorer/export/export.ts +60 -0
  375. package/src/commands/explorer/find/find-instances.lua +174 -0
  376. package/src/commands/explorer/find/find-instances.spec.lua +122 -0
  377. package/src/commands/explorer/find/find.test.ts +53 -0
  378. package/src/commands/explorer/find/find.ts +113 -0
  379. package/src/commands/explorer/grep/grep-scripts.lua +214 -0
  380. package/src/commands/explorer/grep/grep-scripts.spec.lua +130 -0
  381. package/src/commands/explorer/grep/grep.test.ts +45 -0
  382. package/src/commands/explorer/grep/grep.ts +93 -0
  383. package/src/commands/explorer/import/import-instances.lua +106 -0
  384. package/src/commands/explorer/import/import-instances.spec.lua +84 -0
  385. package/src/commands/explorer/import/import.test.ts +60 -0
  386. package/src/commands/explorer/import/import.ts +66 -0
  387. package/src/commands/explorer/query/query-data-model.lua +124 -152
  388. package/src/commands/explorer/query/query-data-model.spec.lua +150 -0
  389. package/src/commands/formatters.test.ts +7 -1
  390. package/src/commands/framework/action-loader.test.ts +28 -0
  391. package/src/commands/framework/action-loader.ts +10 -2
  392. package/src/commands/framework/arg-builder.ts +26 -3
  393. package/src/commands/framework/define-command.ts +32 -3
  394. package/src/commands/framework/index.ts +1 -0
  395. package/src/commands/index.ts +50 -0
  396. package/src/commands/linux/inject-credentials/inject-credentials.ts +1 -3
  397. package/src/commands/linux/setup/setup.ts +1 -3
  398. package/src/commands/linux/status/status.ts +105 -98
  399. package/src/commands/playtest/player/add/add.ts +85 -0
  400. package/src/commands/playtest/player/list/list.ts +57 -0
  401. package/src/commands/playtest/player/playtest-players.test.ts +146 -0
  402. package/src/commands/playtest/player/playtest-players.ts +270 -0
  403. package/src/commands/playtest/player/remove/remove.ts +78 -0
  404. package/src/commands/playtest/playtest-sessions.test.ts +143 -0
  405. package/src/commands/playtest/playtest-sessions.ts +417 -0
  406. package/src/commands/playtest/restart/restart.ts +199 -0
  407. package/src/commands/playtest/run/playtest-runner.luau +264 -0
  408. package/src/commands/playtest/run/playtest-runner.spec.lua +71 -0
  409. package/src/commands/playtest/run/run-playtest-script.lua +139 -0
  410. package/src/commands/playtest/run/run-playtest-script.spec.lua +43 -0
  411. package/src/commands/playtest/run/run.ts +239 -0
  412. package/src/commands/playtest/start/start-playtest.lua +108 -0
  413. package/src/commands/playtest/start/start.ts +138 -0
  414. package/src/commands/playtest/stop/end-playtest.lua +47 -0
  415. package/src/commands/playtest/stop/stop.ts +51 -0
  416. package/src/commands/process/close/close.test.ts +250 -0
  417. package/src/commands/process/close/close.ts +183 -17
  418. package/src/commands/process/info/info.test.ts +198 -44
  419. package/src/commands/process/info/info.ts +204 -15
  420. package/src/commands/process/info/query-state.lua +42 -29
  421. package/src/commands/process/info/query-state.spec.lua +39 -0
  422. package/src/commands/process/launch/launch.test.ts +138 -21
  423. package/src/commands/process/launch/launch.ts +69 -9
  424. package/src/commands/process/list/list.test.ts +1 -0
  425. package/src/commands/process/list/list.ts +14 -6
  426. package/src/commands/process/run/run.ts +26 -5
  427. package/src/commands/serve/serve.test.ts +17 -2
  428. package/src/commands/serve/serve.ts +25 -6
  429. package/src/commands/viewport/screenshot/capture-screenshot.lua +175 -182
  430. package/src/commands/viewport/screenshot/capture-screenshot.spec.lua +129 -0
  431. package/src/commands/viewport/screenshot/screenshot.test.ts +7 -10
  432. package/src/commands/viewport/screenshot/screenshot.ts +6 -1
  433. package/src/deploy/deploy-places.test.ts +127 -0
  434. package/src/deploy/deploy-places.ts +229 -0
  435. package/src/index.ts +11 -0
  436. package/src/plugin/persistent-plugin-installer.test.ts +4 -0
  437. package/src/plugin/persistent-plugin-installer.ts +2 -1
  438. package/src/plugin/plugin-build-version.test.ts +55 -0
  439. package/src/plugin/plugin-build-version.ts +53 -0
  440. package/src/plugin/plugin-injector.ts +7 -1
  441. package/src/process/studio-process-closer.test.ts +107 -0
  442. package/src/process/studio-process-closer.ts +187 -0
  443. package/src/process/studio-settings.test.ts +18 -0
  444. package/src/process/studio-settings.ts +61 -0
  445. package/src/process/studio-window-state.ts +65 -0
  446. package/src/server/studio-bridge-server.ts +15 -4
  447. package/src/server/web-socket-protocol.test.ts +55 -0
  448. package/src/server/web-socket-protocol.ts +468 -8
  449. package/src/test/e2e/persistent-session.test.ts +137 -0
  450. package/src/test/e2e/split-server.test.ts +3 -5
  451. package/templates/studio-bridge-plugin/default.project.json +3 -0
  452. package/templates/studio-bridge-plugin/src/Shared/ActionRouter.lua +208 -159
  453. package/templates/studio-bridge-plugin/src/Shared/ActionRouter.spec.lua +418 -0
  454. package/templates/studio-bridge-plugin/src/Shared/BuiltInActions.lua +94 -0
  455. package/templates/studio-bridge-plugin/src/Shared/BuiltInActions.spec.lua +166 -0
  456. package/templates/studio-bridge-plugin/src/Shared/DiscoveryStateMachine.lua +118 -137
  457. package/templates/studio-bridge-plugin/src/Shared/DiscoveryStateMachine.spec.lua +228 -0
  458. package/templates/studio-bridge-plugin/src/Shared/MessageBuffer.lua +80 -109
  459. package/templates/studio-bridge-plugin/src/Shared/MessageBuffer.spec.lua +116 -0
  460. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeConnection.lua +233 -0
  461. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeConnection.spec.lua +239 -0
  462. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeLogUtils.lua +53 -0
  463. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeLogUtils.spec.lua +27 -0
  464. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeSessionUtils.lua +164 -0
  465. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeSessionUtils.spec.lua +159 -0
  466. package/templates/studio-bridge-plugin/src/StudioBridgePlugin.server.lua +266 -368
  467. package/templates/studio-bridge-plugin/src/Vendor/png.lua +8 -2
  468. package/test/default.project.json +41 -0
  469. package/test/jest.config.lua +3 -0
  470. package/test/scripts/Server/ServerMain.server.lua +10 -0
  471. package/tsconfig.json +1 -0
  472. package/templates/studio-bridge-plugin/src/Shared/Protocol.lua +0 -132
  473. package/templates/studio-bridge-plugin-test/test/actions.test.lua +0 -580
  474. package/templates/studio-bridge-plugin-test/test/discovery.test.lua +0 -622
  475. package/templates/studio-bridge-plugin-test/test/execute-handler.test.lua +0 -517
  476. package/templates/studio-bridge-plugin-test/test/hash-lifecycle.test.lua +0 -814
  477. package/templates/studio-bridge-plugin-test/test/integration.test.lua +0 -1020
  478. package/templates/studio-bridge-plugin-test/test/new-actions.test.lua +0 -339
  479. package/templates/studio-bridge-plugin-test/test/plugin-entry.test.lua +0 -493
  480. package/templates/studio-bridge-plugin-test/test/protocol.test.lua +0 -506
  481. package/templates/studio-bridge-plugin-test/test/roblox-mocks.lua +0 -108
  482. package/templates/studio-bridge-plugin-test/test/test-runner.lua +0 -112
@@ -1,203 +1,184 @@
1
- --[[
2
- Pure state machine for plugin discovery and connection lifecycle.
1
+ --!strict
2
+ --[=[
3
+ State machine for finding a studio-bridge server and holding the connection
4
+ to it. Moves through `idle`, `searching`, `connecting` and `connected`.
3
5
 
4
- Manages the states: idle, searching, connecting, connected.
5
- All external I/O is performed via injected callbacks.
6
+ All I/O goes through the injected callbacks. The caller drives it by calling
7
+ [DiscoveryStateMachine.PollAsync] in a loop, passing how much of the loop's
8
+ time budget is left so scanning never overruns it.
6
9
 
7
- The caller drives the loop by calling pollAsync(remainingExecTimeSec)
8
- repeatedly. The remaining execution time threads through all async
9
- operations so the entire poll cycle completes within a predictable
10
- time budget.
11
- ]]
10
+ @class DiscoveryStateMachine
11
+ ]=]
12
+
13
+ local DEFAULT_PORT_MIN = 38741
14
+ local DEFAULT_PORT_MAX = 38744
15
+ local DEFAULT_POLL_INTERVAL_SEC = 2
16
+ local DEFAULT_TIME_AVAILABLE_SEC = 10
12
17
 
13
18
  local DiscoveryStateMachine = {}
19
+ DiscoveryStateMachine.ClassName = "DiscoveryStateMachine"
14
20
  DiscoveryStateMachine.__index = DiscoveryStateMachine
15
21
 
16
- -- ---------------------------------------------------------------------------
17
- -- Default configuration
18
- -- ---------------------------------------------------------------------------
22
+ export type DiscoveryState = "idle" | "searching" | "connecting" | "connected"
19
23
 
20
- local DEFAULT_CONFIG = {
21
- portRange = { min = 38741, max = 38744 },
22
- pollIntervalSec = 2,
24
+ export type DiscoveryConfig = {
25
+ portRange: { min: number?, max: number? }?,
26
+ pollIntervalSec: number?,
23
27
  }
24
28
 
25
- -- ---------------------------------------------------------------------------
26
- -- Constructor
27
- -- ---------------------------------------------------------------------------
28
-
29
- function DiscoveryStateMachine.new(
30
- config: {
31
- portRange: { min: number, max: number }?,
32
- pollIntervalSec: number?,
33
- }?,
34
- callbacks: {
35
- scanPortsAsync: (ports: { number }, timeoutSec: number) -> (number?, string?),
36
- connectWebSocket: (url: string) -> (boolean, any?),
37
- onStateChange: (oldState: string, newState: string) -> (),
38
- onConnected: (connection: any, port: number) -> (),
39
- onDisconnected: (reason: string?) -> (),
40
- }
41
- )
42
- local resolvedConfig = {}
43
- local userConfig = config or {}
44
- for key, default in DEFAULT_CONFIG do
45
- if key == "portRange" then
46
- local userRange = (userConfig :: any).portRange
47
- if userRange then
48
- resolvedConfig.portRange = {
49
- min = userRange.min or default.min,
50
- max = userRange.max or default.max,
51
- }
52
- else
53
- resolvedConfig.portRange = { min = default.min, max = default.max }
54
- end
55
- else
56
- resolvedConfig[key] = (userConfig :: any)[key] or default
57
- end
58
- end
29
+ export type DiscoveryCallbacks = {
30
+ scanPortsAsync: (ports: { number }, timeoutSec: number) -> (number?, string?),
31
+ connectWebSocket: (url: string) -> (boolean, any?),
32
+ onStateChange: (oldState: DiscoveryState, newState: DiscoveryState) -> (),
33
+ onConnected: (connection: any, port: number) -> (),
34
+ onDisconnected: (reason: string?) -> (),
35
+ }
59
36
 
60
- local self = setmetatable({
61
- _config = resolvedConfig,
62
- _callbacks = callbacks,
63
- _state = "idle" :: string,
64
- _nextPollAt = 0, -- os.clock() time for next scan
65
- _connection = nil :: any?,
66
- }, DiscoveryStateMachine)
37
+ export type DiscoveryStateMachine = typeof(setmetatable(
38
+ {} :: {
39
+ _portMin: number,
40
+ _portMax: number,
41
+ _pollIntervalSec: number,
42
+ _callbacks: DiscoveryCallbacks,
43
+ _state: DiscoveryState,
44
+ _nextPollAt: number,
45
+ _connection: any?,
46
+ },
47
+ {} :: typeof({ __index = DiscoveryStateMachine })
48
+ ))
49
+
50
+ --[=[
51
+ Constructs a state machine in the `idle` state. Scans ports 38741-38744 every
52
+ 2 seconds unless `config` says otherwise.
53
+ ]=]
54
+ function DiscoveryStateMachine.new(config: DiscoveryConfig?, callbacks: DiscoveryCallbacks): DiscoveryStateMachine
55
+ local self: DiscoveryStateMachine = setmetatable({} :: any, DiscoveryStateMachine)
56
+
57
+ local portRange = config and config.portRange
58
+ self._portMin = portRange and portRange.min or DEFAULT_PORT_MIN
59
+ self._portMax = portRange and portRange.max or DEFAULT_PORT_MAX
60
+ self._pollIntervalSec = config and config.pollIntervalSec or DEFAULT_POLL_INTERVAL_SEC
61
+
62
+ self._callbacks = assert(callbacks, "No callbacks")
63
+ self._state = "idle"
64
+ self._nextPollAt = 0
65
+ self._connection = nil
67
66
 
68
67
  return self
69
68
  end
70
69
 
71
- -- ---------------------------------------------------------------------------
72
- -- State accessors
73
- -- ---------------------------------------------------------------------------
74
-
75
- function DiscoveryStateMachine.getState(self: any): string
70
+ --[=[
71
+ Returns the current state.
72
+ ]=]
73
+ function DiscoveryStateMachine.GetState(self: DiscoveryStateMachine): DiscoveryState
76
74
  return self._state
77
75
  end
78
76
 
79
- -- ---------------------------------------------------------------------------
80
- -- Internal state transition
81
- -- ---------------------------------------------------------------------------
82
-
83
- function DiscoveryStateMachine._transitionTo(self: any, newState: string)
84
- local oldState = self._state
85
- if oldState == newState then
86
- return
87
- end
88
- self._state = newState
89
- self._callbacks.onStateChange(oldState, newState)
90
- end
91
-
92
- -- ---------------------------------------------------------------------------
93
- -- Public methods
94
- -- ---------------------------------------------------------------------------
95
-
96
- function DiscoveryStateMachine.start(self: any)
77
+ --[=[
78
+ Starts searching. Does nothing unless idle.
79
+ ]=]
80
+ function DiscoveryStateMachine.Start(self: DiscoveryStateMachine)
97
81
  if self._state ~= "idle" then
98
82
  return
99
83
  end
84
+
100
85
  self._nextPollAt = 0
101
86
  self:_transitionTo("searching")
102
87
  end
103
88
 
104
- function DiscoveryStateMachine.stop(self: any)
89
+ --[=[
90
+ Returns to idle, reporting a `"stopped"` disconnect if a connection was held.
91
+ ]=]
92
+ function DiscoveryStateMachine.Stop(self: DiscoveryStateMachine)
105
93
  if self._state == "idle" then
106
94
  return
107
95
  end
96
+
108
97
  local wasConnected = self._state == "connected"
109
98
  self._connection = nil
110
99
  self._nextPollAt = 0
111
100
  self:_transitionTo("idle")
101
+
112
102
  if wasConnected then
113
103
  self._callbacks.onDisconnected("stopped")
114
104
  end
115
105
  end
116
106
 
117
- function DiscoveryStateMachine.onDisconnect(self: any, reason: string?)
107
+ --[=[
108
+ Reports that the held connection dropped, and resumes searching right away.
109
+ ]=]
110
+ function DiscoveryStateMachine.HandleDisconnect(self: DiscoveryStateMachine, reason: string?)
118
111
  if self._state ~= "connected" then
119
112
  return
120
113
  end
114
+
121
115
  self._connection = nil
122
116
  self._nextPollAt = 0
123
117
  self._callbacks.onDisconnected(reason)
124
118
  self:_transitionTo("searching")
125
119
  end
126
120
 
127
- --[[
128
- Run one poll cycle. remainingExecTimeSec is the number of seconds this
129
- call is allowed to spend on async work (port scanning, connecting).
130
- The caller subtracts elapsed time before each call so the entire loop
131
- iteration stays within its time budget.
132
-
133
- Returns immediately if not time to scan yet, or if in idle/connected state.
134
- May yield during port scanning and WebSocket connection.
135
- ]]
136
- function DiscoveryStateMachine.pollAsync(self: any, remainingExecTimeSec: number?)
137
- if self._state == "idle" or self._state == "connected" then
121
+ --[=[
122
+ Runs one poll cycle, spending at most `remainingExecTimeSec` (default 10) on
123
+ scanning. Returns immediately while idle, connected, or before the next scan
124
+ is due. May yield.
125
+ ]=]
126
+ function DiscoveryStateMachine.PollAsync(self: DiscoveryStateMachine, remainingExecTimeSec: number?)
127
+ if self._state ~= "searching" then
138
128
  return
139
129
  end
140
130
 
141
- local now = os.clock()
142
- local timeAvailable = remainingExecTimeSec or 10
143
-
144
- if self._state == "searching" then
145
- if now < self._nextPollAt then
146
- return
147
- end
148
- if timeAvailable <= 0 then
149
- return
150
- end
151
- self:_scanPortsAsync(timeAvailable)
131
+ if os.clock() < self._nextPollAt then
132
+ return
152
133
  end
134
+
135
+ local timeAvailable = remainingExecTimeSec or DEFAULT_TIME_AVAILABLE_SEC
136
+ if timeAvailable <= 0 then
137
+ return
138
+ end
139
+
140
+ self:_scanPortsAsync(timeAvailable)
153
141
  end
154
142
 
155
- -- ---------------------------------------------------------------------------
156
- -- Internal: port scanning
157
- -- ---------------------------------------------------------------------------
143
+ function DiscoveryStateMachine._transitionTo(self: DiscoveryStateMachine, newState: DiscoveryState)
144
+ local oldState: DiscoveryState = self._state
145
+ if oldState == newState then
146
+ return
147
+ end
158
148
 
159
- function DiscoveryStateMachine._scanPortsAsync(self: any, timeoutSec: number)
160
- local portMin = self._config.portRange.min
161
- local portMax = self._config.portRange.max
149
+ self._state = newState
150
+ self._callbacks.onStateChange(oldState, newState)
151
+ end
162
152
 
163
- -- scanPortsAsync probes every port in parallel and returns whichever
164
- -- responds first, so the order is irrelevant. (An earlier version
165
- -- rotated the starting port via self._currentPort, but the field was
166
- -- never advanced after a failed scan, making the rotation a no-op.)
167
- local ports = {}
168
- for port = portMin, portMax do
153
+ function DiscoveryStateMachine._scanPortsAsync(self: DiscoveryStateMachine, timeoutSec: number)
154
+ -- Every port is probed in parallel and the first to answer wins, so order is irrelevant
155
+ local ports: { number } = {}
156
+ for port = self._portMin, self._portMax do
169
157
  table.insert(ports, port)
170
158
  end
171
159
 
172
- local foundPort, foundBody = self._callbacks.scanPortsAsync(ports, timeoutSec)
173
-
174
- if foundPort then
175
- self:_transitionTo("connecting")
176
- self:_attemptConnect(foundPort, foundBody)
160
+ local foundPort = self._callbacks.scanPortsAsync(ports, timeoutSec)
161
+ if not foundPort then
162
+ self._nextPollAt = os.clock() + self._pollIntervalSec
177
163
  return
178
164
  end
179
165
 
180
- -- All ports failed. Schedule next scan at the regular poll interval.
181
- self._nextPollAt = os.clock() + self._config.pollIntervalSec
166
+ self:_transitionTo("connecting")
167
+ self:_attemptConnect(foundPort)
182
168
  end
183
169
 
184
- -- ---------------------------------------------------------------------------
185
- -- Internal: WebSocket connection attempt
186
- -- ---------------------------------------------------------------------------
187
-
188
- function DiscoveryStateMachine._attemptConnect(self: any, port: number, _healthResponse: string?)
189
- local wsUrl = "ws://localhost:" .. tostring(port) .. "/plugin"
190
- local success, connection = self._callbacks.connectWebSocket(wsUrl)
191
-
192
- if success and connection then
193
- self._connection = connection
194
- self._nextPollAt = 0
195
- self:_transitionTo("connected")
196
- self._callbacks.onConnected(connection, port)
197
- else
198
- self._nextPollAt = os.clock() + self._config.pollIntervalSec
170
+ function DiscoveryStateMachine._attemptConnect(self: DiscoveryStateMachine, port: number)
171
+ local success, connection = self._callbacks.connectWebSocket(`ws://localhost:{port}/plugin`)
172
+ if not (success and connection) then
173
+ self._nextPollAt = os.clock() + self._pollIntervalSec
199
174
  self:_transitionTo("searching")
175
+ return
200
176
  end
177
+
178
+ self._connection = connection
179
+ self._nextPollAt = 0
180
+ self:_transitionTo("connected")
181
+ self._callbacks.onConnected(connection, port)
201
182
  end
202
183
 
203
184
  return DiscoveryStateMachine
@@ -0,0 +1,228 @@
1
+ --!strict
2
+ --[[
3
+ @class DiscoveryStateMachine.spec.lua
4
+ ]]
5
+
6
+ local require = require(script.Parent.loader).load(script)
7
+
8
+ local DiscoveryStateMachine = require("DiscoveryStateMachine")
9
+ local Jest = require("Jest")
10
+
11
+ local describe = Jest.Globals.describe
12
+ local expect = Jest.Globals.expect
13
+ local it = Jest.Globals.it
14
+
15
+ local function setup(config: DiscoveryStateMachine.DiscoveryConfig?): any
16
+ local controller
17
+ controller = {
18
+ foundPort = nil :: number?,
19
+ connectSucceeds = true,
20
+ scans = {} :: { { ports: { number }, timeoutSec: number } },
21
+ connectUrls = {} :: { string },
22
+ stateChanges = {} :: { string },
23
+ connected = {} :: { { connection: any, port: number } },
24
+ disconnectReasons = {} :: { string },
25
+ }
26
+
27
+ controller.machine = DiscoveryStateMachine.new(config, {
28
+ scanPortsAsync = function(ports, timeoutSec)
29
+ table.insert(controller.scans, { ports = ports, timeoutSec = timeoutSec })
30
+ return controller.foundPort, nil
31
+ end,
32
+ connectWebSocket = function(url)
33
+ table.insert(controller.connectUrls, url)
34
+ if controller.connectSucceeds then
35
+ return true, { url = url }
36
+ end
37
+ return false, nil
38
+ end,
39
+ onStateChange = function(oldState, newState)
40
+ table.insert(controller.stateChanges, `{oldState}->{newState}`)
41
+ end,
42
+ onConnected = function(connection, port)
43
+ table.insert(controller.connected, { connection = connection, port = port })
44
+ end,
45
+ onDisconnected = function(reason)
46
+ table.insert(controller.disconnectReasons, reason or "nil")
47
+ end,
48
+ })
49
+
50
+ return controller
51
+ end
52
+
53
+ describe("DiscoveryStateMachine.new()", function()
54
+ it("should start idle", function()
55
+ local controller = setup()
56
+
57
+ expect(controller.machine:GetState()).toEqual("idle")
58
+ end)
59
+ end)
60
+
61
+ describe("DiscoveryStateMachine:Start()", function()
62
+ it("should move from idle to searching", function()
63
+ local controller = setup()
64
+
65
+ controller.machine:Start()
66
+
67
+ expect(controller.machine:GetState()).toEqual("searching")
68
+ expect(controller.stateChanges).toEqual({ "idle->searching" })
69
+ end)
70
+
71
+ it("should do nothing when already started", function()
72
+ local controller = setup()
73
+ controller.machine:Start()
74
+
75
+ controller.machine:Start()
76
+
77
+ expect(controller.stateChanges).toEqual({ "idle->searching" })
78
+ end)
79
+ end)
80
+
81
+ describe("DiscoveryStateMachine:PollAsync()", function()
82
+ it("should not scan while idle", function()
83
+ local controller = setup()
84
+
85
+ controller.machine:PollAsync(1)
86
+
87
+ expect(#controller.scans).toEqual(0)
88
+ end)
89
+
90
+ it("should scan the default port range with the remaining time", function()
91
+ local controller = setup()
92
+ controller.machine:Start()
93
+
94
+ controller.machine:PollAsync(1.5)
95
+
96
+ expect(controller.scans).toEqual({
97
+ { ports = { 38741, 38742, 38743, 38744 }, timeoutSec = 1.5 },
98
+ })
99
+ end)
100
+
101
+ it("should scan a configured port range", function()
102
+ local controller = setup({ portRange = { min = 5000, max = 5001 } })
103
+ controller.machine:Start()
104
+
105
+ controller.machine:PollAsync(1)
106
+
107
+ expect(controller.scans[1].ports).toEqual({ 5000, 5001 })
108
+ end)
109
+
110
+ it("should not scan without time left", function()
111
+ local controller = setup()
112
+ controller.machine:Start()
113
+
114
+ controller.machine:PollAsync(0)
115
+
116
+ expect(#controller.scans).toEqual(0)
117
+ end)
118
+
119
+ it("should wait the poll interval before scanning again after a miss", function()
120
+ local controller = setup({ pollIntervalSec = 60 })
121
+ controller.machine:Start()
122
+
123
+ controller.machine:PollAsync(1)
124
+ controller.machine:PollAsync(1)
125
+
126
+ expect(#controller.scans).toEqual(1)
127
+ expect(controller.machine:GetState()).toEqual("searching")
128
+ end)
129
+
130
+ it("should connect to the port that answered", function()
131
+ local controller = setup()
132
+ controller.foundPort = 38743
133
+ controller.machine:Start()
134
+
135
+ controller.machine:PollAsync(1)
136
+
137
+ expect(controller.machine:GetState()).toEqual("connected")
138
+ expect(controller.connectUrls).toEqual({ "ws://localhost:38743/plugin" })
139
+ expect(controller.stateChanges).toEqual({ "idle->searching", "searching->connecting", "connecting->connected" })
140
+ expect(controller.connected[1].port).toEqual(38743)
141
+ expect(controller.connected[1].connection).toEqual({ url = "ws://localhost:38743/plugin" })
142
+ end)
143
+
144
+ it("should go back to searching when the connection fails", function()
145
+ local controller = setup({ pollIntervalSec = 60 })
146
+ controller.foundPort = 38741
147
+ controller.connectSucceeds = false
148
+ controller.machine:Start()
149
+
150
+ controller.machine:PollAsync(1)
151
+ controller.machine:PollAsync(1)
152
+
153
+ expect(controller.machine:GetState()).toEqual("searching")
154
+ expect(#controller.scans).toEqual(1)
155
+ expect(#controller.connected).toEqual(0)
156
+ end)
157
+
158
+ it("should not scan while connected", function()
159
+ local controller = setup()
160
+ controller.foundPort = 38741
161
+ controller.machine:Start()
162
+ controller.machine:PollAsync(1)
163
+
164
+ controller.machine:PollAsync(1)
165
+
166
+ expect(#controller.scans).toEqual(1)
167
+ end)
168
+ end)
169
+
170
+ describe("DiscoveryStateMachine:HandleDisconnect()", function()
171
+ it("should report the reason and scan again right away", function()
172
+ local controller = setup({ pollIntervalSec = 60 })
173
+ controller.foundPort = 38741
174
+ controller.machine:Start()
175
+ controller.machine:PollAsync(1)
176
+
177
+ controller.machine:HandleDisconnect("closed")
178
+ controller.machine:PollAsync(1)
179
+
180
+ expect(controller.disconnectReasons).toEqual({ "closed" })
181
+ expect(#controller.scans).toEqual(2)
182
+ expect(controller.machine:GetState()).toEqual("connected")
183
+ end)
184
+
185
+ it("should do nothing unless connected", function()
186
+ local controller = setup()
187
+ controller.machine:Start()
188
+
189
+ controller.machine:HandleDisconnect("closed")
190
+
191
+ expect(controller.disconnectReasons).toEqual({})
192
+ expect(controller.machine:GetState()).toEqual("searching")
193
+ end)
194
+ end)
195
+
196
+ describe("DiscoveryStateMachine:Stop()", function()
197
+ it("should return to idle from searching without reporting a disconnect", function()
198
+ local controller = setup()
199
+ controller.machine:Start()
200
+
201
+ controller.machine:Stop()
202
+
203
+ expect(controller.machine:GetState()).toEqual("idle")
204
+ expect(controller.disconnectReasons).toEqual({})
205
+ end)
206
+
207
+ it("should report a stopped disconnect when connected", function()
208
+ local controller = setup()
209
+ controller.foundPort = 38741
210
+ controller.machine:Start()
211
+ controller.machine:PollAsync(1)
212
+
213
+ controller.machine:Stop()
214
+
215
+ expect(controller.machine:GetState()).toEqual("idle")
216
+ expect(controller.disconnectReasons).toEqual({ "stopped" })
217
+ end)
218
+
219
+ it("should allow starting again", function()
220
+ local controller = setup()
221
+ controller.machine:Start()
222
+ controller.machine:Stop()
223
+
224
+ controller.machine:Start()
225
+
226
+ expect(controller.machine:GetState()).toEqual("searching")
227
+ end)
228
+ end)