@quenty/studio-bridge 0.21.0 → 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 (491) hide show
  1. package/CHANGELOG.md +12 -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/linux/linux-studio-launcher.d.ts.map +1 -1
  277. package/dist/src/linux/linux-studio-launcher.js +10 -0
  278. package/dist/src/linux/linux-studio-launcher.js.map +1 -1
  279. package/dist/src/linux/linux-studio-launcher.test.d.ts +2 -0
  280. package/dist/src/linux/linux-studio-launcher.test.d.ts.map +1 -0
  281. package/dist/src/linux/linux-studio-launcher.test.js +68 -0
  282. package/dist/src/linux/linux-studio-launcher.test.js.map +1 -0
  283. package/dist/src/plugin/persistent-plugin-installer.d.ts.map +1 -1
  284. package/dist/src/plugin/persistent-plugin-installer.js +2 -1
  285. package/dist/src/plugin/persistent-plugin-installer.js.map +1 -1
  286. package/dist/src/plugin/persistent-plugin-installer.test.js +3 -0
  287. package/dist/src/plugin/persistent-plugin-installer.test.js.map +1 -1
  288. package/dist/src/plugin/plugin-build-version.d.ts +7 -0
  289. package/dist/src/plugin/plugin-build-version.d.ts.map +1 -0
  290. package/dist/src/plugin/plugin-build-version.js +42 -0
  291. package/dist/src/plugin/plugin-build-version.js.map +1 -0
  292. package/dist/src/plugin/plugin-build-version.test.d.ts +2 -0
  293. package/dist/src/plugin/plugin-build-version.test.d.ts.map +1 -0
  294. package/dist/src/plugin/plugin-build-version.test.js +41 -0
  295. package/dist/src/plugin/plugin-build-version.test.js.map +1 -0
  296. package/dist/src/plugin/plugin-injector.d.ts.map +1 -1
  297. package/dist/src/plugin/plugin-injector.js +7 -1
  298. package/dist/src/plugin/plugin-injector.js.map +1 -1
  299. package/dist/src/process/studio-process-closer.d.ts +35 -0
  300. package/dist/src/process/studio-process-closer.d.ts.map +1 -0
  301. package/dist/src/process/studio-process-closer.js +129 -0
  302. package/dist/src/process/studio-process-closer.js.map +1 -0
  303. package/dist/src/process/studio-process-closer.test.d.ts +2 -0
  304. package/dist/src/process/studio-process-closer.test.d.ts.map +1 -0
  305. package/dist/src/process/studio-process-closer.test.js +80 -0
  306. package/dist/src/process/studio-process-closer.test.js.map +1 -0
  307. package/dist/src/process/studio-settings.d.ts +14 -0
  308. package/dist/src/process/studio-settings.d.ts.map +1 -0
  309. package/dist/src/process/studio-settings.js +50 -0
  310. package/dist/src/process/studio-settings.js.map +1 -0
  311. package/dist/src/process/studio-settings.test.d.ts +2 -0
  312. package/dist/src/process/studio-settings.test.d.ts.map +1 -0
  313. package/dist/src/process/studio-settings.test.js +16 -0
  314. package/dist/src/process/studio-settings.test.js.map +1 -0
  315. package/dist/src/process/studio-window-state.d.ts +13 -0
  316. package/dist/src/process/studio-window-state.d.ts.map +1 -0
  317. package/dist/src/process/studio-window-state.js +48 -0
  318. package/dist/src/process/studio-window-state.js.map +1 -0
  319. package/dist/src/server/studio-bridge-server.d.ts +3 -1
  320. package/dist/src/server/studio-bridge-server.d.ts.map +1 -1
  321. package/dist/src/server/studio-bridge-server.js +12 -4
  322. package/dist/src/server/studio-bridge-server.js.map +1 -1
  323. package/dist/src/server/web-socket-protocol.d.ts +173 -6
  324. package/dist/src/server/web-socket-protocol.d.ts.map +1 -1
  325. package/dist/src/server/web-socket-protocol.js +244 -1
  326. package/dist/src/server/web-socket-protocol.js.map +1 -1
  327. package/dist/src/server/web-socket-protocol.test.js +48 -0
  328. package/dist/src/server/web-socket-protocol.test.js.map +1 -1
  329. package/dist/src/test/e2e/persistent-session.test.js +121 -0
  330. package/dist/src/test/e2e/persistent-session.test.js.map +1 -1
  331. package/dist/src/test/e2e/split-server.test.d.ts +3 -5
  332. package/dist/src/test/e2e/split-server.test.d.ts.map +1 -1
  333. package/dist/src/test/e2e/split-server.test.js +3 -5
  334. package/dist/src/test/e2e/split-server.test.js.map +1 -1
  335. package/dist/tsconfig.tsbuildinfo +1 -1
  336. package/docker/Dockerfile +3 -0
  337. package/package.json +8 -6
  338. package/src/bridge/bridge-connection.test.ts +126 -0
  339. package/src/bridge/bridge-connection.ts +217 -22
  340. package/src/bridge/bridge-session.test.ts +6 -4
  341. package/src/bridge/bridge-session.ts +273 -28
  342. package/src/bridge/index.ts +3 -0
  343. package/src/bridge/internal/bridge-client.test.ts +23 -0
  344. package/src/bridge/internal/bridge-client.ts +25 -7
  345. package/src/bridge/internal/bridge-host.test.ts +38 -0
  346. package/src/bridge/internal/bridge-host.ts +47 -0
  347. package/src/bridge/internal/hand-off.ts +4 -1
  348. package/src/bridge/internal/host-protocol.test.ts +15 -0
  349. package/src/bridge/internal/host-protocol.ts +148 -37
  350. package/src/bridge/internal/instance-state.ts +34 -0
  351. package/src/bridge/internal/transport-client.ts +2 -1
  352. package/src/bridge/internal/transport-server.ts +5 -1
  353. package/src/bridge/types.ts +47 -2
  354. package/src/cli/adapters/cli-command-adapter-handler.test.ts +28 -0
  355. package/src/cli/adapters/cli-command-adapter.ts +150 -18
  356. package/src/cli/adapters/group-builder.test.ts +34 -2
  357. package/src/cli/adapters/group-builder.ts +52 -20
  358. package/src/cli/adapters/help-formatter.test.ts +1 -1
  359. package/src/cli/adapters/help-formatter.ts +4 -3
  360. package/src/cli/adapters/playtest-edit-guard.test.ts +54 -0
  361. package/src/cli/args/global-args.ts +1 -1
  362. package/src/cli/cli-output-context.test.ts +55 -0
  363. package/src/cli/cli-output-context.ts +50 -0
  364. package/src/cli/cli.ts +49 -17
  365. package/src/cli/managed-studio-run.test.ts +71 -0
  366. package/src/cli/managed-studio-run.ts +135 -0
  367. package/src/cli/resolve-session.test.ts +1 -1
  368. package/src/cli/resolve-session.ts +1 -1
  369. package/src/cli/script-executor.ts +99 -51
  370. package/src/commands/console/exec/exec.test.ts +96 -3
  371. package/src/commands/console/exec/exec.ts +59 -6
  372. package/src/commands/console/exec/execute.lua +356 -240
  373. package/src/commands/console/exec/execute.spec.lua +286 -0
  374. package/src/commands/console/logs/logs.test.ts +76 -4
  375. package/src/commands/console/logs/logs.ts +132 -17
  376. package/src/commands/console/logs/query-logs.lua +85 -52
  377. package/src/commands/console/logs/query-logs.spec.lua +132 -0
  378. package/src/commands/explorer/export/export-instances.lua +108 -0
  379. package/src/commands/explorer/export/export-instances.spec.lua +87 -0
  380. package/src/commands/explorer/export/export.test.ts +27 -0
  381. package/src/commands/explorer/export/export.ts +60 -0
  382. package/src/commands/explorer/find/find-instances.lua +174 -0
  383. package/src/commands/explorer/find/find-instances.spec.lua +122 -0
  384. package/src/commands/explorer/find/find.test.ts +53 -0
  385. package/src/commands/explorer/find/find.ts +113 -0
  386. package/src/commands/explorer/grep/grep-scripts.lua +214 -0
  387. package/src/commands/explorer/grep/grep-scripts.spec.lua +130 -0
  388. package/src/commands/explorer/grep/grep.test.ts +45 -0
  389. package/src/commands/explorer/grep/grep.ts +93 -0
  390. package/src/commands/explorer/import/import-instances.lua +106 -0
  391. package/src/commands/explorer/import/import-instances.spec.lua +84 -0
  392. package/src/commands/explorer/import/import.test.ts +60 -0
  393. package/src/commands/explorer/import/import.ts +66 -0
  394. package/src/commands/explorer/query/query-data-model.lua +124 -152
  395. package/src/commands/explorer/query/query-data-model.spec.lua +150 -0
  396. package/src/commands/formatters.test.ts +7 -1
  397. package/src/commands/framework/action-loader.test.ts +28 -0
  398. package/src/commands/framework/action-loader.ts +10 -2
  399. package/src/commands/framework/arg-builder.ts +26 -3
  400. package/src/commands/framework/define-command.ts +32 -3
  401. package/src/commands/framework/index.ts +1 -0
  402. package/src/commands/index.ts +50 -0
  403. package/src/commands/linux/inject-credentials/inject-credentials.ts +1 -3
  404. package/src/commands/linux/setup/setup.ts +1 -3
  405. package/src/commands/linux/status/status.ts +105 -98
  406. package/src/commands/playtest/player/add/add.ts +85 -0
  407. package/src/commands/playtest/player/list/list.ts +57 -0
  408. package/src/commands/playtest/player/playtest-players.test.ts +146 -0
  409. package/src/commands/playtest/player/playtest-players.ts +270 -0
  410. package/src/commands/playtest/player/remove/remove.ts +78 -0
  411. package/src/commands/playtest/playtest-sessions.test.ts +143 -0
  412. package/src/commands/playtest/playtest-sessions.ts +417 -0
  413. package/src/commands/playtest/restart/restart.ts +199 -0
  414. package/src/commands/playtest/run/playtest-runner.luau +264 -0
  415. package/src/commands/playtest/run/playtest-runner.spec.lua +71 -0
  416. package/src/commands/playtest/run/run-playtest-script.lua +139 -0
  417. package/src/commands/playtest/run/run-playtest-script.spec.lua +43 -0
  418. package/src/commands/playtest/run/run.ts +239 -0
  419. package/src/commands/playtest/start/start-playtest.lua +108 -0
  420. package/src/commands/playtest/start/start.ts +138 -0
  421. package/src/commands/playtest/stop/end-playtest.lua +47 -0
  422. package/src/commands/playtest/stop/stop.ts +51 -0
  423. package/src/commands/process/close/close.test.ts +250 -0
  424. package/src/commands/process/close/close.ts +183 -17
  425. package/src/commands/process/info/info.test.ts +198 -44
  426. package/src/commands/process/info/info.ts +204 -15
  427. package/src/commands/process/info/query-state.lua +42 -29
  428. package/src/commands/process/info/query-state.spec.lua +39 -0
  429. package/src/commands/process/launch/launch.test.ts +138 -21
  430. package/src/commands/process/launch/launch.ts +69 -9
  431. package/src/commands/process/list/list.test.ts +1 -0
  432. package/src/commands/process/list/list.ts +14 -6
  433. package/src/commands/process/run/run.ts +26 -5
  434. package/src/commands/serve/serve.test.ts +17 -2
  435. package/src/commands/serve/serve.ts +25 -6
  436. package/src/commands/viewport/screenshot/capture-screenshot.lua +175 -182
  437. package/src/commands/viewport/screenshot/capture-screenshot.spec.lua +129 -0
  438. package/src/commands/viewport/screenshot/screenshot.test.ts +7 -10
  439. package/src/commands/viewport/screenshot/screenshot.ts +6 -1
  440. package/src/deploy/deploy-places.test.ts +127 -0
  441. package/src/deploy/deploy-places.ts +229 -0
  442. package/src/index.ts +11 -0
  443. package/src/linux/linux-studio-launcher.test.ts +89 -0
  444. package/src/linux/linux-studio-launcher.ts +11 -0
  445. package/src/plugin/persistent-plugin-installer.test.ts +4 -0
  446. package/src/plugin/persistent-plugin-installer.ts +2 -1
  447. package/src/plugin/plugin-build-version.test.ts +55 -0
  448. package/src/plugin/plugin-build-version.ts +53 -0
  449. package/src/plugin/plugin-injector.ts +7 -1
  450. package/src/process/studio-process-closer.test.ts +107 -0
  451. package/src/process/studio-process-closer.ts +187 -0
  452. package/src/process/studio-settings.test.ts +18 -0
  453. package/src/process/studio-settings.ts +61 -0
  454. package/src/process/studio-window-state.ts +65 -0
  455. package/src/server/studio-bridge-server.ts +15 -4
  456. package/src/server/web-socket-protocol.test.ts +55 -0
  457. package/src/server/web-socket-protocol.ts +468 -8
  458. package/src/test/e2e/persistent-session.test.ts +137 -0
  459. package/src/test/e2e/split-server.test.ts +3 -5
  460. package/templates/studio-bridge-plugin/default.project.json +3 -0
  461. package/templates/studio-bridge-plugin/src/Shared/ActionRouter.lua +208 -159
  462. package/templates/studio-bridge-plugin/src/Shared/ActionRouter.spec.lua +418 -0
  463. package/templates/studio-bridge-plugin/src/Shared/BuiltInActions.lua +94 -0
  464. package/templates/studio-bridge-plugin/src/Shared/BuiltInActions.spec.lua +166 -0
  465. package/templates/studio-bridge-plugin/src/Shared/DiscoveryStateMachine.lua +118 -137
  466. package/templates/studio-bridge-plugin/src/Shared/DiscoveryStateMachine.spec.lua +228 -0
  467. package/templates/studio-bridge-plugin/src/Shared/MessageBuffer.lua +80 -109
  468. package/templates/studio-bridge-plugin/src/Shared/MessageBuffer.spec.lua +116 -0
  469. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeConnection.lua +233 -0
  470. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeConnection.spec.lua +239 -0
  471. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeLogUtils.lua +53 -0
  472. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeLogUtils.spec.lua +27 -0
  473. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeSessionUtils.lua +164 -0
  474. package/templates/studio-bridge-plugin/src/Shared/StudioBridgeSessionUtils.spec.lua +159 -0
  475. package/templates/studio-bridge-plugin/src/StudioBridgePlugin.server.lua +266 -368
  476. package/templates/studio-bridge-plugin/src/Vendor/png.lua +8 -2
  477. package/test/default.project.json +41 -0
  478. package/test/jest.config.lua +3 -0
  479. package/test/scripts/Server/ServerMain.server.lua +10 -0
  480. package/tsconfig.json +1 -0
  481. package/templates/studio-bridge-plugin/src/Shared/Protocol.lua +0 -132
  482. package/templates/studio-bridge-plugin-test/test/actions.test.lua +0 -580
  483. package/templates/studio-bridge-plugin-test/test/discovery.test.lua +0 -622
  484. package/templates/studio-bridge-plugin-test/test/execute-handler.test.lua +0 -517
  485. package/templates/studio-bridge-plugin-test/test/hash-lifecycle.test.lua +0 -814
  486. package/templates/studio-bridge-plugin-test/test/integration.test.lua +0 -1020
  487. package/templates/studio-bridge-plugin-test/test/new-actions.test.lua +0 -339
  488. package/templates/studio-bridge-plugin-test/test/plugin-entry.test.lua +0 -493
  489. package/templates/studio-bridge-plugin-test/test/protocol.test.lua +0 -506
  490. package/templates/studio-bridge-plugin-test/test/roblox-mocks.lua +0 -108
  491. package/templates/studio-bridge-plugin-test/test/test-runner.lua +0 -112
@@ -0,0 +1,264 @@
1
+ --!strict
2
+ --[=[
3
+ Runs a `playtest run` script inside the playtest's server and ends the
4
+ playtest with the result, so running a script does not depend on Studio
5
+ loading user plugins into playtests.
6
+
7
+ The `run-playtest-script` action plants this source as a Script in the edit
8
+ DataModel, with the code as a ModuleScript named `Code` under it, and starts a
9
+ playtest. The playtest copies the edit DataModel, so the runner starts in its
10
+ server. It only acts in the playtest it was planted for: anywhere else, such
11
+ as a place saved while it was planted, it does nothing.
12
+
13
+ The result crosses back through `StudioTestService:EndTest` in the same shape
14
+ as an `execute` reply. Instances cannot cross DataModels, so values are
15
+ marshalled here. Output capture, tracebacks and the marshaller are copies of
16
+ execute.lua's, since the runner cannot require it.
17
+
18
+ @class PlaytestRunner
19
+ ]=]
20
+
21
+ local MAX_DEPTH = 64
22
+ local PLUGIN_PREFIX = "[StudioBridge]"
23
+ -- Tracebacks name this module's frames the way its first line does
24
+ local OWN_FRAME_PREFIX = string.match(debug.traceback(), "^([^\n]-):%d+")
25
+
26
+ local PlaytestRunner = {}
27
+
28
+ type LogEntry = {
29
+ level: string,
30
+ body: string,
31
+ timestamp: number,
32
+ }
33
+
34
+ local LOG_LEVELS: { [Enum.MessageType]: string } = {
35
+ [Enum.MessageType.MessageOutput] = "Print",
36
+ [Enum.MessageType.MessageInfo] = "Info",
37
+ [Enum.MessageType.MessageWarning] = "Warning",
38
+ [Enum.MessageType.MessageError] = "Error",
39
+ }
40
+
41
+ --[=[
42
+ Runs the `Code` module under `runner` and ends the playtest with the result,
43
+ when this playtest is the one `runner` was planted for.
44
+ ]=]
45
+ function PlaytestRunner.runAsync(runner: Instance, studioTestService: any, players: Players)
46
+ local argsOk, testArgs = pcall(function()
47
+ return studioTestService:GetTestArgs()
48
+ end)
49
+ if not argsOk or type(testArgs) ~= "table" or testArgs.studioBridgeRunnerId ~= runner:GetAttribute("RunnerId") then
50
+ return
51
+ end
52
+
53
+ local hasEnded = false
54
+ local captured: { LogEntry } = {}
55
+ local function endTest(result: { [string]: any })
56
+ if hasEnded then
57
+ return
58
+ end
59
+ hasEnded = true
60
+ studioTestService:EndTest(result)
61
+ end
62
+
63
+ local timeoutSec = testArgs.studioBridgeTimeoutSec
64
+ if type(timeoutSec) == "number" then
65
+ task.delay(timeoutSec, function()
66
+ endTest({
67
+ success = false,
68
+ error = `Script timed out after {timeoutSec}s`,
69
+ code = "SCRIPT_TIMEOUT",
70
+ output = captured,
71
+ })
72
+ end)
73
+ end
74
+
75
+ -- The plugin path waits for the client to connect, so match it in play mode
76
+ if testArgs.studioBridgeWaitForPlayer and #players:GetPlayers() == 0 then
77
+ players.PlayerAdded:Wait()
78
+ end
79
+
80
+ local scriptArgs = if type(testArgs.studioBridgeScriptArgs) == "table" then testArgs.studioBridgeScriptArgs else {}
81
+ endTest(PlaytestRunner.run(runner:FindFirstChild("Code"), captured, scriptArgs))
82
+ end
83
+
84
+ --[=[
85
+ Runs a code module with `args`, collecting everything logged while it runs
86
+ into `captured`, and returns the result in the shape of an `execute` reply.
87
+ ]=]
88
+ function PlaytestRunner.run(codeModule: Instance?, captured: { LogEntry }, args: { any }?): { [string]: any }
89
+ if not (codeModule and codeModule:IsA("ModuleScript")) then
90
+ return { success = false, error = "Runner has no Code module", code = "SCRIPT_LOAD_ERROR", output = captured }
91
+ end
92
+
93
+ local requireOk, fn = pcall(require, codeModule)
94
+ if not requireOk or type(fn) ~= "function" then
95
+ return {
96
+ success = false,
97
+ error = if requireOk then "Code module did not return a function" else tostring(fn),
98
+ code = "SCRIPT_LOAD_ERROR",
99
+ output = captured,
100
+ }
101
+ end
102
+
103
+ local logConnection = PlaytestRunner._captureOutput(captured)
104
+ local returned = table.pack(xpcall(fn, function(err)
105
+ return {
106
+ message = tostring(err),
107
+ traceback = PlaytestRunner._dropOwnFrames(debug.traceback(nil, 2)),
108
+ }
109
+ end, table.unpack(args or {})))
110
+
111
+ -- MessageOut can fire a frame late, after the code's last print
112
+ task.wait()
113
+ logConnection:Disconnect()
114
+
115
+ if not returned[1] then
116
+ return {
117
+ success = false,
118
+ error = returned[2].message,
119
+ traceback = returned[2].traceback,
120
+ code = "SCRIPT_RUNTIME_ERROR",
121
+ output = captured,
122
+ }
123
+ end
124
+
125
+ return {
126
+ success = true,
127
+ output = captured,
128
+ returnValues = PlaytestRunner._serializeReturnValues(returned),
129
+ }
130
+ end
131
+
132
+ --[[
133
+ Drops the frames of this module's own wrapper from a traceback, leaving only
134
+ the script's.
135
+ ]]
136
+ function PlaytestRunner._dropOwnFrames(traceback: string): string
137
+ if not OWN_FRAME_PREFIX then
138
+ return traceback
139
+ end
140
+
141
+ local lines = {}
142
+ for _, line in string.split(traceback, "\n") do
143
+ if string.sub(line, 1, #OWN_FRAME_PREFIX + 1) ~= `{OWN_FRAME_PREFIX}:` then
144
+ table.insert(lines, line)
145
+ end
146
+ end
147
+ return table.concat(lines, "\n")
148
+ end
149
+
150
+ --[[
151
+ Collects every message logged until the connection is disconnected, other
152
+ than the plugin's own.
153
+ ]]
154
+ function PlaytestRunner._captureOutput(captured: { LogEntry }): RBXScriptConnection
155
+ return game:GetService("LogService").MessageOut:Connect(function(message: string, messageType: Enum.MessageType)
156
+ if string.sub(message, 1, #PLUGIN_PREFIX) == PLUGIN_PREFIX then
157
+ return
158
+ end
159
+
160
+ table.insert(captured, {
161
+ level = LOG_LEVELS[messageType] or "Print",
162
+ body = message,
163
+ timestamp = os.clock(),
164
+ })
165
+ end)
166
+ end
167
+
168
+ --[[
169
+ Marshals what a script returned, in order, skipping the pcall status. A nil
170
+ becomes an explicit marker, since an array cannot hold a hole.
171
+ ]]
172
+ function PlaytestRunner._serializeReturnValues(packed: { n: number, [number]: any }): { any }
173
+ local returnValues = {}
174
+ for index = 2, packed.n do
175
+ local serialized = PlaytestRunner._serializeValue(packed[index], 1, {})
176
+ if serialized == nil then
177
+ serialized = { type = "Nil" }
178
+ end
179
+ returnValues[index - 1] = serialized
180
+ end
181
+ return returnValues
182
+ end
183
+
184
+ --[[
185
+ Produces the SerializedReturnValue shapes declared in web-socket-protocol.ts.
186
+ Copied from execute.lua; keep the two in step.
187
+ ]]
188
+ function PlaytestRunner._serializeValue(value: any, depth: number, seen: { [any]: boolean }): any
189
+ local valueType = typeof(value)
190
+
191
+ if valueType == "nil" or valueType == "string" or valueType == "boolean" then
192
+ return value
193
+ elseif valueType == "number" then
194
+ if value ~= value or value == math.huge or value == -math.huge then
195
+ return PlaytestRunner._unsupported("number", tostring(value))
196
+ end
197
+ return value
198
+ elseif valueType == "table" then
199
+ if depth > MAX_DEPTH then
200
+ return PlaytestRunner._unsupported("table", "<max depth exceeded>")
201
+ end
202
+ if seen[value] then
203
+ return PlaytestRunner._unsupported("table", "<cycle>")
204
+ end
205
+
206
+ seen[value] = true
207
+ local serialized = PlaytestRunner._serializeTable(value, depth, seen)
208
+ seen[value] = nil
209
+ return serialized
210
+ elseif valueType == "Vector3" then
211
+ return { type = "Vector3", value = { value.X, value.Y, value.Z } }
212
+ elseif valueType == "Vector2" then
213
+ return { type = "Vector2", value = { value.X, value.Y } }
214
+ elseif valueType == "CFrame" then
215
+ return { type = "CFrame", value = { value:GetComponents() } }
216
+ elseif valueType == "Color3" then
217
+ return { type = "Color3", value = { value.R, value.G, value.B } }
218
+ elseif valueType == "UDim2" then
219
+ return { type = "UDim2", value = { value.X.Scale, value.X.Offset, value.Y.Scale, value.Y.Offset } }
220
+ elseif valueType == "UDim" then
221
+ return { type = "UDim", value = { value.Scale, value.Offset } }
222
+ elseif valueType == "BrickColor" then
223
+ return { type = "BrickColor", name = value.Name, value = value.Number }
224
+ elseif valueType == "EnumItem" then
225
+ return { type = "EnumItem", enum = tostring(value.EnumType), name = value.Name, value = value.Value }
226
+ elseif valueType == "Instance" then
227
+ return { type = "Instance", className = value.ClassName, path = value:GetFullName() }
228
+ else
229
+ return PlaytestRunner._unsupported(valueType, tostring(value))
230
+ end
231
+ end
232
+
233
+ function PlaytestRunner._serializeTable(value: { [any]: any }, depth: number, seen: { [any]: boolean }): any
234
+ local count = 0
235
+ for _ in value do
236
+ count += 1
237
+ end
238
+
239
+ if count == #value then
240
+ local array = {}
241
+ for index = 1, count do
242
+ array[index] = PlaytestRunner._serializeValue(value[index], depth + 1, seen)
243
+ end
244
+ return array
245
+ end
246
+
247
+ local map: { [string]: any } = {}
248
+ for key, item in value do
249
+ map[if type(key) == "string" then key else tostring(key)] =
250
+ PlaytestRunner._serializeValue(item, depth + 1, seen)
251
+ end
252
+ return map
253
+ end
254
+
255
+ function PlaytestRunner._unsupported(typeName: string, text: string): { [string]: any }
256
+ return { type = "Unsupported", typeName = typeName, toString = text }
257
+ end
258
+
259
+ -- Planted as a Script it runs; in the test place it is a ModuleScript specs require
260
+ if script:IsA("Script") then
261
+ task.spawn(PlaytestRunner.runAsync, script, game:GetService("StudioTestService"), game:GetService("Players"))
262
+ end
263
+
264
+ return PlaytestRunner
@@ -0,0 +1,71 @@
1
+ --!strict
2
+ --[[
3
+ @class playtest-runner.spec.lua
4
+ ]]
5
+
6
+ local require = require(script.Parent.loader).load(script)
7
+
8
+ local Jest = require("Jest")
9
+ local PlaytestRunner = require("playtest-runner")
10
+
11
+ local describe = Jest.Globals.describe
12
+ local expect = Jest.Globals.expect
13
+ local it = Jest.Globals.it
14
+
15
+ local function setup(testArgs: any)
16
+ local ended = {}
17
+ local runner = Instance.new("Folder")
18
+ runner:SetAttribute("RunnerId", "runner-1")
19
+
20
+ local studioTestService = {
21
+ GetTestArgs = function()
22
+ return testArgs
23
+ end,
24
+ EndTest = function(_self, value)
25
+ table.insert(ended, value)
26
+ end,
27
+ }
28
+
29
+ return {
30
+ runner = runner,
31
+ studioTestService = studioTestService,
32
+ ended = ended,
33
+ Destroy = function()
34
+ runner:Destroy()
35
+ end,
36
+ }
37
+ end
38
+
39
+ describe("PlaytestRunner.runAsync()", function()
40
+ it("should do nothing in a playtest it was not planted for", function()
41
+ local controller = setup({ studioBridgeRunnerId = "someone-else" })
42
+
43
+ PlaytestRunner.runAsync(controller.runner, controller.studioTestService, game:GetService("Players"))
44
+
45
+ expect(controller.ended).toEqual({})
46
+ controller:Destroy()
47
+ end)
48
+
49
+ it("should end the playtest with a load error when the code module is missing", function()
50
+ local controller = setup({ studioBridgeRunnerId = "runner-1" })
51
+
52
+ PlaytestRunner.runAsync(controller.runner, controller.studioTestService, game:GetService("Players"))
53
+
54
+ expect(#controller.ended).toEqual(1)
55
+ expect(controller.ended[1].success).toEqual(false)
56
+ expect(controller.ended[1].code).toEqual("SCRIPT_LOAD_ERROR")
57
+ controller:Destroy()
58
+ end)
59
+ end)
60
+
61
+ describe("PlaytestRunner._serializeReturnValues()", function()
62
+ it("should keep a nil in its position", function()
63
+ local packed = table.pack(true, 1, nil, Vector3.new(1, 2, 3))
64
+
65
+ expect(PlaytestRunner._serializeReturnValues(packed)).toEqual({
66
+ 1,
67
+ { type = "Nil" },
68
+ { type = "Vector3", value = { 1, 2, 3 } },
69
+ })
70
+ end)
71
+ end)
@@ -0,0 +1,139 @@
1
+ --!strict
2
+ --[=[
3
+ Action that runs a script in a fresh playtest's server and answers with
4
+ `scriptComplete`, the same reply as `execute`.
5
+
6
+ It does not need the playtest's own plugin sessions, so it works whether or
7
+ not Studio loads user plugins into playtests.
8
+
9
+ - Compiles the code first, so a syntax error fails here without starting a
10
+ playtest.
11
+ - Plants the runner source the bridge sends as a Script in
12
+ ServerScriptService, with the code as a ModuleScript named `Code` under it.
13
+ The playtest copies the edit DataModel, so the runner starts in its server,
14
+ runs the code and ends the playtest with the result.
15
+ - Removes the runner from the edit DataModel once the playtest ends.
16
+
17
+ Request: `{ type: "runPlaytestScript", payload: { mode: "play" | "run", script, runnerSource, timeoutSec, args? } }`
18
+ Response: `{ type: "scriptComplete", payload: { success, output, returnValues?, error?, code? } }`
19
+
20
+ @class RunPlaytestScriptAction
21
+ ]=]
22
+
23
+ local RunPlaytestScriptAction = {}
24
+
25
+ type SendMessage = (message: { [string]: any }) -> ()
26
+
27
+ --[=[
28
+ Registers the `runPlaytestScript` handler. The reply waits for the playtest to
29
+ end, so it needs `sendMessage`.
30
+ ]=]
31
+ function RunPlaytestScriptAction.register(router: any, sendMessage: SendMessage?)
32
+ router:setResponseType("runPlaytestScript", "scriptComplete")
33
+ router:register(
34
+ "runPlaytestScript",
35
+ function(payload: { [string]: any }, requestId: string, sessionId: string): { [string]: any }?
36
+ local mode = payload.mode
37
+ if mode ~= "play" and mode ~= "run" then
38
+ error(`Unknown playtest mode: {tostring(mode)}`)
39
+ end
40
+
41
+ local code = payload.script
42
+ local runnerSource = payload.runnerSource
43
+ local timeoutSec = payload.timeoutSec
44
+ if type(code) ~= "string" or type(runnerSource) ~= "string" or type(timeoutSec) ~= "number" then
45
+ error("Missing script, runnerSource or timeoutSec in runPlaytestScript request")
46
+ end
47
+
48
+ local compileErr = RunPlaytestScriptAction._getCompileError(router, code)
49
+ if compileErr then
50
+ return { success = false, error = compileErr, code = "SCRIPT_LOAD_ERROR", output = {} }
51
+ end
52
+
53
+ if not sendMessage then
54
+ error("Running a playtest script requires a sendMessage callback")
55
+ end
56
+
57
+ task.spawn(function()
58
+ local result = RunPlaytestScriptAction._runAsync(mode, code, runnerSource, timeoutSec, payload.args)
59
+ sendMessage({
60
+ type = "scriptComplete",
61
+ sessionId = sessionId,
62
+ requestId = if requestId ~= "" then requestId else nil,
63
+ payload = result,
64
+ })
65
+ end)
66
+
67
+ -- Replied through sendMessage, so the router must not reply as well
68
+ return nil
69
+ end
70
+ )
71
+ end
72
+
73
+ --[[
74
+ Returns why the code does not compile, or nil when it does. Routers from
75
+ older plugins have no Compile, and the edit DataModel always has loadstring.
76
+ ]]
77
+ function RunPlaytestScriptAction._getCompileError(router: any, code: string): string?
78
+ local fn, compileErr
79
+ if type(router.Compile) == "function" then
80
+ fn, compileErr = router:Compile(code)
81
+ else
82
+ fn, compileErr = (loadstring :: any)(code)
83
+ end
84
+
85
+ if fn then
86
+ return nil
87
+ end
88
+ return if compileErr then tostring(compileErr) else "Failed to compile script"
89
+ end
90
+
91
+ function RunPlaytestScriptAction._runAsync(
92
+ mode: string,
93
+ code: string,
94
+ runnerSource: string,
95
+ timeoutSec: number,
96
+ args: { string }?
97
+ ): { [string]: any }
98
+ local runnerId = game:GetService("HttpService"):GenerateGUID(false)
99
+
100
+ local runner = Instance.new("Script")
101
+ runner.Name = "StudioBridgePlaytestRunner"
102
+ runner.Source = runnerSource
103
+ runner:SetAttribute("RunnerId", runnerId)
104
+
105
+ local codeModule = Instance.new("ModuleScript")
106
+ codeModule.Name = "Code"
107
+ -- Wrapping on the first line keeps a top-level `return` legal and line numbers unchanged
108
+ codeModule.Source = `return function(...) {code}\nend`
109
+ codeModule.Parent = runner
110
+
111
+ runner.Parent = game:GetService("ServerScriptService")
112
+
113
+ local ok, result = pcall(function()
114
+ local studioTestService = game:GetService("StudioTestService") :: any
115
+ local testArgs = {
116
+ studioBridgeRunnerId = runnerId,
117
+ studioBridgeTimeoutSec = timeoutSec,
118
+ studioBridgeScriptArgs = args,
119
+ studioBridgeWaitForPlayer = mode == "play",
120
+ }
121
+ if mode == "play" then
122
+ return studioTestService:ExecutePlayModeAsync(testArgs)
123
+ else
124
+ return studioTestService:ExecuteRunModeAsync(testArgs)
125
+ end
126
+ end)
127
+
128
+ runner:Destroy()
129
+
130
+ if not ok then
131
+ return { success = false, error = `Playtest failed to start: {result}`, output = {} }
132
+ end
133
+ if type(result) ~= "table" then
134
+ return { success = false, error = "Playtest was stopped before the script finished", output = {} }
135
+ end
136
+ return result
137
+ end
138
+
139
+ return RunPlaytestScriptAction
@@ -0,0 +1,43 @@
1
+ --!strict
2
+ --[[
3
+ @class run-playtest-script.spec.lua
4
+ ]]
5
+
6
+ local require = require(script.Parent.loader).load(script)
7
+
8
+ local ActionRouter = require("ActionRouter")
9
+ local Jest = require("Jest")
10
+ local RunPlaytestScriptAction = require("run-playtest-script")
11
+
12
+ local describe = Jest.Globals.describe
13
+ local expect = Jest.Globals.expect
14
+ local it = Jest.Globals.it
15
+
16
+ local function dispatch(payload: { [string]: any }): any
17
+ local router = ActionRouter.new()
18
+ RunPlaytestScriptAction.register(router, function() end)
19
+
20
+ return router:Dispatch({
21
+ type = "runPlaytestScript",
22
+ sessionId = "session-1",
23
+ requestId = "req-1",
24
+ payload = payload,
25
+ })
26
+ end
27
+
28
+ describe("runPlaytestScript", function()
29
+ it("should fail a script that does not compile without starting a playtest", function()
30
+ local response = dispatch({ mode = "run", script = "local x = = 1", runnerSource = "", timeoutSec = 10 })
31
+
32
+ expect(response.type).toEqual("scriptComplete")
33
+ expect(response.payload.success).toEqual(false)
34
+ expect(response.payload.code).toEqual("SCRIPT_LOAD_ERROR")
35
+ end)
36
+
37
+ it("should reject an unknown mode", function()
38
+ local response = dispatch({ mode = "nope", script = "return 1", runnerSource = "", timeoutSec = 10 })
39
+
40
+ expect(response.type).toEqual("error")
41
+ expect(response.payload.message).toEqual(expect.stringContaining("Unknown playtest mode"))
42
+ end)
43
+ end)