@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
package/src/index.ts ADDED
@@ -0,0 +1,111 @@
1
+ /**
2
+ * @heojeongbo/wirestage — the core: the stage, its timeline, and the plugin
3
+ * contract every protocol is written against. Protocols live in subpaths:
4
+ * `/connect`, `/rest`, `/sse`, `/websocket`, `/webrtc`; the Playwright
5
+ * fixture in `/playwright`.
6
+ */
7
+
8
+ // The timeline: what every plugin writes and every test reads.
9
+ export type {
10
+ Direction,
11
+ Frame,
12
+ FrameFilter,
13
+ FrameInit,
14
+ FrameKind,
15
+ FrameSource,
16
+ Payload,
17
+ PayloadInput,
18
+ SnapshotFrame,
19
+ SnapshotOptions,
20
+ Timeline,
21
+ TimelineCursor,
22
+ TimelineOptions,
23
+ TimelineSnapshot,
24
+ } from "./entities/frame/index.js";
25
+ export { createTimeline } from "./entities/frame/index.js";
26
+ // The plugin contract: what a protocol is written against.
27
+ export type {
28
+ AbortErrorCode,
29
+ AnyWirePlugin,
30
+ Attachment,
31
+ HttpOutcome,
32
+ HttpRequestView,
33
+ HttpRouter,
34
+ HttpRule,
35
+ HttpRuleHandle,
36
+ PageEntry,
37
+ PageHost,
38
+ PageInstaller,
39
+ PageModule,
40
+ PageModuleEnv,
41
+ PageSource,
42
+ PassthroughResponse,
43
+ PluginApis,
44
+ PluginContext,
45
+ PluginRuntime,
46
+ ResponseStream,
47
+ SocketPeer,
48
+ SocketRouter,
49
+ SocketRule,
50
+ SocketRuleHandle,
51
+ SocketView,
52
+ StreamEnd,
53
+ WaitForOptions,
54
+ WirePlugin,
55
+ } from "./entities/plugin/index.js";
56
+ export { definePlugin, named } from "./entities/plugin/index.js";
57
+ // What the stage is handed: a browser context, its pages, its cookie jar.
58
+ export type {
59
+ ContextPort,
60
+ CookieJarPort,
61
+ FramePort,
62
+ PagePort,
63
+ } from "./shared/api/playwright/index.js";
64
+ // For plugin authors: the pieces every built-in plugin is made of.
65
+ export type {
66
+ Arrivals,
67
+ ArrivalsOptions,
68
+ AsyncQueue,
69
+ Deferred,
70
+ } from "./shared/lib/async/index.js";
71
+ export {
72
+ createArrivals,
73
+ createAsyncQueue,
74
+ createDeferred,
75
+ } from "./shared/lib/async/index.js";
76
+ export type { Clock, ManualClock } from "./shared/lib/clock/index.js";
77
+ export {
78
+ createManualClock,
79
+ createSystemClock,
80
+ } from "./shared/lib/clock/index.js";
81
+ export type { CookieInit } from "./shared/lib/cookies/index.js";
82
+ // The length-prefixed framing gRPC, gRPC-web and Connect streams share, for
83
+ // a test that builds or reads a frame by hand.
84
+ export type { Envelope } from "./shared/lib/envelope/index.js";
85
+ export {
86
+ createEnvelopeReader,
87
+ decodeEnvelopes,
88
+ EnvelopeFlag,
89
+ encodeEnvelope,
90
+ encodeEnvelopes,
91
+ parseTrailerBlock,
92
+ } from "./shared/lib/envelope/index.js";
93
+ export type { WirestageErrorCode } from "./shared/lib/errors/index.js";
94
+ export { isWirestageError, WirestageError } from "./shared/lib/errors/index.js";
95
+ export type {
96
+ LogScope,
97
+ LogThreshold,
98
+ ScopedLogger,
99
+ } from "./shared/lib/logger/index.js";
100
+ export { getLogThreshold, setLogThreshold } from "./shared/lib/logger/index.js";
101
+ export type { UrlMatcher } from "./shared/lib/match/index.js";
102
+ export { compileUrlMatcher } from "./shared/lib/match/index.js";
103
+ export type {
104
+ AttachOptions,
105
+ ReportOptions,
106
+ Stage,
107
+ StageCore,
108
+ StageOptions,
109
+ StageReport,
110
+ } from "./widgets/stage/index.js";
111
+ export { createStage } from "./widgets/stage/index.js";
@@ -0,0 +1,8 @@
1
+ /** @heojeongbo/wirestage/playwright — the `stage` fixture for @playwright/test. */
2
+ export type {
3
+ ReportMode,
4
+ StageFixtureArgs,
5
+ StageFixtureOptions,
6
+ StageTestInfo,
7
+ } from "./app/playwright/index.js";
8
+ export { createStageFixture, withStage } from "./app/playwright/index.js";
package/src/rest.ts ADDED
@@ -0,0 +1,2 @@
1
+ /** @heojeongbo/wirestage/rest — REST and other plain HTTP. */
2
+ export * from "./features/rest/index.js";
@@ -0,0 +1,2 @@
1
+ export type { Listening, ListenOptions } from "./listen.js";
2
+ export { listen } from "./listen.js";
@@ -0,0 +1,71 @@
1
+ import type { AddressInfo, Server, Socket } from "node:net";
2
+
3
+ import { WirestageError } from "../../lib/errors/index.js";
4
+
5
+ export interface ListenOptions {
6
+ /** Names the server in the "port in use" error. */
7
+ readonly name: string;
8
+ readonly protocol: "http" | "https";
9
+ readonly host?: string;
10
+ /** 0, the default, picks a free port. */
11
+ readonly port?: number;
12
+ }
13
+
14
+ export interface Listening {
15
+ readonly url: string;
16
+ readonly port: number;
17
+ /** Stop accepting and drop open connections at once. */
18
+ close(): Promise<void>;
19
+ }
20
+
21
+ /**
22
+ * Start listening and return a handle whose `close` really is immediate.
23
+ * `server.close()` alone waits for every keep-alive and streaming connection to
24
+ * end on its own — a held-open stream would stall test teardown until the
25
+ * runner's timeout.
26
+ *
27
+ * Takes a `net.Server`, which http, https and http2 servers all are.
28
+ */
29
+ export async function listen(
30
+ server: Server,
31
+ options: ListenOptions,
32
+ ): Promise<Listening> {
33
+ const host = options.host ?? "127.0.0.1";
34
+ const sockets = new Set<Socket>();
35
+ server.on("connection", (socket: Socket) => {
36
+ sockets.add(socket);
37
+ socket.once("close", () => sockets.delete(socket));
38
+ });
39
+ await new Promise<void>((resolve, reject) => {
40
+ const onListening = () => {
41
+ server.off("error", onError);
42
+ resolve();
43
+ };
44
+ const onError = (error: NodeJS.ErrnoException) => {
45
+ server.off("listening", onListening);
46
+ reject(
47
+ error.code === "EADDRINUSE"
48
+ ? new WirestageError(
49
+ "INVALID_STATE",
50
+ `${options.name}: ${host}:${options.port} is already in use`,
51
+ { cause: error, details: { host, port: options.port } },
52
+ )
53
+ : error,
54
+ );
55
+ };
56
+ server.once("listening", onListening);
57
+ server.once("error", onError);
58
+ server.listen(options.port ?? 0, host);
59
+ });
60
+ const port = (server.address() as AddressInfo).port;
61
+ return {
62
+ // An IPv6 literal goes in brackets, or the port reads as part of it.
63
+ url: `${options.protocol}://${host.includes(":") ? `[${host}]` : host}:${port}`,
64
+ port,
65
+ close: () =>
66
+ new Promise<void>((resolve) => {
67
+ for (const socket of sockets) socket.destroy();
68
+ server.close(() => resolve());
69
+ }),
70
+ };
71
+ }
@@ -0,0 +1,17 @@
1
+ export type {
2
+ BindingSourcePort,
3
+ ContextPort,
4
+ ContinueOptions,
5
+ CookieJarPort,
6
+ CookiePort,
7
+ FramePort,
8
+ FulfillOptions,
9
+ HeaderMap,
10
+ PagePort,
11
+ RequestPort,
12
+ ResponsePort,
13
+ RouteHandler,
14
+ RoutePort,
15
+ UrlPredicate,
16
+ WebSocketRoutePort,
17
+ } from "./ports.js";
@@ -0,0 +1,145 @@
1
+ /**
2
+ * The slice of Playwright the library drives, as structural types.
3
+ *
4
+ * Real Playwright objects satisfy these as they are — `tests/types` proves it
5
+ * against the pinned version — so the public API takes a `BrowserContext` and
6
+ * hands it inward unchanged. Inside, everything depends on the ports, never on
7
+ * Playwright, which is what lets the unit suite cover every branch with
8
+ * hand-written fakes instead of a browser.
9
+ */
10
+
11
+ import type { CookieInit } from "../../lib/cookies/index.js";
12
+
13
+ export type HeaderMap = Readonly<Record<string, string>>;
14
+
15
+ export interface FramePort {
16
+ evaluate<R>(
17
+ // biome-ignore lint/suspicious/noExplicitAny: Playwright types the page function as PageFunction<Arg, R>, which unboxes Arg through a conditional type. No narrower parameter type accepts both that and the self-contained `(arg: T) => R` functions callers pass; `unknown` and `never` each fail one side. The arguments are JSON values either way.
18
+ pageFunction: (arg: any) => R | Promise<R>,
19
+ arg?: unknown,
20
+ ): Promise<R>;
21
+ }
22
+
23
+ export interface PagePort {
24
+ /** The main frame and every iframe: page hooks run in each of them. */
25
+ frames(): FramePort[];
26
+ isClosed(): boolean;
27
+ }
28
+
29
+ export interface ResponsePort {
30
+ status(): number;
31
+ headers(): HeaderMap;
32
+ body(): Promise<Buffer>;
33
+ }
34
+
35
+ export interface RequestPort {
36
+ url(): string;
37
+ method(): string;
38
+ /** Playwright already lower-cases these names. */
39
+ headers(): HeaderMap;
40
+ /**
41
+ * Every header, including the ones `headers()` leaves out (cookies, and
42
+ * headers the network stack adds such as `last-event-id`).
43
+ */
44
+ allHeaders(): Promise<HeaderMap>;
45
+ postDataBuffer(): Buffer | null;
46
+ resourceType(): string;
47
+ /** Throws for requests a service worker makes; callers must guard it. */
48
+ frame(): { page(): PagePort };
49
+ response(): Promise<ResponsePort | null>;
50
+ failure(): { errorText: string } | null;
51
+ }
52
+
53
+ export interface FulfillOptions {
54
+ readonly status?: number;
55
+ readonly headers?: Record<string, string>;
56
+ readonly body?: string | Buffer;
57
+ }
58
+
59
+ export interface ContinueOptions {
60
+ readonly url?: string;
61
+ readonly method?: string;
62
+ readonly headers?: Record<string, string>;
63
+ readonly postData?: string | Buffer;
64
+ }
65
+
66
+ export interface RoutePort {
67
+ request(): RequestPort;
68
+ fulfill(options: FulfillOptions): Promise<void>;
69
+ continue(options?: ContinueOptions): Promise<void>;
70
+ fallback(): Promise<void>;
71
+ abort(errorCode?: string): Promise<void>;
72
+ }
73
+
74
+ export type RouteHandler = (
75
+ route: RoutePort,
76
+ request: RequestPort,
77
+ ) => Promise<void>;
78
+
79
+ export type UrlPredicate = (url: URL) => boolean;
80
+
81
+ export interface WebSocketRoutePort {
82
+ url(): string;
83
+ onMessage(handler: (message: string | Buffer) => unknown): void;
84
+ onClose(
85
+ handler: (code: number | undefined, reason: string | undefined) => unknown,
86
+ ): void;
87
+ send(message: string | Buffer): void;
88
+ close(options?: { code?: number; reason?: string }): Promise<void>;
89
+ connectToServer(): WebSocketRoutePort;
90
+ }
91
+
92
+ export interface BindingSourcePort {
93
+ readonly page: PagePort;
94
+ }
95
+
96
+ export interface CookiePort {
97
+ readonly name: string;
98
+ readonly value: string;
99
+ }
100
+
101
+ /**
102
+ * The cookie jar of a browser context: all a drive client needs of one, so
103
+ * that is all it is given.
104
+ */
105
+ export interface CookieJarPort {
106
+ cookies(urls?: string | string[]): Promise<CookiePort[]>;
107
+ /**
108
+ * Optional so a fake may omit it; every real BrowserContext has it. Drive
109
+ * clients keep the cookies a response sets here, the way Playwright's own
110
+ * request context does.
111
+ */
112
+ addCookies?(cookies: CookieInit[]): Promise<void>;
113
+ }
114
+
115
+ export interface ContextPort extends CookieJarPort {
116
+ /** Required here: a context always has it, and a plugin's jar calls it. */
117
+ addCookies(cookies: CookieInit[]): Promise<void>;
118
+ route(url: UrlPredicate, handler: RouteHandler): Promise<unknown>;
119
+ unroute(url: UrlPredicate, handler?: RouteHandler): Promise<void>;
120
+ routeWebSocket(
121
+ url: UrlPredicate,
122
+ handler: (route: WebSocketRoutePort) => unknown,
123
+ ): Promise<void>;
124
+ addInitScript(script: { content: string }): Promise<unknown>;
125
+ exposeBinding(
126
+ name: string,
127
+ binding: (source: BindingSourcePort, message: unknown) => unknown,
128
+ ): Promise<unknown>;
129
+ pages(): PagePort[];
130
+ /** Optional so a fake may omit it; every real BrowserContext has it. */
131
+ grantPermissions?(
132
+ permissions: string[],
133
+ options?: { origin?: string },
134
+ ): Promise<void>;
135
+ on(event: "close", listener: () => void): unknown;
136
+ on(
137
+ event: "requestfinished" | "requestfailed",
138
+ listener: (request: RequestPort) => void,
139
+ ): unknown;
140
+ off(event: "close", listener: () => void): unknown;
141
+ off(
142
+ event: "requestfinished" | "requestfailed",
143
+ listener: (request: RequestPort) => void,
144
+ ): unknown;
145
+ }
@@ -0,0 +1,7 @@
1
+ export type {
2
+ NodeHandler,
3
+ StreamServer,
4
+ StreamServerOptions,
5
+ StreamSession,
6
+ } from "./stream-server.js";
7
+ export { createStreamServer } from "./stream-server.js";
@@ -0,0 +1,246 @@
1
+ import {
2
+ createServer as createHttpServer,
3
+ type IncomingMessage,
4
+ type ServerResponse,
5
+ } from "node:http";
6
+ import { createServer as createHttpsServer } from "node:https";
7
+
8
+ import { WirestageError } from "../../lib/errors/index.js";
9
+ import { randomToken } from "../../lib/id/index.js";
10
+ import type { ScopedLogger } from "../../lib/logger/index.js";
11
+ import { type Listening, listen } from "../http-server/index.js";
12
+
13
+ export type NodeHandler = (
14
+ request: IncomingMessage,
15
+ response: ServerResponse,
16
+ ) => void | Promise<void>;
17
+
18
+ export interface StreamSession {
19
+ readonly id: string;
20
+ /** Where the browser's request is redirected to. Single use. */
21
+ readonly url: string;
22
+ /** Forget the session if the redirect never arrives. */
23
+ dispose(): void;
24
+ }
25
+
26
+ export interface StreamServerOptions {
27
+ /** Key and certificate for pages served over https. */
28
+ readonly tls?: {
29
+ readonly key: string | Buffer;
30
+ readonly cert: string | Buffer;
31
+ };
32
+ readonly host?: string;
33
+ readonly log?: ScopedLogger;
34
+ }
35
+
36
+ export interface StreamServer {
37
+ /**
38
+ * Register a handler and return the URL to redirect one request to.
39
+ * `secure` is whether the page's request was https: Playwright only lets
40
+ * `route.continue` change the URL within the same scheme.
41
+ */
42
+ open(
43
+ handler: NodeHandler,
44
+ options: { readonly secure: boolean },
45
+ ): Promise<StreamSession>;
46
+ /** Stop every listener and refuse further sessions. */
47
+ close(): Promise<void>;
48
+ readonly sessions: number;
49
+ }
50
+
51
+ const PATH = "/__wirestage/";
52
+
53
+ /**
54
+ * Headers a browser script may read on a response from another origin. The
55
+ * redirect makes the stream server a different origin from the page as far
56
+ * as CORS is concerned in some engines, and connect-web reads these.
57
+ */
58
+ const EXPOSED_HEADERS = [
59
+ "grpc-status",
60
+ "grpc-message",
61
+ "grpc-status-details-bin",
62
+ "grpc-encoding",
63
+ "connect-protocol-version",
64
+ "content-encoding",
65
+ "content-type",
66
+ ].join(", ");
67
+
68
+ /**
69
+ * Open responses one listener carries. A browser keeps at most six
70
+ * connections to one host and port, and an open stream holds its connection
71
+ * for as long as it lives: the seventh would wait for one of the six to end,
72
+ * which in a test is never. Four leaves room for the preflights the browser
73
+ * sends on the same connection pool.
74
+ */
75
+ const STREAMS_PER_LISTENER = 4;
76
+
77
+ interface Listener {
78
+ readonly listening: Promise<Listening>;
79
+ /** Sessions given this listener's URL whose response has not closed. */
80
+ open: number;
81
+ }
82
+
83
+ interface Session {
84
+ readonly handler: NodeHandler;
85
+ readonly listener: Listener;
86
+ }
87
+
88
+ /**
89
+ * A local server for responses that must stay open — server streams, SSE —
90
+ * which `route.fulfill` cannot express because it takes the whole body at
91
+ * once. A stub answers by redirecting the browser's request here, and the
92
+ * handler then writes to a real socket at whatever pace the test drives.
93
+ *
94
+ * It starts lazily on the first session, so a suite that never streams never
95
+ * opens a port, and adds a port whenever the ones it has are full.
96
+ */
97
+ export function createStreamServer(
98
+ options: StreamServerOptions = {},
99
+ ): StreamServer {
100
+ const secure = options.tls !== undefined;
101
+ const sessions = new Map<string, Session>();
102
+ const listeners = new Set<Listener>();
103
+ let closed = false;
104
+
105
+ const release = (id: string, session: Session) => {
106
+ if (sessions.delete(id)) session.listener.open -= 1;
107
+ };
108
+
109
+ const onRequest = (request: IncomingMessage, response: ServerResponse) => {
110
+ allowCors(request, response);
111
+ if (request.method === "OPTIONS") {
112
+ response.writeHead(204);
113
+ response.end();
114
+ return;
115
+ }
116
+ const id = request.url?.startsWith(PATH)
117
+ ? request.url.slice(PATH.length)
118
+ : "";
119
+ const session = sessions.get(id);
120
+ if (session === undefined) {
121
+ response.writeHead(404);
122
+ response.end();
123
+ return;
124
+ }
125
+ // One request per session: a client that reconnects goes through the
126
+ // page's route again and gets a session of its own. The session keeps
127
+ // its place on the listener until the response is over.
128
+ sessions.delete(id);
129
+ response.once("close", () => {
130
+ session.listener.open -= 1;
131
+ });
132
+ Promise.resolve()
133
+ .then(() => session.handler(request, response))
134
+ .catch((error: unknown) => {
135
+ // A write into a connection the client closed, or a test cut, is
136
+ // the expected end of a stream, not a failure worth an error line.
137
+ if (response.destroyed) {
138
+ options.log?.debug(
139
+ "stream ended by a closed connection",
140
+ { session: id },
141
+ error,
142
+ );
143
+ return;
144
+ }
145
+ options.log?.error("stream handler failed", { session: id }, error);
146
+ if (!response.headersSent) response.writeHead(500);
147
+ response.end();
148
+ });
149
+ };
150
+
151
+ /** A listener with room, starting another when the rest are full. */
152
+ const listenerWithRoom = (): Listener => {
153
+ for (const listener of listeners)
154
+ if (listener.open < STREAMS_PER_LISTENER) return listener;
155
+ const listener: Listener = {
156
+ listening: listen(
157
+ options.tls === undefined
158
+ ? createHttpServer(onRequest)
159
+ : createHttpsServer(options.tls, onRequest),
160
+ {
161
+ name: "wirestage stream server",
162
+ protocol: secure ? "https" : "http",
163
+ host: options.host,
164
+ },
165
+ ),
166
+ open: 0,
167
+ };
168
+ listeners.add(listener);
169
+ // A listener that could not start must not be offered again.
170
+ listener.listening.catch(() => listeners.delete(listener));
171
+ return listener;
172
+ };
173
+
174
+ return {
175
+ async open(handler, { secure: pageIsSecure }) {
176
+ if (closed)
177
+ throw new WirestageError(
178
+ "CLOSED",
179
+ "the stream server is closed: the stage was disposed while a stream was being opened",
180
+ );
181
+ if (pageIsSecure !== secure)
182
+ throw new WirestageError(
183
+ "UNSUPPORTED",
184
+ pageIsSecure
185
+ ? "a live stream on an https page needs `streamServer.tls`: Playwright only redirects a request to a URL with the same scheme"
186
+ : "the stream server was given TLS but the page is http; drop `streamServer.tls` for http pages",
187
+ { details: { pageIsSecure, serverIsSecure: secure } },
188
+ );
189
+ const listener = listenerWithRoom();
190
+ const session: Session = { handler, listener };
191
+ const id = randomToken();
192
+ listener.open += 1;
193
+ sessions.set(id, session);
194
+ try {
195
+ const { url } = await listener.listening;
196
+ return {
197
+ id,
198
+ url: `${url}${PATH}${id}`,
199
+ dispose: () => release(id, session),
200
+ };
201
+ } catch (error) {
202
+ release(id, session);
203
+ throw error;
204
+ }
205
+ },
206
+ async close() {
207
+ closed = true;
208
+ sessions.clear();
209
+ const stopping = [...listeners];
210
+ listeners.clear();
211
+ await Promise.all(
212
+ stopping.map((listener) =>
213
+ listener.listening.then(
214
+ (listening) => listening.close(),
215
+ // It never started; there is nothing to stop.
216
+ () => undefined,
217
+ ),
218
+ ),
219
+ );
220
+ },
221
+ get sessions() {
222
+ return sessions.size;
223
+ },
224
+ };
225
+ }
226
+
227
+ function allowCors(request: IncomingMessage, response: ServerResponse): void {
228
+ const origin = request.headers.origin;
229
+ if (origin === undefined) return;
230
+ response.setHeader("access-control-allow-origin", origin);
231
+ response.setHeader("vary", "origin");
232
+ response.setHeader("access-control-allow-credentials", "true");
233
+ response.setHeader(
234
+ "access-control-allow-methods",
235
+ "GET, POST, PUT, PATCH, DELETE, OPTIONS",
236
+ );
237
+ response.setHeader(
238
+ "access-control-allow-headers",
239
+ request.headers["access-control-request-headers"] ?? "*",
240
+ );
241
+ response.setHeader("access-control-expose-headers", EXPOSED_HEADERS);
242
+ // Private Network Access: a page on a public origin must be told the
243
+ // loopback stream server agrees to be reached, or Chromium refuses.
244
+ if (request.headers["access-control-request-private-network"] === "true")
245
+ response.setHeader("access-control-allow-private-network", "true");
246
+ }