@babylonjs/inspector 9.0.0 → 9.2.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 (293) hide show
  1. package/bin/inspector-bridge.mjs +4734 -0
  2. package/bin/inspector-cli.mjs +4931 -0
  3. package/lib/cli/protocol.d.ts +180 -0
  4. package/lib/components/curveEditor/bottomBar/rangeSelector.d.ts +6 -0
  5. package/lib/components/curveEditor/bottomBar.d.ts +6 -0
  6. package/lib/components/curveEditor/canvas/canvas.d.ts +6 -0
  7. package/lib/components/curveEditor/canvas/curve.d.ts +14 -0
  8. package/lib/components/curveEditor/canvas/curveData.d.ts +40 -0
  9. package/lib/components/curveEditor/canvas/frameBar.d.ts +12 -0
  10. package/lib/components/curveEditor/canvas/graph.d.ts +11 -0
  11. package/lib/components/curveEditor/canvas/keyPoint.d.ts +34 -0
  12. package/lib/components/curveEditor/canvas/playHead.d.ts +12 -0
  13. package/lib/components/curveEditor/canvas/rangeFrameBar.d.ts +10 -0
  14. package/lib/components/curveEditor/curveEditor.d.ts +29 -0
  15. package/lib/components/curveEditor/curveEditorButton.d.ts +31 -0
  16. package/lib/components/curveEditor/curveEditorColors.d.ts +56 -0
  17. package/lib/components/curveEditor/curveEditorContext.d.ts +267 -0
  18. package/lib/components/curveEditor/rangeSelector.d.ts +6 -0
  19. package/lib/components/curveEditor/sideBar/addAnimationPanel.d.ts +10 -0
  20. package/lib/components/curveEditor/sideBar/animationList.d.ts +6 -0
  21. package/lib/components/curveEditor/sideBar/editAnimationPanel.d.ts +12 -0
  22. package/lib/components/curveEditor/sideBar/loadAnimationPanel.d.ts +10 -0
  23. package/lib/components/curveEditor/sideBar/saveAnimationPanel.d.ts +10 -0
  24. package/lib/components/curveEditor/sideBar.d.ts +6 -0
  25. package/lib/components/curveEditor/topBar.d.ts +6 -0
  26. package/lib/components/debug/debugPane.d.ts +6 -0
  27. package/lib/components/errorBoundary.d.ts +31 -0
  28. package/lib/components/extensibleAccordion.d.ts +67 -0
  29. package/lib/components/gizmoToolbar.d.ts +7 -0
  30. package/lib/components/pane.d.ts +4 -0
  31. package/lib/components/performanceViewer/canvasGraph.d.ts +16 -0
  32. package/lib/components/performanceViewer/canvasGraphService.d.ts +238 -0
  33. package/lib/components/performanceViewer/graphSupportingTypes.d.ts +90 -0
  34. package/lib/components/performanceViewer/performanceSidebar.d.ts +10 -0
  35. package/lib/components/performanceViewer/performanceViewer.d.ts +15 -0
  36. package/lib/components/pickingToolbar.d.ts +11 -0
  37. package/lib/components/properties/animation/animationGroupProperties.d.ts +8 -0
  38. package/lib/components/properties/animation/animationsProperties.d.ts +21 -0
  39. package/lib/components/properties/animation/targetedAnimationProperties.d.ts +7 -0
  40. package/lib/components/properties/atmosphereProperties.d.ts +20 -0
  41. package/lib/components/properties/audio/soundProperties.d.ts +8 -0
  42. package/lib/components/properties/boundProperty.d.ts +80 -0
  43. package/lib/components/properties/cameras/arcRotateCameraProperties.d.ts +17 -0
  44. package/lib/components/properties/cameras/cameraProperties.d.ts +10 -0
  45. package/lib/components/properties/cameras/followCameraProperties.d.ts +8 -0
  46. package/lib/components/properties/cameras/freeCameraProperties.d.ts +11 -0
  47. package/lib/components/properties/cameras/geospatialCameraProperties.d.ts +11 -0
  48. package/lib/components/properties/cameras/targetCameraProperties.d.ts +8 -0
  49. package/lib/components/properties/commonGeneralProperties.d.ts +16 -0
  50. package/lib/components/properties/frameGraph/frameGraphProperties.d.ts +8 -0
  51. package/lib/components/properties/generateCopyString.d.ts +7 -0
  52. package/lib/components/properties/lights/areaLightProperties.d.ts +5 -0
  53. package/lib/components/properties/lights/clusteredLightContainerProperties.d.ts +10 -0
  54. package/lib/components/properties/lights/directionalLightProperties.d.ts +8 -0
  55. package/lib/components/properties/lights/hemisphericLightProperties.d.ts +5 -0
  56. package/lib/components/properties/lights/lightProperties.d.ts +7 -0
  57. package/lib/components/properties/lights/pointLightProperties.d.ts +5 -0
  58. package/lib/components/properties/lights/shadowGeneratorProperties.d.ts +6 -0
  59. package/lib/components/properties/lights/shadowLightProperties.d.ts +5 -0
  60. package/lib/components/properties/lights/spotLightProperties.d.ts +5 -0
  61. package/lib/components/properties/linkToEntityPropertyLine.d.ts +27 -0
  62. package/lib/components/properties/materials/materialProperties.d.ts +11 -0
  63. package/lib/components/properties/materials/multiMaterialProperties.d.ts +7 -0
  64. package/lib/components/properties/materials/nodeMaterialProperties.d.ts +8 -0
  65. package/lib/components/properties/materials/normalMapProperties.d.ts +19 -0
  66. package/lib/components/properties/materials/openpbrMaterialProperties.d.ts +64 -0
  67. package/lib/components/properties/materials/pbrBaseMaterialProperties.d.ts +285 -0
  68. package/lib/components/properties/materials/skyMaterialProperties.d.ts +5 -0
  69. package/lib/components/properties/materials/standardMaterialProperties.d.ts +29 -0
  70. package/lib/components/properties/metadataProperties.d.ts +12 -0
  71. package/lib/components/properties/nodes/abstractMeshProperties.d.ts +27 -0
  72. package/lib/components/properties/nodes/gaussianSplattingProperties.d.ts +5 -0
  73. package/lib/components/properties/nodes/meshProperties.d.ts +11 -0
  74. package/lib/components/properties/nodes/nodeProperties.d.ts +7 -0
  75. package/lib/components/properties/particles/attractor.d.ts +23 -0
  76. package/lib/components/properties/particles/attractorAdapter.d.ts +56 -0
  77. package/lib/components/properties/particles/attractorList.d.ts +15 -0
  78. package/lib/components/properties/particles/attractorProperties.d.ts +11 -0
  79. package/lib/components/properties/particles/colorProperties.d.ts +11 -0
  80. package/lib/components/properties/particles/commandsProperties.d.ts +13 -0
  81. package/lib/components/properties/particles/emissionProperties.d.ts +11 -0
  82. package/lib/components/properties/particles/emitterProperties.d.ts +13 -0
  83. package/lib/components/properties/particles/lifetimeProperties.d.ts +11 -0
  84. package/lib/components/properties/particles/nodeEditorProperties.d.ts +12 -0
  85. package/lib/components/properties/particles/rotationProperties.d.ts +11 -0
  86. package/lib/components/properties/particles/sizeProperties.d.ts +11 -0
  87. package/lib/components/properties/particles/spritesheetProperties.d.ts +11 -0
  88. package/lib/components/properties/particles/systemProperties.d.ts +13 -0
  89. package/lib/components/properties/physics/physicsProperties.d.ts +6 -0
  90. package/lib/components/properties/postProcesses/postProcessProperties.d.ts +10 -0
  91. package/lib/components/properties/propertiesPane.d.ts +2 -0
  92. package/lib/components/properties/renderingPipelines/defaultRenderingPipelineProperties.d.ts +23 -0
  93. package/lib/components/properties/renderingPipelines/iblShadowsRenderPipelineProperties.d.ts +11 -0
  94. package/lib/components/properties/renderingPipelines/lensRenderingPipelineProperties.d.ts +8 -0
  95. package/lib/components/properties/renderingPipelines/postProcessRenderPipelineProperties.d.ts +5 -0
  96. package/lib/components/properties/renderingPipelines/ssao2RenderingPipelineProperties.d.ts +8 -0
  97. package/lib/components/properties/renderingPipelines/ssaoRenderingPipelineProperties.d.ts +5 -0
  98. package/lib/components/properties/renderingPipelines/ssrRenderingPipelineProperties.d.ts +17 -0
  99. package/lib/components/properties/skeleton/boneProperties.d.ts +7 -0
  100. package/lib/components/properties/skeleton/skeletonProperties.d.ts +8 -0
  101. package/lib/components/properties/sprites/spriteManagerProperties.d.ts +25 -0
  102. package/lib/components/properties/sprites/spriteProperties.d.ts +19 -0
  103. package/lib/components/properties/textures/advancedDynamicTextureProperties.d.ts +11 -0
  104. package/lib/components/properties/textures/baseTextureProperties.d.ts +16 -0
  105. package/lib/components/properties/textures/cubeTextureProperties.d.ts +5 -0
  106. package/lib/components/properties/textures/multiRenderTargetProperties.d.ts +5 -0
  107. package/lib/components/properties/textures/renderTargetTextureProperties.d.ts +5 -0
  108. package/lib/components/properties/textures/textureFormatUtils.d.ts +48 -0
  109. package/lib/components/properties/textures/texturePreview.d.ts +17 -0
  110. package/lib/components/properties/textures/textureProperties.d.ts +11 -0
  111. package/lib/components/properties/textures/thinTextureProperties.d.ts +8 -0
  112. package/lib/components/properties/transformProperties.d.ts +11 -0
  113. package/lib/components/scene/sceneExplorer.d.ts +182 -0
  114. package/lib/components/scene/sceneExplorerDragDrop.d.ts +38 -0
  115. package/lib/components/scene/sceneProperties.d.ts +19 -0
  116. package/lib/components/stats/countStats.d.ts +5 -0
  117. package/lib/components/stats/frameStepStats.d.ts +8 -0
  118. package/lib/components/stats/performanceStats.d.ts +6 -0
  119. package/lib/components/stats/statsPane.d.ts +3 -0
  120. package/lib/components/stats/systemStats.d.ts +5 -0
  121. package/lib/components/teachingMoment.d.ts +20 -0
  122. package/lib/components/textureEditor/canvasManager.d.ts +113 -0
  123. package/lib/components/textureEditor/canvasShader.d.ts +10 -0
  124. package/lib/components/textureEditor/channels.d.ts +25 -0
  125. package/lib/components/textureEditor/properties.d.ts +23 -0
  126. package/lib/components/textureEditor/status.d.ts +13 -0
  127. package/lib/components/textureEditor/textureEditor.d.ts +113 -0
  128. package/lib/components/textureEditor/tools.d.ts +20 -0
  129. package/lib/components/theme.d.ts +10 -0
  130. package/lib/components/tools/capture/equirectangularCaptureTool.d.ts +5 -0
  131. package/lib/components/tools/capture/gifCaptureTool.d.ts +7 -0
  132. package/lib/components/tools/capture/sceneReplayTool.d.ts +5 -0
  133. package/lib/components/tools/capture/screenshotTool.d.ts +5 -0
  134. package/lib/components/tools/capture/videoCaptureTool.d.ts +5 -0
  135. package/lib/components/tools/exportTools.d.ts +11 -0
  136. package/lib/components/tools/import/gltfAnimationImportTool.d.ts +5 -0
  137. package/lib/components/tools/import/gltfLoaderOptionsTool.d.ts +8 -0
  138. package/lib/components/tools/import/gltfValidationTool.d.ts +5 -0
  139. package/lib/components/tools/reflectorTools.d.ts +5 -0
  140. package/lib/components/tools/toolsPane.d.ts +3 -0
  141. package/lib/components/uxContextProvider.d.ts +2 -0
  142. package/lib/contexts/extensionManagerContext.d.ts +6 -0
  143. package/lib/contexts/propertyContext.d.ts +30 -0
  144. package/lib/contexts/settingsContext.d.ts +3 -0
  145. package/lib/contexts/watcherContext.d.ts +3 -0
  146. package/lib/extensibility/builtInsExtensionFeed.d.ts +21 -0
  147. package/lib/extensibility/defaultInspectorExtensionFeed.d.ts +5 -0
  148. package/lib/extensibility/extensionFeed.d.ts +113 -0
  149. package/lib/extensibility/extensionManager.d.ts +111 -0
  150. package/lib/extensions/quickCreate/cameras.d.ts +14 -0
  151. package/lib/extensions/quickCreate/frameGraphs.d.ts +14 -0
  152. package/lib/extensions/quickCreate/lights.d.ts +14 -0
  153. package/lib/extensions/quickCreate/materials.d.ts +14 -0
  154. package/lib/extensions/quickCreate/meshes.d.ts +10 -0
  155. package/lib/extensions/quickCreate/particles.d.ts +15 -0
  156. package/lib/extensions/quickCreate/quickCreateLayout.d.ts +44 -0
  157. package/lib/extensions/quickCreate/quickCreateToolsService.d.ts +11 -0
  158. package/lib/extensions/quickCreate/renderingPipelines.d.ts +14 -0
  159. package/lib/extensions/quickCreate/settingsPopover.d.ts +14 -0
  160. package/lib/extensions/quickCreate/spriteManagers.d.ts +14 -0
  161. package/lib/{extensionsListService-zYdKn8uM.js → extensionsListService-eRZtqcfj.js} +8 -8
  162. package/lib/extensionsListService-eRZtqcfj.js.map +1 -0
  163. package/lib/hooks/compoundPropertyHooks.d.ts +24 -0
  164. package/lib/hooks/instrumentationHooks.d.ts +9 -0
  165. package/lib/hooks/observableHooks.d.ts +35 -0
  166. package/lib/hooks/pollingHooks.d.ts +7 -0
  167. package/lib/hooks/resourceHooks.d.ts +20 -0
  168. package/lib/hooks/settingsHooks.d.ts +13 -0
  169. package/lib/hooks/teachingMomentHooks.d.ts +34 -0
  170. package/lib/hooks/themeHooks.d.ts +17 -0
  171. package/lib/hooks/useObservableArray.d.ts +11 -0
  172. package/lib/hooks/useResizeHandle.d.ts +35 -0
  173. package/lib/{index-DuVF9zYN.js → index-FWuITINA.js} +1932 -1031
  174. package/lib/index-FWuITINA.js.map +1 -0
  175. package/lib/index.d.ts +111 -74767
  176. package/lib/index.js +6 -6
  177. package/lib/inspectable.d.ts +67 -0
  178. package/lib/inspector.d.ts +41 -0
  179. package/lib/instrumentation/functionInstrumentation.d.ts +20 -0
  180. package/lib/instrumentation/propertyInstrumentation.d.ts +33 -0
  181. package/lib/legacy/debugLayer.d.ts +24 -0
  182. package/lib/legacy/inspectableCustomPropertiesService.d.ts +3 -0
  183. package/lib/legacy/inspector.d.ts +39 -0
  184. package/lib/legacy/legacy.d.ts +9 -0
  185. package/lib/legacy/propertiesSectionMapping.d.ts +99 -0
  186. package/lib/misc/arrayUtils.d.ts +4 -0
  187. package/lib/misc/assert.d.ts +5 -0
  188. package/lib/misc/defaultPerfStrategies.d.ts +16 -0
  189. package/lib/misc/graphUtils.d.ts +44 -0
  190. package/lib/misc/nodeGeometryEditor.d.ts +3 -0
  191. package/lib/misc/nodeMaterialEditor.d.ts +2 -0
  192. package/lib/misc/nodeParticleEditor.d.ts +2 -0
  193. package/lib/misc/nodeRenderGraphEditor.d.ts +2 -0
  194. package/lib/misc/observableCollection.d.ts +23 -0
  195. package/lib/misc/snippetUtils.d.ts +74 -0
  196. package/lib/misc/textureTools.d.ts +34 -0
  197. package/lib/modularTool.d.ts +42 -0
  198. package/lib/modularity/serviceContainer.d.ts +64 -0
  199. package/lib/modularity/serviceDefinition.d.ts +64 -0
  200. package/lib/{quickCreateToolsService-BtsSLeMY.js → quickCreateToolsService-MzZbVrvr.js} +7 -7
  201. package/lib/quickCreateToolsService-MzZbVrvr.js.map +1 -0
  202. package/lib/{reflectorService-Bzs-Ykos.js → reflectorService-DdPEZLjO.js} +7 -7
  203. package/lib/reflectorService-DdPEZLjO.js.map +1 -0
  204. package/lib/services/cli/cliConnectionStatus.d.ts +19 -0
  205. package/lib/services/cli/entityQueryService.d.ts +8 -0
  206. package/lib/services/cli/inspectableBridgeService.d.ts +22 -0
  207. package/lib/services/cli/inspectableCommandRegistry.d.ts +58 -0
  208. package/lib/services/cli/perfTraceCommandService.d.ts +9 -0
  209. package/lib/services/cli/screenshotCommandService.d.ts +8 -0
  210. package/lib/services/cli/shaderCommandService.d.ts +7 -0
  211. package/lib/services/cli/statsCommandService.d.ts +9 -0
  212. package/lib/services/cliConnectionStatusService.d.ts +4 -0
  213. package/lib/services/defaultToolbarMetadata.d.ts +6 -0
  214. package/lib/services/extensionsListService.d.ts +3 -0
  215. package/lib/services/gizmoService.d.ts +84 -0
  216. package/lib/services/gizmoToolbarService.d.ts +5 -0
  217. package/lib/services/globalSettings.d.ts +5 -0
  218. package/lib/services/highlightService.d.ts +8 -0
  219. package/lib/services/miniStatsService.d.ts +4 -0
  220. package/lib/services/panes/debugService.d.ts +25 -0
  221. package/lib/services/panes/properties/animationGroupPropertiesService.d.ts +4 -0
  222. package/lib/services/panes/properties/animationPropertiesService.d.ts +5 -0
  223. package/lib/services/panes/properties/atmospherePropertiesService.d.ts +5 -0
  224. package/lib/services/panes/properties/audioPropertiesService.d.ts +3 -0
  225. package/lib/services/panes/properties/cameraPropertiesService.d.ts +7 -0
  226. package/lib/services/panes/properties/commonPropertiesService.d.ts +3 -0
  227. package/lib/services/panes/properties/effectLayerPropertiesService.d.ts +3 -0
  228. package/lib/services/panes/properties/frameGraphPropertiesService.d.ts +3 -0
  229. package/lib/services/panes/properties/lightPropertiesServices.d.ts +4 -0
  230. package/lib/services/panes/properties/materialPropertiesService.d.ts +4 -0
  231. package/lib/services/panes/properties/metadataPropertiesService.d.ts +3 -0
  232. package/lib/services/panes/properties/nodePropertiesService.d.ts +4 -0
  233. package/lib/services/panes/properties/particleSystemPropertiesService.d.ts +4 -0
  234. package/lib/services/panes/properties/physicsPropertiesService.d.ts +3 -0
  235. package/lib/services/panes/properties/postProcessPropertiesService.d.ts +3 -0
  236. package/lib/services/panes/properties/propertiesService.d.ts +53 -0
  237. package/lib/services/panes/properties/renderingPipelinePropertiesService.d.ts +3 -0
  238. package/lib/services/panes/properties/scenePropertiesService.d.ts +4 -0
  239. package/lib/services/panes/properties/skeletonPropertiesService.d.ts +4 -0
  240. package/lib/services/panes/properties/spritePropertiesService.d.ts +4 -0
  241. package/lib/services/panes/properties/texturePropertiesService.d.ts +4 -0
  242. package/lib/services/panes/properties/transformPropertiesService.d.ts +3 -0
  243. package/lib/services/panes/scene/animationGroupExplorerService.d.ts +5 -0
  244. package/lib/services/panes/scene/atmosphereExplorerService.d.ts +5 -0
  245. package/lib/services/panes/scene/defaultSectionsMetadata.d.ts +33 -0
  246. package/lib/services/panes/scene/disposableCommandService.d.ts +4 -0
  247. package/lib/services/panes/scene/effectLayersExplorerService.d.ts +5 -0
  248. package/lib/services/panes/scene/frameGraphExplorerService.d.ts +5 -0
  249. package/lib/services/panes/scene/guiExplorerService.d.ts +5 -0
  250. package/lib/services/panes/scene/materialExplorerService.d.ts +5 -0
  251. package/lib/services/panes/scene/nodeExplorerService.d.ts +7 -0
  252. package/lib/services/panes/scene/particleSystemExplorerService.d.ts +5 -0
  253. package/lib/services/panes/scene/postProcessExplorerService.d.ts +5 -0
  254. package/lib/services/panes/scene/renderingPipelinesExplorerService.d.ts +5 -0
  255. package/lib/services/panes/scene/sceneExplorerService.d.ts +34 -0
  256. package/lib/services/panes/scene/skeletonExplorerService.d.ts +5 -0
  257. package/lib/services/panes/scene/soundExplorerService.d.ts +5 -0
  258. package/lib/services/panes/scene/spriteManagerExplorerService.d.ts +6 -0
  259. package/lib/services/panes/scene/texturesExplorerService.d.ts +5 -0
  260. package/lib/services/panes/settingsService.d.ts +25 -0
  261. package/lib/services/panes/statsService.d.ts +28 -0
  262. package/lib/services/panes/tools/captureService.d.ts +3 -0
  263. package/lib/services/panes/tools/exportService.d.ts +3 -0
  264. package/lib/services/panes/tools/import/gltfAnimationImportService.d.ts +3 -0
  265. package/lib/services/panes/tools/import/gltfLoaderOptionsDefaults.d.ts +46 -0
  266. package/lib/services/panes/tools/import/gltfLoaderOptionsService.d.ts +4 -0
  267. package/lib/services/panes/tools/import/gltfValidationService.d.ts +3 -0
  268. package/lib/services/panes/tools/reflectorService.d.ts +7 -0
  269. package/lib/services/panes/toolsService.d.ts +29 -0
  270. package/lib/services/pickingService.d.ts +7 -0
  271. package/lib/services/reactContextService.d.ts +18 -0
  272. package/lib/services/sceneContext.d.ts +19 -0
  273. package/lib/services/selectionService.d.ts +24 -0
  274. package/lib/services/settingsStore.d.ts +55 -0
  275. package/lib/services/shellService.d.ts +256 -0
  276. package/lib/services/shellSettingsService.d.ts +3 -0
  277. package/lib/services/textureEditor/textureEditorService.d.ts +21 -0
  278. package/lib/services/textureEditor/tools/contrast.d.ts +2 -0
  279. package/lib/services/textureEditor/tools/eyedropper.d.ts +5 -0
  280. package/lib/services/textureEditor/tools/floodfill.d.ts +5 -0
  281. package/lib/services/textureEditor/tools/paintbrush.d.ts +2 -0
  282. package/lib/services/textureEditor/tools/rectangularSelect.d.ts +5 -0
  283. package/lib/services/themeSelectorService.d.ts +3 -0
  284. package/lib/services/themeService.d.ts +60 -0
  285. package/lib/services/userFeedbackService.d.ts +3 -0
  286. package/lib/services/watcherService.d.ts +38 -0
  287. package/lib/themes/babylonTheme.d.ts +3 -0
  288. package/package.json +12 -5
  289. package/readme.md +27 -0
  290. package/lib/extensionsListService-zYdKn8uM.js.map +0 -1
  291. package/lib/index-DuVF9zYN.js.map +0 -1
  292. package/lib/quickCreateToolsService-BtsSLeMY.js.map +0 -1
  293. package/lib/reflectorService-Bzs-Ykos.js.map +0 -1
@@ -0,0 +1,4931 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { spawn } from 'child_process';
4
+ import require$$1, { join, dirname, resolve } from 'path';
5
+ import require$$7, { fileURLToPath } from 'url';
6
+ import { parseArgs } from 'util';
7
+ import require$$0$3 from 'events';
8
+ import require$$1$1 from 'https';
9
+ import require$$2$1 from 'http';
10
+ import require$$3 from 'net';
11
+ import require$$4 from 'tls';
12
+ import require$$5 from 'crypto';
13
+ import require$$0$2 from 'stream';
14
+ import require$$0$1 from 'zlib';
15
+ import require$$0, { readFileSync, existsSync } from 'fs';
16
+ import require$$2 from 'os';
17
+
18
+ function getDefaultExportFromCjs (x) {
19
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
20
+ }
21
+
22
+ var bufferUtil$1 = {exports: {}};
23
+
24
+ var constants = {
25
+ BINARY_TYPES: ['nodebuffer', 'arraybuffer', 'fragments'],
26
+ GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
27
+ kStatusCode: Symbol('status-code'),
28
+ kWebSocket: Symbol('websocket'),
29
+ EMPTY_BUFFER: Buffer.alloc(0),
30
+ NOOP: () => {}
31
+ };
32
+
33
+ var bufferutil = {exports: {}};
34
+
35
+ function commonjsRequire(path) {
36
+ throw new Error('Could not dynamically require "' + path + '". Please configure the dynamicRequireTargets or/and ignoreDynamicRequires option of @rollup/plugin-commonjs appropriately for this require call to work.');
37
+ }
38
+
39
+ var nodeGypBuild$1 = {exports: {}};
40
+
41
+ var nodeGypBuild;
42
+ var hasRequiredNodeGypBuild$1;
43
+
44
+ function requireNodeGypBuild$1 () {
45
+ if (hasRequiredNodeGypBuild$1) return nodeGypBuild;
46
+ hasRequiredNodeGypBuild$1 = 1;
47
+ var fs = require$$0;
48
+ var path = require$$1;
49
+ var os = require$$2;
50
+
51
+ // Workaround to fix webpack's build warnings: 'the request of a dependency is an expression'
52
+ var runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : commonjsRequire; // eslint-disable-line
53
+
54
+ var vars = (process.config && process.config.variables) || {};
55
+ var prebuildsOnly = !!process.env.PREBUILDS_ONLY;
56
+ var abi = process.versions.modules; // TODO: support old node where this is undef
57
+ var runtime = isElectron() ? 'electron' : (isNwjs() ? 'node-webkit' : 'node');
58
+
59
+ var arch = process.env.npm_config_arch || os.arch();
60
+ var platform = process.env.npm_config_platform || os.platform();
61
+ var libc = process.env.LIBC || (isAlpine(platform) ? 'musl' : 'glibc');
62
+ var armv = process.env.ARM_VERSION || (arch === 'arm64' ? '8' : vars.arm_version) || '';
63
+ var uv = (process.versions.uv || '').split('.')[0];
64
+
65
+ nodeGypBuild = load;
66
+
67
+ function load (dir) {
68
+ return runtimeRequire(load.resolve(dir))
69
+ }
70
+
71
+ load.resolve = load.path = function (dir) {
72
+ dir = path.resolve(dir || '.');
73
+
74
+ try {
75
+ var name = runtimeRequire(path.join(dir, 'package.json')).name.toUpperCase().replace(/-/g, '_');
76
+ if (process.env[name + '_PREBUILD']) dir = process.env[name + '_PREBUILD'];
77
+ } catch (err) {}
78
+
79
+ if (!prebuildsOnly) {
80
+ var release = getFirst(path.join(dir, 'build/Release'), matchBuild);
81
+ if (release) return release
82
+
83
+ var debug = getFirst(path.join(dir, 'build/Debug'), matchBuild);
84
+ if (debug) return debug
85
+ }
86
+
87
+ var prebuild = resolve(dir);
88
+ if (prebuild) return prebuild
89
+
90
+ var nearby = resolve(path.dirname(process.execPath));
91
+ if (nearby) return nearby
92
+
93
+ var target = [
94
+ 'platform=' + platform,
95
+ 'arch=' + arch,
96
+ 'runtime=' + runtime,
97
+ 'abi=' + abi,
98
+ 'uv=' + uv,
99
+ armv ? 'armv=' + armv : '',
100
+ 'libc=' + libc,
101
+ 'node=' + process.versions.node,
102
+ process.versions.electron ? 'electron=' + process.versions.electron : '',
103
+ typeof __webpack_require__ === 'function' ? 'webpack=true' : '' // eslint-disable-line
104
+ ].filter(Boolean).join(' ');
105
+
106
+ throw new Error('No native build was found for ' + target + '\n loaded from: ' + dir + '\n')
107
+
108
+ function resolve (dir) {
109
+ // Find matching "prebuilds/<platform>-<arch>" directory
110
+ var tuples = readdirSync(path.join(dir, 'prebuilds')).map(parseTuple);
111
+ var tuple = tuples.filter(matchTuple(platform, arch)).sort(compareTuples)[0];
112
+ if (!tuple) return
113
+
114
+ // Find most specific flavor first
115
+ var prebuilds = path.join(dir, 'prebuilds', tuple.name);
116
+ var parsed = readdirSync(prebuilds).map(parseTags);
117
+ var candidates = parsed.filter(matchTags(runtime, abi));
118
+ var winner = candidates.sort(compareTags(runtime))[0];
119
+ if (winner) return path.join(prebuilds, winner.file)
120
+ }
121
+ };
122
+
123
+ function readdirSync (dir) {
124
+ try {
125
+ return fs.readdirSync(dir)
126
+ } catch (err) {
127
+ return []
128
+ }
129
+ }
130
+
131
+ function getFirst (dir, filter) {
132
+ var files = readdirSync(dir).filter(filter);
133
+ return files[0] && path.join(dir, files[0])
134
+ }
135
+
136
+ function matchBuild (name) {
137
+ return /\.node$/.test(name)
138
+ }
139
+
140
+ function parseTuple (name) {
141
+ // Example: darwin-x64+arm64
142
+ var arr = name.split('-');
143
+ if (arr.length !== 2) return
144
+
145
+ var platform = arr[0];
146
+ var architectures = arr[1].split('+');
147
+
148
+ if (!platform) return
149
+ if (!architectures.length) return
150
+ if (!architectures.every(Boolean)) return
151
+
152
+ return { name, platform, architectures }
153
+ }
154
+
155
+ function matchTuple (platform, arch) {
156
+ return function (tuple) {
157
+ if (tuple == null) return false
158
+ if (tuple.platform !== platform) return false
159
+ return tuple.architectures.includes(arch)
160
+ }
161
+ }
162
+
163
+ function compareTuples (a, b) {
164
+ // Prefer single-arch prebuilds over multi-arch
165
+ return a.architectures.length - b.architectures.length
166
+ }
167
+
168
+ function parseTags (file) {
169
+ var arr = file.split('.');
170
+ var extension = arr.pop();
171
+ var tags = { file: file, specificity: 0 };
172
+
173
+ if (extension !== 'node') return
174
+
175
+ for (var i = 0; i < arr.length; i++) {
176
+ var tag = arr[i];
177
+
178
+ if (tag === 'node' || tag === 'electron' || tag === 'node-webkit') {
179
+ tags.runtime = tag;
180
+ } else if (tag === 'napi') {
181
+ tags.napi = true;
182
+ } else if (tag.slice(0, 3) === 'abi') {
183
+ tags.abi = tag.slice(3);
184
+ } else if (tag.slice(0, 2) === 'uv') {
185
+ tags.uv = tag.slice(2);
186
+ } else if (tag.slice(0, 4) === 'armv') {
187
+ tags.armv = tag.slice(4);
188
+ } else if (tag === 'glibc' || tag === 'musl') {
189
+ tags.libc = tag;
190
+ } else {
191
+ continue
192
+ }
193
+
194
+ tags.specificity++;
195
+ }
196
+
197
+ return tags
198
+ }
199
+
200
+ function matchTags (runtime, abi) {
201
+ return function (tags) {
202
+ if (tags == null) return false
203
+ if (tags.runtime && tags.runtime !== runtime && !runtimeAgnostic(tags)) return false
204
+ if (tags.abi && tags.abi !== abi && !tags.napi) return false
205
+ if (tags.uv && tags.uv !== uv) return false
206
+ if (tags.armv && tags.armv !== armv) return false
207
+ if (tags.libc && tags.libc !== libc) return false
208
+
209
+ return true
210
+ }
211
+ }
212
+
213
+ function runtimeAgnostic (tags) {
214
+ return tags.runtime === 'node' && tags.napi
215
+ }
216
+
217
+ function compareTags (runtime) {
218
+ // Precedence: non-agnostic runtime, abi over napi, then by specificity.
219
+ return function (a, b) {
220
+ if (a.runtime !== b.runtime) {
221
+ return a.runtime === runtime ? -1 : 1
222
+ } else if (a.abi !== b.abi) {
223
+ return a.abi ? -1 : 1
224
+ } else if (a.specificity !== b.specificity) {
225
+ return a.specificity > b.specificity ? -1 : 1
226
+ } else {
227
+ return 0
228
+ }
229
+ }
230
+ }
231
+
232
+ function isNwjs () {
233
+ return !!(process.versions && process.versions.nw)
234
+ }
235
+
236
+ function isElectron () {
237
+ if (process.versions && process.versions.electron) return true
238
+ if (process.env.ELECTRON_RUN_AS_NODE) return true
239
+ return typeof window !== 'undefined' && window.process && window.process.type === 'renderer'
240
+ }
241
+
242
+ function isAlpine (platform) {
243
+ return platform === 'linux' && fs.existsSync('/etc/alpine-release')
244
+ }
245
+
246
+ // Exposed for unit tests
247
+ // TODO: move to lib
248
+ load.parseTags = parseTags;
249
+ load.matchTags = matchTags;
250
+ load.compareTags = compareTags;
251
+ load.parseTuple = parseTuple;
252
+ load.matchTuple = matchTuple;
253
+ load.compareTuples = compareTuples;
254
+ return nodeGypBuild;
255
+ }
256
+
257
+ var hasRequiredNodeGypBuild;
258
+
259
+ function requireNodeGypBuild () {
260
+ if (hasRequiredNodeGypBuild) return nodeGypBuild$1.exports;
261
+ hasRequiredNodeGypBuild = 1;
262
+ const runtimeRequire = typeof __webpack_require__ === 'function' ? __non_webpack_require__ : commonjsRequire; // eslint-disable-line
263
+ if (typeof runtimeRequire.addon === 'function') { // if the platform supports native resolving prefer that
264
+ nodeGypBuild$1.exports = runtimeRequire.addon.bind(runtimeRequire);
265
+ } else { // else use the runtime version here
266
+ nodeGypBuild$1.exports = requireNodeGypBuild$1();
267
+ }
268
+ return nodeGypBuild$1.exports;
269
+ }
270
+
271
+ var fallback$1;
272
+ var hasRequiredFallback$1;
273
+
274
+ function requireFallback$1 () {
275
+ if (hasRequiredFallback$1) return fallback$1;
276
+ hasRequiredFallback$1 = 1;
277
+
278
+ /**
279
+ * Masks a buffer using the given mask.
280
+ *
281
+ * @param {Buffer} source The buffer to mask
282
+ * @param {Buffer} mask The mask to use
283
+ * @param {Buffer} output The buffer where to store the result
284
+ * @param {Number} offset The offset at which to start writing
285
+ * @param {Number} length The number of bytes to mask.
286
+ * @public
287
+ */
288
+ const mask = (source, mask, output, offset, length) => {
289
+ for (var i = 0; i < length; i++) {
290
+ output[offset + i] = source[i] ^ mask[i & 3];
291
+ }
292
+ };
293
+
294
+ /**
295
+ * Unmasks a buffer using the given mask.
296
+ *
297
+ * @param {Buffer} buffer The buffer to unmask
298
+ * @param {Buffer} mask The mask to use
299
+ * @public
300
+ */
301
+ const unmask = (buffer, mask) => {
302
+ // Required until https://github.com/nodejs/node/issues/9006 is resolved.
303
+ const length = buffer.length;
304
+ for (var i = 0; i < length; i++) {
305
+ buffer[i] ^= mask[i & 3];
306
+ }
307
+ };
308
+
309
+ fallback$1 = { mask, unmask };
310
+ return fallback$1;
311
+ }
312
+
313
+ var hasRequiredBufferutil;
314
+
315
+ function requireBufferutil () {
316
+ if (hasRequiredBufferutil) return bufferutil.exports;
317
+ hasRequiredBufferutil = 1;
318
+
319
+ try {
320
+ bufferutil.exports = requireNodeGypBuild()(__dirname);
321
+ } catch (e) {
322
+ bufferutil.exports = requireFallback$1();
323
+ }
324
+ return bufferutil.exports;
325
+ }
326
+
327
+ const { EMPTY_BUFFER: EMPTY_BUFFER$3 } = constants;
328
+
329
+ /**
330
+ * Merges an array of buffers into a new buffer.
331
+ *
332
+ * @param {Buffer[]} list The array of buffers to concat
333
+ * @param {Number} totalLength The total length of buffers in the list
334
+ * @return {Buffer} The resulting buffer
335
+ * @public
336
+ */
337
+ function concat$1(list, totalLength) {
338
+ if (list.length === 0) return EMPTY_BUFFER$3;
339
+ if (list.length === 1) return list[0];
340
+
341
+ const target = Buffer.allocUnsafe(totalLength);
342
+ let offset = 0;
343
+
344
+ for (let i = 0; i < list.length; i++) {
345
+ const buf = list[i];
346
+ target.set(buf, offset);
347
+ offset += buf.length;
348
+ }
349
+
350
+ if (offset < totalLength) return target.slice(0, offset);
351
+
352
+ return target;
353
+ }
354
+
355
+ /**
356
+ * Masks a buffer using the given mask.
357
+ *
358
+ * @param {Buffer} source The buffer to mask
359
+ * @param {Buffer} mask The mask to use
360
+ * @param {Buffer} output The buffer where to store the result
361
+ * @param {Number} offset The offset at which to start writing
362
+ * @param {Number} length The number of bytes to mask.
363
+ * @public
364
+ */
365
+ function _mask(source, mask, output, offset, length) {
366
+ for (let i = 0; i < length; i++) {
367
+ output[offset + i] = source[i] ^ mask[i & 3];
368
+ }
369
+ }
370
+
371
+ /**
372
+ * Unmasks a buffer using the given mask.
373
+ *
374
+ * @param {Buffer} buffer The buffer to unmask
375
+ * @param {Buffer} mask The mask to use
376
+ * @public
377
+ */
378
+ function _unmask(buffer, mask) {
379
+ // Required until https://github.com/nodejs/node/issues/9006 is resolved.
380
+ const length = buffer.length;
381
+ for (let i = 0; i < length; i++) {
382
+ buffer[i] ^= mask[i & 3];
383
+ }
384
+ }
385
+
386
+ /**
387
+ * Converts a buffer to an `ArrayBuffer`.
388
+ *
389
+ * @param {Buffer} buf The buffer to convert
390
+ * @return {ArrayBuffer} Converted buffer
391
+ * @public
392
+ */
393
+ function toArrayBuffer$1(buf) {
394
+ if (buf.byteLength === buf.buffer.byteLength) {
395
+ return buf.buffer;
396
+ }
397
+
398
+ return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
399
+ }
400
+
401
+ /**
402
+ * Converts `data` to a `Buffer`.
403
+ *
404
+ * @param {*} data The data to convert
405
+ * @return {Buffer} The buffer
406
+ * @throws {TypeError}
407
+ * @public
408
+ */
409
+ function toBuffer$2(data) {
410
+ toBuffer$2.readOnly = true;
411
+
412
+ if (Buffer.isBuffer(data)) return data;
413
+
414
+ let buf;
415
+
416
+ if (data instanceof ArrayBuffer) {
417
+ buf = Buffer.from(data);
418
+ } else if (ArrayBuffer.isView(data)) {
419
+ buf = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
420
+ } else {
421
+ buf = Buffer.from(data);
422
+ toBuffer$2.readOnly = false;
423
+ }
424
+
425
+ return buf;
426
+ }
427
+
428
+ try {
429
+ const bufferUtil = requireBufferutil();
430
+ const bu = bufferUtil.BufferUtil || bufferUtil;
431
+
432
+ bufferUtil$1.exports = {
433
+ concat: concat$1,
434
+ mask(source, mask, output, offset, length) {
435
+ if (length < 48) _mask(source, mask, output, offset, length);
436
+ else bu.mask(source, mask, output, offset, length);
437
+ },
438
+ toArrayBuffer: toArrayBuffer$1,
439
+ toBuffer: toBuffer$2,
440
+ unmask(buffer, mask) {
441
+ if (buffer.length < 32) _unmask(buffer, mask);
442
+ else bu.unmask(buffer, mask);
443
+ }
444
+ };
445
+ } catch (e) /* istanbul ignore next */ {
446
+ bufferUtil$1.exports = {
447
+ concat: concat$1,
448
+ mask: _mask,
449
+ toArrayBuffer: toArrayBuffer$1,
450
+ toBuffer: toBuffer$2,
451
+ unmask: _unmask
452
+ };
453
+ }
454
+
455
+ var bufferUtilExports = bufferUtil$1.exports;
456
+
457
+ const kDone = Symbol('kDone');
458
+ const kRun = Symbol('kRun');
459
+
460
+ /**
461
+ * A very simple job queue with adjustable concurrency. Adapted from
462
+ * https://github.com/STRML/async-limiter
463
+ */
464
+ let Limiter$1 = class Limiter {
465
+ /**
466
+ * Creates a new `Limiter`.
467
+ *
468
+ * @param {Number} [concurrency=Infinity] The maximum number of jobs allowed
469
+ * to run concurrently
470
+ */
471
+ constructor(concurrency) {
472
+ this[kDone] = () => {
473
+ this.pending--;
474
+ this[kRun]();
475
+ };
476
+ this.concurrency = concurrency || Infinity;
477
+ this.jobs = [];
478
+ this.pending = 0;
479
+ }
480
+
481
+ /**
482
+ * Adds a job to the queue.
483
+ *
484
+ * @param {Function} job The job to run
485
+ * @public
486
+ */
487
+ add(job) {
488
+ this.jobs.push(job);
489
+ this[kRun]();
490
+ }
491
+
492
+ /**
493
+ * Removes a job from the queue and runs it if possible.
494
+ *
495
+ * @private
496
+ */
497
+ [kRun]() {
498
+ if (this.pending === this.concurrency) return;
499
+
500
+ if (this.jobs.length) {
501
+ const job = this.jobs.shift();
502
+
503
+ this.pending++;
504
+ job(this[kDone]);
505
+ }
506
+ }
507
+ };
508
+
509
+ var limiter = Limiter$1;
510
+
511
+ const zlib = require$$0$1;
512
+
513
+ const bufferUtil = bufferUtilExports;
514
+ const Limiter = limiter;
515
+ const { kStatusCode: kStatusCode$2, NOOP: NOOP$1 } = constants;
516
+
517
+ const TRAILER = Buffer.from([0x00, 0x00, 0xff, 0xff]);
518
+ const kPerMessageDeflate = Symbol('permessage-deflate');
519
+ const kTotalLength = Symbol('total-length');
520
+ const kCallback = Symbol('callback');
521
+ const kBuffers = Symbol('buffers');
522
+ const kError = Symbol('error');
523
+
524
+ //
525
+ // We limit zlib concurrency, which prevents severe memory fragmentation
526
+ // as documented in https://github.com/nodejs/node/issues/8871#issuecomment-250915913
527
+ // and https://github.com/websockets/ws/issues/1202
528
+ //
529
+ // Intentionally global; it's the global thread pool that's an issue.
530
+ //
531
+ let zlibLimiter;
532
+
533
+ /**
534
+ * permessage-deflate implementation.
535
+ */
536
+ let PerMessageDeflate$4 = class PerMessageDeflate {
537
+ /**
538
+ * Creates a PerMessageDeflate instance.
539
+ *
540
+ * @param {Object} [options] Configuration options
541
+ * @param {Boolean} [options.serverNoContextTakeover=false] Request/accept
542
+ * disabling of server context takeover
543
+ * @param {Boolean} [options.clientNoContextTakeover=false] Advertise/
544
+ * acknowledge disabling of client context takeover
545
+ * @param {(Boolean|Number)} [options.serverMaxWindowBits] Request/confirm the
546
+ * use of a custom server window size
547
+ * @param {(Boolean|Number)} [options.clientMaxWindowBits] Advertise support
548
+ * for, or request, a custom client window size
549
+ * @param {Object} [options.zlibDeflateOptions] Options to pass to zlib on
550
+ * deflate
551
+ * @param {Object} [options.zlibInflateOptions] Options to pass to zlib on
552
+ * inflate
553
+ * @param {Number} [options.threshold=1024] Size (in bytes) below which
554
+ * messages should not be compressed
555
+ * @param {Number} [options.concurrencyLimit=10] The number of concurrent
556
+ * calls to zlib
557
+ * @param {Boolean} [isServer=false] Create the instance in either server or
558
+ * client mode
559
+ * @param {Number} [maxPayload=0] The maximum allowed message length
560
+ */
561
+ constructor(options, isServer, maxPayload) {
562
+ this._maxPayload = maxPayload | 0;
563
+ this._options = options || {};
564
+ this._threshold =
565
+ this._options.threshold !== undefined ? this._options.threshold : 1024;
566
+ this._isServer = !!isServer;
567
+ this._deflate = null;
568
+ this._inflate = null;
569
+
570
+ this.params = null;
571
+
572
+ if (!zlibLimiter) {
573
+ const concurrency =
574
+ this._options.concurrencyLimit !== undefined
575
+ ? this._options.concurrencyLimit
576
+ : 10;
577
+ zlibLimiter = new Limiter(concurrency);
578
+ }
579
+ }
580
+
581
+ /**
582
+ * @type {String}
583
+ */
584
+ static get extensionName() {
585
+ return 'permessage-deflate';
586
+ }
587
+
588
+ /**
589
+ * Create an extension negotiation offer.
590
+ *
591
+ * @return {Object} Extension parameters
592
+ * @public
593
+ */
594
+ offer() {
595
+ const params = {};
596
+
597
+ if (this._options.serverNoContextTakeover) {
598
+ params.server_no_context_takeover = true;
599
+ }
600
+ if (this._options.clientNoContextTakeover) {
601
+ params.client_no_context_takeover = true;
602
+ }
603
+ if (this._options.serverMaxWindowBits) {
604
+ params.server_max_window_bits = this._options.serverMaxWindowBits;
605
+ }
606
+ if (this._options.clientMaxWindowBits) {
607
+ params.client_max_window_bits = this._options.clientMaxWindowBits;
608
+ } else if (this._options.clientMaxWindowBits == null) {
609
+ params.client_max_window_bits = true;
610
+ }
611
+
612
+ return params;
613
+ }
614
+
615
+ /**
616
+ * Accept an extension negotiation offer/response.
617
+ *
618
+ * @param {Array} configurations The extension negotiation offers/reponse
619
+ * @return {Object} Accepted configuration
620
+ * @public
621
+ */
622
+ accept(configurations) {
623
+ configurations = this.normalizeParams(configurations);
624
+
625
+ this.params = this._isServer
626
+ ? this.acceptAsServer(configurations)
627
+ : this.acceptAsClient(configurations);
628
+
629
+ return this.params;
630
+ }
631
+
632
+ /**
633
+ * Releases all resources used by the extension.
634
+ *
635
+ * @public
636
+ */
637
+ cleanup() {
638
+ if (this._inflate) {
639
+ this._inflate.close();
640
+ this._inflate = null;
641
+ }
642
+
643
+ if (this._deflate) {
644
+ const callback = this._deflate[kCallback];
645
+
646
+ this._deflate.close();
647
+ this._deflate = null;
648
+
649
+ if (callback) {
650
+ callback(
651
+ new Error(
652
+ 'The deflate stream was closed while data was being processed'
653
+ )
654
+ );
655
+ }
656
+ }
657
+ }
658
+
659
+ /**
660
+ * Accept an extension negotiation offer.
661
+ *
662
+ * @param {Array} offers The extension negotiation offers
663
+ * @return {Object} Accepted configuration
664
+ * @private
665
+ */
666
+ acceptAsServer(offers) {
667
+ const opts = this._options;
668
+ const accepted = offers.find((params) => {
669
+ if (
670
+ (opts.serverNoContextTakeover === false &&
671
+ params.server_no_context_takeover) ||
672
+ (params.server_max_window_bits &&
673
+ (opts.serverMaxWindowBits === false ||
674
+ (typeof opts.serverMaxWindowBits === 'number' &&
675
+ opts.serverMaxWindowBits > params.server_max_window_bits))) ||
676
+ (typeof opts.clientMaxWindowBits === 'number' &&
677
+ !params.client_max_window_bits)
678
+ ) {
679
+ return false;
680
+ }
681
+
682
+ return true;
683
+ });
684
+
685
+ if (!accepted) {
686
+ throw new Error('None of the extension offers can be accepted');
687
+ }
688
+
689
+ if (opts.serverNoContextTakeover) {
690
+ accepted.server_no_context_takeover = true;
691
+ }
692
+ if (opts.clientNoContextTakeover) {
693
+ accepted.client_no_context_takeover = true;
694
+ }
695
+ if (typeof opts.serverMaxWindowBits === 'number') {
696
+ accepted.server_max_window_bits = opts.serverMaxWindowBits;
697
+ }
698
+ if (typeof opts.clientMaxWindowBits === 'number') {
699
+ accepted.client_max_window_bits = opts.clientMaxWindowBits;
700
+ } else if (
701
+ accepted.client_max_window_bits === true ||
702
+ opts.clientMaxWindowBits === false
703
+ ) {
704
+ delete accepted.client_max_window_bits;
705
+ }
706
+
707
+ return accepted;
708
+ }
709
+
710
+ /**
711
+ * Accept the extension negotiation response.
712
+ *
713
+ * @param {Array} response The extension negotiation response
714
+ * @return {Object} Accepted configuration
715
+ * @private
716
+ */
717
+ acceptAsClient(response) {
718
+ const params = response[0];
719
+
720
+ if (
721
+ this._options.clientNoContextTakeover === false &&
722
+ params.client_no_context_takeover
723
+ ) {
724
+ throw new Error('Unexpected parameter "client_no_context_takeover"');
725
+ }
726
+
727
+ if (!params.client_max_window_bits) {
728
+ if (typeof this._options.clientMaxWindowBits === 'number') {
729
+ params.client_max_window_bits = this._options.clientMaxWindowBits;
730
+ }
731
+ } else if (
732
+ this._options.clientMaxWindowBits === false ||
733
+ (typeof this._options.clientMaxWindowBits === 'number' &&
734
+ params.client_max_window_bits > this._options.clientMaxWindowBits)
735
+ ) {
736
+ throw new Error(
737
+ 'Unexpected or invalid parameter "client_max_window_bits"'
738
+ );
739
+ }
740
+
741
+ return params;
742
+ }
743
+
744
+ /**
745
+ * Normalize parameters.
746
+ *
747
+ * @param {Array} configurations The extension negotiation offers/reponse
748
+ * @return {Array} The offers/response with normalized parameters
749
+ * @private
750
+ */
751
+ normalizeParams(configurations) {
752
+ configurations.forEach((params) => {
753
+ Object.keys(params).forEach((key) => {
754
+ let value = params[key];
755
+
756
+ if (value.length > 1) {
757
+ throw new Error(`Parameter "${key}" must have only a single value`);
758
+ }
759
+
760
+ value = value[0];
761
+
762
+ if (key === 'client_max_window_bits') {
763
+ if (value !== true) {
764
+ const num = +value;
765
+ if (!Number.isInteger(num) || num < 8 || num > 15) {
766
+ throw new TypeError(
767
+ `Invalid value for parameter "${key}": ${value}`
768
+ );
769
+ }
770
+ value = num;
771
+ } else if (!this._isServer) {
772
+ throw new TypeError(
773
+ `Invalid value for parameter "${key}": ${value}`
774
+ );
775
+ }
776
+ } else if (key === 'server_max_window_bits') {
777
+ const num = +value;
778
+ if (!Number.isInteger(num) || num < 8 || num > 15) {
779
+ throw new TypeError(
780
+ `Invalid value for parameter "${key}": ${value}`
781
+ );
782
+ }
783
+ value = num;
784
+ } else if (
785
+ key === 'client_no_context_takeover' ||
786
+ key === 'server_no_context_takeover'
787
+ ) {
788
+ if (value !== true) {
789
+ throw new TypeError(
790
+ `Invalid value for parameter "${key}": ${value}`
791
+ );
792
+ }
793
+ } else {
794
+ throw new Error(`Unknown parameter "${key}"`);
795
+ }
796
+
797
+ params[key] = value;
798
+ });
799
+ });
800
+
801
+ return configurations;
802
+ }
803
+
804
+ /**
805
+ * Decompress data. Concurrency limited.
806
+ *
807
+ * @param {Buffer} data Compressed data
808
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
809
+ * @param {Function} callback Callback
810
+ * @public
811
+ */
812
+ decompress(data, fin, callback) {
813
+ zlibLimiter.add((done) => {
814
+ this._decompress(data, fin, (err, result) => {
815
+ done();
816
+ callback(err, result);
817
+ });
818
+ });
819
+ }
820
+
821
+ /**
822
+ * Compress data. Concurrency limited.
823
+ *
824
+ * @param {Buffer} data Data to compress
825
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
826
+ * @param {Function} callback Callback
827
+ * @public
828
+ */
829
+ compress(data, fin, callback) {
830
+ zlibLimiter.add((done) => {
831
+ this._compress(data, fin, (err, result) => {
832
+ done();
833
+ callback(err, result);
834
+ });
835
+ });
836
+ }
837
+
838
+ /**
839
+ * Decompress data.
840
+ *
841
+ * @param {Buffer} data Compressed data
842
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
843
+ * @param {Function} callback Callback
844
+ * @private
845
+ */
846
+ _decompress(data, fin, callback) {
847
+ const endpoint = this._isServer ? 'client' : 'server';
848
+
849
+ if (!this._inflate) {
850
+ const key = `${endpoint}_max_window_bits`;
851
+ const windowBits =
852
+ typeof this.params[key] !== 'number'
853
+ ? zlib.Z_DEFAULT_WINDOWBITS
854
+ : this.params[key];
855
+
856
+ this._inflate = zlib.createInflateRaw({
857
+ ...this._options.zlibInflateOptions,
858
+ windowBits
859
+ });
860
+ this._inflate[kPerMessageDeflate] = this;
861
+ this._inflate[kTotalLength] = 0;
862
+ this._inflate[kBuffers] = [];
863
+ this._inflate.on('error', inflateOnError);
864
+ this._inflate.on('data', inflateOnData);
865
+ }
866
+
867
+ this._inflate[kCallback] = callback;
868
+
869
+ this._inflate.write(data);
870
+ if (fin) this._inflate.write(TRAILER);
871
+
872
+ this._inflate.flush(() => {
873
+ const err = this._inflate[kError];
874
+
875
+ if (err) {
876
+ this._inflate.close();
877
+ this._inflate = null;
878
+ callback(err);
879
+ return;
880
+ }
881
+
882
+ const data = bufferUtil.concat(
883
+ this._inflate[kBuffers],
884
+ this._inflate[kTotalLength]
885
+ );
886
+
887
+ if (this._inflate._readableState.endEmitted) {
888
+ this._inflate.close();
889
+ this._inflate = null;
890
+ } else {
891
+ this._inflate[kTotalLength] = 0;
892
+ this._inflate[kBuffers] = [];
893
+
894
+ if (fin && this.params[`${endpoint}_no_context_takeover`]) {
895
+ this._inflate.reset();
896
+ }
897
+ }
898
+
899
+ callback(null, data);
900
+ });
901
+ }
902
+
903
+ /**
904
+ * Compress data.
905
+ *
906
+ * @param {Buffer} data Data to compress
907
+ * @param {Boolean} fin Specifies whether or not this is the last fragment
908
+ * @param {Function} callback Callback
909
+ * @private
910
+ */
911
+ _compress(data, fin, callback) {
912
+ const endpoint = this._isServer ? 'server' : 'client';
913
+
914
+ if (!this._deflate) {
915
+ const key = `${endpoint}_max_window_bits`;
916
+ const windowBits =
917
+ typeof this.params[key] !== 'number'
918
+ ? zlib.Z_DEFAULT_WINDOWBITS
919
+ : this.params[key];
920
+
921
+ this._deflate = zlib.createDeflateRaw({
922
+ ...this._options.zlibDeflateOptions,
923
+ windowBits
924
+ });
925
+
926
+ this._deflate[kTotalLength] = 0;
927
+ this._deflate[kBuffers] = [];
928
+
929
+ //
930
+ // An `'error'` event is emitted, only on Node.js < 10.0.0, if the
931
+ // `zlib.DeflateRaw` instance is closed while data is being processed.
932
+ // This can happen if `PerMessageDeflate#cleanup()` is called at the wrong
933
+ // time due to an abnormal WebSocket closure.
934
+ //
935
+ this._deflate.on('error', NOOP$1);
936
+ this._deflate.on('data', deflateOnData);
937
+ }
938
+
939
+ this._deflate[kCallback] = callback;
940
+
941
+ this._deflate.write(data);
942
+ this._deflate.flush(zlib.Z_SYNC_FLUSH, () => {
943
+ if (!this._deflate) {
944
+ //
945
+ // The deflate stream was closed while data was being processed.
946
+ //
947
+ return;
948
+ }
949
+
950
+ let data = bufferUtil.concat(
951
+ this._deflate[kBuffers],
952
+ this._deflate[kTotalLength]
953
+ );
954
+
955
+ if (fin) data = data.slice(0, data.length - 4);
956
+
957
+ //
958
+ // Ensure that the callback will not be called again in
959
+ // `PerMessageDeflate#cleanup()`.
960
+ //
961
+ this._deflate[kCallback] = null;
962
+
963
+ this._deflate[kTotalLength] = 0;
964
+ this._deflate[kBuffers] = [];
965
+
966
+ if (fin && this.params[`${endpoint}_no_context_takeover`]) {
967
+ this._deflate.reset();
968
+ }
969
+
970
+ callback(null, data);
971
+ });
972
+ }
973
+ };
974
+
975
+ var permessageDeflate = PerMessageDeflate$4;
976
+
977
+ /**
978
+ * The listener of the `zlib.DeflateRaw` stream `'data'` event.
979
+ *
980
+ * @param {Buffer} chunk A chunk of data
981
+ * @private
982
+ */
983
+ function deflateOnData(chunk) {
984
+ this[kBuffers].push(chunk);
985
+ this[kTotalLength] += chunk.length;
986
+ }
987
+
988
+ /**
989
+ * The listener of the `zlib.InflateRaw` stream `'data'` event.
990
+ *
991
+ * @param {Buffer} chunk A chunk of data
992
+ * @private
993
+ */
994
+ function inflateOnData(chunk) {
995
+ this[kTotalLength] += chunk.length;
996
+
997
+ if (
998
+ this[kPerMessageDeflate]._maxPayload < 1 ||
999
+ this[kTotalLength] <= this[kPerMessageDeflate]._maxPayload
1000
+ ) {
1001
+ this[kBuffers].push(chunk);
1002
+ return;
1003
+ }
1004
+
1005
+ this[kError] = new RangeError('Max payload size exceeded');
1006
+ this[kError].code = 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH';
1007
+ this[kError][kStatusCode$2] = 1009;
1008
+ this.removeListener('data', inflateOnData);
1009
+ this.reset();
1010
+ }
1011
+
1012
+ /**
1013
+ * The listener of the `zlib.InflateRaw` stream `'error'` event.
1014
+ *
1015
+ * @param {Error} err The emitted error
1016
+ * @private
1017
+ */
1018
+ function inflateOnError(err) {
1019
+ //
1020
+ // There is no need to call `Zlib#close()` as the handle is automatically
1021
+ // closed when an error is emitted.
1022
+ //
1023
+ this[kPerMessageDeflate]._inflate = null;
1024
+ err[kStatusCode$2] = 1007;
1025
+ this[kCallback](err);
1026
+ }
1027
+
1028
+ var validation = {exports: {}};
1029
+
1030
+ var utf8Validate = {exports: {}};
1031
+
1032
+ var fallback;
1033
+ var hasRequiredFallback;
1034
+
1035
+ function requireFallback () {
1036
+ if (hasRequiredFallback) return fallback;
1037
+ hasRequiredFallback = 1;
1038
+
1039
+ /**
1040
+ * Checks if a given buffer contains only correct UTF-8.
1041
+ * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by
1042
+ * Markus Kuhn.
1043
+ *
1044
+ * @param {Buffer} buf The buffer to check
1045
+ * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`
1046
+ * @public
1047
+ */
1048
+ function isValidUTF8(buf) {
1049
+ const len = buf.length;
1050
+ let i = 0;
1051
+
1052
+ while (i < len) {
1053
+ if ((buf[i] & 0x80) === 0x00) { // 0xxxxxxx
1054
+ i++;
1055
+ } else if ((buf[i] & 0xe0) === 0xc0) { // 110xxxxx 10xxxxxx
1056
+ if (
1057
+ i + 1 === len ||
1058
+ (buf[i + 1] & 0xc0) !== 0x80 ||
1059
+ (buf[i] & 0xfe) === 0xc0 // overlong
1060
+ ) {
1061
+ return false;
1062
+ }
1063
+
1064
+ i += 2;
1065
+ } else if ((buf[i] & 0xf0) === 0xe0) { // 1110xxxx 10xxxxxx 10xxxxxx
1066
+ if (
1067
+ i + 2 >= len ||
1068
+ (buf[i + 1] & 0xc0) !== 0x80 ||
1069
+ (buf[i + 2] & 0xc0) !== 0x80 ||
1070
+ buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80 || // overlong
1071
+ buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0 // surrogate (U+D800 - U+DFFF)
1072
+ ) {
1073
+ return false;
1074
+ }
1075
+
1076
+ i += 3;
1077
+ } else if ((buf[i] & 0xf8) === 0xf0) { // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1078
+ if (
1079
+ i + 3 >= len ||
1080
+ (buf[i + 1] & 0xc0) !== 0x80 ||
1081
+ (buf[i + 2] & 0xc0) !== 0x80 ||
1082
+ (buf[i + 3] & 0xc0) !== 0x80 ||
1083
+ buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80 || // overlong
1084
+ buf[i] === 0xf4 && buf[i + 1] > 0x8f || buf[i] > 0xf4 // > U+10FFFF
1085
+ ) {
1086
+ return false;
1087
+ }
1088
+
1089
+ i += 4;
1090
+ } else {
1091
+ return false;
1092
+ }
1093
+ }
1094
+
1095
+ return true;
1096
+ }
1097
+
1098
+ fallback = isValidUTF8;
1099
+ return fallback;
1100
+ }
1101
+
1102
+ var hasRequiredUtf8Validate;
1103
+
1104
+ function requireUtf8Validate () {
1105
+ if (hasRequiredUtf8Validate) return utf8Validate.exports;
1106
+ hasRequiredUtf8Validate = 1;
1107
+
1108
+ try {
1109
+ utf8Validate.exports = requireNodeGypBuild()(__dirname);
1110
+ } catch (e) {
1111
+ utf8Validate.exports = requireFallback();
1112
+ }
1113
+ return utf8Validate.exports;
1114
+ }
1115
+
1116
+ /**
1117
+ * Checks if a status code is allowed in a close frame.
1118
+ *
1119
+ * @param {Number} code The status code
1120
+ * @return {Boolean} `true` if the status code is valid, else `false`
1121
+ * @public
1122
+ */
1123
+ function isValidStatusCode$2(code) {
1124
+ return (
1125
+ (code >= 1000 &&
1126
+ code <= 1014 &&
1127
+ code !== 1004 &&
1128
+ code !== 1005 &&
1129
+ code !== 1006) ||
1130
+ (code >= 3000 && code <= 4999)
1131
+ );
1132
+ }
1133
+
1134
+ /**
1135
+ * Checks if a given buffer contains only correct UTF-8.
1136
+ * Ported from https://www.cl.cam.ac.uk/%7Emgk25/ucs/utf8_check.c by
1137
+ * Markus Kuhn.
1138
+ *
1139
+ * @param {Buffer} buf The buffer to check
1140
+ * @return {Boolean} `true` if `buf` contains only correct UTF-8, else `false`
1141
+ * @public
1142
+ */
1143
+ function _isValidUTF8(buf) {
1144
+ const len = buf.length;
1145
+ let i = 0;
1146
+
1147
+ while (i < len) {
1148
+ if ((buf[i] & 0x80) === 0) {
1149
+ // 0xxxxxxx
1150
+ i++;
1151
+ } else if ((buf[i] & 0xe0) === 0xc0) {
1152
+ // 110xxxxx 10xxxxxx
1153
+ if (
1154
+ i + 1 === len ||
1155
+ (buf[i + 1] & 0xc0) !== 0x80 ||
1156
+ (buf[i] & 0xfe) === 0xc0 // Overlong
1157
+ ) {
1158
+ return false;
1159
+ }
1160
+
1161
+ i += 2;
1162
+ } else if ((buf[i] & 0xf0) === 0xe0) {
1163
+ // 1110xxxx 10xxxxxx 10xxxxxx
1164
+ if (
1165
+ i + 2 >= len ||
1166
+ (buf[i + 1] & 0xc0) !== 0x80 ||
1167
+ (buf[i + 2] & 0xc0) !== 0x80 ||
1168
+ (buf[i] === 0xe0 && (buf[i + 1] & 0xe0) === 0x80) || // Overlong
1169
+ (buf[i] === 0xed && (buf[i + 1] & 0xe0) === 0xa0) // Surrogate (U+D800 - U+DFFF)
1170
+ ) {
1171
+ return false;
1172
+ }
1173
+
1174
+ i += 3;
1175
+ } else if ((buf[i] & 0xf8) === 0xf0) {
1176
+ // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
1177
+ if (
1178
+ i + 3 >= len ||
1179
+ (buf[i + 1] & 0xc0) !== 0x80 ||
1180
+ (buf[i + 2] & 0xc0) !== 0x80 ||
1181
+ (buf[i + 3] & 0xc0) !== 0x80 ||
1182
+ (buf[i] === 0xf0 && (buf[i + 1] & 0xf0) === 0x80) || // Overlong
1183
+ (buf[i] === 0xf4 && buf[i + 1] > 0x8f) ||
1184
+ buf[i] > 0xf4 // > U+10FFFF
1185
+ ) {
1186
+ return false;
1187
+ }
1188
+
1189
+ i += 4;
1190
+ } else {
1191
+ return false;
1192
+ }
1193
+ }
1194
+
1195
+ return true;
1196
+ }
1197
+
1198
+ try {
1199
+ let isValidUTF8 = requireUtf8Validate();
1200
+
1201
+ /* istanbul ignore if */
1202
+ if (typeof isValidUTF8 === 'object') {
1203
+ isValidUTF8 = isValidUTF8.Validation.isValidUTF8; // utf-8-validate@<3.0.0
1204
+ }
1205
+
1206
+ validation.exports = {
1207
+ isValidStatusCode: isValidStatusCode$2,
1208
+ isValidUTF8(buf) {
1209
+ return buf.length < 150 ? _isValidUTF8(buf) : isValidUTF8(buf);
1210
+ }
1211
+ };
1212
+ } catch (e) /* istanbul ignore next */ {
1213
+ validation.exports = {
1214
+ isValidStatusCode: isValidStatusCode$2,
1215
+ isValidUTF8: _isValidUTF8
1216
+ };
1217
+ }
1218
+
1219
+ var validationExports = validation.exports;
1220
+
1221
+ const { Writable } = require$$0$2;
1222
+
1223
+ const PerMessageDeflate$3 = permessageDeflate;
1224
+ const {
1225
+ BINARY_TYPES: BINARY_TYPES$1,
1226
+ EMPTY_BUFFER: EMPTY_BUFFER$2,
1227
+ kStatusCode: kStatusCode$1,
1228
+ kWebSocket: kWebSocket$2
1229
+ } = constants;
1230
+ const { concat, toArrayBuffer, unmask } = bufferUtilExports;
1231
+ const { isValidStatusCode: isValidStatusCode$1, isValidUTF8 } = validationExports;
1232
+
1233
+ const GET_INFO = 0;
1234
+ const GET_PAYLOAD_LENGTH_16 = 1;
1235
+ const GET_PAYLOAD_LENGTH_64 = 2;
1236
+ const GET_MASK = 3;
1237
+ const GET_DATA = 4;
1238
+ const INFLATING = 5;
1239
+
1240
+ /**
1241
+ * HyBi Receiver implementation.
1242
+ *
1243
+ * @extends Writable
1244
+ */
1245
+ let Receiver$1 = class Receiver extends Writable {
1246
+ /**
1247
+ * Creates a Receiver instance.
1248
+ *
1249
+ * @param {String} [binaryType=nodebuffer] The type for binary data
1250
+ * @param {Object} [extensions] An object containing the negotiated extensions
1251
+ * @param {Boolean} [isServer=false] Specifies whether to operate in client or
1252
+ * server mode
1253
+ * @param {Number} [maxPayload=0] The maximum allowed message length
1254
+ */
1255
+ constructor(binaryType, extensions, isServer, maxPayload) {
1256
+ super();
1257
+
1258
+ this._binaryType = binaryType || BINARY_TYPES$1[0];
1259
+ this[kWebSocket$2] = undefined;
1260
+ this._extensions = extensions || {};
1261
+ this._isServer = !!isServer;
1262
+ this._maxPayload = maxPayload | 0;
1263
+
1264
+ this._bufferedBytes = 0;
1265
+ this._buffers = [];
1266
+
1267
+ this._compressed = false;
1268
+ this._payloadLength = 0;
1269
+ this._mask = undefined;
1270
+ this._fragmented = 0;
1271
+ this._masked = false;
1272
+ this._fin = false;
1273
+ this._opcode = 0;
1274
+
1275
+ this._totalPayloadLength = 0;
1276
+ this._messageLength = 0;
1277
+ this._fragments = [];
1278
+
1279
+ this._state = GET_INFO;
1280
+ this._loop = false;
1281
+ }
1282
+
1283
+ /**
1284
+ * Implements `Writable.prototype._write()`.
1285
+ *
1286
+ * @param {Buffer} chunk The chunk of data to write
1287
+ * @param {String} encoding The character encoding of `chunk`
1288
+ * @param {Function} cb Callback
1289
+ * @private
1290
+ */
1291
+ _write(chunk, encoding, cb) {
1292
+ if (this._opcode === 0x08 && this._state == GET_INFO) return cb();
1293
+
1294
+ this._bufferedBytes += chunk.length;
1295
+ this._buffers.push(chunk);
1296
+ this.startLoop(cb);
1297
+ }
1298
+
1299
+ /**
1300
+ * Consumes `n` bytes from the buffered data.
1301
+ *
1302
+ * @param {Number} n The number of bytes to consume
1303
+ * @return {Buffer} The consumed bytes
1304
+ * @private
1305
+ */
1306
+ consume(n) {
1307
+ this._bufferedBytes -= n;
1308
+
1309
+ if (n === this._buffers[0].length) return this._buffers.shift();
1310
+
1311
+ if (n < this._buffers[0].length) {
1312
+ const buf = this._buffers[0];
1313
+ this._buffers[0] = buf.slice(n);
1314
+ return buf.slice(0, n);
1315
+ }
1316
+
1317
+ const dst = Buffer.allocUnsafe(n);
1318
+
1319
+ do {
1320
+ const buf = this._buffers[0];
1321
+ const offset = dst.length - n;
1322
+
1323
+ if (n >= buf.length) {
1324
+ dst.set(this._buffers.shift(), offset);
1325
+ } else {
1326
+ dst.set(new Uint8Array(buf.buffer, buf.byteOffset, n), offset);
1327
+ this._buffers[0] = buf.slice(n);
1328
+ }
1329
+
1330
+ n -= buf.length;
1331
+ } while (n > 0);
1332
+
1333
+ return dst;
1334
+ }
1335
+
1336
+ /**
1337
+ * Starts the parsing loop.
1338
+ *
1339
+ * @param {Function} cb Callback
1340
+ * @private
1341
+ */
1342
+ startLoop(cb) {
1343
+ let err;
1344
+ this._loop = true;
1345
+
1346
+ do {
1347
+ switch (this._state) {
1348
+ case GET_INFO:
1349
+ err = this.getInfo();
1350
+ break;
1351
+ case GET_PAYLOAD_LENGTH_16:
1352
+ err = this.getPayloadLength16();
1353
+ break;
1354
+ case GET_PAYLOAD_LENGTH_64:
1355
+ err = this.getPayloadLength64();
1356
+ break;
1357
+ case GET_MASK:
1358
+ this.getMask();
1359
+ break;
1360
+ case GET_DATA:
1361
+ err = this.getData(cb);
1362
+ break;
1363
+ default:
1364
+ // `INFLATING`
1365
+ this._loop = false;
1366
+ return;
1367
+ }
1368
+ } while (this._loop);
1369
+
1370
+ cb(err);
1371
+ }
1372
+
1373
+ /**
1374
+ * Reads the first two bytes of a frame.
1375
+ *
1376
+ * @return {(RangeError|undefined)} A possible error
1377
+ * @private
1378
+ */
1379
+ getInfo() {
1380
+ if (this._bufferedBytes < 2) {
1381
+ this._loop = false;
1382
+ return;
1383
+ }
1384
+
1385
+ const buf = this.consume(2);
1386
+
1387
+ if ((buf[0] & 0x30) !== 0x00) {
1388
+ this._loop = false;
1389
+ return error(
1390
+ RangeError,
1391
+ 'RSV2 and RSV3 must be clear',
1392
+ true,
1393
+ 1002,
1394
+ 'WS_ERR_UNEXPECTED_RSV_2_3'
1395
+ );
1396
+ }
1397
+
1398
+ const compressed = (buf[0] & 0x40) === 0x40;
1399
+
1400
+ if (compressed && !this._extensions[PerMessageDeflate$3.extensionName]) {
1401
+ this._loop = false;
1402
+ return error(
1403
+ RangeError,
1404
+ 'RSV1 must be clear',
1405
+ true,
1406
+ 1002,
1407
+ 'WS_ERR_UNEXPECTED_RSV_1'
1408
+ );
1409
+ }
1410
+
1411
+ this._fin = (buf[0] & 0x80) === 0x80;
1412
+ this._opcode = buf[0] & 0x0f;
1413
+ this._payloadLength = buf[1] & 0x7f;
1414
+
1415
+ if (this._opcode === 0x00) {
1416
+ if (compressed) {
1417
+ this._loop = false;
1418
+ return error(
1419
+ RangeError,
1420
+ 'RSV1 must be clear',
1421
+ true,
1422
+ 1002,
1423
+ 'WS_ERR_UNEXPECTED_RSV_1'
1424
+ );
1425
+ }
1426
+
1427
+ if (!this._fragmented) {
1428
+ this._loop = false;
1429
+ return error(
1430
+ RangeError,
1431
+ 'invalid opcode 0',
1432
+ true,
1433
+ 1002,
1434
+ 'WS_ERR_INVALID_OPCODE'
1435
+ );
1436
+ }
1437
+
1438
+ this._opcode = this._fragmented;
1439
+ } else if (this._opcode === 0x01 || this._opcode === 0x02) {
1440
+ if (this._fragmented) {
1441
+ this._loop = false;
1442
+ return error(
1443
+ RangeError,
1444
+ `invalid opcode ${this._opcode}`,
1445
+ true,
1446
+ 1002,
1447
+ 'WS_ERR_INVALID_OPCODE'
1448
+ );
1449
+ }
1450
+
1451
+ this._compressed = compressed;
1452
+ } else if (this._opcode > 0x07 && this._opcode < 0x0b) {
1453
+ if (!this._fin) {
1454
+ this._loop = false;
1455
+ return error(
1456
+ RangeError,
1457
+ 'FIN must be set',
1458
+ true,
1459
+ 1002,
1460
+ 'WS_ERR_EXPECTED_FIN'
1461
+ );
1462
+ }
1463
+
1464
+ if (compressed) {
1465
+ this._loop = false;
1466
+ return error(
1467
+ RangeError,
1468
+ 'RSV1 must be clear',
1469
+ true,
1470
+ 1002,
1471
+ 'WS_ERR_UNEXPECTED_RSV_1'
1472
+ );
1473
+ }
1474
+
1475
+ if (this._payloadLength > 0x7d) {
1476
+ this._loop = false;
1477
+ return error(
1478
+ RangeError,
1479
+ `invalid payload length ${this._payloadLength}`,
1480
+ true,
1481
+ 1002,
1482
+ 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'
1483
+ );
1484
+ }
1485
+ } else {
1486
+ this._loop = false;
1487
+ return error(
1488
+ RangeError,
1489
+ `invalid opcode ${this._opcode}`,
1490
+ true,
1491
+ 1002,
1492
+ 'WS_ERR_INVALID_OPCODE'
1493
+ );
1494
+ }
1495
+
1496
+ if (!this._fin && !this._fragmented) this._fragmented = this._opcode;
1497
+ this._masked = (buf[1] & 0x80) === 0x80;
1498
+
1499
+ if (this._isServer) {
1500
+ if (!this._masked) {
1501
+ this._loop = false;
1502
+ return error(
1503
+ RangeError,
1504
+ 'MASK must be set',
1505
+ true,
1506
+ 1002,
1507
+ 'WS_ERR_EXPECTED_MASK'
1508
+ );
1509
+ }
1510
+ } else if (this._masked) {
1511
+ this._loop = false;
1512
+ return error(
1513
+ RangeError,
1514
+ 'MASK must be clear',
1515
+ true,
1516
+ 1002,
1517
+ 'WS_ERR_UNEXPECTED_MASK'
1518
+ );
1519
+ }
1520
+
1521
+ if (this._payloadLength === 126) this._state = GET_PAYLOAD_LENGTH_16;
1522
+ else if (this._payloadLength === 127) this._state = GET_PAYLOAD_LENGTH_64;
1523
+ else return this.haveLength();
1524
+ }
1525
+
1526
+ /**
1527
+ * Gets extended payload length (7+16).
1528
+ *
1529
+ * @return {(RangeError|undefined)} A possible error
1530
+ * @private
1531
+ */
1532
+ getPayloadLength16() {
1533
+ if (this._bufferedBytes < 2) {
1534
+ this._loop = false;
1535
+ return;
1536
+ }
1537
+
1538
+ this._payloadLength = this.consume(2).readUInt16BE(0);
1539
+ return this.haveLength();
1540
+ }
1541
+
1542
+ /**
1543
+ * Gets extended payload length (7+64).
1544
+ *
1545
+ * @return {(RangeError|undefined)} A possible error
1546
+ * @private
1547
+ */
1548
+ getPayloadLength64() {
1549
+ if (this._bufferedBytes < 8) {
1550
+ this._loop = false;
1551
+ return;
1552
+ }
1553
+
1554
+ const buf = this.consume(8);
1555
+ const num = buf.readUInt32BE(0);
1556
+
1557
+ //
1558
+ // The maximum safe integer in JavaScript is 2^53 - 1. An error is returned
1559
+ // if payload length is greater than this number.
1560
+ //
1561
+ if (num > Math.pow(2, 53 - 32) - 1) {
1562
+ this._loop = false;
1563
+ return error(
1564
+ RangeError,
1565
+ 'Unsupported WebSocket frame: payload length > 2^53 - 1',
1566
+ false,
1567
+ 1009,
1568
+ 'WS_ERR_UNSUPPORTED_DATA_PAYLOAD_LENGTH'
1569
+ );
1570
+ }
1571
+
1572
+ this._payloadLength = num * Math.pow(2, 32) + buf.readUInt32BE(4);
1573
+ return this.haveLength();
1574
+ }
1575
+
1576
+ /**
1577
+ * Payload length has been read.
1578
+ *
1579
+ * @return {(RangeError|undefined)} A possible error
1580
+ * @private
1581
+ */
1582
+ haveLength() {
1583
+ if (this._payloadLength && this._opcode < 0x08) {
1584
+ this._totalPayloadLength += this._payloadLength;
1585
+ if (this._totalPayloadLength > this._maxPayload && this._maxPayload > 0) {
1586
+ this._loop = false;
1587
+ return error(
1588
+ RangeError,
1589
+ 'Max payload size exceeded',
1590
+ false,
1591
+ 1009,
1592
+ 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
1593
+ );
1594
+ }
1595
+ }
1596
+
1597
+ if (this._masked) this._state = GET_MASK;
1598
+ else this._state = GET_DATA;
1599
+ }
1600
+
1601
+ /**
1602
+ * Reads mask bytes.
1603
+ *
1604
+ * @private
1605
+ */
1606
+ getMask() {
1607
+ if (this._bufferedBytes < 4) {
1608
+ this._loop = false;
1609
+ return;
1610
+ }
1611
+
1612
+ this._mask = this.consume(4);
1613
+ this._state = GET_DATA;
1614
+ }
1615
+
1616
+ /**
1617
+ * Reads data bytes.
1618
+ *
1619
+ * @param {Function} cb Callback
1620
+ * @return {(Error|RangeError|undefined)} A possible error
1621
+ * @private
1622
+ */
1623
+ getData(cb) {
1624
+ let data = EMPTY_BUFFER$2;
1625
+
1626
+ if (this._payloadLength) {
1627
+ if (this._bufferedBytes < this._payloadLength) {
1628
+ this._loop = false;
1629
+ return;
1630
+ }
1631
+
1632
+ data = this.consume(this._payloadLength);
1633
+ if (this._masked) unmask(data, this._mask);
1634
+ }
1635
+
1636
+ if (this._opcode > 0x07) return this.controlMessage(data);
1637
+
1638
+ if (this._compressed) {
1639
+ this._state = INFLATING;
1640
+ this.decompress(data, cb);
1641
+ return;
1642
+ }
1643
+
1644
+ if (data.length) {
1645
+ //
1646
+ // This message is not compressed so its lenght is the sum of the payload
1647
+ // length of all fragments.
1648
+ //
1649
+ this._messageLength = this._totalPayloadLength;
1650
+ this._fragments.push(data);
1651
+ }
1652
+
1653
+ return this.dataMessage();
1654
+ }
1655
+
1656
+ /**
1657
+ * Decompresses data.
1658
+ *
1659
+ * @param {Buffer} data Compressed data
1660
+ * @param {Function} cb Callback
1661
+ * @private
1662
+ */
1663
+ decompress(data, cb) {
1664
+ const perMessageDeflate = this._extensions[PerMessageDeflate$3.extensionName];
1665
+
1666
+ perMessageDeflate.decompress(data, this._fin, (err, buf) => {
1667
+ if (err) return cb(err);
1668
+
1669
+ if (buf.length) {
1670
+ this._messageLength += buf.length;
1671
+ if (this._messageLength > this._maxPayload && this._maxPayload > 0) {
1672
+ return cb(
1673
+ error(
1674
+ RangeError,
1675
+ 'Max payload size exceeded',
1676
+ false,
1677
+ 1009,
1678
+ 'WS_ERR_UNSUPPORTED_MESSAGE_LENGTH'
1679
+ )
1680
+ );
1681
+ }
1682
+
1683
+ this._fragments.push(buf);
1684
+ }
1685
+
1686
+ const er = this.dataMessage();
1687
+ if (er) return cb(er);
1688
+
1689
+ this.startLoop(cb);
1690
+ });
1691
+ }
1692
+
1693
+ /**
1694
+ * Handles a data message.
1695
+ *
1696
+ * @return {(Error|undefined)} A possible error
1697
+ * @private
1698
+ */
1699
+ dataMessage() {
1700
+ if (this._fin) {
1701
+ const messageLength = this._messageLength;
1702
+ const fragments = this._fragments;
1703
+
1704
+ this._totalPayloadLength = 0;
1705
+ this._messageLength = 0;
1706
+ this._fragmented = 0;
1707
+ this._fragments = [];
1708
+
1709
+ if (this._opcode === 2) {
1710
+ let data;
1711
+
1712
+ if (this._binaryType === 'nodebuffer') {
1713
+ data = concat(fragments, messageLength);
1714
+ } else if (this._binaryType === 'arraybuffer') {
1715
+ data = toArrayBuffer(concat(fragments, messageLength));
1716
+ } else {
1717
+ data = fragments;
1718
+ }
1719
+
1720
+ this.emit('message', data);
1721
+ } else {
1722
+ const buf = concat(fragments, messageLength);
1723
+
1724
+ if (!isValidUTF8(buf)) {
1725
+ this._loop = false;
1726
+ return error(
1727
+ Error,
1728
+ 'invalid UTF-8 sequence',
1729
+ true,
1730
+ 1007,
1731
+ 'WS_ERR_INVALID_UTF8'
1732
+ );
1733
+ }
1734
+
1735
+ this.emit('message', buf.toString());
1736
+ }
1737
+ }
1738
+
1739
+ this._state = GET_INFO;
1740
+ }
1741
+
1742
+ /**
1743
+ * Handles a control message.
1744
+ *
1745
+ * @param {Buffer} data Data to handle
1746
+ * @return {(Error|RangeError|undefined)} A possible error
1747
+ * @private
1748
+ */
1749
+ controlMessage(data) {
1750
+ if (this._opcode === 0x08) {
1751
+ this._loop = false;
1752
+
1753
+ if (data.length === 0) {
1754
+ this.emit('conclude', 1005, '');
1755
+ this.end();
1756
+ } else if (data.length === 1) {
1757
+ return error(
1758
+ RangeError,
1759
+ 'invalid payload length 1',
1760
+ true,
1761
+ 1002,
1762
+ 'WS_ERR_INVALID_CONTROL_PAYLOAD_LENGTH'
1763
+ );
1764
+ } else {
1765
+ const code = data.readUInt16BE(0);
1766
+
1767
+ if (!isValidStatusCode$1(code)) {
1768
+ return error(
1769
+ RangeError,
1770
+ `invalid status code ${code}`,
1771
+ true,
1772
+ 1002,
1773
+ 'WS_ERR_INVALID_CLOSE_CODE'
1774
+ );
1775
+ }
1776
+
1777
+ const buf = data.slice(2);
1778
+
1779
+ if (!isValidUTF8(buf)) {
1780
+ return error(
1781
+ Error,
1782
+ 'invalid UTF-8 sequence',
1783
+ true,
1784
+ 1007,
1785
+ 'WS_ERR_INVALID_UTF8'
1786
+ );
1787
+ }
1788
+
1789
+ this.emit('conclude', code, buf.toString());
1790
+ this.end();
1791
+ }
1792
+ } else if (this._opcode === 0x09) {
1793
+ this.emit('ping', data);
1794
+ } else {
1795
+ this.emit('pong', data);
1796
+ }
1797
+
1798
+ this._state = GET_INFO;
1799
+ }
1800
+ };
1801
+
1802
+ var receiver = Receiver$1;
1803
+
1804
+ /**
1805
+ * Builds an error object.
1806
+ *
1807
+ * @param {function(new:Error|RangeError)} ErrorCtor The error constructor
1808
+ * @param {String} message The error message
1809
+ * @param {Boolean} prefix Specifies whether or not to add a default prefix to
1810
+ * `message`
1811
+ * @param {Number} statusCode The status code
1812
+ * @param {String} errorCode The exposed error code
1813
+ * @return {(Error|RangeError)} The error
1814
+ * @private
1815
+ */
1816
+ function error(ErrorCtor, message, prefix, statusCode, errorCode) {
1817
+ const err = new ErrorCtor(
1818
+ prefix ? `Invalid WebSocket frame: ${message}` : message
1819
+ );
1820
+
1821
+ Error.captureStackTrace(err, error);
1822
+ err.code = errorCode;
1823
+ err[kStatusCode$1] = statusCode;
1824
+ return err;
1825
+ }
1826
+
1827
+ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^net|tls$" }] */
1828
+ const { randomFillSync } = require$$5;
1829
+
1830
+ const PerMessageDeflate$2 = permessageDeflate;
1831
+ const { EMPTY_BUFFER: EMPTY_BUFFER$1 } = constants;
1832
+ const { isValidStatusCode } = validationExports;
1833
+ const { mask: applyMask, toBuffer: toBuffer$1 } = bufferUtilExports;
1834
+
1835
+ const mask = Buffer.alloc(4);
1836
+
1837
+ /**
1838
+ * HyBi Sender implementation.
1839
+ */
1840
+ let Sender$1 = class Sender {
1841
+ /**
1842
+ * Creates a Sender instance.
1843
+ *
1844
+ * @param {(net.Socket|tls.Socket)} socket The connection socket
1845
+ * @param {Object} [extensions] An object containing the negotiated extensions
1846
+ */
1847
+ constructor(socket, extensions) {
1848
+ this._extensions = extensions || {};
1849
+ this._socket = socket;
1850
+
1851
+ this._firstFragment = true;
1852
+ this._compress = false;
1853
+
1854
+ this._bufferedBytes = 0;
1855
+ this._deflating = false;
1856
+ this._queue = [];
1857
+ }
1858
+
1859
+ /**
1860
+ * Frames a piece of data according to the HyBi WebSocket protocol.
1861
+ *
1862
+ * @param {Buffer} data The data to frame
1863
+ * @param {Object} options Options object
1864
+ * @param {Number} options.opcode The opcode
1865
+ * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
1866
+ * modified
1867
+ * @param {Boolean} [options.fin=false] Specifies whether or not to set the
1868
+ * FIN bit
1869
+ * @param {Boolean} [options.mask=false] Specifies whether or not to mask
1870
+ * `data`
1871
+ * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
1872
+ * RSV1 bit
1873
+ * @return {Buffer[]} The framed data as a list of `Buffer` instances
1874
+ * @public
1875
+ */
1876
+ static frame(data, options) {
1877
+ const merge = options.mask && options.readOnly;
1878
+ let offset = options.mask ? 6 : 2;
1879
+ let payloadLength = data.length;
1880
+
1881
+ if (data.length >= 65536) {
1882
+ offset += 8;
1883
+ payloadLength = 127;
1884
+ } else if (data.length > 125) {
1885
+ offset += 2;
1886
+ payloadLength = 126;
1887
+ }
1888
+
1889
+ const target = Buffer.allocUnsafe(merge ? data.length + offset : offset);
1890
+
1891
+ target[0] = options.fin ? options.opcode | 0x80 : options.opcode;
1892
+ if (options.rsv1) target[0] |= 0x40;
1893
+
1894
+ target[1] = payloadLength;
1895
+
1896
+ if (payloadLength === 126) {
1897
+ target.writeUInt16BE(data.length, 2);
1898
+ } else if (payloadLength === 127) {
1899
+ target.writeUInt32BE(0, 2);
1900
+ target.writeUInt32BE(data.length, 6);
1901
+ }
1902
+
1903
+ if (!options.mask) return [target, data];
1904
+
1905
+ randomFillSync(mask, 0, 4);
1906
+
1907
+ target[1] |= 0x80;
1908
+ target[offset - 4] = mask[0];
1909
+ target[offset - 3] = mask[1];
1910
+ target[offset - 2] = mask[2];
1911
+ target[offset - 1] = mask[3];
1912
+
1913
+ if (merge) {
1914
+ applyMask(data, mask, target, offset, data.length);
1915
+ return [target];
1916
+ }
1917
+
1918
+ applyMask(data, mask, data, 0, data.length);
1919
+ return [target, data];
1920
+ }
1921
+
1922
+ /**
1923
+ * Sends a close message to the other peer.
1924
+ *
1925
+ * @param {Number} [code] The status code component of the body
1926
+ * @param {String} [data] The message component of the body
1927
+ * @param {Boolean} [mask=false] Specifies whether or not to mask the message
1928
+ * @param {Function} [cb] Callback
1929
+ * @public
1930
+ */
1931
+ close(code, data, mask, cb) {
1932
+ let buf;
1933
+
1934
+ if (code === undefined) {
1935
+ buf = EMPTY_BUFFER$1;
1936
+ } else if (typeof code !== 'number' || !isValidStatusCode(code)) {
1937
+ throw new TypeError('First argument must be a valid error code number');
1938
+ } else if (data === undefined || data === '') {
1939
+ buf = Buffer.allocUnsafe(2);
1940
+ buf.writeUInt16BE(code, 0);
1941
+ } else {
1942
+ const length = Buffer.byteLength(data);
1943
+
1944
+ if (length > 123) {
1945
+ throw new RangeError('The message must not be greater than 123 bytes');
1946
+ }
1947
+
1948
+ buf = Buffer.allocUnsafe(2 + length);
1949
+ buf.writeUInt16BE(code, 0);
1950
+ buf.write(data, 2);
1951
+ }
1952
+
1953
+ if (this._deflating) {
1954
+ this.enqueue([this.doClose, buf, mask, cb]);
1955
+ } else {
1956
+ this.doClose(buf, mask, cb);
1957
+ }
1958
+ }
1959
+
1960
+ /**
1961
+ * Frames and sends a close message.
1962
+ *
1963
+ * @param {Buffer} data The message to send
1964
+ * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
1965
+ * @param {Function} [cb] Callback
1966
+ * @private
1967
+ */
1968
+ doClose(data, mask, cb) {
1969
+ this.sendFrame(
1970
+ Sender.frame(data, {
1971
+ fin: true,
1972
+ rsv1: false,
1973
+ opcode: 0x08,
1974
+ mask,
1975
+ readOnly: false
1976
+ }),
1977
+ cb
1978
+ );
1979
+ }
1980
+
1981
+ /**
1982
+ * Sends a ping message to the other peer.
1983
+ *
1984
+ * @param {*} data The message to send
1985
+ * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
1986
+ * @param {Function} [cb] Callback
1987
+ * @public
1988
+ */
1989
+ ping(data, mask, cb) {
1990
+ const buf = toBuffer$1(data);
1991
+
1992
+ if (buf.length > 125) {
1993
+ throw new RangeError('The data size must not be greater than 125 bytes');
1994
+ }
1995
+
1996
+ if (this._deflating) {
1997
+ this.enqueue([this.doPing, buf, mask, toBuffer$1.readOnly, cb]);
1998
+ } else {
1999
+ this.doPing(buf, mask, toBuffer$1.readOnly, cb);
2000
+ }
2001
+ }
2002
+
2003
+ /**
2004
+ * Frames and sends a ping message.
2005
+ *
2006
+ * @param {Buffer} data The message to send
2007
+ * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
2008
+ * @param {Boolean} [readOnly=false] Specifies whether `data` can be modified
2009
+ * @param {Function} [cb] Callback
2010
+ * @private
2011
+ */
2012
+ doPing(data, mask, readOnly, cb) {
2013
+ this.sendFrame(
2014
+ Sender.frame(data, {
2015
+ fin: true,
2016
+ rsv1: false,
2017
+ opcode: 0x09,
2018
+ mask,
2019
+ readOnly
2020
+ }),
2021
+ cb
2022
+ );
2023
+ }
2024
+
2025
+ /**
2026
+ * Sends a pong message to the other peer.
2027
+ *
2028
+ * @param {*} data The message to send
2029
+ * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
2030
+ * @param {Function} [cb] Callback
2031
+ * @public
2032
+ */
2033
+ pong(data, mask, cb) {
2034
+ const buf = toBuffer$1(data);
2035
+
2036
+ if (buf.length > 125) {
2037
+ throw new RangeError('The data size must not be greater than 125 bytes');
2038
+ }
2039
+
2040
+ if (this._deflating) {
2041
+ this.enqueue([this.doPong, buf, mask, toBuffer$1.readOnly, cb]);
2042
+ } else {
2043
+ this.doPong(buf, mask, toBuffer$1.readOnly, cb);
2044
+ }
2045
+ }
2046
+
2047
+ /**
2048
+ * Frames and sends a pong message.
2049
+ *
2050
+ * @param {Buffer} data The message to send
2051
+ * @param {Boolean} [mask=false] Specifies whether or not to mask `data`
2052
+ * @param {Boolean} [readOnly=false] Specifies whether `data` can be modified
2053
+ * @param {Function} [cb] Callback
2054
+ * @private
2055
+ */
2056
+ doPong(data, mask, readOnly, cb) {
2057
+ this.sendFrame(
2058
+ Sender.frame(data, {
2059
+ fin: true,
2060
+ rsv1: false,
2061
+ opcode: 0x0a,
2062
+ mask,
2063
+ readOnly
2064
+ }),
2065
+ cb
2066
+ );
2067
+ }
2068
+
2069
+ /**
2070
+ * Sends a data message to the other peer.
2071
+ *
2072
+ * @param {*} data The message to send
2073
+ * @param {Object} options Options object
2074
+ * @param {Boolean} [options.compress=false] Specifies whether or not to
2075
+ * compress `data`
2076
+ * @param {Boolean} [options.binary=false] Specifies whether `data` is binary
2077
+ * or text
2078
+ * @param {Boolean} [options.fin=false] Specifies whether the fragment is the
2079
+ * last one
2080
+ * @param {Boolean} [options.mask=false] Specifies whether or not to mask
2081
+ * `data`
2082
+ * @param {Function} [cb] Callback
2083
+ * @public
2084
+ */
2085
+ send(data, options, cb) {
2086
+ const buf = toBuffer$1(data);
2087
+ const perMessageDeflate = this._extensions[PerMessageDeflate$2.extensionName];
2088
+ let opcode = options.binary ? 2 : 1;
2089
+ let rsv1 = options.compress;
2090
+
2091
+ if (this._firstFragment) {
2092
+ this._firstFragment = false;
2093
+ if (rsv1 && perMessageDeflate) {
2094
+ rsv1 = buf.length >= perMessageDeflate._threshold;
2095
+ }
2096
+ this._compress = rsv1;
2097
+ } else {
2098
+ rsv1 = false;
2099
+ opcode = 0;
2100
+ }
2101
+
2102
+ if (options.fin) this._firstFragment = true;
2103
+
2104
+ if (perMessageDeflate) {
2105
+ const opts = {
2106
+ fin: options.fin,
2107
+ rsv1,
2108
+ opcode,
2109
+ mask: options.mask,
2110
+ readOnly: toBuffer$1.readOnly
2111
+ };
2112
+
2113
+ if (this._deflating) {
2114
+ this.enqueue([this.dispatch, buf, this._compress, opts, cb]);
2115
+ } else {
2116
+ this.dispatch(buf, this._compress, opts, cb);
2117
+ }
2118
+ } else {
2119
+ this.sendFrame(
2120
+ Sender.frame(buf, {
2121
+ fin: options.fin,
2122
+ rsv1: false,
2123
+ opcode,
2124
+ mask: options.mask,
2125
+ readOnly: toBuffer$1.readOnly
2126
+ }),
2127
+ cb
2128
+ );
2129
+ }
2130
+ }
2131
+
2132
+ /**
2133
+ * Dispatches a data message.
2134
+ *
2135
+ * @param {Buffer} data The message to send
2136
+ * @param {Boolean} [compress=false] Specifies whether or not to compress
2137
+ * `data`
2138
+ * @param {Object} options Options object
2139
+ * @param {Number} options.opcode The opcode
2140
+ * @param {Boolean} [options.readOnly=false] Specifies whether `data` can be
2141
+ * modified
2142
+ * @param {Boolean} [options.fin=false] Specifies whether or not to set the
2143
+ * FIN bit
2144
+ * @param {Boolean} [options.mask=false] Specifies whether or not to mask
2145
+ * `data`
2146
+ * @param {Boolean} [options.rsv1=false] Specifies whether or not to set the
2147
+ * RSV1 bit
2148
+ * @param {Function} [cb] Callback
2149
+ * @private
2150
+ */
2151
+ dispatch(data, compress, options, cb) {
2152
+ if (!compress) {
2153
+ this.sendFrame(Sender.frame(data, options), cb);
2154
+ return;
2155
+ }
2156
+
2157
+ const perMessageDeflate = this._extensions[PerMessageDeflate$2.extensionName];
2158
+
2159
+ this._bufferedBytes += data.length;
2160
+ this._deflating = true;
2161
+ perMessageDeflate.compress(data, options.fin, (_, buf) => {
2162
+ if (this._socket.destroyed) {
2163
+ const err = new Error(
2164
+ 'The socket was closed while data was being compressed'
2165
+ );
2166
+
2167
+ if (typeof cb === 'function') cb(err);
2168
+
2169
+ for (let i = 0; i < this._queue.length; i++) {
2170
+ const callback = this._queue[i][4];
2171
+
2172
+ if (typeof callback === 'function') callback(err);
2173
+ }
2174
+
2175
+ return;
2176
+ }
2177
+
2178
+ this._bufferedBytes -= data.length;
2179
+ this._deflating = false;
2180
+ options.readOnly = false;
2181
+ this.sendFrame(Sender.frame(buf, options), cb);
2182
+ this.dequeue();
2183
+ });
2184
+ }
2185
+
2186
+ /**
2187
+ * Executes queued send operations.
2188
+ *
2189
+ * @private
2190
+ */
2191
+ dequeue() {
2192
+ while (!this._deflating && this._queue.length) {
2193
+ const params = this._queue.shift();
2194
+
2195
+ this._bufferedBytes -= params[1].length;
2196
+ Reflect.apply(params[0], this, params.slice(1));
2197
+ }
2198
+ }
2199
+
2200
+ /**
2201
+ * Enqueues a send operation.
2202
+ *
2203
+ * @param {Array} params Send operation parameters.
2204
+ * @private
2205
+ */
2206
+ enqueue(params) {
2207
+ this._bufferedBytes += params[1].length;
2208
+ this._queue.push(params);
2209
+ }
2210
+
2211
+ /**
2212
+ * Sends a frame.
2213
+ *
2214
+ * @param {Buffer[]} list The frame to send
2215
+ * @param {Function} [cb] Callback
2216
+ * @private
2217
+ */
2218
+ sendFrame(list, cb) {
2219
+ if (list.length === 2) {
2220
+ this._socket.cork();
2221
+ this._socket.write(list[0]);
2222
+ this._socket.write(list[1], cb);
2223
+ this._socket.uncork();
2224
+ } else {
2225
+ this._socket.write(list[0], cb);
2226
+ }
2227
+ }
2228
+ };
2229
+
2230
+ var sender = Sender$1;
2231
+
2232
+ /**
2233
+ * Class representing an event.
2234
+ *
2235
+ * @private
2236
+ */
2237
+ class Event {
2238
+ /**
2239
+ * Create a new `Event`.
2240
+ *
2241
+ * @param {String} type The name of the event
2242
+ * @param {Object} target A reference to the target to which the event was
2243
+ * dispatched
2244
+ */
2245
+ constructor(type, target) {
2246
+ this.target = target;
2247
+ this.type = type;
2248
+ }
2249
+ }
2250
+
2251
+ /**
2252
+ * Class representing a message event.
2253
+ *
2254
+ * @extends Event
2255
+ * @private
2256
+ */
2257
+ class MessageEvent extends Event {
2258
+ /**
2259
+ * Create a new `MessageEvent`.
2260
+ *
2261
+ * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The received data
2262
+ * @param {WebSocket} target A reference to the target to which the event was
2263
+ * dispatched
2264
+ */
2265
+ constructor(data, target) {
2266
+ super('message', target);
2267
+
2268
+ this.data = data;
2269
+ }
2270
+ }
2271
+
2272
+ /**
2273
+ * Class representing a close event.
2274
+ *
2275
+ * @extends Event
2276
+ * @private
2277
+ */
2278
+ class CloseEvent extends Event {
2279
+ /**
2280
+ * Create a new `CloseEvent`.
2281
+ *
2282
+ * @param {Number} code The status code explaining why the connection is being
2283
+ * closed
2284
+ * @param {String} reason A human-readable string explaining why the
2285
+ * connection is closing
2286
+ * @param {WebSocket} target A reference to the target to which the event was
2287
+ * dispatched
2288
+ */
2289
+ constructor(code, reason, target) {
2290
+ super('close', target);
2291
+
2292
+ this.wasClean = target._closeFrameReceived && target._closeFrameSent;
2293
+ this.reason = reason;
2294
+ this.code = code;
2295
+ }
2296
+ }
2297
+
2298
+ /**
2299
+ * Class representing an open event.
2300
+ *
2301
+ * @extends Event
2302
+ * @private
2303
+ */
2304
+ class OpenEvent extends Event {
2305
+ /**
2306
+ * Create a new `OpenEvent`.
2307
+ *
2308
+ * @param {WebSocket} target A reference to the target to which the event was
2309
+ * dispatched
2310
+ */
2311
+ constructor(target) {
2312
+ super('open', target);
2313
+ }
2314
+ }
2315
+
2316
+ /**
2317
+ * Class representing an error event.
2318
+ *
2319
+ * @extends Event
2320
+ * @private
2321
+ */
2322
+ class ErrorEvent extends Event {
2323
+ /**
2324
+ * Create a new `ErrorEvent`.
2325
+ *
2326
+ * @param {Object} error The error that generated this event
2327
+ * @param {WebSocket} target A reference to the target to which the event was
2328
+ * dispatched
2329
+ */
2330
+ constructor(error, target) {
2331
+ super('error', target);
2332
+
2333
+ this.message = error.message;
2334
+ this.error = error;
2335
+ }
2336
+ }
2337
+
2338
+ /**
2339
+ * This provides methods for emulating the `EventTarget` interface. It's not
2340
+ * meant to be used directly.
2341
+ *
2342
+ * @mixin
2343
+ */
2344
+ const EventTarget = {
2345
+ /**
2346
+ * Register an event listener.
2347
+ *
2348
+ * @param {String} type A string representing the event type to listen for
2349
+ * @param {Function} listener The listener to add
2350
+ * @param {Object} [options] An options object specifies characteristics about
2351
+ * the event listener
2352
+ * @param {Boolean} [options.once=false] A `Boolean`` indicating that the
2353
+ * listener should be invoked at most once after being added. If `true`,
2354
+ * the listener would be automatically removed when invoked.
2355
+ * @public
2356
+ */
2357
+ addEventListener(type, listener, options) {
2358
+ if (typeof listener !== 'function') return;
2359
+
2360
+ function onMessage(data) {
2361
+ listener.call(this, new MessageEvent(data, this));
2362
+ }
2363
+
2364
+ function onClose(code, message) {
2365
+ listener.call(this, new CloseEvent(code, message, this));
2366
+ }
2367
+
2368
+ function onError(error) {
2369
+ listener.call(this, new ErrorEvent(error, this));
2370
+ }
2371
+
2372
+ function onOpen() {
2373
+ listener.call(this, new OpenEvent(this));
2374
+ }
2375
+
2376
+ const method = options && options.once ? 'once' : 'on';
2377
+
2378
+ if (type === 'message') {
2379
+ onMessage._listener = listener;
2380
+ this[method](type, onMessage);
2381
+ } else if (type === 'close') {
2382
+ onClose._listener = listener;
2383
+ this[method](type, onClose);
2384
+ } else if (type === 'error') {
2385
+ onError._listener = listener;
2386
+ this[method](type, onError);
2387
+ } else if (type === 'open') {
2388
+ onOpen._listener = listener;
2389
+ this[method](type, onOpen);
2390
+ } else {
2391
+ this[method](type, listener);
2392
+ }
2393
+ },
2394
+
2395
+ /**
2396
+ * Remove an event listener.
2397
+ *
2398
+ * @param {String} type A string representing the event type to remove
2399
+ * @param {Function} listener The listener to remove
2400
+ * @public
2401
+ */
2402
+ removeEventListener(type, listener) {
2403
+ const listeners = this.listeners(type);
2404
+
2405
+ for (let i = 0; i < listeners.length; i++) {
2406
+ if (listeners[i] === listener || listeners[i]._listener === listener) {
2407
+ this.removeListener(type, listeners[i]);
2408
+ }
2409
+ }
2410
+ }
2411
+ };
2412
+
2413
+ var eventTarget = EventTarget;
2414
+
2415
+ //
2416
+ // Allowed token characters:
2417
+ //
2418
+ // '!', '#', '$', '%', '&', ''', '*', '+', '-',
2419
+ // '.', 0-9, A-Z, '^', '_', '`', a-z, '|', '~'
2420
+ //
2421
+ // tokenChars[32] === 0 // ' '
2422
+ // tokenChars[33] === 1 // '!'
2423
+ // tokenChars[34] === 0 // '"'
2424
+ // ...
2425
+ //
2426
+ // prettier-ignore
2427
+ const tokenChars = [
2428
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0 - 15
2429
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 - 31
2430
+ 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 1, 1, 0, // 32 - 47
2431
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 48 - 63
2432
+ 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 64 - 79
2433
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, // 80 - 95
2434
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 96 - 111
2435
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 1, 0 // 112 - 127
2436
+ ];
2437
+
2438
+ /**
2439
+ * Adds an offer to the map of extension offers or a parameter to the map of
2440
+ * parameters.
2441
+ *
2442
+ * @param {Object} dest The map of extension offers or parameters
2443
+ * @param {String} name The extension or parameter name
2444
+ * @param {(Object|Boolean|String)} elem The extension parameters or the
2445
+ * parameter value
2446
+ * @private
2447
+ */
2448
+ function push(dest, name, elem) {
2449
+ if (dest[name] === undefined) dest[name] = [elem];
2450
+ else dest[name].push(elem);
2451
+ }
2452
+
2453
+ /**
2454
+ * Parses the `Sec-WebSocket-Extensions` header into an object.
2455
+ *
2456
+ * @param {String} header The field value of the header
2457
+ * @return {Object} The parsed object
2458
+ * @public
2459
+ */
2460
+ function parse$2(header) {
2461
+ const offers = Object.create(null);
2462
+
2463
+ if (header === undefined || header === '') return offers;
2464
+
2465
+ let params = Object.create(null);
2466
+ let mustUnescape = false;
2467
+ let isEscaping = false;
2468
+ let inQuotes = false;
2469
+ let extensionName;
2470
+ let paramName;
2471
+ let start = -1;
2472
+ let end = -1;
2473
+ let i = 0;
2474
+
2475
+ for (; i < header.length; i++) {
2476
+ const code = header.charCodeAt(i);
2477
+
2478
+ if (extensionName === undefined) {
2479
+ if (end === -1 && tokenChars[code] === 1) {
2480
+ if (start === -1) start = i;
2481
+ } else if (code === 0x20 /* ' ' */ || code === 0x09 /* '\t' */) {
2482
+ if (end === -1 && start !== -1) end = i;
2483
+ } else if (code === 0x3b /* ';' */ || code === 0x2c /* ',' */) {
2484
+ if (start === -1) {
2485
+ throw new SyntaxError(`Unexpected character at index ${i}`);
2486
+ }
2487
+
2488
+ if (end === -1) end = i;
2489
+ const name = header.slice(start, end);
2490
+ if (code === 0x2c) {
2491
+ push(offers, name, params);
2492
+ params = Object.create(null);
2493
+ } else {
2494
+ extensionName = name;
2495
+ }
2496
+
2497
+ start = end = -1;
2498
+ } else {
2499
+ throw new SyntaxError(`Unexpected character at index ${i}`);
2500
+ }
2501
+ } else if (paramName === undefined) {
2502
+ if (end === -1 && tokenChars[code] === 1) {
2503
+ if (start === -1) start = i;
2504
+ } else if (code === 0x20 || code === 0x09) {
2505
+ if (end === -1 && start !== -1) end = i;
2506
+ } else if (code === 0x3b || code === 0x2c) {
2507
+ if (start === -1) {
2508
+ throw new SyntaxError(`Unexpected character at index ${i}`);
2509
+ }
2510
+
2511
+ if (end === -1) end = i;
2512
+ push(params, header.slice(start, end), true);
2513
+ if (code === 0x2c) {
2514
+ push(offers, extensionName, params);
2515
+ params = Object.create(null);
2516
+ extensionName = undefined;
2517
+ }
2518
+
2519
+ start = end = -1;
2520
+ } else if (code === 0x3d /* '=' */ && start !== -1 && end === -1) {
2521
+ paramName = header.slice(start, i);
2522
+ start = end = -1;
2523
+ } else {
2524
+ throw new SyntaxError(`Unexpected character at index ${i}`);
2525
+ }
2526
+ } else {
2527
+ //
2528
+ // The value of a quoted-string after unescaping must conform to the
2529
+ // token ABNF, so only token characters are valid.
2530
+ // Ref: https://tools.ietf.org/html/rfc6455#section-9.1
2531
+ //
2532
+ if (isEscaping) {
2533
+ if (tokenChars[code] !== 1) {
2534
+ throw new SyntaxError(`Unexpected character at index ${i}`);
2535
+ }
2536
+ if (start === -1) start = i;
2537
+ else if (!mustUnescape) mustUnescape = true;
2538
+ isEscaping = false;
2539
+ } else if (inQuotes) {
2540
+ if (tokenChars[code] === 1) {
2541
+ if (start === -1) start = i;
2542
+ } else if (code === 0x22 /* '"' */ && start !== -1) {
2543
+ inQuotes = false;
2544
+ end = i;
2545
+ } else if (code === 0x5c /* '\' */) {
2546
+ isEscaping = true;
2547
+ } else {
2548
+ throw new SyntaxError(`Unexpected character at index ${i}`);
2549
+ }
2550
+ } else if (code === 0x22 && header.charCodeAt(i - 1) === 0x3d) {
2551
+ inQuotes = true;
2552
+ } else if (end === -1 && tokenChars[code] === 1) {
2553
+ if (start === -1) start = i;
2554
+ } else if (start !== -1 && (code === 0x20 || code === 0x09)) {
2555
+ if (end === -1) end = i;
2556
+ } else if (code === 0x3b || code === 0x2c) {
2557
+ if (start === -1) {
2558
+ throw new SyntaxError(`Unexpected character at index ${i}`);
2559
+ }
2560
+
2561
+ if (end === -1) end = i;
2562
+ let value = header.slice(start, end);
2563
+ if (mustUnescape) {
2564
+ value = value.replace(/\\/g, '');
2565
+ mustUnescape = false;
2566
+ }
2567
+ push(params, paramName, value);
2568
+ if (code === 0x2c) {
2569
+ push(offers, extensionName, params);
2570
+ params = Object.create(null);
2571
+ extensionName = undefined;
2572
+ }
2573
+
2574
+ paramName = undefined;
2575
+ start = end = -1;
2576
+ } else {
2577
+ throw new SyntaxError(`Unexpected character at index ${i}`);
2578
+ }
2579
+ }
2580
+ }
2581
+
2582
+ if (start === -1 || inQuotes) {
2583
+ throw new SyntaxError('Unexpected end of input');
2584
+ }
2585
+
2586
+ if (end === -1) end = i;
2587
+ const token = header.slice(start, end);
2588
+ if (extensionName === undefined) {
2589
+ push(offers, token, params);
2590
+ } else {
2591
+ if (paramName === undefined) {
2592
+ push(params, token, true);
2593
+ } else if (mustUnescape) {
2594
+ push(params, paramName, token.replace(/\\/g, ''));
2595
+ } else {
2596
+ push(params, paramName, token);
2597
+ }
2598
+ push(offers, extensionName, params);
2599
+ }
2600
+
2601
+ return offers;
2602
+ }
2603
+
2604
+ /**
2605
+ * Builds the `Sec-WebSocket-Extensions` header field value.
2606
+ *
2607
+ * @param {Object} extensions The map of extensions and parameters to format
2608
+ * @return {String} A string representing the given object
2609
+ * @public
2610
+ */
2611
+ function format$2(extensions) {
2612
+ return Object.keys(extensions)
2613
+ .map((extension) => {
2614
+ let configurations = extensions[extension];
2615
+ if (!Array.isArray(configurations)) configurations = [configurations];
2616
+ return configurations
2617
+ .map((params) => {
2618
+ return [extension]
2619
+ .concat(
2620
+ Object.keys(params).map((k) => {
2621
+ let values = params[k];
2622
+ if (!Array.isArray(values)) values = [values];
2623
+ return values
2624
+ .map((v) => (v === true ? k : `${k}=${v}`))
2625
+ .join('; ');
2626
+ })
2627
+ )
2628
+ .join('; ');
2629
+ })
2630
+ .join(', ');
2631
+ })
2632
+ .join(', ');
2633
+ }
2634
+
2635
+ var extension = { format: format$2, parse: parse$2 };
2636
+
2637
+ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Readable$" }] */
2638
+
2639
+ const EventEmitter$1 = require$$0$3;
2640
+ const https = require$$1$1;
2641
+ const http$1 = require$$2$1;
2642
+ const net = require$$3;
2643
+ const tls = require$$4;
2644
+ const { randomBytes, createHash: createHash$1 } = require$$5;
2645
+ const { Readable } = require$$0$2;
2646
+ const { URL } = require$$7;
2647
+
2648
+ const PerMessageDeflate$1 = permessageDeflate;
2649
+ const Receiver = receiver;
2650
+ const Sender = sender;
2651
+ const {
2652
+ BINARY_TYPES,
2653
+ EMPTY_BUFFER,
2654
+ GUID: GUID$1,
2655
+ kStatusCode,
2656
+ kWebSocket: kWebSocket$1,
2657
+ NOOP
2658
+ } = constants;
2659
+ const { addEventListener, removeEventListener } = eventTarget;
2660
+ const { format: format$1, parse: parse$1 } = extension;
2661
+ const { toBuffer } = bufferUtilExports;
2662
+
2663
+ const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
2664
+ const protocolVersions = [8, 13];
2665
+ const closeTimeout = 30 * 1000;
2666
+
2667
+ /**
2668
+ * Class representing a WebSocket.
2669
+ *
2670
+ * @extends EventEmitter
2671
+ */
2672
+ let WebSocket$3 = class WebSocket extends EventEmitter$1 {
2673
+ /**
2674
+ * Create a new `WebSocket`.
2675
+ *
2676
+ * @param {(String|URL)} address The URL to which to connect
2677
+ * @param {(String|String[])} [protocols] The subprotocols
2678
+ * @param {Object} [options] Connection options
2679
+ */
2680
+ constructor(address, protocols, options) {
2681
+ super();
2682
+
2683
+ this._binaryType = BINARY_TYPES[0];
2684
+ this._closeCode = 1006;
2685
+ this._closeFrameReceived = false;
2686
+ this._closeFrameSent = false;
2687
+ this._closeMessage = '';
2688
+ this._closeTimer = null;
2689
+ this._extensions = {};
2690
+ this._protocol = '';
2691
+ this._readyState = WebSocket.CONNECTING;
2692
+ this._receiver = null;
2693
+ this._sender = null;
2694
+ this._socket = null;
2695
+
2696
+ if (address !== null) {
2697
+ this._bufferedAmount = 0;
2698
+ this._isServer = false;
2699
+ this._redirects = 0;
2700
+
2701
+ if (Array.isArray(protocols)) {
2702
+ protocols = protocols.join(', ');
2703
+ } else if (typeof protocols === 'object' && protocols !== null) {
2704
+ options = protocols;
2705
+ protocols = undefined;
2706
+ }
2707
+
2708
+ initAsClient(this, address, protocols, options);
2709
+ } else {
2710
+ this._isServer = true;
2711
+ }
2712
+ }
2713
+
2714
+ /**
2715
+ * This deviates from the WHATWG interface since ws doesn't support the
2716
+ * required default "blob" type (instead we define a custom "nodebuffer"
2717
+ * type).
2718
+ *
2719
+ * @type {String}
2720
+ */
2721
+ get binaryType() {
2722
+ return this._binaryType;
2723
+ }
2724
+
2725
+ set binaryType(type) {
2726
+ if (!BINARY_TYPES.includes(type)) return;
2727
+
2728
+ this._binaryType = type;
2729
+
2730
+ //
2731
+ // Allow to change `binaryType` on the fly.
2732
+ //
2733
+ if (this._receiver) this._receiver._binaryType = type;
2734
+ }
2735
+
2736
+ /**
2737
+ * @type {Number}
2738
+ */
2739
+ get bufferedAmount() {
2740
+ if (!this._socket) return this._bufferedAmount;
2741
+
2742
+ return this._socket._writableState.length + this._sender._bufferedBytes;
2743
+ }
2744
+
2745
+ /**
2746
+ * @type {String}
2747
+ */
2748
+ get extensions() {
2749
+ return Object.keys(this._extensions).join();
2750
+ }
2751
+
2752
+ /**
2753
+ * @type {Function}
2754
+ */
2755
+ /* istanbul ignore next */
2756
+ get onclose() {
2757
+ return undefined;
2758
+ }
2759
+
2760
+ /* istanbul ignore next */
2761
+ set onclose(listener) {}
2762
+
2763
+ /**
2764
+ * @type {Function}
2765
+ */
2766
+ /* istanbul ignore next */
2767
+ get onerror() {
2768
+ return undefined;
2769
+ }
2770
+
2771
+ /* istanbul ignore next */
2772
+ set onerror(listener) {}
2773
+
2774
+ /**
2775
+ * @type {Function}
2776
+ */
2777
+ /* istanbul ignore next */
2778
+ get onopen() {
2779
+ return undefined;
2780
+ }
2781
+
2782
+ /* istanbul ignore next */
2783
+ set onopen(listener) {}
2784
+
2785
+ /**
2786
+ * @type {Function}
2787
+ */
2788
+ /* istanbul ignore next */
2789
+ get onmessage() {
2790
+ return undefined;
2791
+ }
2792
+
2793
+ /* istanbul ignore next */
2794
+ set onmessage(listener) {}
2795
+
2796
+ /**
2797
+ * @type {String}
2798
+ */
2799
+ get protocol() {
2800
+ return this._protocol;
2801
+ }
2802
+
2803
+ /**
2804
+ * @type {Number}
2805
+ */
2806
+ get readyState() {
2807
+ return this._readyState;
2808
+ }
2809
+
2810
+ /**
2811
+ * @type {String}
2812
+ */
2813
+ get url() {
2814
+ return this._url;
2815
+ }
2816
+
2817
+ /**
2818
+ * Set up the socket and the internal resources.
2819
+ *
2820
+ * @param {(net.Socket|tls.Socket)} socket The network socket between the
2821
+ * server and client
2822
+ * @param {Buffer} head The first packet of the upgraded stream
2823
+ * @param {Number} [maxPayload=0] The maximum allowed message size
2824
+ * @private
2825
+ */
2826
+ setSocket(socket, head, maxPayload) {
2827
+ const receiver = new Receiver(
2828
+ this.binaryType,
2829
+ this._extensions,
2830
+ this._isServer,
2831
+ maxPayload
2832
+ );
2833
+
2834
+ this._sender = new Sender(socket, this._extensions);
2835
+ this._receiver = receiver;
2836
+ this._socket = socket;
2837
+
2838
+ receiver[kWebSocket$1] = this;
2839
+ socket[kWebSocket$1] = this;
2840
+
2841
+ receiver.on('conclude', receiverOnConclude);
2842
+ receiver.on('drain', receiverOnDrain);
2843
+ receiver.on('error', receiverOnError);
2844
+ receiver.on('message', receiverOnMessage);
2845
+ receiver.on('ping', receiverOnPing);
2846
+ receiver.on('pong', receiverOnPong);
2847
+
2848
+ socket.setTimeout(0);
2849
+ socket.setNoDelay();
2850
+
2851
+ if (head.length > 0) socket.unshift(head);
2852
+
2853
+ socket.on('close', socketOnClose);
2854
+ socket.on('data', socketOnData);
2855
+ socket.on('end', socketOnEnd);
2856
+ socket.on('error', socketOnError$1);
2857
+
2858
+ this._readyState = WebSocket.OPEN;
2859
+ this.emit('open');
2860
+ }
2861
+
2862
+ /**
2863
+ * Emit the `'close'` event.
2864
+ *
2865
+ * @private
2866
+ */
2867
+ emitClose() {
2868
+ if (!this._socket) {
2869
+ this._readyState = WebSocket.CLOSED;
2870
+ this.emit('close', this._closeCode, this._closeMessage);
2871
+ return;
2872
+ }
2873
+
2874
+ if (this._extensions[PerMessageDeflate$1.extensionName]) {
2875
+ this._extensions[PerMessageDeflate$1.extensionName].cleanup();
2876
+ }
2877
+
2878
+ this._receiver.removeAllListeners();
2879
+ this._readyState = WebSocket.CLOSED;
2880
+ this.emit('close', this._closeCode, this._closeMessage);
2881
+ }
2882
+
2883
+ /**
2884
+ * Start a closing handshake.
2885
+ *
2886
+ * +----------+ +-----------+ +----------+
2887
+ * - - -|ws.close()|-->|close frame|-->|ws.close()|- - -
2888
+ * | +----------+ +-----------+ +----------+ |
2889
+ * +----------+ +-----------+ |
2890
+ * CLOSING |ws.close()|<--|close frame|<--+-----+ CLOSING
2891
+ * +----------+ +-----------+ |
2892
+ * | | | +---+ |
2893
+ * +------------------------+-->|fin| - - - -
2894
+ * | +---+ | +---+
2895
+ * - - - - -|fin|<---------------------+
2896
+ * +---+
2897
+ *
2898
+ * @param {Number} [code] Status code explaining why the connection is closing
2899
+ * @param {String} [data] A string explaining why the connection is closing
2900
+ * @public
2901
+ */
2902
+ close(code, data) {
2903
+ if (this.readyState === WebSocket.CLOSED) return;
2904
+ if (this.readyState === WebSocket.CONNECTING) {
2905
+ const msg = 'WebSocket was closed before the connection was established';
2906
+ return abortHandshake$1(this, this._req, msg);
2907
+ }
2908
+
2909
+ if (this.readyState === WebSocket.CLOSING) {
2910
+ if (
2911
+ this._closeFrameSent &&
2912
+ (this._closeFrameReceived || this._receiver._writableState.errorEmitted)
2913
+ ) {
2914
+ this._socket.end();
2915
+ }
2916
+
2917
+ return;
2918
+ }
2919
+
2920
+ this._readyState = WebSocket.CLOSING;
2921
+ this._sender.close(code, data, !this._isServer, (err) => {
2922
+ //
2923
+ // This error is handled by the `'error'` listener on the socket. We only
2924
+ // want to know if the close frame has been sent here.
2925
+ //
2926
+ if (err) return;
2927
+
2928
+ this._closeFrameSent = true;
2929
+
2930
+ if (
2931
+ this._closeFrameReceived ||
2932
+ this._receiver._writableState.errorEmitted
2933
+ ) {
2934
+ this._socket.end();
2935
+ }
2936
+ });
2937
+
2938
+ //
2939
+ // Specify a timeout for the closing handshake to complete.
2940
+ //
2941
+ this._closeTimer = setTimeout(
2942
+ this._socket.destroy.bind(this._socket),
2943
+ closeTimeout
2944
+ );
2945
+ }
2946
+
2947
+ /**
2948
+ * Send a ping.
2949
+ *
2950
+ * @param {*} [data] The data to send
2951
+ * @param {Boolean} [mask] Indicates whether or not to mask `data`
2952
+ * @param {Function} [cb] Callback which is executed when the ping is sent
2953
+ * @public
2954
+ */
2955
+ ping(data, mask, cb) {
2956
+ if (this.readyState === WebSocket.CONNECTING) {
2957
+ throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
2958
+ }
2959
+
2960
+ if (typeof data === 'function') {
2961
+ cb = data;
2962
+ data = mask = undefined;
2963
+ } else if (typeof mask === 'function') {
2964
+ cb = mask;
2965
+ mask = undefined;
2966
+ }
2967
+
2968
+ if (typeof data === 'number') data = data.toString();
2969
+
2970
+ if (this.readyState !== WebSocket.OPEN) {
2971
+ sendAfterClose(this, data, cb);
2972
+ return;
2973
+ }
2974
+
2975
+ if (mask === undefined) mask = !this._isServer;
2976
+ this._sender.ping(data || EMPTY_BUFFER, mask, cb);
2977
+ }
2978
+
2979
+ /**
2980
+ * Send a pong.
2981
+ *
2982
+ * @param {*} [data] The data to send
2983
+ * @param {Boolean} [mask] Indicates whether or not to mask `data`
2984
+ * @param {Function} [cb] Callback which is executed when the pong is sent
2985
+ * @public
2986
+ */
2987
+ pong(data, mask, cb) {
2988
+ if (this.readyState === WebSocket.CONNECTING) {
2989
+ throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
2990
+ }
2991
+
2992
+ if (typeof data === 'function') {
2993
+ cb = data;
2994
+ data = mask = undefined;
2995
+ } else if (typeof mask === 'function') {
2996
+ cb = mask;
2997
+ mask = undefined;
2998
+ }
2999
+
3000
+ if (typeof data === 'number') data = data.toString();
3001
+
3002
+ if (this.readyState !== WebSocket.OPEN) {
3003
+ sendAfterClose(this, data, cb);
3004
+ return;
3005
+ }
3006
+
3007
+ if (mask === undefined) mask = !this._isServer;
3008
+ this._sender.pong(data || EMPTY_BUFFER, mask, cb);
3009
+ }
3010
+
3011
+ /**
3012
+ * Send a data message.
3013
+ *
3014
+ * @param {*} data The message to send
3015
+ * @param {Object} [options] Options object
3016
+ * @param {Boolean} [options.compress] Specifies whether or not to compress
3017
+ * `data`
3018
+ * @param {Boolean} [options.binary] Specifies whether `data` is binary or
3019
+ * text
3020
+ * @param {Boolean} [options.fin=true] Specifies whether the fragment is the
3021
+ * last one
3022
+ * @param {Boolean} [options.mask] Specifies whether or not to mask `data`
3023
+ * @param {Function} [cb] Callback which is executed when data is written out
3024
+ * @public
3025
+ */
3026
+ send(data, options, cb) {
3027
+ if (this.readyState === WebSocket.CONNECTING) {
3028
+ throw new Error('WebSocket is not open: readyState 0 (CONNECTING)');
3029
+ }
3030
+
3031
+ if (typeof options === 'function') {
3032
+ cb = options;
3033
+ options = {};
3034
+ }
3035
+
3036
+ if (typeof data === 'number') data = data.toString();
3037
+
3038
+ if (this.readyState !== WebSocket.OPEN) {
3039
+ sendAfterClose(this, data, cb);
3040
+ return;
3041
+ }
3042
+
3043
+ const opts = {
3044
+ binary: typeof data !== 'string',
3045
+ mask: !this._isServer,
3046
+ compress: true,
3047
+ fin: true,
3048
+ ...options
3049
+ };
3050
+
3051
+ if (!this._extensions[PerMessageDeflate$1.extensionName]) {
3052
+ opts.compress = false;
3053
+ }
3054
+
3055
+ this._sender.send(data || EMPTY_BUFFER, opts, cb);
3056
+ }
3057
+
3058
+ /**
3059
+ * Forcibly close the connection.
3060
+ *
3061
+ * @public
3062
+ */
3063
+ terminate() {
3064
+ if (this.readyState === WebSocket.CLOSED) return;
3065
+ if (this.readyState === WebSocket.CONNECTING) {
3066
+ const msg = 'WebSocket was closed before the connection was established';
3067
+ return abortHandshake$1(this, this._req, msg);
3068
+ }
3069
+
3070
+ if (this._socket) {
3071
+ this._readyState = WebSocket.CLOSING;
3072
+ this._socket.destroy();
3073
+ }
3074
+ }
3075
+ };
3076
+
3077
+ /**
3078
+ * @constant {Number} CONNECTING
3079
+ * @memberof WebSocket
3080
+ */
3081
+ Object.defineProperty(WebSocket$3, 'CONNECTING', {
3082
+ enumerable: true,
3083
+ value: readyStates.indexOf('CONNECTING')
3084
+ });
3085
+
3086
+ /**
3087
+ * @constant {Number} CONNECTING
3088
+ * @memberof WebSocket.prototype
3089
+ */
3090
+ Object.defineProperty(WebSocket$3.prototype, 'CONNECTING', {
3091
+ enumerable: true,
3092
+ value: readyStates.indexOf('CONNECTING')
3093
+ });
3094
+
3095
+ /**
3096
+ * @constant {Number} OPEN
3097
+ * @memberof WebSocket
3098
+ */
3099
+ Object.defineProperty(WebSocket$3, 'OPEN', {
3100
+ enumerable: true,
3101
+ value: readyStates.indexOf('OPEN')
3102
+ });
3103
+
3104
+ /**
3105
+ * @constant {Number} OPEN
3106
+ * @memberof WebSocket.prototype
3107
+ */
3108
+ Object.defineProperty(WebSocket$3.prototype, 'OPEN', {
3109
+ enumerable: true,
3110
+ value: readyStates.indexOf('OPEN')
3111
+ });
3112
+
3113
+ /**
3114
+ * @constant {Number} CLOSING
3115
+ * @memberof WebSocket
3116
+ */
3117
+ Object.defineProperty(WebSocket$3, 'CLOSING', {
3118
+ enumerable: true,
3119
+ value: readyStates.indexOf('CLOSING')
3120
+ });
3121
+
3122
+ /**
3123
+ * @constant {Number} CLOSING
3124
+ * @memberof WebSocket.prototype
3125
+ */
3126
+ Object.defineProperty(WebSocket$3.prototype, 'CLOSING', {
3127
+ enumerable: true,
3128
+ value: readyStates.indexOf('CLOSING')
3129
+ });
3130
+
3131
+ /**
3132
+ * @constant {Number} CLOSED
3133
+ * @memberof WebSocket
3134
+ */
3135
+ Object.defineProperty(WebSocket$3, 'CLOSED', {
3136
+ enumerable: true,
3137
+ value: readyStates.indexOf('CLOSED')
3138
+ });
3139
+
3140
+ /**
3141
+ * @constant {Number} CLOSED
3142
+ * @memberof WebSocket.prototype
3143
+ */
3144
+ Object.defineProperty(WebSocket$3.prototype, 'CLOSED', {
3145
+ enumerable: true,
3146
+ value: readyStates.indexOf('CLOSED')
3147
+ });
3148
+
3149
+ [
3150
+ 'binaryType',
3151
+ 'bufferedAmount',
3152
+ 'extensions',
3153
+ 'protocol',
3154
+ 'readyState',
3155
+ 'url'
3156
+ ].forEach((property) => {
3157
+ Object.defineProperty(WebSocket$3.prototype, property, { enumerable: true });
3158
+ });
3159
+
3160
+ //
3161
+ // Add the `onopen`, `onerror`, `onclose`, and `onmessage` attributes.
3162
+ // See https://html.spec.whatwg.org/multipage/comms.html#the-websocket-interface
3163
+ //
3164
+ ['open', 'error', 'close', 'message'].forEach((method) => {
3165
+ Object.defineProperty(WebSocket$3.prototype, `on${method}`, {
3166
+ enumerable: true,
3167
+ get() {
3168
+ const listeners = this.listeners(method);
3169
+ for (let i = 0; i < listeners.length; i++) {
3170
+ if (listeners[i]._listener) return listeners[i]._listener;
3171
+ }
3172
+
3173
+ return undefined;
3174
+ },
3175
+ set(listener) {
3176
+ const listeners = this.listeners(method);
3177
+ for (let i = 0; i < listeners.length; i++) {
3178
+ //
3179
+ // Remove only the listeners added via `addEventListener`.
3180
+ //
3181
+ if (listeners[i]._listener) this.removeListener(method, listeners[i]);
3182
+ }
3183
+ this.addEventListener(method, listener);
3184
+ }
3185
+ });
3186
+ });
3187
+
3188
+ WebSocket$3.prototype.addEventListener = addEventListener;
3189
+ WebSocket$3.prototype.removeEventListener = removeEventListener;
3190
+
3191
+ var websocket = WebSocket$3;
3192
+
3193
+ /**
3194
+ * Initialize a WebSocket client.
3195
+ *
3196
+ * @param {WebSocket} websocket The client to initialize
3197
+ * @param {(String|URL)} address The URL to which to connect
3198
+ * @param {String} [protocols] The subprotocols
3199
+ * @param {Object} [options] Connection options
3200
+ * @param {(Boolean|Object)} [options.perMessageDeflate=true] Enable/disable
3201
+ * permessage-deflate
3202
+ * @param {Number} [options.handshakeTimeout] Timeout in milliseconds for the
3203
+ * handshake request
3204
+ * @param {Number} [options.protocolVersion=13] Value of the
3205
+ * `Sec-WebSocket-Version` header
3206
+ * @param {String} [options.origin] Value of the `Origin` or
3207
+ * `Sec-WebSocket-Origin` header
3208
+ * @param {Number} [options.maxPayload=104857600] The maximum allowed message
3209
+ * size
3210
+ * @param {Boolean} [options.followRedirects=false] Whether or not to follow
3211
+ * redirects
3212
+ * @param {Number} [options.maxRedirects=10] The maximum number of redirects
3213
+ * allowed
3214
+ * @private
3215
+ */
3216
+ function initAsClient(websocket, address, protocols, options) {
3217
+ const opts = {
3218
+ protocolVersion: protocolVersions[1],
3219
+ maxPayload: 100 * 1024 * 1024,
3220
+ perMessageDeflate: true,
3221
+ followRedirects: false,
3222
+ maxRedirects: 10,
3223
+ ...options,
3224
+ createConnection: undefined,
3225
+ socketPath: undefined,
3226
+ hostname: undefined,
3227
+ protocol: undefined,
3228
+ timeout: undefined,
3229
+ method: undefined,
3230
+ host: undefined,
3231
+ path: undefined,
3232
+ port: undefined
3233
+ };
3234
+
3235
+ if (!protocolVersions.includes(opts.protocolVersion)) {
3236
+ throw new RangeError(
3237
+ `Unsupported protocol version: ${opts.protocolVersion} ` +
3238
+ `(supported versions: ${protocolVersions.join(', ')})`
3239
+ );
3240
+ }
3241
+
3242
+ let parsedUrl;
3243
+
3244
+ if (address instanceof URL) {
3245
+ parsedUrl = address;
3246
+ websocket._url = address.href;
3247
+ } else {
3248
+ parsedUrl = new URL(address);
3249
+ websocket._url = address;
3250
+ }
3251
+
3252
+ const isUnixSocket = parsedUrl.protocol === 'ws+unix:';
3253
+
3254
+ if (!parsedUrl.host && (!isUnixSocket || !parsedUrl.pathname)) {
3255
+ const err = new Error(`Invalid URL: ${websocket.url}`);
3256
+
3257
+ if (websocket._redirects === 0) {
3258
+ throw err;
3259
+ } else {
3260
+ emitErrorAndClose(websocket, err);
3261
+ return;
3262
+ }
3263
+ }
3264
+
3265
+ const isSecure =
3266
+ parsedUrl.protocol === 'wss:' || parsedUrl.protocol === 'https:';
3267
+ const defaultPort = isSecure ? 443 : 80;
3268
+ const key = randomBytes(16).toString('base64');
3269
+ const get = isSecure ? https.get : http$1.get;
3270
+ let perMessageDeflate;
3271
+
3272
+ opts.createConnection = isSecure ? tlsConnect : netConnect;
3273
+ opts.defaultPort = opts.defaultPort || defaultPort;
3274
+ opts.port = parsedUrl.port || defaultPort;
3275
+ opts.host = parsedUrl.hostname.startsWith('[')
3276
+ ? parsedUrl.hostname.slice(1, -1)
3277
+ : parsedUrl.hostname;
3278
+ opts.headers = {
3279
+ 'Sec-WebSocket-Version': opts.protocolVersion,
3280
+ 'Sec-WebSocket-Key': key,
3281
+ Connection: 'Upgrade',
3282
+ Upgrade: 'websocket',
3283
+ ...opts.headers
3284
+ };
3285
+ opts.path = parsedUrl.pathname + parsedUrl.search;
3286
+ opts.timeout = opts.handshakeTimeout;
3287
+
3288
+ if (opts.perMessageDeflate) {
3289
+ perMessageDeflate = new PerMessageDeflate$1(
3290
+ opts.perMessageDeflate !== true ? opts.perMessageDeflate : {},
3291
+ false,
3292
+ opts.maxPayload
3293
+ );
3294
+ opts.headers['Sec-WebSocket-Extensions'] = format$1({
3295
+ [PerMessageDeflate$1.extensionName]: perMessageDeflate.offer()
3296
+ });
3297
+ }
3298
+ if (protocols) {
3299
+ opts.headers['Sec-WebSocket-Protocol'] = protocols;
3300
+ }
3301
+ if (opts.origin) {
3302
+ if (opts.protocolVersion < 13) {
3303
+ opts.headers['Sec-WebSocket-Origin'] = opts.origin;
3304
+ } else {
3305
+ opts.headers.Origin = opts.origin;
3306
+ }
3307
+ }
3308
+ if (parsedUrl.username || parsedUrl.password) {
3309
+ opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
3310
+ }
3311
+
3312
+ if (isUnixSocket) {
3313
+ const parts = opts.path.split(':');
3314
+
3315
+ opts.socketPath = parts[0];
3316
+ opts.path = parts[1];
3317
+ }
3318
+
3319
+ if (opts.followRedirects) {
3320
+ if (websocket._redirects === 0) {
3321
+ websocket._originalUnixSocket = isUnixSocket;
3322
+ websocket._originalSecure = isSecure;
3323
+ websocket._originalHostOrSocketPath = isUnixSocket
3324
+ ? opts.socketPath
3325
+ : parsedUrl.host;
3326
+
3327
+ const headers = options && options.headers;
3328
+
3329
+ //
3330
+ // Shallow copy the user provided options so that headers can be changed
3331
+ // without mutating the original object.
3332
+ //
3333
+ options = { ...options, headers: {} };
3334
+
3335
+ if (headers) {
3336
+ for (const [key, value] of Object.entries(headers)) {
3337
+ options.headers[key.toLowerCase()] = value;
3338
+ }
3339
+ }
3340
+ } else {
3341
+ const isSameHost = isUnixSocket
3342
+ ? websocket._originalUnixSocket
3343
+ ? opts.socketPath === websocket._originalHostOrSocketPath
3344
+ : false
3345
+ : websocket._originalUnixSocket
3346
+ ? false
3347
+ : parsedUrl.host === websocket._originalHostOrSocketPath;
3348
+
3349
+ if (!isSameHost || (websocket._originalSecure && !isSecure)) {
3350
+ //
3351
+ // Match curl 7.77.0 behavior and drop the following headers. These
3352
+ // headers are also dropped when following a redirect to a subdomain.
3353
+ //
3354
+ delete opts.headers.authorization;
3355
+ delete opts.headers.cookie;
3356
+
3357
+ if (!isSameHost) delete opts.headers.host;
3358
+
3359
+ opts.auth = undefined;
3360
+ }
3361
+ }
3362
+
3363
+ //
3364
+ // Match curl 7.77.0 behavior and make the first `Authorization` header win.
3365
+ // If the `Authorization` header is set, then there is nothing to do as it
3366
+ // will take precedence.
3367
+ //
3368
+ if (opts.auth && !options.headers.authorization) {
3369
+ options.headers.authorization =
3370
+ 'Basic ' + Buffer.from(opts.auth).toString('base64');
3371
+ }
3372
+ }
3373
+
3374
+ let req = (websocket._req = get(opts));
3375
+
3376
+ if (opts.timeout) {
3377
+ req.on('timeout', () => {
3378
+ abortHandshake$1(websocket, req, 'Opening handshake has timed out');
3379
+ });
3380
+ }
3381
+
3382
+ req.on('error', (err) => {
3383
+ if (req === null || req.aborted) return;
3384
+
3385
+ req = websocket._req = null;
3386
+ emitErrorAndClose(websocket, err);
3387
+ });
3388
+
3389
+ req.on('response', (res) => {
3390
+ const location = res.headers.location;
3391
+ const statusCode = res.statusCode;
3392
+
3393
+ if (
3394
+ location &&
3395
+ opts.followRedirects &&
3396
+ statusCode >= 300 &&
3397
+ statusCode < 400
3398
+ ) {
3399
+ if (++websocket._redirects > opts.maxRedirects) {
3400
+ abortHandshake$1(websocket, req, 'Maximum redirects exceeded');
3401
+ return;
3402
+ }
3403
+
3404
+ req.abort();
3405
+
3406
+ let addr;
3407
+
3408
+ try {
3409
+ addr = new URL(location, address);
3410
+ } catch (err) {
3411
+ emitErrorAndClose(websocket, err);
3412
+ return;
3413
+ }
3414
+
3415
+ initAsClient(websocket, addr, protocols, options);
3416
+ } else if (!websocket.emit('unexpected-response', req, res)) {
3417
+ abortHandshake$1(
3418
+ websocket,
3419
+ req,
3420
+ `Unexpected server response: ${res.statusCode}`
3421
+ );
3422
+ }
3423
+ });
3424
+
3425
+ req.on('upgrade', (res, socket, head) => {
3426
+ websocket.emit('upgrade', res);
3427
+
3428
+ //
3429
+ // The user may have closed the connection from a listener of the `upgrade`
3430
+ // event.
3431
+ //
3432
+ if (websocket.readyState !== WebSocket$3.CONNECTING) return;
3433
+
3434
+ req = websocket._req = null;
3435
+
3436
+ const upgrade = res.headers.upgrade;
3437
+
3438
+ if (upgrade === undefined || upgrade.toLowerCase() !== 'websocket') {
3439
+ abortHandshake$1(websocket, socket, 'Invalid Upgrade header');
3440
+ return;
3441
+ }
3442
+
3443
+ const digest = createHash$1('sha1')
3444
+ .update(key + GUID$1)
3445
+ .digest('base64');
3446
+
3447
+ if (res.headers['sec-websocket-accept'] !== digest) {
3448
+ abortHandshake$1(websocket, socket, 'Invalid Sec-WebSocket-Accept header');
3449
+ return;
3450
+ }
3451
+
3452
+ const serverProt = res.headers['sec-websocket-protocol'];
3453
+ const protList = (protocols || '').split(/, */);
3454
+ let protError;
3455
+
3456
+ if (!protocols && serverProt) {
3457
+ protError = 'Server sent a subprotocol but none was requested';
3458
+ } else if (protocols && !serverProt) {
3459
+ protError = 'Server sent no subprotocol';
3460
+ } else if (serverProt && !protList.includes(serverProt)) {
3461
+ protError = 'Server sent an invalid subprotocol';
3462
+ }
3463
+
3464
+ if (protError) {
3465
+ abortHandshake$1(websocket, socket, protError);
3466
+ return;
3467
+ }
3468
+
3469
+ if (serverProt) websocket._protocol = serverProt;
3470
+
3471
+ const secWebSocketExtensions = res.headers['sec-websocket-extensions'];
3472
+
3473
+ if (secWebSocketExtensions !== undefined) {
3474
+ if (!perMessageDeflate) {
3475
+ const message =
3476
+ 'Server sent a Sec-WebSocket-Extensions header but no extension ' +
3477
+ 'was requested';
3478
+ abortHandshake$1(websocket, socket, message);
3479
+ return;
3480
+ }
3481
+
3482
+ let extensions;
3483
+
3484
+ try {
3485
+ extensions = parse$1(secWebSocketExtensions);
3486
+ } catch (err) {
3487
+ const message = 'Invalid Sec-WebSocket-Extensions header';
3488
+ abortHandshake$1(websocket, socket, message);
3489
+ return;
3490
+ }
3491
+
3492
+ const extensionNames = Object.keys(extensions);
3493
+
3494
+ if (extensionNames.length) {
3495
+ if (
3496
+ extensionNames.length !== 1 ||
3497
+ extensionNames[0] !== PerMessageDeflate$1.extensionName
3498
+ ) {
3499
+ const message =
3500
+ 'Server indicated an extension that was not requested';
3501
+ abortHandshake$1(websocket, socket, message);
3502
+ return;
3503
+ }
3504
+
3505
+ try {
3506
+ perMessageDeflate.accept(extensions[PerMessageDeflate$1.extensionName]);
3507
+ } catch (err) {
3508
+ const message = 'Invalid Sec-WebSocket-Extensions header';
3509
+ abortHandshake$1(websocket, socket, message);
3510
+ return;
3511
+ }
3512
+
3513
+ websocket._extensions[PerMessageDeflate$1.extensionName] =
3514
+ perMessageDeflate;
3515
+ }
3516
+ }
3517
+
3518
+ websocket.setSocket(socket, head, opts.maxPayload);
3519
+ });
3520
+ }
3521
+
3522
+ /**
3523
+ * Emit the `'error'` and `'close'` event.
3524
+ *
3525
+ * @param {WebSocket} websocket The WebSocket instance
3526
+ * @param {Error} The error to emit
3527
+ * @private
3528
+ */
3529
+ function emitErrorAndClose(websocket, err) {
3530
+ websocket._readyState = WebSocket$3.CLOSING;
3531
+ websocket.emit('error', err);
3532
+ websocket.emitClose();
3533
+ }
3534
+
3535
+ /**
3536
+ * Create a `net.Socket` and initiate a connection.
3537
+ *
3538
+ * @param {Object} options Connection options
3539
+ * @return {net.Socket} The newly created socket used to start the connection
3540
+ * @private
3541
+ */
3542
+ function netConnect(options) {
3543
+ options.path = options.socketPath;
3544
+ return net.connect(options);
3545
+ }
3546
+
3547
+ /**
3548
+ * Create a `tls.TLSSocket` and initiate a connection.
3549
+ *
3550
+ * @param {Object} options Connection options
3551
+ * @return {tls.TLSSocket} The newly created socket used to start the connection
3552
+ * @private
3553
+ */
3554
+ function tlsConnect(options) {
3555
+ options.path = undefined;
3556
+
3557
+ if (!options.servername && options.servername !== '') {
3558
+ options.servername = net.isIP(options.host) ? '' : options.host;
3559
+ }
3560
+
3561
+ return tls.connect(options);
3562
+ }
3563
+
3564
+ /**
3565
+ * Abort the handshake and emit an error.
3566
+ *
3567
+ * @param {WebSocket} websocket The WebSocket instance
3568
+ * @param {(http.ClientRequest|net.Socket|tls.Socket)} stream The request to
3569
+ * abort or the socket to destroy
3570
+ * @param {String} message The error message
3571
+ * @private
3572
+ */
3573
+ function abortHandshake$1(websocket, stream, message) {
3574
+ websocket._readyState = WebSocket$3.CLOSING;
3575
+
3576
+ const err = new Error(message);
3577
+ Error.captureStackTrace(err, abortHandshake$1);
3578
+
3579
+ if (stream.setHeader) {
3580
+ stream.abort();
3581
+
3582
+ if (stream.socket && !stream.socket.destroyed) {
3583
+ //
3584
+ // On Node.js >= 14.3.0 `request.abort()` does not destroy the socket if
3585
+ // called after the request completed. See
3586
+ // https://github.com/websockets/ws/issues/1869.
3587
+ //
3588
+ stream.socket.destroy();
3589
+ }
3590
+
3591
+ stream.once('abort', websocket.emitClose.bind(websocket));
3592
+ websocket.emit('error', err);
3593
+ } else {
3594
+ stream.destroy(err);
3595
+ stream.once('error', websocket.emit.bind(websocket, 'error'));
3596
+ stream.once('close', websocket.emitClose.bind(websocket));
3597
+ }
3598
+ }
3599
+
3600
+ /**
3601
+ * Handle cases where the `ping()`, `pong()`, or `send()` methods are called
3602
+ * when the `readyState` attribute is `CLOSING` or `CLOSED`.
3603
+ *
3604
+ * @param {WebSocket} websocket The WebSocket instance
3605
+ * @param {*} [data] The data to send
3606
+ * @param {Function} [cb] Callback
3607
+ * @private
3608
+ */
3609
+ function sendAfterClose(websocket, data, cb) {
3610
+ if (data) {
3611
+ const length = toBuffer(data).length;
3612
+
3613
+ //
3614
+ // The `_bufferedAmount` property is used only when the peer is a client and
3615
+ // the opening handshake fails. Under these circumstances, in fact, the
3616
+ // `setSocket()` method is not called, so the `_socket` and `_sender`
3617
+ // properties are set to `null`.
3618
+ //
3619
+ if (websocket._socket) websocket._sender._bufferedBytes += length;
3620
+ else websocket._bufferedAmount += length;
3621
+ }
3622
+
3623
+ if (cb) {
3624
+ const err = new Error(
3625
+ `WebSocket is not open: readyState ${websocket.readyState} ` +
3626
+ `(${readyStates[websocket.readyState]})`
3627
+ );
3628
+ cb(err);
3629
+ }
3630
+ }
3631
+
3632
+ /**
3633
+ * The listener of the `Receiver` `'conclude'` event.
3634
+ *
3635
+ * @param {Number} code The status code
3636
+ * @param {String} reason The reason for closing
3637
+ * @private
3638
+ */
3639
+ function receiverOnConclude(code, reason) {
3640
+ const websocket = this[kWebSocket$1];
3641
+
3642
+ websocket._closeFrameReceived = true;
3643
+ websocket._closeMessage = reason;
3644
+ websocket._closeCode = code;
3645
+
3646
+ if (websocket._socket[kWebSocket$1] === undefined) return;
3647
+
3648
+ websocket._socket.removeListener('data', socketOnData);
3649
+ process.nextTick(resume, websocket._socket);
3650
+
3651
+ if (code === 1005) websocket.close();
3652
+ else websocket.close(code, reason);
3653
+ }
3654
+
3655
+ /**
3656
+ * The listener of the `Receiver` `'drain'` event.
3657
+ *
3658
+ * @private
3659
+ */
3660
+ function receiverOnDrain() {
3661
+ this[kWebSocket$1]._socket.resume();
3662
+ }
3663
+
3664
+ /**
3665
+ * The listener of the `Receiver` `'error'` event.
3666
+ *
3667
+ * @param {(RangeError|Error)} err The emitted error
3668
+ * @private
3669
+ */
3670
+ function receiverOnError(err) {
3671
+ const websocket = this[kWebSocket$1];
3672
+
3673
+ if (websocket._socket[kWebSocket$1] !== undefined) {
3674
+ websocket._socket.removeListener('data', socketOnData);
3675
+
3676
+ //
3677
+ // On Node.js < 14.0.0 the `'error'` event is emitted synchronously. See
3678
+ // https://github.com/websockets/ws/issues/1940.
3679
+ //
3680
+ process.nextTick(resume, websocket._socket);
3681
+
3682
+ websocket.close(err[kStatusCode]);
3683
+ }
3684
+
3685
+ websocket.emit('error', err);
3686
+ }
3687
+
3688
+ /**
3689
+ * The listener of the `Receiver` `'finish'` event.
3690
+ *
3691
+ * @private
3692
+ */
3693
+ function receiverOnFinish() {
3694
+ this[kWebSocket$1].emitClose();
3695
+ }
3696
+
3697
+ /**
3698
+ * The listener of the `Receiver` `'message'` event.
3699
+ *
3700
+ * @param {(String|Buffer|ArrayBuffer|Buffer[])} data The message
3701
+ * @private
3702
+ */
3703
+ function receiverOnMessage(data) {
3704
+ this[kWebSocket$1].emit('message', data);
3705
+ }
3706
+
3707
+ /**
3708
+ * The listener of the `Receiver` `'ping'` event.
3709
+ *
3710
+ * @param {Buffer} data The data included in the ping frame
3711
+ * @private
3712
+ */
3713
+ function receiverOnPing(data) {
3714
+ const websocket = this[kWebSocket$1];
3715
+
3716
+ websocket.pong(data, !websocket._isServer, NOOP);
3717
+ websocket.emit('ping', data);
3718
+ }
3719
+
3720
+ /**
3721
+ * The listener of the `Receiver` `'pong'` event.
3722
+ *
3723
+ * @param {Buffer} data The data included in the pong frame
3724
+ * @private
3725
+ */
3726
+ function receiverOnPong(data) {
3727
+ this[kWebSocket$1].emit('pong', data);
3728
+ }
3729
+
3730
+ /**
3731
+ * Resume a readable stream
3732
+ *
3733
+ * @param {Readable} stream The readable stream
3734
+ * @private
3735
+ */
3736
+ function resume(stream) {
3737
+ stream.resume();
3738
+ }
3739
+
3740
+ /**
3741
+ * The listener of the `net.Socket` `'close'` event.
3742
+ *
3743
+ * @private
3744
+ */
3745
+ function socketOnClose() {
3746
+ const websocket = this[kWebSocket$1];
3747
+
3748
+ this.removeListener('close', socketOnClose);
3749
+ this.removeListener('data', socketOnData);
3750
+ this.removeListener('end', socketOnEnd);
3751
+
3752
+ websocket._readyState = WebSocket$3.CLOSING;
3753
+
3754
+ let chunk;
3755
+
3756
+ //
3757
+ // The close frame might not have been received or the `'end'` event emitted,
3758
+ // for example, if the socket was destroyed due to an error. Ensure that the
3759
+ // `receiver` stream is closed after writing any remaining buffered data to
3760
+ // it. If the readable side of the socket is in flowing mode then there is no
3761
+ // buffered data as everything has been already written and `readable.read()`
3762
+ // will return `null`. If instead, the socket is paused, any possible buffered
3763
+ // data will be read as a single chunk.
3764
+ //
3765
+ if (
3766
+ !this._readableState.endEmitted &&
3767
+ !websocket._closeFrameReceived &&
3768
+ !websocket._receiver._writableState.errorEmitted &&
3769
+ (chunk = websocket._socket.read()) !== null
3770
+ ) {
3771
+ websocket._receiver.write(chunk);
3772
+ }
3773
+
3774
+ websocket._receiver.end();
3775
+
3776
+ this[kWebSocket$1] = undefined;
3777
+
3778
+ clearTimeout(websocket._closeTimer);
3779
+
3780
+ if (
3781
+ websocket._receiver._writableState.finished ||
3782
+ websocket._receiver._writableState.errorEmitted
3783
+ ) {
3784
+ websocket.emitClose();
3785
+ } else {
3786
+ websocket._receiver.on('error', receiverOnFinish);
3787
+ websocket._receiver.on('finish', receiverOnFinish);
3788
+ }
3789
+ }
3790
+
3791
+ /**
3792
+ * The listener of the `net.Socket` `'data'` event.
3793
+ *
3794
+ * @param {Buffer} chunk A chunk of data
3795
+ * @private
3796
+ */
3797
+ function socketOnData(chunk) {
3798
+ if (!this[kWebSocket$1]._receiver.write(chunk)) {
3799
+ this.pause();
3800
+ }
3801
+ }
3802
+
3803
+ /**
3804
+ * The listener of the `net.Socket` `'end'` event.
3805
+ *
3806
+ * @private
3807
+ */
3808
+ function socketOnEnd() {
3809
+ const websocket = this[kWebSocket$1];
3810
+
3811
+ websocket._readyState = WebSocket$3.CLOSING;
3812
+ websocket._receiver.end();
3813
+ this.end();
3814
+ }
3815
+
3816
+ /**
3817
+ * The listener of the `net.Socket` `'error'` event.
3818
+ *
3819
+ * @private
3820
+ */
3821
+ function socketOnError$1() {
3822
+ const websocket = this[kWebSocket$1];
3823
+
3824
+ this.removeListener('error', socketOnError$1);
3825
+ this.on('error', NOOP);
3826
+
3827
+ if (websocket) {
3828
+ websocket._readyState = WebSocket$3.CLOSING;
3829
+ this.destroy();
3830
+ }
3831
+ }
3832
+
3833
+ const { Duplex } = require$$0$2;
3834
+
3835
+ /**
3836
+ * Emits the `'close'` event on a stream.
3837
+ *
3838
+ * @param {Duplex} stream The stream.
3839
+ * @private
3840
+ */
3841
+ function emitClose$1(stream) {
3842
+ stream.emit('close');
3843
+ }
3844
+
3845
+ /**
3846
+ * The listener of the `'end'` event.
3847
+ *
3848
+ * @private
3849
+ */
3850
+ function duplexOnEnd() {
3851
+ if (!this.destroyed && this._writableState.finished) {
3852
+ this.destroy();
3853
+ }
3854
+ }
3855
+
3856
+ /**
3857
+ * The listener of the `'error'` event.
3858
+ *
3859
+ * @param {Error} err The error
3860
+ * @private
3861
+ */
3862
+ function duplexOnError(err) {
3863
+ this.removeListener('error', duplexOnError);
3864
+ this.destroy();
3865
+ if (this.listenerCount('error') === 0) {
3866
+ // Do not suppress the throwing behavior.
3867
+ this.emit('error', err);
3868
+ }
3869
+ }
3870
+
3871
+ /**
3872
+ * Wraps a `WebSocket` in a duplex stream.
3873
+ *
3874
+ * @param {WebSocket} ws The `WebSocket` to wrap
3875
+ * @param {Object} [options] The options for the `Duplex` constructor
3876
+ * @return {Duplex} The duplex stream
3877
+ * @public
3878
+ */
3879
+ function createWebSocketStream(ws, options) {
3880
+ let resumeOnReceiverDrain = true;
3881
+ let terminateOnDestroy = true;
3882
+
3883
+ function receiverOnDrain() {
3884
+ if (resumeOnReceiverDrain) ws._socket.resume();
3885
+ }
3886
+
3887
+ if (ws.readyState === ws.CONNECTING) {
3888
+ ws.once('open', function open() {
3889
+ ws._receiver.removeAllListeners('drain');
3890
+ ws._receiver.on('drain', receiverOnDrain);
3891
+ });
3892
+ } else {
3893
+ ws._receiver.removeAllListeners('drain');
3894
+ ws._receiver.on('drain', receiverOnDrain);
3895
+ }
3896
+
3897
+ const duplex = new Duplex({
3898
+ ...options,
3899
+ autoDestroy: false,
3900
+ emitClose: false,
3901
+ objectMode: false,
3902
+ writableObjectMode: false
3903
+ });
3904
+
3905
+ ws.on('message', function message(msg) {
3906
+ if (!duplex.push(msg)) {
3907
+ resumeOnReceiverDrain = false;
3908
+ ws._socket.pause();
3909
+ }
3910
+ });
3911
+
3912
+ ws.once('error', function error(err) {
3913
+ if (duplex.destroyed) return;
3914
+
3915
+ // Prevent `ws.terminate()` from being called by `duplex._destroy()`.
3916
+ //
3917
+ // - If the `'error'` event is emitted before the `'open'` event, then
3918
+ // `ws.terminate()` is a noop as no socket is assigned.
3919
+ // - Otherwise, the error is re-emitted by the listener of the `'error'`
3920
+ // event of the `Receiver` object. The listener already closes the
3921
+ // connection by calling `ws.close()`. This allows a close frame to be
3922
+ // sent to the other peer. If `ws.terminate()` is called right after this,
3923
+ // then the close frame might not be sent.
3924
+ terminateOnDestroy = false;
3925
+ duplex.destroy(err);
3926
+ });
3927
+
3928
+ ws.once('close', function close() {
3929
+ if (duplex.destroyed) return;
3930
+
3931
+ duplex.push(null);
3932
+ });
3933
+
3934
+ duplex._destroy = function (err, callback) {
3935
+ if (ws.readyState === ws.CLOSED) {
3936
+ callback(err);
3937
+ process.nextTick(emitClose$1, duplex);
3938
+ return;
3939
+ }
3940
+
3941
+ let called = false;
3942
+
3943
+ ws.once('error', function error(err) {
3944
+ called = true;
3945
+ callback(err);
3946
+ });
3947
+
3948
+ ws.once('close', function close() {
3949
+ if (!called) callback(err);
3950
+ process.nextTick(emitClose$1, duplex);
3951
+ });
3952
+
3953
+ if (terminateOnDestroy) ws.terminate();
3954
+ };
3955
+
3956
+ duplex._final = function (callback) {
3957
+ if (ws.readyState === ws.CONNECTING) {
3958
+ ws.once('open', function open() {
3959
+ duplex._final(callback);
3960
+ });
3961
+ return;
3962
+ }
3963
+
3964
+ // If the value of the `_socket` property is `null` it means that `ws` is a
3965
+ // client websocket and the handshake failed. In fact, when this happens, a
3966
+ // socket is never assigned to the websocket. Wait for the `'error'` event
3967
+ // that will be emitted by the websocket.
3968
+ if (ws._socket === null) return;
3969
+
3970
+ if (ws._socket._writableState.finished) {
3971
+ callback();
3972
+ if (duplex._readableState.endEmitted) duplex.destroy();
3973
+ } else {
3974
+ ws._socket.once('finish', function finish() {
3975
+ // `duplex` is not destroyed here because the `'end'` event will be
3976
+ // emitted on `duplex` after this `'finish'` event. The EOF signaling
3977
+ // `null` chunk is, in fact, pushed when the websocket emits `'close'`.
3978
+ callback();
3979
+ });
3980
+ ws.close();
3981
+ }
3982
+ };
3983
+
3984
+ duplex._read = function () {
3985
+ if (
3986
+ (ws.readyState === ws.OPEN || ws.readyState === ws.CLOSING) &&
3987
+ !resumeOnReceiverDrain
3988
+ ) {
3989
+ resumeOnReceiverDrain = true;
3990
+ if (!ws._receiver._writableState.needDrain) ws._socket.resume();
3991
+ }
3992
+ };
3993
+
3994
+ duplex._write = function (chunk, encoding, callback) {
3995
+ if (ws.readyState === ws.CONNECTING) {
3996
+ ws.once('open', function open() {
3997
+ duplex._write(chunk, encoding, callback);
3998
+ });
3999
+ return;
4000
+ }
4001
+
4002
+ ws.send(chunk, callback);
4003
+ };
4004
+
4005
+ duplex.on('end', duplexOnEnd);
4006
+ duplex.on('error', duplexOnError);
4007
+ return duplex;
4008
+ }
4009
+
4010
+ var stream = createWebSocketStream;
4011
+
4012
+ /* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^net|tls|https$" }] */
4013
+
4014
+ const EventEmitter = require$$0$3;
4015
+ const http = require$$2$1;
4016
+ const { createHash } = require$$5;
4017
+
4018
+ const PerMessageDeflate = permessageDeflate;
4019
+ const WebSocket$2 = websocket;
4020
+ const { format, parse } = extension;
4021
+ const { GUID, kWebSocket } = constants;
4022
+
4023
+ const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
4024
+
4025
+ const RUNNING = 0;
4026
+ const CLOSING = 1;
4027
+ const CLOSED = 2;
4028
+
4029
+ /**
4030
+ * Class representing a WebSocket server.
4031
+ *
4032
+ * @extends EventEmitter
4033
+ */
4034
+ class WebSocketServer extends EventEmitter {
4035
+ /**
4036
+ * Create a `WebSocketServer` instance.
4037
+ *
4038
+ * @param {Object} options Configuration options
4039
+ * @param {Number} [options.backlog=511] The maximum length of the queue of
4040
+ * pending connections
4041
+ * @param {Boolean} [options.clientTracking=true] Specifies whether or not to
4042
+ * track clients
4043
+ * @param {Function} [options.handleProtocols] A hook to handle protocols
4044
+ * @param {String} [options.host] The hostname where to bind the server
4045
+ * @param {Number} [options.maxPayload=104857600] The maximum allowed message
4046
+ * size
4047
+ * @param {Boolean} [options.noServer=false] Enable no server mode
4048
+ * @param {String} [options.path] Accept only connections matching this path
4049
+ * @param {(Boolean|Object)} [options.perMessageDeflate=false] Enable/disable
4050
+ * permessage-deflate
4051
+ * @param {Number} [options.port] The port where to bind the server
4052
+ * @param {(http.Server|https.Server)} [options.server] A pre-created HTTP/S
4053
+ * server to use
4054
+ * @param {Function} [options.verifyClient] A hook to reject connections
4055
+ * @param {Function} [callback] A listener for the `listening` event
4056
+ */
4057
+ constructor(options, callback) {
4058
+ super();
4059
+
4060
+ options = {
4061
+ maxPayload: 100 * 1024 * 1024,
4062
+ perMessageDeflate: false,
4063
+ handleProtocols: null,
4064
+ clientTracking: true,
4065
+ verifyClient: null,
4066
+ noServer: false,
4067
+ backlog: null, // use default (511 as implemented in net.js)
4068
+ server: null,
4069
+ host: null,
4070
+ path: null,
4071
+ port: null,
4072
+ ...options
4073
+ };
4074
+
4075
+ if (
4076
+ (options.port == null && !options.server && !options.noServer) ||
4077
+ (options.port != null && (options.server || options.noServer)) ||
4078
+ (options.server && options.noServer)
4079
+ ) {
4080
+ throw new TypeError(
4081
+ 'One and only one of the "port", "server", or "noServer" options ' +
4082
+ 'must be specified'
4083
+ );
4084
+ }
4085
+
4086
+ if (options.port != null) {
4087
+ this._server = http.createServer((req, res) => {
4088
+ const body = http.STATUS_CODES[426];
4089
+
4090
+ res.writeHead(426, {
4091
+ 'Content-Length': body.length,
4092
+ 'Content-Type': 'text/plain'
4093
+ });
4094
+ res.end(body);
4095
+ });
4096
+ this._server.listen(
4097
+ options.port,
4098
+ options.host,
4099
+ options.backlog,
4100
+ callback
4101
+ );
4102
+ } else if (options.server) {
4103
+ this._server = options.server;
4104
+ }
4105
+
4106
+ if (this._server) {
4107
+ const emitConnection = this.emit.bind(this, 'connection');
4108
+
4109
+ this._removeListeners = addListeners(this._server, {
4110
+ listening: this.emit.bind(this, 'listening'),
4111
+ error: this.emit.bind(this, 'error'),
4112
+ upgrade: (req, socket, head) => {
4113
+ this.handleUpgrade(req, socket, head, emitConnection);
4114
+ }
4115
+ });
4116
+ }
4117
+
4118
+ if (options.perMessageDeflate === true) options.perMessageDeflate = {};
4119
+ if (options.clientTracking) this.clients = new Set();
4120
+ this.options = options;
4121
+ this._state = RUNNING;
4122
+ }
4123
+
4124
+ /**
4125
+ * Returns the bound address, the address family name, and port of the server
4126
+ * as reported by the operating system if listening on an IP socket.
4127
+ * If the server is listening on a pipe or UNIX domain socket, the name is
4128
+ * returned as a string.
4129
+ *
4130
+ * @return {(Object|String|null)} The address of the server
4131
+ * @public
4132
+ */
4133
+ address() {
4134
+ if (this.options.noServer) {
4135
+ throw new Error('The server is operating in "noServer" mode');
4136
+ }
4137
+
4138
+ if (!this._server) return null;
4139
+ return this._server.address();
4140
+ }
4141
+
4142
+ /**
4143
+ * Close the server.
4144
+ *
4145
+ * @param {Function} [cb] Callback
4146
+ * @public
4147
+ */
4148
+ close(cb) {
4149
+ if (cb) this.once('close', cb);
4150
+
4151
+ if (this._state === CLOSED) {
4152
+ process.nextTick(emitClose, this);
4153
+ return;
4154
+ }
4155
+
4156
+ if (this._state === CLOSING) return;
4157
+ this._state = CLOSING;
4158
+
4159
+ //
4160
+ // Terminate all associated clients.
4161
+ //
4162
+ if (this.clients) {
4163
+ for (const client of this.clients) client.terminate();
4164
+ }
4165
+
4166
+ const server = this._server;
4167
+
4168
+ if (server) {
4169
+ this._removeListeners();
4170
+ this._removeListeners = this._server = null;
4171
+
4172
+ //
4173
+ // Close the http server if it was internally created.
4174
+ //
4175
+ if (this.options.port != null) {
4176
+ server.close(emitClose.bind(undefined, this));
4177
+ return;
4178
+ }
4179
+ }
4180
+
4181
+ process.nextTick(emitClose, this);
4182
+ }
4183
+
4184
+ /**
4185
+ * See if a given request should be handled by this server instance.
4186
+ *
4187
+ * @param {http.IncomingMessage} req Request object to inspect
4188
+ * @return {Boolean} `true` if the request is valid, else `false`
4189
+ * @public
4190
+ */
4191
+ shouldHandle(req) {
4192
+ if (this.options.path) {
4193
+ const index = req.url.indexOf('?');
4194
+ const pathname = index !== -1 ? req.url.slice(0, index) : req.url;
4195
+
4196
+ if (pathname !== this.options.path) return false;
4197
+ }
4198
+
4199
+ return true;
4200
+ }
4201
+
4202
+ /**
4203
+ * Handle a HTTP Upgrade request.
4204
+ *
4205
+ * @param {http.IncomingMessage} req The request object
4206
+ * @param {(net.Socket|tls.Socket)} socket The network socket between the
4207
+ * server and client
4208
+ * @param {Buffer} head The first packet of the upgraded stream
4209
+ * @param {Function} cb Callback
4210
+ * @public
4211
+ */
4212
+ handleUpgrade(req, socket, head, cb) {
4213
+ socket.on('error', socketOnError);
4214
+
4215
+ const key =
4216
+ req.headers['sec-websocket-key'] !== undefined
4217
+ ? req.headers['sec-websocket-key'].trim()
4218
+ : false;
4219
+ const upgrade = req.headers.upgrade;
4220
+ const version = +req.headers['sec-websocket-version'];
4221
+ const extensions = {};
4222
+
4223
+ if (
4224
+ req.method !== 'GET' ||
4225
+ upgrade === undefined ||
4226
+ upgrade.toLowerCase() !== 'websocket' ||
4227
+ !key ||
4228
+ !keyRegex.test(key) ||
4229
+ (version !== 8 && version !== 13) ||
4230
+ !this.shouldHandle(req)
4231
+ ) {
4232
+ return abortHandshake(socket, 400);
4233
+ }
4234
+
4235
+ if (this.options.perMessageDeflate) {
4236
+ const perMessageDeflate = new PerMessageDeflate(
4237
+ this.options.perMessageDeflate,
4238
+ true,
4239
+ this.options.maxPayload
4240
+ );
4241
+
4242
+ try {
4243
+ const offers = parse(req.headers['sec-websocket-extensions']);
4244
+
4245
+ if (offers[PerMessageDeflate.extensionName]) {
4246
+ perMessageDeflate.accept(offers[PerMessageDeflate.extensionName]);
4247
+ extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
4248
+ }
4249
+ } catch (err) {
4250
+ return abortHandshake(socket, 400);
4251
+ }
4252
+ }
4253
+
4254
+ //
4255
+ // Optionally call external client verification handler.
4256
+ //
4257
+ if (this.options.verifyClient) {
4258
+ const info = {
4259
+ origin:
4260
+ req.headers[`${version === 8 ? 'sec-websocket-origin' : 'origin'}`],
4261
+ secure: !!(req.socket.authorized || req.socket.encrypted),
4262
+ req
4263
+ };
4264
+
4265
+ if (this.options.verifyClient.length === 2) {
4266
+ this.options.verifyClient(info, (verified, code, message, headers) => {
4267
+ if (!verified) {
4268
+ return abortHandshake(socket, code || 401, message, headers);
4269
+ }
4270
+
4271
+ this.completeUpgrade(key, extensions, req, socket, head, cb);
4272
+ });
4273
+ return;
4274
+ }
4275
+
4276
+ if (!this.options.verifyClient(info)) return abortHandshake(socket, 401);
4277
+ }
4278
+
4279
+ this.completeUpgrade(key, extensions, req, socket, head, cb);
4280
+ }
4281
+
4282
+ /**
4283
+ * Upgrade the connection to WebSocket.
4284
+ *
4285
+ * @param {String} key The value of the `Sec-WebSocket-Key` header
4286
+ * @param {Object} extensions The accepted extensions
4287
+ * @param {http.IncomingMessage} req The request object
4288
+ * @param {(net.Socket|tls.Socket)} socket The network socket between the
4289
+ * server and client
4290
+ * @param {Buffer} head The first packet of the upgraded stream
4291
+ * @param {Function} cb Callback
4292
+ * @throws {Error} If called more than once with the same socket
4293
+ * @private
4294
+ */
4295
+ completeUpgrade(key, extensions, req, socket, head, cb) {
4296
+ //
4297
+ // Destroy the socket if the client has already sent a FIN packet.
4298
+ //
4299
+ if (!socket.readable || !socket.writable) return socket.destroy();
4300
+
4301
+ if (socket[kWebSocket]) {
4302
+ throw new Error(
4303
+ 'server.handleUpgrade() was called more than once with the same ' +
4304
+ 'socket, possibly due to a misconfiguration'
4305
+ );
4306
+ }
4307
+
4308
+ if (this._state > RUNNING) return abortHandshake(socket, 503);
4309
+
4310
+ const digest = createHash('sha1')
4311
+ .update(key + GUID)
4312
+ .digest('base64');
4313
+
4314
+ const headers = [
4315
+ 'HTTP/1.1 101 Switching Protocols',
4316
+ 'Upgrade: websocket',
4317
+ 'Connection: Upgrade',
4318
+ `Sec-WebSocket-Accept: ${digest}`
4319
+ ];
4320
+
4321
+ const ws = new WebSocket$2(null);
4322
+ let protocol = req.headers['sec-websocket-protocol'];
4323
+
4324
+ if (protocol) {
4325
+ protocol = protocol.split(',').map(trim);
4326
+
4327
+ //
4328
+ // Optionally call external protocol selection handler.
4329
+ //
4330
+ if (this.options.handleProtocols) {
4331
+ protocol = this.options.handleProtocols(protocol, req);
4332
+ } else {
4333
+ protocol = protocol[0];
4334
+ }
4335
+
4336
+ if (protocol) {
4337
+ headers.push(`Sec-WebSocket-Protocol: ${protocol}`);
4338
+ ws._protocol = protocol;
4339
+ }
4340
+ }
4341
+
4342
+ if (extensions[PerMessageDeflate.extensionName]) {
4343
+ const params = extensions[PerMessageDeflate.extensionName].params;
4344
+ const value = format({
4345
+ [PerMessageDeflate.extensionName]: [params]
4346
+ });
4347
+ headers.push(`Sec-WebSocket-Extensions: ${value}`);
4348
+ ws._extensions = extensions;
4349
+ }
4350
+
4351
+ //
4352
+ // Allow external modification/inspection of handshake headers.
4353
+ //
4354
+ this.emit('headers', headers, req);
4355
+
4356
+ socket.write(headers.concat('\r\n').join('\r\n'));
4357
+ socket.removeListener('error', socketOnError);
4358
+
4359
+ ws.setSocket(socket, head, this.options.maxPayload);
4360
+
4361
+ if (this.clients) {
4362
+ this.clients.add(ws);
4363
+ ws.on('close', () => this.clients.delete(ws));
4364
+ }
4365
+
4366
+ cb(ws, req);
4367
+ }
4368
+ }
4369
+
4370
+ var websocketServer = WebSocketServer;
4371
+
4372
+ /**
4373
+ * Add event listeners on an `EventEmitter` using a map of <event, listener>
4374
+ * pairs.
4375
+ *
4376
+ * @param {EventEmitter} server The event emitter
4377
+ * @param {Object.<String, Function>} map The listeners to add
4378
+ * @return {Function} A function that will remove the added listeners when
4379
+ * called
4380
+ * @private
4381
+ */
4382
+ function addListeners(server, map) {
4383
+ for (const event of Object.keys(map)) server.on(event, map[event]);
4384
+
4385
+ return function removeListeners() {
4386
+ for (const event of Object.keys(map)) {
4387
+ server.removeListener(event, map[event]);
4388
+ }
4389
+ };
4390
+ }
4391
+
4392
+ /**
4393
+ * Emit a `'close'` event on an `EventEmitter`.
4394
+ *
4395
+ * @param {EventEmitter} server The event emitter
4396
+ * @private
4397
+ */
4398
+ function emitClose(server) {
4399
+ server._state = CLOSED;
4400
+ server.emit('close');
4401
+ }
4402
+
4403
+ /**
4404
+ * Handle premature socket errors.
4405
+ *
4406
+ * @private
4407
+ */
4408
+ function socketOnError() {
4409
+ this.destroy();
4410
+ }
4411
+
4412
+ /**
4413
+ * Close the connection when preconditions are not fulfilled.
4414
+ *
4415
+ * @param {(net.Socket|tls.Socket)} socket The socket of the upgrade request
4416
+ * @param {Number} code The HTTP response status code
4417
+ * @param {String} [message] The HTTP response body
4418
+ * @param {Object} [headers] Additional HTTP response headers
4419
+ * @private
4420
+ */
4421
+ function abortHandshake(socket, code, message, headers) {
4422
+ if (socket.writable) {
4423
+ message = message || http.STATUS_CODES[code];
4424
+ headers = {
4425
+ Connection: 'close',
4426
+ 'Content-Type': 'text/html',
4427
+ 'Content-Length': Buffer.byteLength(message),
4428
+ ...headers
4429
+ };
4430
+
4431
+ socket.write(
4432
+ `HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
4433
+ Object.keys(headers)
4434
+ .map((h) => `${h}: ${headers[h]}`)
4435
+ .join('\r\n') +
4436
+ '\r\n\r\n' +
4437
+ message
4438
+ );
4439
+ }
4440
+
4441
+ socket.removeListener('error', socketOnError);
4442
+ socket.destroy();
4443
+ }
4444
+
4445
+ /**
4446
+ * Remove whitespace characters from both ends of a string.
4447
+ *
4448
+ * @param {String} str The string
4449
+ * @return {String} A new string representing `str` stripped of whitespace
4450
+ * characters from both its beginning and end
4451
+ * @private
4452
+ */
4453
+ function trim(str) {
4454
+ return str.trim();
4455
+ }
4456
+
4457
+ const WebSocket$1 = websocket;
4458
+
4459
+ WebSocket$1.createWebSocketStream = stream;
4460
+ WebSocket$1.Server = websocketServer;
4461
+ WebSocket$1.Receiver = receiver;
4462
+ WebSocket$1.Sender = sender;
4463
+
4464
+ var ws = WebSocket$1;
4465
+
4466
+ var ws$1 = /*@__PURE__*/getDefaultExportFromCjs(ws);
4467
+
4468
+ /**
4469
+ * Re-exports WebSocket and WebSocketServer from the ws package.
4470
+ *
4471
+ * ws is a CJS module — named exports like WebSocketServer aren't available
4472
+ * at runtime when Node auto-detects ESM from tsc output. This module works
4473
+ * around that by extracting them from the default export and re-exporting
4474
+ * them as merged type+value pairs.
4475
+ */
4476
+ const WebSocket = ws$1;
4477
+ ws$1.Server;
4478
+
4479
+ const CONFIG_FILENAME = ".babyloninspector";
4480
+ const DefaultBrowserPort = 4400;
4481
+ const DefaultCliPort = 4401;
4482
+ /**
4483
+ * Searches for a `.babyloninspector` config file starting from the given directory
4484
+ * and walking up the parent chain. Returns the path to the first file found, or
4485
+ * undefined if none is found.
4486
+ * @param startDir The directory to start searching from.
4487
+ * @returns The absolute path to the config file, or undefined.
4488
+ */
4489
+ function FindConfigFile(startDir) {
4490
+ let current = startDir;
4491
+ for (;;) {
4492
+ const candidate = join(current, CONFIG_FILENAME);
4493
+ if (existsSync(candidate)) {
4494
+ return candidate;
4495
+ }
4496
+ const parent = dirname(current);
4497
+ if (parent === current) {
4498
+ // Reached filesystem root.
4499
+ return undefined;
4500
+ }
4501
+ current = parent;
4502
+ }
4503
+ }
4504
+ /**
4505
+ * Loads the Inspector bridge configuration by searching for a `.babyloninspector`
4506
+ * file in the directory parent chain starting from `cwd`. If no file is found,
4507
+ * or if fields are missing, defaults are used.
4508
+ * @param cwd The working directory to start the search from. Defaults to `process.cwd()`.
4509
+ * @returns The resolved configuration.
4510
+ */
4511
+ function LoadConfig(cwd) {
4512
+ const defaults = {
4513
+ browserPort: DefaultBrowserPort,
4514
+ cliPort: DefaultCliPort,
4515
+ };
4516
+ const configPath = FindConfigFile(process.cwd());
4517
+ if (!configPath) {
4518
+ return defaults;
4519
+ }
4520
+ try {
4521
+ const raw = readFileSync(configPath, "utf-8");
4522
+ const parsed = JSON.parse(raw);
4523
+ return {
4524
+ browserPort: typeof parsed.browserPort === "number" ? parsed.browserPort : defaults.browserPort,
4525
+ cliPort: typeof parsed.cliPort === "number" ? parsed.cliPort : defaults.cliPort,
4526
+ };
4527
+ }
4528
+ catch {
4529
+ // If the file is malformed, fall back to defaults.
4530
+ return defaults;
4531
+ }
4532
+ }
4533
+
4534
+ /* eslint-disable no-console */
4535
+ const Config = LoadConfig();
4536
+ const HELP_TEXT = `babylon-inspector — Interact with running Babylon.js scenes from the terminal.
4537
+
4538
+ USAGE
4539
+ babylon-inspector [options]
4540
+ babylon-inspector --command <command-id> [--arg value ...]
4541
+
4542
+ OPTIONS
4543
+ --help Show this help message.
4544
+ --session [session-id] List active sessions, or specifies the target session.
4545
+ A session id is only needed when multiple sessions
4546
+ are active.
4547
+ --command [command-id] List available commands, or execute one.
4548
+ Use --command <id> --help to see its arguments.
4549
+ --stop Stop the bridge process.
4550
+
4551
+ CONFIGURATION
4552
+ Place a .babyloninspector JSON file anywhere in the directory parent chain:
4553
+ { "browserPort": 4400, "cliPort": 4401 }
4554
+
4555
+ EXAMPLES
4556
+ babylon-inspector --session
4557
+ babylon-inspector --command
4558
+ babylon-inspector --session 2 --command
4559
+ babylon-inspector --command query-mesh --help
4560
+ babylon-inspector --command query-mesh --uniqueId 42
4561
+ babylon-inspector --session 2 --command query-mesh --uniqueId 42
4562
+ `;
4563
+ const KnownOptions = new Set(["help", "stop", "session", "command", "bridge-script"]);
4564
+ /**
4565
+ * Parses the CLI arguments into a structured object.
4566
+ * @param argv Optional array of arguments to parse. Defaults to process.argv.
4567
+ * @returns The parsed arguments.
4568
+ */
4569
+ function ParseCliArgs(argv) {
4570
+ const { values, tokens } = parseArgs({
4571
+ options: {
4572
+ help: { type: "boolean", default: false },
4573
+ session: { type: "boolean", default: false },
4574
+ stop: { type: "boolean", default: false },
4575
+ command: { type: "boolean", default: false },
4576
+ // eslint-disable-next-line @typescript-eslint/naming-convention
4577
+ "bridge-script": { type: "string" },
4578
+ },
4579
+ strict: false,
4580
+ allowPositionals: true,
4581
+ tokens: true,
4582
+ ...(argv !== undefined ? { args: argv } : {}),
4583
+ });
4584
+ // Walk the token stream to extract:
4585
+ // - The first positional after --session as sessionId (if it's a number)
4586
+ // - Remaining positionals and unknown --key value pairs into rest
4587
+ let sessionId;
4588
+ const rest = [];
4589
+ if (tokens) {
4590
+ let expectingSessionId = false;
4591
+ let pendingOptionName = null;
4592
+ for (const token of tokens) {
4593
+ // After seeing --session, the next positional (if numeric) is the session id.
4594
+ if (token.kind === "option" && token.name === "session") {
4595
+ expectingSessionId = true;
4596
+ continue;
4597
+ }
4598
+ if (expectingSessionId && token.kind === "positional" && !isNaN(parseInt(token.value, 10))) {
4599
+ sessionId = token.value;
4600
+ expectingSessionId = false;
4601
+ continue;
4602
+ }
4603
+ expectingSessionId = false;
4604
+ if (token.kind === "option" && !KnownOptions.has(token.name)) {
4605
+ if (pendingOptionName !== null) {
4606
+ rest.push(`--${pendingOptionName}`);
4607
+ }
4608
+ if (token.value !== undefined) {
4609
+ rest.push(`--${token.name}`, token.value);
4610
+ }
4611
+ else {
4612
+ pendingOptionName = token.name;
4613
+ }
4614
+ continue;
4615
+ }
4616
+ if (token.kind === "positional" && pendingOptionName !== null) {
4617
+ rest.push(`--${pendingOptionName}`, token.value);
4618
+ pendingOptionName = null;
4619
+ continue;
4620
+ }
4621
+ if (token.kind === "positional") {
4622
+ rest.push(token.value);
4623
+ }
4624
+ }
4625
+ if (pendingOptionName !== null) {
4626
+ rest.push(`--${pendingOptionName}`);
4627
+ }
4628
+ }
4629
+ return {
4630
+ help: !!values.help,
4631
+ session: !!values.session,
4632
+ sessionId,
4633
+ stop: !!values.stop,
4634
+ command: !!values.command,
4635
+ bridgeScript: values["bridge-script"],
4636
+ rest,
4637
+ };
4638
+ }
4639
+ async function ConnectToBridge(port) {
4640
+ return await new Promise((resolve, reject) => {
4641
+ const socket = new WebSocket(`ws://127.0.0.1:${port}`);
4642
+ socket.on("open", () => resolve(socket));
4643
+ socket.on("error", (err) => reject(err));
4644
+ });
4645
+ }
4646
+ /**
4647
+ * Sends a JSON message to the bridge over WebSocket and waits for a response.
4648
+ * @param socket The WebSocket connection to the bridge.
4649
+ * @param message The CLI request to send.
4650
+ * @returns The parsed bridge response.
4651
+ */
4652
+ async function SendAndReceive(socket, message) {
4653
+ return await new Promise((resolve, reject) => {
4654
+ const timeout = setTimeout(() => {
4655
+ reject(new Error("Timeout waiting for bridge response."));
4656
+ }, 15000);
4657
+ socket.once("message", (data) => {
4658
+ clearTimeout(timeout);
4659
+ try {
4660
+ resolve(JSON.parse(data.toString()));
4661
+ }
4662
+ catch {
4663
+ reject(new Error("Failed to parse bridge response."));
4664
+ }
4665
+ });
4666
+ socket.send(JSON.stringify(message));
4667
+ });
4668
+ }
4669
+ function SpawnBridge(bridgeScript) {
4670
+ const bridgePath = bridgeScript ? resolve(bridgeScript) : join(dirname(fileURLToPath(import.meta.url)), "inspector-bridge.mjs");
4671
+ const child = spawn(process.execPath, [bridgePath], {
4672
+ detached: true,
4673
+ stdio: "ignore",
4674
+ });
4675
+ child.unref();
4676
+ }
4677
+ async function EnsureBridge(port, bridgeScript, maxRetries = 10, retryDelayMs = 500) {
4678
+ try {
4679
+ return await ConnectToBridge(port);
4680
+ }
4681
+ catch {
4682
+ // Bridge not running — spawn it.
4683
+ SpawnBridge(bridgeScript);
4684
+ }
4685
+ for (let i = 0; i < maxRetries; i++) {
4686
+ // eslint-disable-next-line no-await-in-loop
4687
+ await new Promise((resolve) => setTimeout(resolve, retryDelayMs));
4688
+ try {
4689
+ // eslint-disable-next-line no-await-in-loop
4690
+ return await ConnectToBridge(port);
4691
+ }
4692
+ catch {
4693
+ // Keep retrying.
4694
+ }
4695
+ }
4696
+ throw new Error(`Unable to connect to the Inspector bridge on port ${port} after spawning it.`);
4697
+ }
4698
+ /**
4699
+ * Connects to the bridge, runs the provided callback, and closes the socket.
4700
+ * @param bridgeScript Optional path to the bridge script.
4701
+ * @param fn The callback to run with the connected socket.
4702
+ */
4703
+ async function WithBridge(bridgeScript, fn) {
4704
+ const socket = await EnsureBridge(Config.cliPort, bridgeScript);
4705
+ try {
4706
+ await fn(socket);
4707
+ }
4708
+ finally {
4709
+ socket.close();
4710
+ }
4711
+ }
4712
+ /**
4713
+ * Resolves the session id to use. If an explicit id is provided, returns it.
4714
+ * If not, queries the bridge: returns the sole session's id when exactly one
4715
+ * is active, or errors if zero or multiple sessions are active.
4716
+ * @param socket The WebSocket connection to the bridge.
4717
+ * @param explicitId An optional explicit session id string.
4718
+ * @returns The resolved numeric session id.
4719
+ */
4720
+ /**
4721
+ * Parses and validates an explicit session id string against the list of active sessions.
4722
+ * @param explicitId The session id string to validate.
4723
+ * @param sessions The list of active sessions from the bridge.
4724
+ * @returns The matching session info.
4725
+ */
4726
+ function ValidateSessionId(explicitId, sessions) {
4727
+ const parsed = parseInt(explicitId, 10);
4728
+ if (isNaN(parsed)) {
4729
+ throw new Error("Session id must be a number.");
4730
+ }
4731
+ const match = sessions.find((s) => s.id === parsed);
4732
+ if (!match) {
4733
+ if (sessions.length === 0) {
4734
+ throw new Error(`Session ${parsed} does not exist. No active sessions.`);
4735
+ }
4736
+ const list = sessions.map((s) => ` [${s.id}] ${s.name}`).join("\n");
4737
+ throw new Error(`Session ${parsed} does not exist. Active sessions:\n${list}`);
4738
+ }
4739
+ return match;
4740
+ }
4741
+ /**
4742
+ * Resolves the session id to use. If an explicit id is provided, validates it
4743
+ * against the active sessions. If not, queries the bridge: returns the sole
4744
+ * session's id when exactly one is active, or errors if zero or multiple.
4745
+ * @param socket The WebSocket connection to the bridge.
4746
+ * @param explicitId An optional explicit session id string.
4747
+ * @returns The resolved numeric session id.
4748
+ */
4749
+ async function ResolveSessionId(socket, explicitId) {
4750
+ const response = await SendAndReceive(socket, { type: "sessions" });
4751
+ if (explicitId !== undefined) {
4752
+ return ValidateSessionId(explicitId, response.sessions).id;
4753
+ }
4754
+ if (response.sessions.length === 0) {
4755
+ throw new Error("No active sessions. Make sure a browser is running with StartInspectable enabled.");
4756
+ }
4757
+ if (response.sessions.length > 1) {
4758
+ const list = response.sessions.map((s) => ` [${s.id}] ${s.name}`).join("\n");
4759
+ throw new Error(`Multiple active sessions:\n${list}\nSpecify a session id with --session <session-id>`);
4760
+ }
4761
+ return response.sessions[0].id;
4762
+ }
4763
+ /**
4764
+ * Parses command arguments from the rest array (everything after the command id).
4765
+ * @param rest The remaining CLI tokens after the command id.
4766
+ * @param globalHelp Whether --help was specified at the top level.
4767
+ * @returns The parsed command arguments and whether help was requested.
4768
+ */
4769
+ function ParseCommandArgs(rest, globalHelp) {
4770
+ const args = {};
4771
+ let wantsHelp = globalHelp;
4772
+ for (let i = 1; i < rest.length; i++) {
4773
+ const token = rest[i];
4774
+ if (token === "--help") {
4775
+ wantsHelp = true;
4776
+ }
4777
+ else if (token.startsWith("--") && i + 1 < rest.length) {
4778
+ args[token.slice(2)] = rest[++i];
4779
+ }
4780
+ }
4781
+ return { args, wantsHelp };
4782
+ }
4783
+ /**
4784
+ * Prints help text for a command, including its description and argument list.
4785
+ * If there are missing required arguments and help was not explicitly requested,
4786
+ * prints an error and sets a non-zero exit code.
4787
+ * @param commandId The command identifier.
4788
+ * @param descriptor The command descriptor.
4789
+ * @param missingRequired The list of missing required arguments.
4790
+ * @param wantsHelp Whether help was explicitly requested.
4791
+ */
4792
+ function PrintCommandHelp(commandId, descriptor, missingRequired, wantsHelp) {
4793
+ if (missingRequired.length > 0 && !wantsHelp) {
4794
+ console.error(`Missing required argument(s): ${missingRequired.map((a) => `--${a.name}`).join(", ")}\n`);
4795
+ }
4796
+ console.log(`${commandId}: ${descriptor.description}\n`);
4797
+ if (descriptor.args && descriptor.args.length > 0) {
4798
+ console.log("Arguments:");
4799
+ const maxLen = Math.max(...descriptor.args.map((a) => `--${a.name}${a.required ? " (required)" : ""}`.length));
4800
+ for (const arg of descriptor.args) {
4801
+ const label = `--${arg.name}${arg.required ? " (required)" : ""}`;
4802
+ console.log(` ${label.padEnd(maxLen)} ${arg.description}`);
4803
+ }
4804
+ }
4805
+ if (missingRequired.length > 0 && !wantsHelp) {
4806
+ process.exitCode = 1;
4807
+ }
4808
+ }
4809
+ /**
4810
+ * Handles `--session` without `--command`: lists active sessions, or shows
4811
+ * details for a specific session when an explicit id is provided.
4812
+ * @param socket The WebSocket connection to the bridge.
4813
+ * @param explicitId An optional explicit session id string.
4814
+ */
4815
+ async function HandleSessions(socket, explicitId) {
4816
+ const response = await SendAndReceive(socket, { type: "sessions" });
4817
+ if (explicitId !== undefined) {
4818
+ const match = ValidateSessionId(explicitId, response.sessions);
4819
+ console.log(` [${match.id}] ${match.name} (connected: ${match.connectedAt})`);
4820
+ return;
4821
+ }
4822
+ if (response.sessions.length === 0) {
4823
+ console.log("No active sessions.");
4824
+ }
4825
+ else {
4826
+ console.log("Active sessions:");
4827
+ for (const session of response.sessions) {
4828
+ console.log(` [${session.id}] ${session.name} (connected: ${session.connectedAt})`);
4829
+ }
4830
+ }
4831
+ }
4832
+ /**
4833
+ * Handles `--command`: lists commands or executes one.
4834
+ * @param socket The WebSocket connection to the bridge.
4835
+ * @param args The parsed CLI arguments.
4836
+ */
4837
+ async function HandleCommand(socket, args) {
4838
+ const commandId = args.rest.length > 0 ? args.rest[0] : undefined;
4839
+ if (!commandId) {
4840
+ // --command with no id: list available commands.
4841
+ const sessionId = await ResolveSessionId(socket, args.sessionId);
4842
+ const response = await SendAndReceive(socket, { type: "commands", sessionId });
4843
+ if (response.error) {
4844
+ console.error(`Error: ${response.error}`);
4845
+ process.exitCode = 1;
4846
+ return;
4847
+ }
4848
+ if (!response.commands || response.commands.length === 0) {
4849
+ console.log("No commands available.");
4850
+ }
4851
+ else {
4852
+ console.log("Available commands:");
4853
+ const maxLen = Math.max(...response.commands.map((c) => c.id.length));
4854
+ for (const cmd of response.commands) {
4855
+ console.log(` ${cmd.id.padEnd(maxLen)} ${cmd.description}`);
4856
+ }
4857
+ console.log("\nRun --command <id> --help to see arguments for a command.");
4858
+ console.log("Run --command <id> [--arg value ...] to execute a command.");
4859
+ }
4860
+ return;
4861
+ }
4862
+ const sessionId = await ResolveSessionId(socket, args.sessionId);
4863
+ const { args: commandArgs, wantsHelp } = ParseCommandArgs(args.rest, args.help);
4864
+ // Fetch the command descriptor to check for --help or missing required args.
4865
+ const commandsResponse = await SendAndReceive(socket, { type: "commands", sessionId });
4866
+ const descriptor = commandsResponse.commands?.find((c) => c.id === commandId);
4867
+ if (!descriptor) {
4868
+ console.error(`Error: Unknown command "${commandId}".`);
4869
+ process.exitCode = 1;
4870
+ return;
4871
+ }
4872
+ // Check for --help or missing required arguments.
4873
+ const missingRequired = (descriptor.args ?? []).filter((a) => a.required && !(a.name in commandArgs));
4874
+ if (wantsHelp || missingRequired.length > 0) {
4875
+ PrintCommandHelp(commandId, descriptor, missingRequired, wantsHelp);
4876
+ return;
4877
+ }
4878
+ const response = await SendAndReceive(socket, {
4879
+ type: "exec",
4880
+ sessionId,
4881
+ commandId,
4882
+ args: commandArgs,
4883
+ });
4884
+ if (response.error) {
4885
+ console.error(`Error: ${response.error}`);
4886
+ process.exitCode = 1;
4887
+ }
4888
+ else {
4889
+ console.log(response.result ?? "");
4890
+ }
4891
+ }
4892
+ async function Main() {
4893
+ const args = ParseCliArgs();
4894
+ if (args.help && !args.command) {
4895
+ console.log(HELP_TEXT);
4896
+ return;
4897
+ }
4898
+ if (args.stop) {
4899
+ try {
4900
+ const socket = await ConnectToBridge(Config.cliPort);
4901
+ await SendAndReceive(socket, { type: "stop" });
4902
+ socket.close();
4903
+ console.log("Bridge stopped.");
4904
+ }
4905
+ catch {
4906
+ console.log("Bridge is not running.");
4907
+ }
4908
+ return;
4909
+ }
4910
+ if (args.session && !args.command) {
4911
+ await WithBridge(args.bridgeScript, async (socket) => await HandleSessions(socket, args.sessionId));
4912
+ return;
4913
+ }
4914
+ if (args.command) {
4915
+ await WithBridge(args.bridgeScript, async (socket) => await HandleCommand(socket, args));
4916
+ return;
4917
+ }
4918
+ // No recognized option — show help.
4919
+ console.log(HELP_TEXT);
4920
+ }
4921
+ void (async () => {
4922
+ try {
4923
+ await Main();
4924
+ }
4925
+ catch (error) {
4926
+ console.error(`Error: ${error}`);
4927
+ process.exitCode = 1;
4928
+ }
4929
+ })();
4930
+
4931
+ export { ParseCliArgs, ParseCommandArgs, PrintCommandHelp, ResolveSessionId, SendAndReceive, ValidateSessionId };