@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,239 @@
1
+ --!strict
2
+ --[[
3
+ @class StudioBridgeConnection.spec.lua
4
+ ]]
5
+
6
+ local require = require(script.Parent.loader).load(script)
7
+
8
+ local HttpService = game:GetService("HttpService")
9
+
10
+ local ActionRouter = require("ActionRouter")
11
+ local Jest = require("Jest")
12
+ local StudioBridgeConnection = require("StudioBridgeConnection")
13
+ local StudioBridgeLogUtils = require("StudioBridgeLogUtils")
14
+
15
+ local describe = Jest.Globals.describe
16
+ local expect = Jest.Globals.expect
17
+ local it = Jest.Globals.it
18
+
19
+ local REGISTER_PAYLOAD = table.freeze({
20
+ pluginVersion = "test",
21
+ state = "Edit",
22
+ })
23
+
24
+ local function createFakeSignal(): any
25
+ local handlers: { (...any) -> () } = {}
26
+ return {
27
+ Connect = function(_self, handler)
28
+ table.insert(handlers, handler)
29
+ return {
30
+ Disconnect = function()
31
+ local index = table.find(handlers, handler)
32
+ if index then
33
+ table.remove(handlers, index)
34
+ end
35
+ end,
36
+ }
37
+ end,
38
+ Fire = function(_self, ...)
39
+ for _, handler in table.clone(handlers) do
40
+ handler(...)
41
+ end
42
+ end,
43
+ GetHandlerCount = function()
44
+ return #handlers
45
+ end,
46
+ }
47
+ end
48
+
49
+ local function setup(maxMessageBytes: number?): any
50
+ local sentData: { string } = {}
51
+ local webSocket: any = {
52
+ closeCount = 0,
53
+ MessageReceived = createFakeSignal(),
54
+ Closed = createFakeSignal(),
55
+ }
56
+
57
+ function webSocket.Send(_self, data: string)
58
+ table.insert(sentData, data)
59
+ end
60
+
61
+ function webSocket.Close(self)
62
+ self.closeCount += 1
63
+ end
64
+
65
+ local router = ActionRouter.new()
66
+ local connection = StudioBridgeConnection.new({
67
+ webSocket = webSocket :: any,
68
+ router = router,
69
+ sessionId = "session-1",
70
+ registerPayload = REGISTER_PAYLOAD,
71
+ maxMessageBytes = maxMessageBytes,
72
+ })
73
+
74
+ local controller = {
75
+ webSocket = webSocket,
76
+ router = router,
77
+ connection = connection,
78
+ receive = function(message: { [string]: any })
79
+ webSocket.MessageReceived:Fire(HttpService:JSONEncode(message))
80
+ end,
81
+ getSent = function(): { any }
82
+ local messages = {}
83
+ for _, data in sentData do
84
+ table.insert(messages, HttpService:JSONDecode(data))
85
+ end
86
+ return messages
87
+ end,
88
+ clearSent = function()
89
+ table.clear(sentData)
90
+ end,
91
+ Destroy = function(_self)
92
+ connection:Destroy()
93
+ end,
94
+ }
95
+
96
+ return controller
97
+ end
98
+
99
+ describe("StudioBridgeConnection.new()", function()
100
+ it("should register, then send a heartbeat", function()
101
+ local controller = setup()
102
+
103
+ local sent = controller.getSent()
104
+
105
+ expect(#sent).toEqual(2)
106
+ expect(sent[1]).toEqual({
107
+ type = "register",
108
+ sessionId = "session-1",
109
+ payload = { pluginVersion = "test", state = "Edit" },
110
+ })
111
+ expect(sent[2].type).toEqual("heartbeat")
112
+ expect(sent[2].sessionId).toEqual("session-1")
113
+ expect(sent[2].payload.state).toEqual("Edit")
114
+ expect(sent[2].payload.pendingRequests).toEqual(0)
115
+ expect(type(sent[2].payload.uptimeMs)).toEqual("number")
116
+ expect(controller.connection:IsOpen()).toEqual(true)
117
+
118
+ controller:Destroy()
119
+ end)
120
+ end)
121
+
122
+ describe("StudioBridgeConnection message handling", function()
123
+ it("should dispatch a message and send back the response", function()
124
+ local controller = setup()
125
+ controller.router:register("ping", function(payload)
126
+ return { echo = payload.value }
127
+ end)
128
+ controller.clearSent()
129
+
130
+ controller.receive({ type = "ping", sessionId = "session-1", requestId = "req-1", payload = { value = 3 } })
131
+
132
+ expect(controller.getSent()).toEqual({
133
+ {
134
+ type = "pingResult",
135
+ sessionId = "session-1",
136
+ requestId = "req-1",
137
+ payload = { echo = 3 },
138
+ },
139
+ })
140
+
141
+ controller:Destroy()
142
+ end)
143
+
144
+ it("should answer a reply over the size limit with RESULT_TOO_LARGE instead", function()
145
+ local controller = setup(1000)
146
+ controller.router:register("dump", function()
147
+ return { data = string.rep("a", 2000) }
148
+ end)
149
+ controller.clearSent()
150
+
151
+ controller.receive({ type = "dump", sessionId = "session-1", requestId = "req-1", payload = {} })
152
+
153
+ local sent = controller.getSent()
154
+ expect(#sent).toEqual(1)
155
+ expect(sent[1].type).toEqual("error")
156
+ expect(sent[1].requestId).toEqual("req-1")
157
+ expect(sent[1].payload.code).toEqual("RESULT_TOO_LARGE")
158
+ expect(controller.connection:IsOpen()).toEqual(true)
159
+
160
+ controller:Destroy()
161
+ end)
162
+
163
+ it("should send nothing when the handler returns nil", function()
164
+ local controller = setup()
165
+ controller.router:register("quiet", function()
166
+ return nil
167
+ end)
168
+ controller.clearSent()
169
+
170
+ controller.receive({ type = "quiet", sessionId = "session-1", payload = {} })
171
+
172
+ expect(controller.getSent()).toEqual({})
173
+
174
+ controller:Destroy()
175
+ end)
176
+
177
+ it("should ignore a message that is not JSON", function()
178
+ local controller = setup()
179
+ controller.clearSent()
180
+
181
+ controller.webSocket.MessageReceived:Fire("not json")
182
+
183
+ expect(controller.getSent()).toEqual({})
184
+ expect(controller.connection:IsOpen()).toEqual(true)
185
+
186
+ controller:Destroy()
187
+ end)
188
+
189
+ it("should close the socket on shutdown and stop sending", function()
190
+ local controller = setup()
191
+ controller.clearSent()
192
+
193
+ controller.receive({ type = "shutdown", sessionId = "session-1", payload = {} })
194
+ controller.connection:Send({ type = "late" })
195
+
196
+ expect(controller.webSocket.closeCount).toEqual(1)
197
+ expect(controller.connection:IsOpen()).toEqual(false)
198
+ expect(controller.getSent()).toEqual({})
199
+
200
+ controller:Destroy()
201
+ end)
202
+ end)
203
+
204
+ describe("StudioBridgeConnection socket close", function()
205
+ it("should stop listening once the socket closes", function()
206
+ local controller = setup()
207
+
208
+ controller.webSocket.Closed:Fire()
209
+
210
+ expect(controller.connection:IsOpen()).toEqual(false)
211
+ expect(controller.webSocket.MessageReceived.GetHandlerCount()).toEqual(0)
212
+ expect(controller.webSocket.Closed.GetHandlerCount()).toEqual(0)
213
+
214
+ controller:Destroy()
215
+ end)
216
+
217
+ it("should end verbose logging with the command that asked for it", function()
218
+ local controller = setup()
219
+ StudioBridgeLogUtils.setVerbose(true)
220
+
221
+ controller.webSocket.Closed:Fire()
222
+
223
+ expect(StudioBridgeLogUtils.isVerbose()).toEqual(false)
224
+
225
+ controller:Destroy()
226
+ end)
227
+ end)
228
+
229
+ describe("StudioBridgeConnection:Destroy()", function()
230
+ it("should disconnect from the socket without closing it", function()
231
+ local controller = setup()
232
+
233
+ controller:Destroy()
234
+
235
+ expect(controller.connection:IsOpen()).toEqual(false)
236
+ expect(controller.webSocket.closeCount).toEqual(0)
237
+ expect(controller.webSocket.MessageReceived.GetHandlerCount()).toEqual(0)
238
+ end)
239
+ end)
@@ -0,0 +1,53 @@
1
+ --!strict
2
+ --[=[
3
+ Plugin output, kept quiet unless the command talking to the plugin ran with
4
+ --verbose. Real failures warn regardless.
5
+
6
+ @class StudioBridgeLogUtils
7
+ ]=]
8
+
9
+ local StudioBridgeLogUtils = {}
10
+
11
+ --[=[
12
+ Prefix on every line the plugin writes, so its own output can be told
13
+ apart from the place's.
14
+
15
+ @prop PREFIX string
16
+ @within StudioBridgeLogUtils
17
+ ]=]
18
+ StudioBridgeLogUtils.PREFIX = "[StudioBridge]"
19
+
20
+ StudioBridgeLogUtils._isVerbose = false
21
+
22
+ --[=[
23
+ Sets whether diagnostic output is printed. The bridge sends this with every
24
+ `syncActions`, so it follows the --verbose flag of the current command.
25
+ ]=]
26
+ function StudioBridgeLogUtils.setVerbose(isVerbose: boolean)
27
+ StudioBridgeLogUtils._isVerbose = isVerbose
28
+ end
29
+
30
+ --[=[
31
+ Returns whether diagnostic output is printed.
32
+ ]=]
33
+ function StudioBridgeLogUtils.isVerbose(): boolean
34
+ return StudioBridgeLogUtils._isVerbose
35
+ end
36
+
37
+ --[=[
38
+ Prints diagnostic output, only while verbose.
39
+ ]=]
40
+ function StudioBridgeLogUtils.logVerbose(message: string)
41
+ if StudioBridgeLogUtils._isVerbose then
42
+ print(`{StudioBridgeLogUtils.PREFIX} {message}`)
43
+ end
44
+ end
45
+
46
+ --[=[
47
+ Warns about a real failure, whether or not verbose is on.
48
+ ]=]
49
+ function StudioBridgeLogUtils.warn(message: string)
50
+ warn(`{StudioBridgeLogUtils.PREFIX} {message}`)
51
+ end
52
+
53
+ return StudioBridgeLogUtils
@@ -0,0 +1,27 @@
1
+ --!strict
2
+ --[[
3
+ @class StudioBridgeLogUtils.spec.lua
4
+ ]]
5
+
6
+ local require = require(script.Parent.loader).load(script)
7
+
8
+ local Jest = require("Jest")
9
+ local StudioBridgeLogUtils = require("StudioBridgeLogUtils")
10
+
11
+ local describe = Jest.Globals.describe
12
+ local expect = Jest.Globals.expect
13
+ local it = Jest.Globals.it
14
+
15
+ describe("StudioBridgeLogUtils.setVerbose()", function()
16
+ it("should start quiet", function()
17
+ expect(StudioBridgeLogUtils.isVerbose()).toEqual(false)
18
+ end)
19
+
20
+ it("should toggle verbose output", function()
21
+ StudioBridgeLogUtils.setVerbose(true)
22
+ expect(StudioBridgeLogUtils.isVerbose()).toEqual(true)
23
+
24
+ StudioBridgeLogUtils.setVerbose(false)
25
+ expect(StudioBridgeLogUtils.isVerbose()).toEqual(false)
26
+ end)
27
+ end)
@@ -0,0 +1,164 @@
1
+ --!strict
2
+ --[=[
3
+ Identifies this plugin instance to the bridge: which place it is in, which
4
+ DataModel context it runs in, and what it can do.
5
+
6
+ @class StudioBridgeSessionUtils
7
+ ]=]
8
+
9
+ local RunService = game:GetService("RunService")
10
+
11
+ local PLUGIN_VERSION = "{{PLUGIN_VERSION}}"
12
+ local MAX_SLUG_LENGTH = 24
13
+ local NONCE_VALUE_NAME = "StudioBridgeNonce"
14
+ local LAUNCH_ID_ATTRIBUTE = "StudioBridgeSessionId"
15
+
16
+ local StudioBridgeSessionUtils = {}
17
+
18
+ export type PluginContext = "edit" | "client" | "server"
19
+
20
+ export type PlaytestArgs = {
21
+ port: number,
22
+ instanceId: string,
23
+ multiplayer: boolean,
24
+ }
25
+
26
+ --[=[
27
+ Every message type the plugin can handle. Most arrive as action source pushed
28
+ by the bridge right after registering, but the plugin advertises them up front.
29
+
30
+ @prop CAPABILITIES { string }
31
+ @within StudioBridgeSessionUtils
32
+ ]=]
33
+ StudioBridgeSessionUtils.CAPABILITIES = table.freeze({
34
+ "registerAction",
35
+ "syncActions",
36
+ "heartbeat",
37
+ "execute",
38
+ "queryState",
39
+ "captureScreenshot",
40
+ "queryDataModel",
41
+ "queryLogs",
42
+ "exportInstances",
43
+ "importInstances",
44
+ "findInstances",
45
+ "grepScripts",
46
+ "startPlaytest",
47
+ "endPlaytest",
48
+ })
49
+
50
+ --[=[
51
+ Returns the DataModel context this plugin instance runs in.
52
+ ]=]
53
+ function StudioBridgeSessionUtils.getContext(): PluginContext
54
+ if not RunService:IsRunning() then
55
+ return "edit"
56
+ elseif RunService:IsClient() then
57
+ return "client"
58
+ else
59
+ return "server"
60
+ end
61
+ end
62
+
63
+ function StudioBridgeSessionUtils._slugify(text: string, fallback: string): string
64
+ local slug = string.lower(text)
65
+ slug = string.gsub(slug, "[^%w]+", "-")
66
+ slug = string.gsub(slug, "^%-+", "")
67
+ slug = string.sub(slug, 1, MAX_SLUG_LENGTH)
68
+ slug = string.gsub(slug, "%-+$", "")
69
+ return if slug == "" then fallback else slug
70
+ end
71
+
72
+ --[=[
73
+ Returns a short, readable id for the open place: its name as a slug plus
74
+ `nonce`, which tells apart two Studios with the same place open.
75
+ ]=]
76
+ function StudioBridgeSessionUtils.getInstanceId(placeName: string?, nonce: string): string
77
+ local name = string.gsub(placeName or "", "%.rbxl[x]?$", "")
78
+ return `{StudioBridgeSessionUtils._slugify(name, "place")}-{nonce}`
79
+ end
80
+
81
+ --[=[
82
+ Returns the nonce stored under `container`, creating it on first use. The
83
+ value is not archivable, so it lasts as long as the DataModel: plugin reloads
84
+ keep their session id, and a fresh Studio gets a new one.
85
+ ]=]
86
+ function StudioBridgeSessionUtils.getOrCreateNonce(container: Instance, createNonce: () -> string): string
87
+ local existing = container:FindFirstChild(NONCE_VALUE_NAME)
88
+ if existing and existing:IsA("StringValue") and existing.Value ~= "" then
89
+ return existing.Value
90
+ end
91
+
92
+ local value = Instance.new("StringValue")
93
+ value.Name = NONCE_VALUE_NAME
94
+ value.Archivable = false
95
+ value.Value = createNonce()
96
+ value.Parent = container
97
+ return value.Value
98
+ end
99
+
100
+ --[=[
101
+ Returns the session id for an instance id and context. The clients of a
102
+ multiplayer test share both, so they add their player's name.
103
+ ]=]
104
+ function StudioBridgeSessionUtils.getSessionId(instanceId: string, context: PluginContext, playerName: string?): string
105
+ if playerName then
106
+ return `{instanceId}-{context}-{StudioBridgeSessionUtils._slugify(playerName, "player")}`
107
+ end
108
+ return `{instanceId}-{context}`
109
+ end
110
+
111
+ --[=[
112
+ Returns the payload of the `register` message the plugin sends on connect.
113
+ ]=]
114
+ function StudioBridgeSessionUtils.createRegisterPayload(
115
+ instanceId: string,
116
+ context: PluginContext,
117
+ launchId: string?,
118
+ playerName: string?
119
+ ): { [string]: any }
120
+ return {
121
+ pluginVersion = PLUGIN_VERSION,
122
+ instanceId = instanceId,
123
+ context = context,
124
+ launchId = launchId,
125
+ playerName = playerName,
126
+ placeName = game.Name or "Unknown",
127
+ placeId = game.PlaceId,
128
+ gameId = game.GameId,
129
+ state = "Edit",
130
+ capabilities = table.clone(StudioBridgeSessionUtils.CAPABILITIES),
131
+ }
132
+ end
133
+
134
+ --[=[
135
+ Returns the launch id `process run` stamped onto the place it launched
136
+ Studio with, or nil for a place the user opened.
137
+ ]=]
138
+ function StudioBridgeSessionUtils.getLaunchId(workspace: Instance): string?
139
+ local launchId = workspace:GetAttribute(LAUNCH_ID_ATTRIBUTE)
140
+ return if type(launchId) == "string" then launchId else nil
141
+ end
142
+
143
+ --[=[
144
+ Returns what studio-bridge handed a playtest through its StudioTestService
145
+ test args: the bridge port, the instance id of the edit session that
146
+ started it, and whether it is a multiplayer test. Nil when studio-bridge
147
+ did not start the playtest.
148
+ ]=]
149
+ function StudioBridgeSessionUtils.getPlaytestArgs(testArgs: any): PlaytestArgs?
150
+ if
151
+ type(testArgs) == "table"
152
+ and type(testArgs.studioBridgePort) == "number"
153
+ and type(testArgs.studioBridgeInstanceId) == "string"
154
+ then
155
+ return {
156
+ port = testArgs.studioBridgePort,
157
+ instanceId = testArgs.studioBridgeInstanceId,
158
+ multiplayer = type(testArgs.studioBridgePlayers) == "number",
159
+ }
160
+ end
161
+ return nil
162
+ end
163
+
164
+ return StudioBridgeSessionUtils
@@ -0,0 +1,159 @@
1
+ --!strict
2
+ --[[
3
+ @class StudioBridgeSessionUtils.spec.lua
4
+ ]]
5
+
6
+ local require = require(script.Parent.loader).load(script)
7
+
8
+ local Jest = require("Jest")
9
+ local StudioBridgeSessionUtils = require("StudioBridgeSessionUtils")
10
+
11
+ local describe = Jest.Globals.describe
12
+ local expect = Jest.Globals.expect
13
+ local it = Jest.Globals.it
14
+
15
+ describe("StudioBridgeSessionUtils.getInstanceId()", function()
16
+ it("should slug the place name and append the nonce", function()
17
+ expect(StudioBridgeSessionUtils.getInstanceId("My Cool Place!", "3f9a")).toEqual("my-cool-place-3f9a")
18
+ end)
19
+
20
+ it("should drop a place file extension", function()
21
+ expect(StudioBridgeSessionUtils.getInstanceId("test-place.rbxl", "3f9a")).toEqual("test-place-3f9a")
22
+ expect(StudioBridgeSessionUtils.getInstanceId("Map.rbxlx", "3f9a")).toEqual("map-3f9a")
23
+ end)
24
+
25
+ it("should keep long names short", function()
26
+ expect(StudioBridgeSessionUtils.getInstanceId("An Extremely Long Place Name For Testing", "3f9a")).toEqual(
27
+ "an-extremely-long-place-3f9a"
28
+ )
29
+ end)
30
+
31
+ it("should fall back to place when the name has nothing usable", function()
32
+ expect(StudioBridgeSessionUtils.getInstanceId("!!!", "3f9a")).toEqual("place-3f9a")
33
+ expect(StudioBridgeSessionUtils.getInstanceId(nil, "3f9a")).toEqual("place-3f9a")
34
+ end)
35
+ end)
36
+
37
+ describe("StudioBridgeSessionUtils.getOrCreateNonce()", function()
38
+ it("should keep the first nonce for later calls", function()
39
+ local container = Instance.new("Folder")
40
+ local count = 0
41
+ local function createNonce(): string
42
+ count += 1
43
+ return "nonce" .. tostring(count)
44
+ end
45
+
46
+ expect(StudioBridgeSessionUtils.getOrCreateNonce(container, createNonce)).toEqual("nonce1")
47
+ expect(StudioBridgeSessionUtils.getOrCreateNonce(container, createNonce)).toEqual("nonce1")
48
+
49
+ container:Destroy()
50
+ end)
51
+
52
+ it("should not save the nonce with the place", function()
53
+ local container = Instance.new("Folder")
54
+
55
+ StudioBridgeSessionUtils.getOrCreateNonce(container, function()
56
+ return "3f9a"
57
+ end)
58
+
59
+ expect((container:FindFirstChild("StudioBridgeNonce") :: Instance).Archivable).toEqual(false)
60
+
61
+ container:Destroy()
62
+ end)
63
+ end)
64
+
65
+ describe("StudioBridgeSessionUtils.getLaunchId()", function()
66
+ it("should read the launch id stamped onto the workspace", function()
67
+ local container = Instance.new("Folder")
68
+ container:SetAttribute("StudioBridgeSessionId", "launch-1")
69
+
70
+ expect(StudioBridgeSessionUtils.getLaunchId(container)).toEqual("launch-1")
71
+
72
+ container:Destroy()
73
+ end)
74
+
75
+ it("should be nil for a place the user opened", function()
76
+ local container = Instance.new("Folder")
77
+
78
+ expect(StudioBridgeSessionUtils.getLaunchId(container)).toBeNil()
79
+
80
+ container:Destroy()
81
+ end)
82
+ end)
83
+
84
+ describe("StudioBridgeSessionUtils.getPlaytestArgs()", function()
85
+ it("should read the port and instance id studio-bridge passed in the test args", function()
86
+ expect(StudioBridgeSessionUtils.getPlaytestArgs({
87
+ studioBridgePlaytestId = "abc",
88
+ studioBridgePort = 38741,
89
+ studioBridgeInstanceId = "test-place-3f9a",
90
+ })).toEqual({ port = 38741, instanceId = "test-place-3f9a", multiplayer = false })
91
+ end)
92
+
93
+ it("should report a multiplayer test", function()
94
+ local args = StudioBridgeSessionUtils.getPlaytestArgs({
95
+ studioBridgePort = 38741,
96
+ studioBridgeInstanceId = "test-place-3f9a",
97
+ studioBridgePlayers = 2,
98
+ })
99
+
100
+ expect(args and args.multiplayer).toEqual(true)
101
+ end)
102
+
103
+ it("should return nil for a playtest studio-bridge did not start", function()
104
+ expect(StudioBridgeSessionUtils.getPlaytestArgs(nil)).toBeNil()
105
+ expect(StudioBridgeSessionUtils.getPlaytestArgs({ custom = true })).toBeNil()
106
+ end)
107
+ end)
108
+
109
+ describe("StudioBridgeSessionUtils.getSessionId()", function()
110
+ it("should append the context to the instance id", function()
111
+ expect(StudioBridgeSessionUtils.getSessionId("test-place-3f9a", "edit")).toEqual("test-place-3f9a-edit")
112
+ end)
113
+
114
+ it("should append the player of a multiplayer client", function()
115
+ expect(StudioBridgeSessionUtils.getSessionId("test-place-3f9a", "client", "Player2")).toEqual(
116
+ "test-place-3f9a-client-player2"
117
+ )
118
+ end)
119
+ end)
120
+
121
+ describe("StudioBridgeSessionUtils.getContext()", function()
122
+ it("should be edit when the game is not running", function()
123
+ expect(StudioBridgeSessionUtils.getContext()).toEqual("edit")
124
+ end)
125
+ end)
126
+
127
+ describe("StudioBridgeSessionUtils.createRegisterPayload()", function()
128
+ it("should describe the plugin and the open place", function()
129
+ local payload = StudioBridgeSessionUtils.createRegisterPayload("test-place-3f9a", "edit")
130
+
131
+ expect(payload.instanceId).toEqual("test-place-3f9a")
132
+ expect(payload.context).toEqual("edit")
133
+ expect(payload.state).toEqual("Edit")
134
+ expect(payload.placeId).toEqual(game.PlaceId)
135
+ expect(payload.gameId).toEqual(game.GameId)
136
+ expect(type(payload.pluginVersion)).toEqual("string")
137
+ expect(payload.capabilities).toEqual(StudioBridgeSessionUtils.CAPABILITIES)
138
+ end)
139
+
140
+ it("should carry the launch id of a Studio that process run launched", function()
141
+ local payload = StudioBridgeSessionUtils.createRegisterPayload("test-place-3f9a", "edit", "launch-1")
142
+
143
+ expect(payload.launchId).toEqual("launch-1")
144
+ end)
145
+
146
+ it("should carry the player of a multiplayer client", function()
147
+ local payload = StudioBridgeSessionUtils.createRegisterPayload("test-place-3f9a", "client", nil, "Player2")
148
+
149
+ expect(payload.playerName).toEqual("Player2")
150
+ end)
151
+
152
+ it("should hand out a capabilities list the caller can change", function()
153
+ local payload = StudioBridgeSessionUtils.createRegisterPayload("test-place-3f9a", "edit")
154
+
155
+ table.insert(payload.capabilities, "extra")
156
+
157
+ expect(table.find(StudioBridgeSessionUtils.CAPABILITIES, "extra")).toBeNil()
158
+ end)
159
+ end)