@heojeongbo/wirestage 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (489) hide show
  1. package/LICENSE +21 -0
  2. package/LICENSES.md +21 -0
  3. package/README.md +150 -2
  4. package/dist/app/playwright/index.d.ts +3 -0
  5. package/dist/app/playwright/index.d.ts.map +1 -0
  6. package/dist/app/playwright/index.js +2 -0
  7. package/dist/app/playwright/index.js.map +1 -0
  8. package/dist/app/playwright/lib/fixture.d.ts +61 -0
  9. package/dist/app/playwright/lib/fixture.d.ts.map +1 -0
  10. package/dist/app/playwright/lib/fixture.js +110 -0
  11. package/dist/app/playwright/lib/fixture.js.map +1 -0
  12. package/dist/connect.d.ts +7 -0
  13. package/dist/connect.d.ts.map +1 -0
  14. package/dist/connect.js +7 -0
  15. package/dist/connect.js.map +1 -0
  16. package/dist/entities/frame/@x/plugin.d.ts +9 -0
  17. package/dist/entities/frame/@x/plugin.d.ts.map +1 -0
  18. package/dist/entities/frame/@x/plugin.js +2 -0
  19. package/dist/entities/frame/@x/plugin.js.map +1 -0
  20. package/dist/entities/frame/index.d.ts +6 -0
  21. package/dist/entities/frame/index.d.ts.map +1 -0
  22. package/dist/entities/frame/index.js +4 -0
  23. package/dist/entities/frame/index.js.map +1 -0
  24. package/dist/entities/frame/lib/filter.d.ts +8 -0
  25. package/dist/entities/frame/lib/filter.d.ts.map +1 -0
  26. package/dist/entities/frame/lib/filter.js +62 -0
  27. package/dist/entities/frame/lib/filter.js.map +1 -0
  28. package/dist/entities/frame/lib/payload.d.ts +8 -0
  29. package/dist/entities/frame/lib/payload.d.ts.map +1 -0
  30. package/dist/entities/frame/lib/payload.js +42 -0
  31. package/dist/entities/frame/lib/payload.js.map +1 -0
  32. package/dist/entities/frame/lib/snapshot.d.ts +15 -0
  33. package/dist/entities/frame/lib/snapshot.d.ts.map +1 -0
  34. package/dist/entities/frame/lib/snapshot.js +90 -0
  35. package/dist/entities/frame/lib/snapshot.js.map +1 -0
  36. package/dist/entities/frame/lib/timeline.d.ts +23 -0
  37. package/dist/entities/frame/lib/timeline.d.ts.map +1 -0
  38. package/dist/entities/frame/lib/timeline.js +122 -0
  39. package/dist/entities/frame/lib/timeline.js.map +1 -0
  40. package/dist/entities/frame/model/frame.d.ts +182 -0
  41. package/dist/entities/frame/model/frame.d.ts.map +1 -0
  42. package/dist/entities/frame/model/frame.js +2 -0
  43. package/dist/entities/frame/model/frame.js.map +1 -0
  44. package/dist/entities/plugin/index.d.ts +9 -0
  45. package/dist/entities/plugin/index.d.ts.map +1 -0
  46. package/dist/entities/plugin/index.js +3 -0
  47. package/dist/entities/plugin/index.js.map +1 -0
  48. package/dist/entities/plugin/lib/define-plugin.d.ts +8 -0
  49. package/dist/entities/plugin/lib/define-plugin.d.ts.map +1 -0
  50. package/dist/entities/plugin/lib/define-plugin.js +9 -0
  51. package/dist/entities/plugin/lib/define-plugin.js.map +1 -0
  52. package/dist/entities/plugin/lib/named.d.ts +10 -0
  53. package/dist/entities/plugin/lib/named.d.ts.map +1 -0
  54. package/dist/entities/plugin/lib/named.js +17 -0
  55. package/dist/entities/plugin/lib/named.js.map +1 -0
  56. package/dist/entities/plugin/model/attachment.d.ts +18 -0
  57. package/dist/entities/plugin/model/attachment.d.ts.map +1 -0
  58. package/dist/entities/plugin/model/attachment.js +2 -0
  59. package/dist/entities/plugin/model/attachment.js.map +1 -0
  60. package/dist/entities/plugin/model/http.d.ts +126 -0
  61. package/dist/entities/plugin/model/http.d.ts.map +1 -0
  62. package/dist/entities/plugin/model/http.js +2 -0
  63. package/dist/entities/plugin/model/http.js.map +1 -0
  64. package/dist/entities/plugin/model/page.d.ts +100 -0
  65. package/dist/entities/plugin/model/page.d.ts.map +1 -0
  66. package/dist/entities/plugin/model/page.js +2 -0
  67. package/dist/entities/plugin/model/page.js.map +1 -0
  68. package/dist/entities/plugin/model/plugin.d.ts +83 -0
  69. package/dist/entities/plugin/model/plugin.d.ts.map +1 -0
  70. package/dist/entities/plugin/model/plugin.js +2 -0
  71. package/dist/entities/plugin/model/plugin.js.map +1 -0
  72. package/dist/entities/plugin/model/socket.d.ts +102 -0
  73. package/dist/entities/plugin/model/socket.d.ts.map +1 -0
  74. package/dist/entities/plugin/model/socket.js +2 -0
  75. package/dist/entities/plugin/model/socket.js.map +1 -0
  76. package/dist/entities/plugin/model/stream.d.ts +43 -0
  77. package/dist/entities/plugin/model/stream.d.ts.map +1 -0
  78. package/dist/entities/plugin/model/stream.js +2 -0
  79. package/dist/entities/plugin/model/stream.js.map +1 -0
  80. package/dist/features/connect/index.d.ts +5 -0
  81. package/dist/features/connect/index.d.ts.map +1 -0
  82. package/dist/features/connect/index.js +4 -0
  83. package/dist/features/connect/index.js.map +1 -0
  84. package/dist/features/connect/lib/calls.d.ts +9 -0
  85. package/dist/features/connect/lib/calls.d.ts.map +1 -0
  86. package/dist/features/connect/lib/calls.js +46 -0
  87. package/dist/features/connect/lib/calls.js.map +1 -0
  88. package/dist/features/connect/lib/client.d.ts +33 -0
  89. package/dist/features/connect/lib/client.d.ts.map +1 -0
  90. package/dist/features/connect/lib/client.js +147 -0
  91. package/dist/features/connect/lib/client.js.map +1 -0
  92. package/dist/features/connect/lib/create-connect.d.ts +14 -0
  93. package/dist/features/connect/lib/create-connect.d.ts.map +1 -0
  94. package/dist/features/connect/lib/create-connect.js +124 -0
  95. package/dist/features/connect/lib/create-connect.js.map +1 -0
  96. package/dist/features/connect/lib/faults.d.ts +18 -0
  97. package/dist/features/connect/lib/faults.d.ts.map +1 -0
  98. package/dist/features/connect/lib/faults.js +85 -0
  99. package/dist/features/connect/lib/faults.js.map +1 -0
  100. package/dist/features/connect/lib/protocol.d.ts +42 -0
  101. package/dist/features/connect/lib/protocol.d.ts.map +1 -0
  102. package/dist/features/connect/lib/protocol.js +228 -0
  103. package/dist/features/connect/lib/protocol.js.map +1 -0
  104. package/dist/features/connect/lib/record.d.ts +14 -0
  105. package/dist/features/connect/lib/record.d.ts.map +1 -0
  106. package/dist/features/connect/lib/record.js +36 -0
  107. package/dist/features/connect/lib/record.js.map +1 -0
  108. package/dist/features/connect/lib/recorder.d.ts +77 -0
  109. package/dist/features/connect/lib/recorder.d.ts.map +1 -0
  110. package/dist/features/connect/lib/recorder.js +209 -0
  111. package/dist/features/connect/lib/recorder.js.map +1 -0
  112. package/dist/features/connect/lib/rules.d.ts +51 -0
  113. package/dist/features/connect/lib/rules.d.ts.map +1 -0
  114. package/dist/features/connect/lib/rules.js +222 -0
  115. package/dist/features/connect/lib/rules.js.map +1 -0
  116. package/dist/features/connect/lib/serve.d.ts +10 -0
  117. package/dist/features/connect/lib/serve.d.ts.map +1 -0
  118. package/dist/features/connect/lib/serve.js +78 -0
  119. package/dist/features/connect/lib/serve.js.map +1 -0
  120. package/dist/features/connect/lib/status-of.d.ts +11 -0
  121. package/dist/features/connect/lib/status-of.d.ts.map +1 -0
  122. package/dist/features/connect/lib/status-of.js +22 -0
  123. package/dist/features/connect/lib/status-of.js.map +1 -0
  124. package/dist/features/connect/lib/stubs.d.ts +18 -0
  125. package/dist/features/connect/lib/stubs.d.ts.map +1 -0
  126. package/dist/features/connect/lib/stubs.js +174 -0
  127. package/dist/features/connect/lib/stubs.js.map +1 -0
  128. package/dist/features/connect/lib/universal.d.ts +19 -0
  129. package/dist/features/connect/lib/universal.d.ts.map +1 -0
  130. package/dist/features/connect/lib/universal.js +71 -0
  131. package/dist/features/connect/lib/universal.js.map +1 -0
  132. package/dist/features/connect/model/types.d.ts +247 -0
  133. package/dist/features/connect/model/types.d.ts.map +1 -0
  134. package/dist/features/connect/model/types.js +2 -0
  135. package/dist/features/connect/model/types.js.map +1 -0
  136. package/dist/features/rest/index.d.ts +5 -0
  137. package/dist/features/rest/index.d.ts.map +1 -0
  138. package/dist/features/rest/index.js +3 -0
  139. package/dist/features/rest/index.js.map +1 -0
  140. package/dist/features/rest/lib/calls.d.ts +8 -0
  141. package/dist/features/rest/lib/calls.d.ts.map +1 -0
  142. package/dist/features/rest/lib/calls.js +32 -0
  143. package/dist/features/rest/lib/calls.js.map +1 -0
  144. package/dist/features/rest/lib/create-rest.d.ts +8 -0
  145. package/dist/features/rest/lib/create-rest.d.ts.map +1 -0
  146. package/dist/features/rest/lib/create-rest.js +136 -0
  147. package/dist/features/rest/lib/create-rest.js.map +1 -0
  148. package/dist/features/rest/lib/path.d.ts +14 -0
  149. package/dist/features/rest/lib/path.d.ts.map +1 -0
  150. package/dist/features/rest/lib/path.js +58 -0
  151. package/dist/features/rest/lib/path.js.map +1 -0
  152. package/dist/features/rest/lib/reply.d.ts +25 -0
  153. package/dist/features/rest/lib/reply.d.ts.map +1 -0
  154. package/dist/features/rest/lib/reply.js +40 -0
  155. package/dist/features/rest/lib/reply.js.map +1 -0
  156. package/dist/features/rest/model/types.d.ts +74 -0
  157. package/dist/features/rest/model/types.d.ts.map +1 -0
  158. package/dist/features/rest/model/types.js +2 -0
  159. package/dist/features/rest/model/types.js.map +1 -0
  160. package/dist/features/sse/index.d.ts +4 -0
  161. package/dist/features/sse/index.d.ts.map +1 -0
  162. package/dist/features/sse/index.js +3 -0
  163. package/dist/features/sse/index.js.map +1 -0
  164. package/dist/features/sse/lib/create-sse.d.ts +9 -0
  165. package/dist/features/sse/lib/create-sse.d.ts.map +1 -0
  166. package/dist/features/sse/lib/create-sse.js +120 -0
  167. package/dist/features/sse/lib/create-sse.js.map +1 -0
  168. package/dist/features/sse/lib/encode.d.ts +8 -0
  169. package/dist/features/sse/lib/encode.d.ts.map +1 -0
  170. package/dist/features/sse/lib/encode.js +29 -0
  171. package/dist/features/sse/lib/encode.js.map +1 -0
  172. package/dist/features/sse/model/types.d.ts +62 -0
  173. package/dist/features/sse/model/types.d.ts.map +1 -0
  174. package/dist/features/sse/model/types.js +2 -0
  175. package/dist/features/sse/model/types.js.map +1 -0
  176. package/dist/features/webrtc/index.d.ts +3 -0
  177. package/dist/features/webrtc/index.d.ts.map +1 -0
  178. package/dist/features/webrtc/index.js +2 -0
  179. package/dist/features/webrtc/index.js.map +1 -0
  180. package/dist/features/webrtc/lib/create-webrtc.d.ts +9 -0
  181. package/dist/features/webrtc/lib/create-webrtc.d.ts.map +1 -0
  182. package/dist/features/webrtc/lib/create-webrtc.js +123 -0
  183. package/dist/features/webrtc/lib/create-webrtc.js.map +1 -0
  184. package/dist/features/webrtc/lib/rtc-page-module.d.ts +22 -0
  185. package/dist/features/webrtc/lib/rtc-page-module.d.ts.map +1 -0
  186. package/dist/features/webrtc/lib/rtc-page-module.js +161 -0
  187. package/dist/features/webrtc/lib/rtc-page-module.js.map +1 -0
  188. package/dist/features/webrtc/lib/to-frame.d.ts +9 -0
  189. package/dist/features/webrtc/lib/to-frame.d.ts.map +1 -0
  190. package/dist/features/webrtc/lib/to-frame.js +43 -0
  191. package/dist/features/webrtc/lib/to-frame.js.map +1 -0
  192. package/dist/features/webrtc/model/types.d.ts +70 -0
  193. package/dist/features/webrtc/model/types.d.ts.map +1 -0
  194. package/dist/features/webrtc/model/types.js +2 -0
  195. package/dist/features/webrtc/model/types.js.map +1 -0
  196. package/dist/features/websocket/index.d.ts +3 -0
  197. package/dist/features/websocket/index.d.ts.map +1 -0
  198. package/dist/features/websocket/index.js +2 -0
  199. package/dist/features/websocket/index.js.map +1 -0
  200. package/dist/features/websocket/lib/create-websocket.d.ts +9 -0
  201. package/dist/features/websocket/lib/create-websocket.d.ts.map +1 -0
  202. package/dist/features/websocket/lib/create-websocket.js +34 -0
  203. package/dist/features/websocket/lib/create-websocket.js.map +1 -0
  204. package/dist/features/websocket/lib/mock.d.ts +6 -0
  205. package/dist/features/websocket/lib/mock.d.ts.map +1 -0
  206. package/dist/features/websocket/lib/mock.js +96 -0
  207. package/dist/features/websocket/lib/mock.js.map +1 -0
  208. package/dist/features/websocket/lib/proxy.d.ts +9 -0
  209. package/dist/features/websocket/lib/proxy.d.ts.map +1 -0
  210. package/dist/features/websocket/lib/proxy.js +107 -0
  211. package/dist/features/websocket/lib/proxy.js.map +1 -0
  212. package/dist/features/websocket/lib/wire.d.ts +16 -0
  213. package/dist/features/websocket/lib/wire.d.ts.map +1 -0
  214. package/dist/features/websocket/lib/wire.js +46 -0
  215. package/dist/features/websocket/lib/wire.js.map +1 -0
  216. package/dist/features/websocket/model/types.d.ts +129 -0
  217. package/dist/features/websocket/model/types.d.ts.map +1 -0
  218. package/dist/features/websocket/model/types.js +2 -0
  219. package/dist/features/websocket/model/types.js.map +1 -0
  220. package/dist/index.d.ts +27 -0
  221. package/dist/index.d.ts.map +1 -0
  222. package/dist/index.js +16 -0
  223. package/dist/index.js.map +1 -0
  224. package/dist/playwright.d.ts +4 -0
  225. package/dist/playwright.d.ts.map +1 -0
  226. package/dist/playwright.js +2 -0
  227. package/dist/playwright.js.map +1 -0
  228. package/dist/rest.d.ts +3 -0
  229. package/dist/rest.d.ts.map +1 -0
  230. package/dist/rest.js +3 -0
  231. package/dist/rest.js.map +1 -0
  232. package/dist/shared/api/http-server/index.d.ts +3 -0
  233. package/dist/shared/api/http-server/index.d.ts.map +1 -0
  234. package/dist/shared/api/http-server/index.js +2 -0
  235. package/dist/shared/api/http-server/index.js.map +1 -0
  236. package/dist/shared/api/http-server/listen.d.ts +25 -0
  237. package/dist/shared/api/http-server/listen.d.ts.map +1 -0
  238. package/dist/shared/api/http-server/listen.js +44 -0
  239. package/dist/shared/api/http-server/listen.js.map +1 -0
  240. package/dist/shared/api/playwright/index.d.ts +2 -0
  241. package/dist/shared/api/playwright/index.d.ts.map +1 -0
  242. package/dist/shared/api/playwright/index.js +2 -0
  243. package/dist/shared/api/playwright/index.js.map +1 -0
  244. package/dist/shared/api/playwright/ports.d.ts +117 -0
  245. package/dist/shared/api/playwright/ports.d.ts.map +1 -0
  246. package/dist/shared/api/playwright/ports.js +11 -0
  247. package/dist/shared/api/playwright/ports.js.map +1 -0
  248. package/dist/shared/api/stream-server/index.d.ts +3 -0
  249. package/dist/shared/api/stream-server/index.d.ts.map +1 -0
  250. package/dist/shared/api/stream-server/index.js +2 -0
  251. package/dist/shared/api/stream-server/index.js.map +1 -0
  252. package/dist/shared/api/stream-server/stream-server.d.ts +43 -0
  253. package/dist/shared/api/stream-server/stream-server.d.ts.map +1 -0
  254. package/dist/shared/api/stream-server/stream-server.js +160 -0
  255. package/dist/shared/api/stream-server/stream-server.js.map +1 -0
  256. package/dist/shared/lib/async/arrivals.d.ts +31 -0
  257. package/dist/shared/lib/async/arrivals.d.ts.map +1 -0
  258. package/dist/shared/lib/async/arrivals.js +57 -0
  259. package/dist/shared/lib/async/arrivals.js.map +1 -0
  260. package/dist/shared/lib/async/async-queue.d.ts +23 -0
  261. package/dist/shared/lib/async/async-queue.d.ts.map +1 -0
  262. package/dist/shared/lib/async/async-queue.js +80 -0
  263. package/dist/shared/lib/async/async-queue.js.map +1 -0
  264. package/dist/shared/lib/async/deferred.d.ts +12 -0
  265. package/dist/shared/lib/async/deferred.d.ts.map +1 -0
  266. package/dist/shared/lib/async/deferred.js +34 -0
  267. package/dist/shared/lib/async/deferred.js.map +1 -0
  268. package/dist/shared/lib/async/index.d.ts +8 -0
  269. package/dist/shared/lib/async/index.d.ts.map +1 -0
  270. package/dist/shared/lib/async/index.js +5 -0
  271. package/dist/shared/lib/async/index.js.map +1 -0
  272. package/dist/shared/lib/async/run-all.d.ts +8 -0
  273. package/dist/shared/lib/async/run-all.d.ts.map +1 -0
  274. package/dist/shared/lib/async/run-all.js +22 -0
  275. package/dist/shared/lib/async/run-all.js.map +1 -0
  276. package/dist/shared/lib/bytes/bytes.d.ts +18 -0
  277. package/dist/shared/lib/bytes/bytes.d.ts.map +1 -0
  278. package/dist/shared/lib/bytes/bytes.js +48 -0
  279. package/dist/shared/lib/bytes/bytes.js.map +1 -0
  280. package/dist/shared/lib/bytes/index.d.ts +3 -0
  281. package/dist/shared/lib/bytes/index.d.ts.map +1 -0
  282. package/dist/shared/lib/bytes/index.js +2 -0
  283. package/dist/shared/lib/bytes/index.js.map +1 -0
  284. package/dist/shared/lib/clock/clock.d.ts +29 -0
  285. package/dist/shared/lib/clock/clock.d.ts.map +1 -0
  286. package/dist/shared/lib/clock/clock.js +85 -0
  287. package/dist/shared/lib/clock/clock.js.map +1 -0
  288. package/dist/shared/lib/clock/index.d.ts +3 -0
  289. package/dist/shared/lib/clock/index.d.ts.map +1 -0
  290. package/dist/shared/lib/clock/index.js +2 -0
  291. package/dist/shared/lib/clock/index.js.map +1 -0
  292. package/dist/shared/lib/cookies/index.d.ts +3 -0
  293. package/dist/shared/lib/cookies/index.d.ts.map +1 -0
  294. package/dist/shared/lib/cookies/index.js +2 -0
  295. package/dist/shared/lib/cookies/index.js.map +1 -0
  296. package/dist/shared/lib/cookies/set-cookie.d.ts +22 -0
  297. package/dist/shared/lib/cookies/set-cookie.d.ts.map +1 -0
  298. package/dist/shared/lib/cookies/set-cookie.js +89 -0
  299. package/dist/shared/lib/cookies/set-cookie.js.map +1 -0
  300. package/dist/shared/lib/envelope/envelope.d.ts +50 -0
  301. package/dist/shared/lib/envelope/envelope.d.ts.map +1 -0
  302. package/dist/shared/lib/envelope/envelope.js +111 -0
  303. package/dist/shared/lib/envelope/envelope.js.map +1 -0
  304. package/dist/shared/lib/envelope/index.d.ts +3 -0
  305. package/dist/shared/lib/envelope/index.d.ts.map +1 -0
  306. package/dist/shared/lib/envelope/index.js +2 -0
  307. package/dist/shared/lib/envelope/index.js.map +1 -0
  308. package/dist/shared/lib/errors/index.d.ts +3 -0
  309. package/dist/shared/lib/errors/index.d.ts.map +1 -0
  310. package/dist/shared/lib/errors/index.js +2 -0
  311. package/dist/shared/lib/errors/index.js.map +1 -0
  312. package/dist/shared/lib/errors/wirestage-error.d.ts +28 -0
  313. package/dist/shared/lib/errors/wirestage-error.d.ts.map +1 -0
  314. package/dist/shared/lib/errors/wirestage-error.js +16 -0
  315. package/dist/shared/lib/errors/wirestage-error.js.map +1 -0
  316. package/dist/shared/lib/id/id.d.ts +10 -0
  317. package/dist/shared/lib/id/id.d.ts.map +1 -0
  318. package/dist/shared/lib/id/id.js +26 -0
  319. package/dist/shared/lib/id/id.js.map +1 -0
  320. package/dist/shared/lib/id/index.d.ts +2 -0
  321. package/dist/shared/lib/id/index.d.ts.map +1 -0
  322. package/dist/shared/lib/id/index.js +2 -0
  323. package/dist/shared/lib/id/index.js.map +1 -0
  324. package/dist/shared/lib/logger/index.d.ts +3 -0
  325. package/dist/shared/lib/logger/index.d.ts.map +1 -0
  326. package/dist/shared/lib/logger/index.js +2 -0
  327. package/dist/shared/lib/logger/index.js.map +1 -0
  328. package/dist/shared/lib/logger/logger.d.ts +46 -0
  329. package/dist/shared/lib/logger/logger.d.ts.map +1 -0
  330. package/dist/shared/lib/logger/logger.js +67 -0
  331. package/dist/shared/lib/logger/logger.js.map +1 -0
  332. package/dist/shared/lib/match/index.d.ts +3 -0
  333. package/dist/shared/lib/match/index.d.ts.map +1 -0
  334. package/dist/shared/lib/match/index.js +2 -0
  335. package/dist/shared/lib/match/index.js.map +1 -0
  336. package/dist/shared/lib/match/url-matcher.d.ts +27 -0
  337. package/dist/shared/lib/match/url-matcher.d.ts.map +1 -0
  338. package/dist/shared/lib/match/url-matcher.js +88 -0
  339. package/dist/shared/lib/match/url-matcher.js.map +1 -0
  340. package/dist/sse.d.ts +3 -0
  341. package/dist/sse.d.ts.map +1 -0
  342. package/dist/sse.js +3 -0
  343. package/dist/sse.js.map +1 -0
  344. package/dist/webrtc.d.ts +3 -0
  345. package/dist/webrtc.d.ts.map +1 -0
  346. package/dist/webrtc.js +3 -0
  347. package/dist/webrtc.js.map +1 -0
  348. package/dist/websocket.d.ts +3 -0
  349. package/dist/websocket.d.ts.map +1 -0
  350. package/dist/websocket.js +3 -0
  351. package/dist/websocket.js.map +1 -0
  352. package/dist/widgets/stage/index.d.ts +3 -0
  353. package/dist/widgets/stage/index.d.ts.map +1 -0
  354. package/dist/widgets/stage/index.js +2 -0
  355. package/dist/widgets/stage/index.js.map +1 -0
  356. package/dist/widgets/stage/lib/attached-context.d.ts +10 -0
  357. package/dist/widgets/stage/lib/attached-context.d.ts.map +1 -0
  358. package/dist/widgets/stage/lib/attached-context.js +2 -0
  359. package/dist/widgets/stage/lib/attached-context.js.map +1 -0
  360. package/dist/widgets/stage/lib/create-stage.d.ts +12 -0
  361. package/dist/widgets/stage/lib/create-stage.d.ts.map +1 -0
  362. package/dist/widgets/stage/lib/create-stage.js +248 -0
  363. package/dist/widgets/stage/lib/create-stage.js.map +1 -0
  364. package/dist/widgets/stage/lib/http-router.d.ts +35 -0
  365. package/dist/widgets/stage/lib/http-router.d.ts.map +1 -0
  366. package/dist/widgets/stage/lib/http-router.js +455 -0
  367. package/dist/widgets/stage/lib/http-router.js.map +1 -0
  368. package/dist/widgets/stage/lib/page-host.d.ts +36 -0
  369. package/dist/widgets/stage/lib/page-host.d.ts.map +1 -0
  370. package/dist/widgets/stage/lib/page-host.js +240 -0
  371. package/dist/widgets/stage/lib/page-host.js.map +1 -0
  372. package/dist/widgets/stage/lib/page-runtime.d.ts +93 -0
  373. package/dist/widgets/stage/lib/page-runtime.d.ts.map +1 -0
  374. package/dist/widgets/stage/lib/page-runtime.js +247 -0
  375. package/dist/widgets/stage/lib/page-runtime.js.map +1 -0
  376. package/dist/widgets/stage/lib/reads.d.ts +21 -0
  377. package/dist/widgets/stage/lib/reads.d.ts.map +1 -0
  378. package/dist/widgets/stage/lib/reads.js +97 -0
  379. package/dist/widgets/stage/lib/reads.js.map +1 -0
  380. package/dist/widgets/stage/lib/response-stream.d.ts +9 -0
  381. package/dist/widgets/stage/lib/response-stream.d.ts.map +1 -0
  382. package/dist/widgets/stage/lib/response-stream.js +56 -0
  383. package/dist/widgets/stage/lib/response-stream.js.map +1 -0
  384. package/dist/widgets/stage/lib/socket-router.d.ts +25 -0
  385. package/dist/widgets/stage/lib/socket-router.d.ts.map +1 -0
  386. package/dist/widgets/stage/lib/socket-router.js +204 -0
  387. package/dist/widgets/stage/lib/socket-router.js.map +1 -0
  388. package/dist/widgets/stage/model/stage.d.ts +86 -0
  389. package/dist/widgets/stage/model/stage.d.ts.map +1 -0
  390. package/dist/widgets/stage/model/stage.js +2 -0
  391. package/dist/widgets/stage/model/stage.js.map +1 -0
  392. package/package.json +140 -5
  393. package/src/app/playwright/index.ts +7 -0
  394. package/src/app/playwright/lib/fixture.ts +201 -0
  395. package/src/connect.ts +6 -0
  396. package/src/entities/frame/@x/plugin.ts +8 -0
  397. package/src/entities/frame/index.ts +19 -0
  398. package/src/entities/frame/lib/filter.ts +58 -0
  399. package/src/entities/frame/lib/payload.ts +42 -0
  400. package/src/entities/frame/lib/snapshot.ts +105 -0
  401. package/src/entities/frame/lib/timeline.ts +147 -0
  402. package/src/entities/frame/model/frame.ts +191 -0
  403. package/src/entities/plugin/index.ts +36 -0
  404. package/src/entities/plugin/lib/define-plugin.ts +12 -0
  405. package/src/entities/plugin/lib/named.ts +21 -0
  406. package/src/entities/plugin/model/attachment.ts +18 -0
  407. package/src/entities/plugin/model/http.ts +147 -0
  408. package/src/entities/plugin/model/page.ts +110 -0
  409. package/src/entities/plugin/model/plugin.ts +96 -0
  410. package/src/entities/plugin/model/socket.ts +108 -0
  411. package/src/entities/plugin/model/stream.ts +43 -0
  412. package/src/features/connect/index.ts +23 -0
  413. package/src/features/connect/lib/calls.ts +58 -0
  414. package/src/features/connect/lib/client.ts +203 -0
  415. package/src/features/connect/lib/create-connect.ts +164 -0
  416. package/src/features/connect/lib/faults.ts +132 -0
  417. package/src/features/connect/lib/protocol.ts +321 -0
  418. package/src/features/connect/lib/record.ts +48 -0
  419. package/src/features/connect/lib/recorder.ts +306 -0
  420. package/src/features/connect/lib/rules.ts +385 -0
  421. package/src/features/connect/lib/serve.ts +114 -0
  422. package/src/features/connect/lib/status-of.ts +20 -0
  423. package/src/features/connect/lib/stubs.ts +282 -0
  424. package/src/features/connect/lib/universal.ts +100 -0
  425. package/src/features/connect/model/types.ts +305 -0
  426. package/src/features/rest/index.ts +23 -0
  427. package/src/features/rest/lib/calls.ts +31 -0
  428. package/src/features/rest/lib/create-rest.ts +169 -0
  429. package/src/features/rest/lib/path.ts +70 -0
  430. package/src/features/rest/lib/reply.ts +74 -0
  431. package/src/features/rest/model/types.ts +113 -0
  432. package/src/features/sse/index.ts +10 -0
  433. package/src/features/sse/lib/create-sse.ts +128 -0
  434. package/src/features/sse/lib/encode.ts +28 -0
  435. package/src/features/sse/model/types.ts +66 -0
  436. package/src/features/webrtc/index.ts +6 -0
  437. package/src/features/webrtc/lib/create-webrtc.ts +149 -0
  438. package/src/features/webrtc/lib/rtc-page-module.ts +189 -0
  439. package/src/features/webrtc/lib/to-frame.ts +63 -0
  440. package/src/features/webrtc/model/types.ts +80 -0
  441. package/src/features/websocket/index.ts +15 -0
  442. package/src/features/websocket/lib/create-websocket.ts +41 -0
  443. package/src/features/websocket/lib/mock.ts +114 -0
  444. package/src/features/websocket/lib/proxy.ts +141 -0
  445. package/src/features/websocket/lib/wire.ts +78 -0
  446. package/src/features/websocket/model/types.ts +130 -0
  447. package/src/index.ts +111 -0
  448. package/src/playwright.ts +8 -0
  449. package/src/rest.ts +2 -0
  450. package/src/shared/api/http-server/index.ts +2 -0
  451. package/src/shared/api/http-server/listen.ts +71 -0
  452. package/src/shared/api/playwright/index.ts +17 -0
  453. package/src/shared/api/playwright/ports.ts +145 -0
  454. package/src/shared/api/stream-server/index.ts +7 -0
  455. package/src/shared/api/stream-server/stream-server.ts +246 -0
  456. package/src/shared/lib/async/arrivals.ts +91 -0
  457. package/src/shared/lib/async/async-queue.ts +101 -0
  458. package/src/shared/lib/async/deferred.ts +38 -0
  459. package/src/shared/lib/async/index.ts +11 -0
  460. package/src/shared/lib/async/run-all.ts +19 -0
  461. package/src/shared/lib/bytes/bytes.ts +53 -0
  462. package/src/shared/lib/bytes/index.ts +9 -0
  463. package/src/shared/lib/clock/clock.ts +114 -0
  464. package/src/shared/lib/clock/index.ts +2 -0
  465. package/src/shared/lib/cookies/index.ts +2 -0
  466. package/src/shared/lib/cookies/set-cookie.ts +105 -0
  467. package/src/shared/lib/envelope/envelope.ts +133 -0
  468. package/src/shared/lib/envelope/index.ts +9 -0
  469. package/src/shared/lib/errors/index.ts +5 -0
  470. package/src/shared/lib/errors/wirestage-error.ts +50 -0
  471. package/src/shared/lib/id/id.ts +29 -0
  472. package/src/shared/lib/id/index.ts +1 -0
  473. package/src/shared/lib/logger/index.ts +12 -0
  474. package/src/shared/lib/logger/logger.ts +126 -0
  475. package/src/shared/lib/match/index.ts +6 -0
  476. package/src/shared/lib/match/url-matcher.ts +107 -0
  477. package/src/sse.ts +2 -0
  478. package/src/webrtc.ts +2 -0
  479. package/src/websocket.ts +2 -0
  480. package/src/widgets/stage/index.ts +9 -0
  481. package/src/widgets/stage/lib/attached-context.ts +10 -0
  482. package/src/widgets/stage/lib/create-stage.ts +305 -0
  483. package/src/widgets/stage/lib/http-router.ts +620 -0
  484. package/src/widgets/stage/lib/page-host.ts +375 -0
  485. package/src/widgets/stage/lib/page-runtime.ts +314 -0
  486. package/src/widgets/stage/lib/reads.ts +128 -0
  487. package/src/widgets/stage/lib/response-stream.ts +66 -0
  488. package/src/widgets/stage/lib/socket-router.ts +271 -0
  489. package/src/widgets/stage/model/stage.ts +108 -0
@@ -0,0 +1,63 @@
1
+ import type {
2
+ Direction,
3
+ FrameInit,
4
+ FrameKind,
5
+ FrameSource,
6
+ } from "../../../entities/frame/index.js";
7
+ import type { PageEntry, PageSource } from "../../../entities/plugin/index.js";
8
+ import { fromBase64 } from "../../../shared/lib/bytes/index.js";
9
+
10
+ interface Shape {
11
+ readonly kind: FrameKind;
12
+ readonly direction: Direction;
13
+ /** Who produced it: the app, the peer, or the stub that dropped it. */
14
+ readonly source: FrameSource;
15
+ }
16
+
17
+ /** Page entry types, as the page module emits them. */
18
+ const SHAPES: Readonly<Record<string, Shape>> = {
19
+ out: { kind: "message", direction: "out", source: "page" },
20
+ in: { kind: "message", direction: "in", source: "network" },
21
+ open: { kind: "lifecycle", direction: "none", source: "page" },
22
+ close: { kind: "lifecycle", direction: "none", source: "page" },
23
+ suppressed: { kind: "fault", direction: "in", source: "stub" },
24
+ blocked: { kind: "fault", direction: "out", source: "stub" },
25
+ };
26
+
27
+ /** An entry type nobody declared: the page runtime's own `error`. */
28
+ const BROKEN: Shape = { kind: "fault", direction: "none", source: "page" };
29
+
30
+ /**
31
+ * One page entry as a frame. A lifecycle frame says which `event` it was, a
32
+ * fault says its `reason`, as every protocol's do, and an unknown type (the
33
+ * runtime's own `error`) still lands as a fault instead of vanishing.
34
+ */
35
+ export function toFrame(
36
+ protocol: string,
37
+ entry: PageEntry,
38
+ origin: PageSource,
39
+ ): FrameInit {
40
+ const shape = SHAPES[entry.type] ?? BROKEN;
41
+ const label = entry.meta?.["label"];
42
+ return {
43
+ protocol,
44
+ kind: shape.kind,
45
+ direction: shape.direction,
46
+ endpoint: typeof label === "string" ? label : "",
47
+ // A message the test injected is the test's, not the peer's.
48
+ source: entry.meta?.["injected"] === true ? "test" : shape.source,
49
+ at: entry.at,
50
+ ...(entry.data === undefined
51
+ ? entry.text === undefined
52
+ ? {}
53
+ : { data: entry.text }
54
+ : { data: fromBase64(entry.data) }),
55
+ meta: {
56
+ ...entry.meta,
57
+ ...(shape.kind === "lifecycle" ? { event: entry.type } : {}),
58
+ ...(shape.kind === "fault" ? { reason: entry.type } : {}),
59
+ },
60
+ page: origin.page,
61
+ context: origin.context,
62
+ };
63
+ }
@@ -0,0 +1,80 @@
1
+ import type { Frame, FrameFilter } from "../../../entities/frame/index.js";
2
+ import type { PagePort } from "../../../shared/api/playwright/index.js";
3
+
4
+ export interface WebRtcOptions {
5
+ /**
6
+ * Data channel labels to record. Every channel when omitted. Recording a
7
+ * 60 Hz channel nobody asserts on costs a base64 copy per frame.
8
+ */
9
+ readonly labels?: readonly string[];
10
+ /** Directions to record. Both by default. */
11
+ readonly record?: readonly ("in" | "out")[];
12
+ /** Record channel open/close as lifecycle frames. Default true. */
13
+ readonly lifecycle?: boolean;
14
+ }
15
+
16
+ export type RtcDirection = "in" | "out" | "both";
17
+
18
+ export interface WebRtcApi {
19
+ /** Every WebRTC frame (messages, lifecycle, faults), narrowed by `filter`. */
20
+ frames(filter?: Omit<FrameFilter, "protocol">): Promise<Frame[]>;
21
+ /** Messages on one channel, oldest first. */
22
+ messages(
23
+ label: string,
24
+ options?: { readonly direction?: "in" | "out" },
25
+ ): Promise<Frame[]>;
26
+ /**
27
+ * Drop messages on `label` while the channel stays open — the lossy-link
28
+ * case no server-side knob can produce, because the server is behaving.
29
+ * `in` (the default) swallows what the peer sends the page; `out` swallows
30
+ * what the page sends. Injected messages still get through, so a test can
31
+ * silence the real peer and speak in its place.
32
+ *
33
+ * Returns a function that undoes exactly this call: the label stays
34
+ * suppressed for as long as another call on it is still in force.
35
+ */
36
+ suppress(
37
+ label: string,
38
+ options?: { readonly direction?: RtcDirection },
39
+ ): Promise<() => Promise<void>>;
40
+ /** Undo every suppression on `label`, or on every label. */
41
+ restore(label?: string): Promise<void>;
42
+ /**
43
+ * Deliver a message to the page as if the remote peer sent it, on every
44
+ * open channel with this label (or one page's). Returns how many channels
45
+ * received it.
46
+ */
47
+ inject(
48
+ label: string,
49
+ data: Uint8Array | string,
50
+ options?: { readonly page?: PagePort },
51
+ ): Promise<number>;
52
+ /**
53
+ * Resolve with the channel's open frame. Needs `lifecycle` recording, and
54
+ * says so at once when it is off.
55
+ */
56
+ waitForChannel(
57
+ label: string,
58
+ options?: { readonly timeout?: number },
59
+ ): Promise<Frame>;
60
+ }
61
+
62
+ /** The page module's fixed configuration. */
63
+ export interface RtcPageConfig {
64
+ readonly labels: readonly string[] | null;
65
+ readonly recordIn: boolean;
66
+ readonly recordOut: boolean;
67
+ readonly lifecycle: boolean;
68
+ }
69
+
70
+ /** The page module's live state, pushed to every page on change. */
71
+ export interface RtcPageState {
72
+ readonly suppressIn: readonly string[];
73
+ readonly blockOut: readonly string[];
74
+ }
75
+
76
+ export interface RtcInjectArgs {
77
+ readonly label: string;
78
+ readonly data?: string;
79
+ readonly text?: string;
80
+ }
@@ -0,0 +1,15 @@
1
+ export { websocket } from "./lib/create-websocket.js";
2
+ export type {
3
+ WebSocketApi,
4
+ WebSocketOptions,
5
+ WsCloseInfo,
6
+ WsCloseOptions,
7
+ WsConnection,
8
+ WsData,
9
+ WsMessage,
10
+ WsMock,
11
+ WsMockOptions,
12
+ WsProxy,
13
+ WsProxyConnection,
14
+ WsProxyOptions,
15
+ } from "./model/types.js";
@@ -0,0 +1,41 @@
1
+ import {
2
+ definePlugin,
3
+ type WirePlugin,
4
+ } from "../../../entities/plugin/index.js";
5
+ import type { WebSocketApi, WebSocketOptions } from "../model/types.js";
6
+ import { createMock } from "./mock.js";
7
+ import { createProxy } from "./proxy.js";
8
+
9
+ /**
10
+ * WebSockets: fake servers driven from the test, and pass-through proxies
11
+ * that record and can drop messages. Both are rules on the stage's socket
12
+ * router, which owns the browser's side of it.
13
+ */
14
+ export function websocket(
15
+ options: WebSocketOptions = {},
16
+ ): WirePlugin<"websocket", WebSocketApi> {
17
+ return definePlugin({
18
+ name: "websocket",
19
+ scope: "Ws",
20
+ setup(context) {
21
+ const { name } = context;
22
+ if (!options.lazy) context.sockets.prepare();
23
+ const api: WebSocketApi = {
24
+ mock: (url, mockOptions = {}) =>
25
+ createMock(context, name, url, mockOptions),
26
+ proxy: (url, proxyOptions = {}) =>
27
+ createProxy(context, name, url, proxyOptions),
28
+ async frames(filter = {}) {
29
+ await context.sync();
30
+ return context.timeline.frames({
31
+ protocol: name,
32
+ ...(filter.endpoint === undefined
33
+ ? {}
34
+ : { endpoint: filter.endpoint }),
35
+ });
36
+ },
37
+ };
38
+ return { api };
39
+ },
40
+ });
41
+ }
@@ -0,0 +1,114 @@
1
+ import type { PluginContext } from "../../../entities/plugin/index.js";
2
+ import {
3
+ createArrivals,
4
+ createDeferred,
5
+ } from "../../../shared/lib/async/index.js";
6
+ import type { UrlMatcher } from "../../../shared/lib/match/index.js";
7
+ import type {
8
+ WsCloseInfo,
9
+ WsConnection,
10
+ WsMessage,
11
+ WsMock,
12
+ WsMockOptions,
13
+ } from "../model/types.js";
14
+ import {
15
+ closedError,
16
+ createSocketLog,
17
+ encodeOutgoing,
18
+ toMessage,
19
+ } from "./wire.js";
20
+
21
+ /** A fake server: every matching socket becomes a connection the test drives. */
22
+ export async function createMock(
23
+ context: PluginContext,
24
+ protocol: string,
25
+ url: UrlMatcher,
26
+ options: WsMockOptions,
27
+ ): Promise<WsMock> {
28
+ const connections = createArrivals<WsConnection>({
29
+ clock: context.clock,
30
+ label: "WebSocket connection",
31
+ });
32
+ /** Each connection, with whether it is over: `broadcast` skips those. */
33
+ const ended = new Map<WsConnection, () => boolean>();
34
+ const rule = await context.sockets.add({
35
+ protocol,
36
+ label: `mock ${String(url)}`,
37
+ url,
38
+ ...(options.times === undefined ? {} : { times: options.times }),
39
+ async open(socket) {
40
+ const log = createSocketLog(context, protocol, socket);
41
+ const messages = createArrivals<WsMessage>({
42
+ clock: context.clock,
43
+ label: `message on ${socket.url.pathname}`,
44
+ });
45
+ const closed = createDeferred<WsCloseInfo>();
46
+ // The page hears of a close the stub starts through the same event
47
+ // as its own; whoever asked first is who closed.
48
+ let closedBy: "page" | "stub" = "page";
49
+ log("lifecycle", "none", "page", { event: "open", url: socket.url.href });
50
+ socket.page.onMessage((raw) => {
51
+ messages.push(toMessage("out", raw, context.clock.now()));
52
+ log("message", "out", "page", {}, raw);
53
+ });
54
+ socket.page.onClose((code, reason) => {
55
+ // Once per connection: a close is reported again when the route
56
+ // completes it, which the close below does.
57
+ if (closed.settled) return;
58
+ closed.resolve({ code, reason });
59
+ log("lifecycle", "none", closedBy, { event: "close", code, reason });
60
+ // A handler here turns off Playwright's own answer to the page's
61
+ // close, and without one the page's socket would hang in CLOSING.
62
+ if (closedBy === "page")
63
+ void socket.page.close({
64
+ ...(code === undefined ? {} : { code }),
65
+ ...(reason === undefined ? {} : { reason }),
66
+ });
67
+ });
68
+ // Over from the moment the stub closes it, before the page hears.
69
+ const over = () => closed.settled || closedBy === "stub";
70
+ const connection: WsConnection = {
71
+ url: socket.url.href,
72
+ get messages() {
73
+ return messages.items;
74
+ },
75
+ nextMessage: (waitOptions) => messages.next(waitOptions),
76
+ send(data) {
77
+ if (over()) throw closedError(socket);
78
+ const encoded = encodeOutgoing(data);
79
+ socket.page.send(encoded);
80
+ log("message", "in", "stub", {}, encoded);
81
+ },
82
+ async close(closeOptions) {
83
+ closedBy = "stub";
84
+ await socket.page.close(closeOptions);
85
+ },
86
+ closed: closed.promise,
87
+ };
88
+ connections.push(connection);
89
+ ended.set(connection, over);
90
+ try {
91
+ await options.onConnect?.(connection);
92
+ } catch (error) {
93
+ // The stage closes the socket of a rule that throws: the close
94
+ // the page then hears of is the stub's doing.
95
+ closedBy = "stub";
96
+ throw error;
97
+ }
98
+ },
99
+ });
100
+ return {
101
+ get hits() {
102
+ return rule.hits;
103
+ },
104
+ get connections() {
105
+ return connections.items;
106
+ },
107
+ next: (waitOptions) => connections.next(waitOptions),
108
+ broadcast(data) {
109
+ for (const [connection, isOver] of ended)
110
+ if (!isOver()) connection.send(data);
111
+ },
112
+ remove: () => rule.remove(),
113
+ };
114
+ }
@@ -0,0 +1,141 @@
1
+ import type {
2
+ PluginContext,
3
+ SocketPeer,
4
+ } from "../../../entities/plugin/index.js";
5
+ import {
6
+ createArrivals,
7
+ createDeferred,
8
+ } from "../../../shared/lib/async/index.js";
9
+ import type { UrlMatcher } from "../../../shared/lib/match/index.js";
10
+ import type {
11
+ WsCloseInfo,
12
+ WsMessage,
13
+ WsProxy,
14
+ WsProxyConnection,
15
+ WsProxyOptions,
16
+ } from "../model/types.js";
17
+ import {
18
+ closedError,
19
+ createSocketLog,
20
+ encodeOutgoing,
21
+ toMessage,
22
+ } from "./wire.js";
23
+
24
+ /**
25
+ * A pass-through to the real server that records both directions and can
26
+ * drop or inject messages on the way.
27
+ */
28
+ export async function createProxy(
29
+ context: PluginContext,
30
+ protocol: string,
31
+ url: UrlMatcher,
32
+ options: WsProxyOptions,
33
+ ): Promise<WsProxy> {
34
+ const connections = createArrivals<WsProxyConnection>({
35
+ clock: context.clock,
36
+ label: "WebSocket connection",
37
+ });
38
+ const rule = await context.sockets.add({
39
+ protocol,
40
+ label: `proxy ${String(url)}`,
41
+ url,
42
+ ...(options.times === undefined ? {} : { times: options.times }),
43
+ open(socket) {
44
+ const log = createSocketLog(context, protocol, socket);
45
+ const page = socket.page;
46
+ const server = socket.connectToServer();
47
+ const messages = createArrivals<WsMessage>({
48
+ clock: context.clock,
49
+ label: `message on ${socket.url.pathname}`,
50
+ });
51
+ const closed = createDeferred<WsCloseInfo>();
52
+ log("lifecycle", "none", "page", { event: "open", url: socket.url.href });
53
+ const forward = (
54
+ direction: "in" | "out",
55
+ raw: string | Uint8Array,
56
+ to: SocketPeer,
57
+ ) => {
58
+ const passing = toMessage(direction, raw, context.clock.now());
59
+ messages.push(passing);
60
+ if (options.drop?.(passing)) {
61
+ log("fault", direction, "stub", { reason: "dropped" }, raw);
62
+ return;
63
+ }
64
+ log(
65
+ "message",
66
+ direction,
67
+ direction === "out" ? "page" : "network",
68
+ {},
69
+ raw,
70
+ );
71
+ to.send(raw);
72
+ };
73
+ page.onMessage((raw) => forward("out", raw, server));
74
+ server.onMessage((raw) => forward("in", raw, page));
75
+ // A close handler turns off Playwright's own forwarding of the close,
76
+ // so whichever end closes first, both are closed by hand: the other
77
+ // end to pass the close on, and the end that started it to complete
78
+ // it — the page's socket hangs in CLOSING until its end is closed.
79
+ // Once: each of those closes is reported back through a handler.
80
+ let closedBy: "test" | undefined;
81
+ const relay =
82
+ (from: "page" | "network") =>
83
+ (code: number | undefined, reason: string | undefined) => {
84
+ if (closed.settled) return;
85
+ closed.resolve({ code, reason });
86
+ log("lifecycle", "none", closedBy ?? from, {
87
+ event: "close",
88
+ code,
89
+ reason,
90
+ });
91
+ const passed = {
92
+ ...(code === undefined ? {} : { code }),
93
+ ...(reason === undefined ? {} : { reason }),
94
+ };
95
+ void page.close(passed);
96
+ void server.close(passed);
97
+ };
98
+ page.onClose(relay("page"));
99
+ server.onClose(relay("network"));
100
+ // Over from the moment the test closes it, before either end hears.
101
+ const over = () => closed.settled || closedBy !== undefined;
102
+ connections.push({
103
+ url: socket.url.href,
104
+ get messages() {
105
+ return messages.items;
106
+ },
107
+ nextMessage: (waitOptions) => messages.next(waitOptions),
108
+ toPage(data) {
109
+ if (over()) throw closedError(socket);
110
+ const encoded = encodeOutgoing(data);
111
+ page.send(encoded);
112
+ log("message", "in", "test", { injected: true }, encoded);
113
+ },
114
+ toServer(data) {
115
+ if (over()) throw closedError(socket);
116
+ const encoded = encodeOutgoing(data);
117
+ server.send(encoded);
118
+ log("message", "out", "test", { injected: true }, encoded);
119
+ },
120
+ async close(closeOptions) {
121
+ closedBy = "test";
122
+ await Promise.all([
123
+ page.close(closeOptions),
124
+ server.close(closeOptions),
125
+ ]);
126
+ },
127
+ closed: closed.promise,
128
+ });
129
+ },
130
+ });
131
+ return {
132
+ get hits() {
133
+ return rule.hits;
134
+ },
135
+ get connections() {
136
+ return connections.items;
137
+ },
138
+ next: (waitOptions) => connections.next(waitOptions),
139
+ remove: () => rule.remove(),
140
+ };
141
+ }
@@ -0,0 +1,78 @@
1
+ import type {
2
+ Direction,
3
+ FrameKind,
4
+ FrameSource,
5
+ } from "../../../entities/frame/index.js";
6
+ import type {
7
+ PluginContext,
8
+ SocketView,
9
+ } from "../../../entities/plugin/index.js";
10
+ import { toBytes, utf8 } from "../../../shared/lib/bytes/index.js";
11
+ import { WirestageError } from "../../../shared/lib/errors/index.js";
12
+ import type { WsData, WsMessage } from "../model/types.js";
13
+
14
+ /**
15
+ * What a send to a connection that is over throws. Playwright would drop
16
+ * the message without a word, and the timeline would show it delivered.
17
+ */
18
+ export function closedError(socket: SocketView): WirestageError {
19
+ return new WirestageError(
20
+ "CLOSED",
21
+ `the WebSocket connection to ${socket.url.href} is closed`,
22
+ );
23
+ }
24
+
25
+ /** What a test passes to `send`, as the wire carries it. */
26
+ export function encodeOutgoing(data: WsData): string | Uint8Array {
27
+ if (typeof data === "string") return data;
28
+ // Any binary form goes out as bytes; only what is left is a value.
29
+ if (data instanceof ArrayBuffer || ArrayBuffer.isView(data))
30
+ return toBytes(data);
31
+ return JSON.stringify(data);
32
+ }
33
+
34
+ export function toMessage(
35
+ direction: "in" | "out",
36
+ raw: string | Uint8Array,
37
+ at: number,
38
+ ): WsMessage {
39
+ const text = () => (typeof raw === "string" ? raw : utf8(raw));
40
+ return {
41
+ direction,
42
+ data: raw,
43
+ at,
44
+ text,
45
+ json: <T>() => JSON.parse(text()) as T,
46
+ };
47
+ }
48
+
49
+ /** Writes one connection's frames: same endpoint, correlation and context. */
50
+ export type SocketLog = (
51
+ kind: FrameKind,
52
+ direction: Direction,
53
+ source: FrameSource,
54
+ meta: Readonly<Record<string, unknown>>,
55
+ data?: string | Uint8Array,
56
+ ) => void;
57
+
58
+ export function createSocketLog(
59
+ context: Pick<PluginContext, "timeline">,
60
+ protocol: string,
61
+ socket: SocketView,
62
+ ): SocketLog {
63
+ return (kind, direction, source, meta, data) => {
64
+ context.timeline.append({
65
+ protocol,
66
+ kind,
67
+ direction,
68
+ // The path, like every HTTP frame: it reads the same on the dev
69
+ // server, the preview build and CI, whose origins all differ.
70
+ endpoint: socket.url.pathname,
71
+ source,
72
+ correlation: socket.correlation,
73
+ context: socket.context,
74
+ meta,
75
+ ...(data === undefined ? {} : { data }),
76
+ });
77
+ };
78
+ }
@@ -0,0 +1,130 @@
1
+ import type { Frame } from "../../../entities/frame/index.js";
2
+ import type { UrlMatcher } from "../../../shared/lib/match/index.js";
3
+
4
+ export interface WebSocketOptions {
5
+ /**
6
+ * Leave `WebSocket` alone until the first `mock()` or `proxy()`.
7
+ *
8
+ * By default the plugin routes WebSockets from the moment a context is
9
+ * attached, so a mock added mid-test reaches the pages that are already
10
+ * open. Playwright routes by replacing `WebSocket` in every document as it
11
+ * loads, and a socket no rule takes is passed through to the real server.
12
+ * With `lazy`, nothing is replaced until the first rule exists — and that
13
+ * rule then applies only to the documents loaded after it.
14
+ */
15
+ readonly lazy?: boolean;
16
+ }
17
+
18
+ /** What a test may send: text, bytes in any binary form, or a value sent as JSON. */
19
+ export type WsData = string | ArrayBuffer | ArrayBufferView | object;
20
+
21
+ export interface WsMessage {
22
+ /** `out` came from the page, `in` went to it. */
23
+ readonly direction: "in" | "out";
24
+ readonly data: string | Uint8Array;
25
+ readonly at: number;
26
+ text(): string;
27
+ json<T = unknown>(): T;
28
+ }
29
+
30
+ export interface WsCloseInfo {
31
+ readonly code: number | undefined;
32
+ readonly reason: string | undefined;
33
+ }
34
+
35
+ export interface WsCloseOptions {
36
+ /**
37
+ * The code the page's socket closes with: any a server may send. A proxy
38
+ * also closes the real server's end, through the browser, which sends
39
+ * only 1000 and 3000-4999 — another code reaches the page as given and
40
+ * the server as a normal closure, 1000.
41
+ */
42
+ readonly code?: number;
43
+ /**
44
+ * The page gets it whole. A proxy's real server gets at most 123 bytes
45
+ * of it, cut on a character: all a close frame carries, and all the
46
+ * browser will send.
47
+ */
48
+ readonly reason?: string;
49
+ }
50
+
51
+ export interface WsConnection {
52
+ readonly url: string;
53
+ /** Messages the page sent, oldest first. */
54
+ readonly messages: readonly WsMessage[];
55
+ /** The next message the page sends (or sent and nobody took). */
56
+ nextMessage(options?: { readonly timeout?: number }): Promise<WsMessage>;
57
+ /**
58
+ * Send to the page. Throws `CLOSED` once the connection is over — from
59
+ * the moment `close()` is called — since the page would never get it.
60
+ */
61
+ send(data: WsData): void;
62
+ close(options?: WsCloseOptions): Promise<void>;
63
+ /** Resolves when the connection is over, whoever closed it. */
64
+ readonly closed: Promise<WsCloseInfo>;
65
+ }
66
+
67
+ export interface WsMockOptions {
68
+ /** Answer this many connections, then leave the rest to the next rule. */
69
+ readonly times?: number;
70
+ /**
71
+ * Called for each new connection, e.g. to send a greeting. The page's
72
+ * socket opens once it settles. If it throws, the stage closes the
73
+ * page's socket with 1011 and records a `rule-error` fault.
74
+ */
75
+ readonly onConnect?: (connection: WsConnection) => void | Promise<void>;
76
+ }
77
+
78
+ export interface WsMock {
79
+ /** Connections this mock took. */
80
+ readonly hits: number;
81
+ readonly connections: readonly WsConnection[];
82
+ /** The next connection the page opens (or opened and nobody took). */
83
+ next(options?: { readonly timeout?: number }): Promise<WsConnection>;
84
+ /** Send to every connection that is not over yet. */
85
+ broadcast(data: WsData): void;
86
+ /** New connections go to the real server again. */
87
+ remove(): Promise<void>;
88
+ }
89
+
90
+ export interface WsProxyOptions {
91
+ /** Proxy this many connections, then leave the rest to the next rule. */
92
+ readonly times?: number;
93
+ /** Drop a message instead of forwarding it. Dropped messages are recorded as faults. */
94
+ readonly drop?: (message: WsMessage) => boolean;
95
+ }
96
+
97
+ export interface WsProxyConnection {
98
+ readonly url: string;
99
+ /** Messages in both directions, oldest first. */
100
+ readonly messages: readonly WsMessage[];
101
+ nextMessage(options?: { readonly timeout?: number }): Promise<WsMessage>;
102
+ /**
103
+ * Inject a message to the page, as if the server sent it. Throws
104
+ * `CLOSED` once the connection is over, as `toServer` does.
105
+ */
106
+ toPage(data: WsData): void;
107
+ /** Inject a message to the server, as if the page sent it. */
108
+ toServer(data: WsData): void;
109
+ /** Close both sides. */
110
+ close(options?: WsCloseOptions): Promise<void>;
111
+ /** Resolves when the connection is over, whoever closed it. */
112
+ readonly closed: Promise<WsCloseInfo>;
113
+ }
114
+
115
+ export interface WsProxy {
116
+ /** Connections this proxy took. */
117
+ readonly hits: number;
118
+ readonly connections: readonly WsProxyConnection[];
119
+ next(options?: { readonly timeout?: number }): Promise<WsProxyConnection>;
120
+ remove(): Promise<void>;
121
+ }
122
+
123
+ export interface WebSocketApi {
124
+ /** Answer matching WebSockets with a fake server the test drives. */
125
+ mock(url: UrlMatcher, options?: WsMockOptions): Promise<WsMock>;
126
+ /** Pass matching WebSockets through to the real server, recording and optionally dropping messages. */
127
+ proxy(url: UrlMatcher, options?: WsProxyOptions): Promise<WsProxy>;
128
+ /** Every recorded frame: opens, messages, drops, closes. */
129
+ frames(filter?: { readonly endpoint?: string | RegExp }): Promise<Frame[]>;
130
+ }