From cf36ed5cd9bd536c42bb8023861f823b1f4ca738 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Sat, 30 May 2026 05:38:44 +0000 Subject: [PATCH] Publish 0.1.16 from develop to main Source ref: develop Source commit: 58d3a868d9fec4172bea59f97d6289008cbba834 Target branch: main Previous target: d2765f8acb081e864acf864819d2ec684b930bcf Release base: d2765f8acb081e864acf864819d2ec684b930bcf Included commits since origin/main: 58d3a86 Prepare develop branch for v0.1.16 --- plugins/cad/skills/bambu-labs | 1 - plugins/cad/skills/bambu-labs/LICENSE | 21 + plugins/cad/skills/bambu-labs/SKILL.md | 209 + .../cad/skills/bambu-labs/agents/openai.yaml | 4 + .../references/local-lan-protocol.md | 123 + .../references/new-printer-onboarding.md | 139 + .../references/real-printer-checklist.md | 56 + .../bambu-labs/scripts/bambu_lan_print.py | 1771 ++ .../scripts/test_bambu_lan_print.py | 981 + plugins/cad/skills/cad | 1 - plugins/cad/skills/cad-viewer | 1 - plugins/cad/skills/cad-viewer/LICENSE | 21 + plugins/cad/skills/cad-viewer/SKILL.md | 127 + .../cad/skills/cad-viewer/agents/openai.yaml | 4 + .../cad-viewer/references/development.md | 12 + .../cad-viewer/references/moveit2-server.md | 29 + .../cad-viewer/references/viewer-features.md | 22 + .../cad/skills/cad-viewer/requirements.txt | 1 + .../cad-viewer/scripts/viewer/.gitignore | 12 + .../scripts/viewer/backend/server.mjs | 26045 ++++++++++++++++ .../assets/BufferGeometryUtils-xu92ooFc.js | 2 + .../BufferGeometryUtils-xu92ooFc.js.map | 1 + .../viewer/dist/assets/GLTFLoader-B3ztFMBW.js | 2 + .../dist/assets/GLTFLoader-B3ztFMBW.js.map | 1 + .../viewer/dist/assets/STLLoader-C7hGonJR.js | 2 + .../dist/assets/STLLoader-C7hGonJR.js.map | 1 + .../viewer/dist/assets/favicon-DLqji3p4.ico | Bin 0 -> 98287 bytes .../dist/assets/glbMeshWorker-iyKraBym.js | 2 + .../dist/assets/glbMeshWorker-iyKraBym.js.map | 1 + .../viewer/dist/assets/index-ClRs8z4T.css | 1 + .../viewer/dist/assets/index-CxYr6aiy.js | 97 + .../viewer/dist/assets/index-CxYr6aiy.js.map | 1 + .../viewer/dist/assets/parseSdf-DaTRWVrj.js | 2 + .../dist/assets/parseSdf-DaTRWVrj.js.map | 1 + .../viewer/dist/assets/parseSrdf-5nF_MoHR.js | 2 + .../dist/assets/parseSrdf-5nF_MoHR.js.map | 1 + .../viewer/dist/assets/parseUrdf-DKAcUsKE.js | 2 + .../dist/assets/parseUrdf-DKAcUsKE.js.map | 1 + .../dist/assets/stlMeshWorker-0yVf-FuZ.js | 2 + .../dist/assets/stlMeshWorker-0yVf-FuZ.js.map | 1 + .../dist/assets/three.module-BB51Dq4E.js | 2 + .../dist/assets/three.module-BB51Dq4E.js.map | 1 + .../dist/assets/three.module-DJHaYUcg.js | 3683 +++ .../dist/assets/three.module-DJHaYUcg.js.map | 1 + .../dist/assets/vendor-icons-CG23pCZa.js | 2 + .../dist/assets/vendor-icons-CG23pCZa.js.map | 1 + .../dist/assets/vendor-react-7jnMmQ9s.js | 9 + .../dist/assets/vendor-react-7jnMmQ9s.js.map | 1 + .../dist/assets/vendor-three-zG29gTWo.js | 4053 +++ .../dist/assets/vendor-three-zG29gTWo.js.map | 1 + .../viewer/dist/assets/vendor-ui-CDgkaHGz.js | 52 + .../dist/assets/vendor-ui-CDgkaHGz.js.map | 1 + .../cad-viewer/scripts/viewer/dist/index.html | 39 + .../scripts/viewer/moveit2_server/__init__.py | 3 + .../moveit2_server/check-moveit2-server.sh | 14 + .../viewer/moveit2_server/conda-common.sh | 53 + .../viewer/moveit2_server/environment.yml | 14 + .../moveit2_server/moveit2_server/__init__.py | 1 + .../moveit2_server/moveit2_server/context.py | 904 + .../moveit2_server/dispatcher.py | 29 + .../moveit2_server/joint_state_seed.py | 61 + .../moveit2_server/moveit_py.py | 589 + .../moveit2_server/moveit2_server/protocol.py | 222 + .../moveit2_server/moveit2_server/server.py | 108 + .../moveit2_server/srdf_source.py | 261 + .../viewer/moveit2_server/pyproject.toml | 21 + .../moveit2_server/run-moveit2-server.sh | 19 + .../scripts/viewer/moveit2_server/setup.sh | 16 + .../cad-viewer/scripts/viewer/package.json | 13 + .../viewer/packages/cadjs/package-lock.json | 28 + .../viewer/packages/cadjs/package.json | 23 + .../packages/cadjs/scripts/run-tests.mjs | 48 + .../packages/cadjs/src/common/cadScene.js | 1972 ++ .../packages/cadjs/src/common/camera.js | 337 + .../cadjs/src/common/displaySettings.js | 47 + .../cadjs/src/common/headlessRenderEntry.js | 256 + .../packages/cadjs/src/common/render.html | 29 + .../packages/cadjs/src/common/renderEdges.js | 641 + .../cadjs/src/common/renderMeshScene.js | 973 + .../packages/cadjs/src/common/renderModel.js | 223 + .../cadjs/src/common/renderOptions.js | 562 + .../packages/cadjs/src/common/source.js | 224 + .../packages/cadjs/src/common/stepModule.js | 518 + .../cadjs/src/common/stepModuleEffects.js | 323 + .../cadjs/src/common/stepParameters.js | 173 + .../cadjs/src/common/stepSidecars.mjs | 43 + .../cadjs/src/common/stepTopology.mjs | 103 + .../cadjs/src/common/themeSettings.js | 1807 ++ .../src/common/topologyDisplayEdgeRuntime.js | 197 + .../cadjs/src/common/topologyDisplayEdges.js | 434 + .../cadjs/src/common/webglRenderer.js | 39 + .../viewer/packages/cadjs/src/index.js | 4 + .../cadjs/src/lib/assembly/meshData.js | 472 + .../cadjs/src/lib/async/concurrency.js | 20 + .../cadjs/src/lib/cadDirectoryScanner.mjs | 2087 ++ .../cadjs/src/lib/cadManifestStore.js | 482 + .../viewer/packages/cadjs/src/lib/cadRefs.js | 180 + .../packages/cadjs/src/lib/displaySettings.js | 1 + .../cadjs/src/lib/dxf/buildPreviewMesh.js | 1278 + .../packages/cadjs/src/lib/dxf/parseDxf.js | 462 + .../packages/cadjs/src/lib/entryAssets.js | 171 + .../packages/cadjs/src/lib/fileFormats.js | 185 + .../cadjs/src/lib/gcode/buildPreviewMesh.js | 505 + .../cadjs/src/lib/gcode/parseGcode.js | 787 + .../cadjs/src/lib/generationStatus.mjs | 251 + .../packages/cadjs/src/lib/pathUtils.mjs | 56 + .../packages/cadjs/src/lib/perspective.js | 125 + .../cadjs/src/lib/render/glbMeshData.js | 479 + .../cadjs/src/lib/render/glbMeshWorker.js | 61 + .../src/lib/render/glbMeshWorkerClient.js | 94 + .../packages/cadjs/src/lib/render/meshCost.js | 68 + .../cadjs/src/lib/render/meshLoaders.js | 58 + .../cadjs/src/lib/render/meshTransfer.js | 13 + .../cadjs/src/lib/render/stlMeshData.js | 85 + .../cadjs/src/lib/render/stlMeshWorker.js | 61 + .../src/lib/render/stlMeshWorkerClient.js | 94 + .../cadjs/src/lib/render/threeMfMeshData.js | 577 + .../cadjs/src/lib/renderAssetClient.js | 618 + .../cadjs/src/lib/selectors/runtime.js | 849 + .../cadjs/src/lib/step/pythonStepArtifact.mjs | 226 + .../src/lib/step/stepArtifactCompiler.mjs | 273 + .../cadjs/src/lib/step/stepMetadata.mjs | 101 + .../packages/cadjs/src/lib/step/stepModule.js | 1 + .../packages/cadjs/src/lib/step/stepTree.js | 247 + .../cadjs/src/lib/stepRenderAssetClient.js | 402 + .../packages/cadjs/src/lib/themeSettings.js | 1 + .../cadjs/src/lib/urdf/jointAnimation.js | 127 + .../packages/cadjs/src/lib/urdf/kinematics.js | 682 + .../packages/cadjs/src/lib/urdf/motion.js | 161 + .../cadjs/src/lib/urdf/moveit2ServerClient.js | 237 + .../packages/cadjs/src/lib/urdf/parseSdf.js | 890 + .../packages/cadjs/src/lib/urdf/parseSrdf.js | 468 + .../packages/cadjs/src/lib/urdf/parseUrdf.js | 488 + .../cadjs/src/lib/viewer/clipPlane.js | 120 + .../cadjs/src/lib/viewer/constants.js | 6 + .../cadjs/src/lib/viewer/displayEdgePolicy.js | 32 + .../cadjs/src/lib/viewer/drawingCanvas.js | 801 + .../cadjs/src/lib/viewer/drawingGeometry.js | 169 + .../cadjs/src/lib/viewer/drawingTools.js | 11 + .../cadjs/src/lib/viewer/modelRuntime.js | 117 + .../cadjs/src/lib/viewer/partVisualState.js | 205 + .../cadjs/src/lib/viewer/pickingThresholds.js | 47 + .../cadjs/src/lib/viewer/referenceGeometry.js | 666 + .../cadjs/src/lib/viewer/renderQuality.js | 17 + .../cadjs/src/lib/viewer/sceneScale.js | 77 + .../cadjs/src/lib/viewer/screenshotCapture.js | 257 + .../src/lib/viewer/selectorPickGroups.js | 263 + .../cadjs/src/lib/viewer/stageGrid.js | 134 + .../cadjs/src/lib/viewer/stageTheme.js | 544 + .../src/lib/viewer/surfaceLineGeometry.js | 225 + .../cadjs/src/lib/viewer/surfaceMaterials.js | 198 + .../src/lib/viewer/topologyDisplayEdgeLine.js | 289 + .../cadjs/src/lib/viewer/urdfPosePicker.js | 458 + .../cadjs/src/lib/viewer/webglSupport.js | 33 + .../packages/cadjs/src/lib/viewerConfig.mjs | 56 + .../cadjs/src/lib/viewerServerInfo.mjs | 83 + .../cadjs/src/lib/viewerServerRegistry.mjs | 115 + .../viewer/packages/cadpy/pyproject.toml | 26 + .../packages/cadpy/src/cadpy/__init__.py | 14 + .../packages/cadpy/src/cadpy/analysis.py | 683 + .../viewer/packages/cadpy/src/cadpy/api.py | 6 + .../cadpy/src/cadpy/assembly_composition.py | 1269 + .../cadpy/src/cadpy/assembly_export.py | 1103 + .../cadpy/src/cadpy/assembly_flatten.py | 249 + .../packages/cadpy/src/cadpy/assembly_spec.py | 458 + .../cadpy/src/cadpy/cad_ref_syntax.py | 145 + .../packages/cadpy/src/cadpy/catalog.py | 546 + .../packages/cadpy/src/cadpy/cli_logging.py | 58 + .../packages/cadpy/src/cadpy/file_metadata.py | 64 + .../packages/cadpy/src/cadpy/generation.py | 2323 ++ .../cadpy/src/cadpy/generation_status.py | 179 + .../viewer/packages/cadpy/src/cadpy/glb.py | 1124 + .../cadpy/src/cadpy/glb_mesh_payload.py | 431 + .../packages/cadpy/src/cadpy/glb_topology.py | 499 + .../viewer/packages/cadpy/src/cadpy/lookup.py | 243 + .../packages/cadpy/src/cadpy/metadata.py | 512 + .../viewer/packages/cadpy/src/cadpy/py.typed | 1 + .../viewer/packages/cadpy/src/cadpy/render.py | 97 + .../packages/cadpy/src/cadpy/reporting.py | 133 + .../cadpy/src/cadpy/selector_types.py | 18 + .../packages/cadpy/src/cadpy/source_hash.py | 264 + .../packages/cadpy/src/cadpy/step_artifact.py | 410 + .../cadpy/src/cadpy/step_artifacts.py | 247 + .../packages/cadpy/src/cadpy/step_export.py | 306 + .../packages/cadpy/src/cadpy/step_metadata.py | 333 + .../packages/cadpy/src/cadpy/step_scene.py | 2609 ++ .../packages/cadpy/src/cadpy/step_targets.py | 492 + .../viewer/packages/cadpy/src/cadpy/stl.py | 33 + .../packages/cadpy/src/cadpy/threemf.py | 557 + .../packages/cadpy/src/cadpy/validators.py | 119 + .../scripts/viewer/requirements.txt | 1 + plugins/cad/skills/cad/LICENSE | 21 + plugins/cad/skills/cad/SKILL.md | 116 + plugins/cad/skills/cad/agents/openai.yaml | 4 + .../cad/assets/design-brief-template.md | 22 + .../cad/references/build123d-modeling.md | 180 + plugins/cad/skills/cad/references/dxf.md | 69 + .../references/inspection-and-validation.md | 172 + .../cad/references/natural-language-specs.md | 123 + .../cad/skills/cad/references/parameters.md | 151 + .../cad/skills/cad/references/positioning.md | 261 + .../cad/skills/cad/references/repair-loop.md | 209 + .../skills/cad/references/snapshot-review.md | 78 + .../skills/cad/references/step-generation.md | 114 + .../cad/references/supported-exports.md | 80 + plugins/cad/skills/cad/requirements.txt | 3 + .../cad/scripts/cadpy_common/__init__.py | 13 + .../cadpy_common/assembly_composition.py | 1269 + .../scripts/cadpy_common/assembly_export.py | 1084 + .../scripts/cadpy_common/assembly_flatten.py | 249 + .../cad/scripts/cadpy_common/assembly_spec.py | 458 + .../scripts/cadpy_common/cad_ref_syntax.py | 145 + .../cad/scripts/cadpy_common/catalog.py | 546 + .../cad/scripts/cadpy_common/cli_logging.py | 58 + .../cad/scripts/cadpy_common/generation.py | 2153 ++ .../skills/cad/scripts/cadpy_common/glb.py | 1097 + .../scripts/cadpy_common/glb_mesh_payload.py | 431 + .../cad/scripts/cadpy_common/glb_topology.py | 499 + .../scripts/cadpy_common/inspect_imports.py | 11 + .../cad/scripts/cadpy_common/metadata.py | 397 + .../cad/scripts/cadpy_common/package_path.py | 18 + .../skills/cad/scripts/cadpy_common/render.py | 85 + .../cad/scripts/cadpy_common/reporting.py | 137 + .../scripts/cadpy_common/selector_types.py | 18 + .../cad/scripts/cadpy_common/source_hash.py | 252 + .../scripts/cadpy_common/step_artifacts.py | 268 + .../cad/scripts/cadpy_common/step_export.py | 228 + .../cad/scripts/cadpy_common/step_metadata.py | 304 + .../cad/scripts/cadpy_common/step_scene.py | 2587 ++ .../cad/scripts/cadpy_common/step_targets.py | 477 + .../skills/cad/scripts/cadpy_common/stl.py | 33 + .../cadpy_common/tests/cad_test_roots.py | 56 + .../tests/test_assembly_composition.py | 1000 + .../tests/test_assembly_export.py | 385 + .../tests/test_assembly_flatten.py | 173 + .../cadpy_common/tests/test_assembly_spec.py | 120 + .../cadpy_common/tests/test_generation.py | 2817 ++ .../scripts/cadpy_common/tests/test_glb.py | 423 + .../cadpy_common/tests/test_step_metadata.py | 87 + .../cadpy_common/tests/test_step_scene.py | 262 + .../scripts/cadpy_common/tests/test_stl.py | 58 + .../cadpy_common/tests/test_threemf.py | 425 + .../scripts/cadpy_common/tests/tmp_root.py | 20 + .../cad/scripts/cadpy_common/threemf.py | 557 + .../cad/scripts/cadpy_common/validators.py | 123 + .../skills/cad/scripts/cadpy_dxf/__init__.py | 13 + .../skills/cad/scripts/cadpy_dxf/__main__.py | 16 + .../cad/skills/cad/scripts/cadpy_dxf/cli.py | 31 + .../cad/scripts/cadpy_dxf/render_payload.py | 360 + .../cad/scripts/cadpy_dxf/tests/test_cli.py | 60 + .../cadpy_dxf/tests/test_render_payload.py | 33 + .../cad/scripts/cadpy_inspect/__main__.py | 16 + .../skills/cad/scripts/cadpy_inspect/cli.py | 21 + .../cadpy_inspect/inspect_refs/__init__.py | 13 + .../cadpy_inspect/inspect_refs/analysis.py | 683 + .../scripts/cadpy_inspect/inspect_refs/cli.py | 635 + .../cadpy_inspect/inspect_refs/inspect.py | 831 + .../cadpy_inspect/inspect_refs/lookup.py | 243 + .../inspect_refs/tests/test_refs_inspect.py | 882 + .../scripts/cadpy_inspect/tests/test_cli.py | 76 + .../cad/scripts/cadpy_snapshot/__init__.py | 1 + .../cad/scripts/cadpy_snapshot/__main__.py | 1251 + .../cadpy_snapshot/runtime/render.html | 20 + .../cadpy_snapshot/runtime/snapshot-render.js | 4136 +++ .../scripts/cadpy_snapshot/tests/test_cli.py | 362 + .../skills/cad/scripts/cadpy_step/__init__.py | 15 + .../skills/cad/scripts/cadpy_step/__main__.py | 16 + .../cad/skills/cad/scripts/cadpy_step/cli.py | 136 + .../cad/scripts/cadpy_step/tests/test_cli.py | 143 + plugins/cad/skills/cad/scripts/dxf | 20 + plugins/cad/skills/cad/scripts/inspect | 20 + .../cad/scripts/packages/cadpy/pyproject.toml | 26 + .../packages/cadpy/src/cadpy/__init__.py | 14 + .../packages/cadpy/src/cadpy/analysis.py | 683 + .../scripts/packages/cadpy/src/cadpy/api.py | 6 + .../cadpy/src/cadpy/assembly_composition.py | 1269 + .../cadpy/src/cadpy/assembly_export.py | 1103 + .../cadpy/src/cadpy/assembly_flatten.py | 249 + .../packages/cadpy/src/cadpy/assembly_spec.py | 458 + .../cadpy/src/cadpy/cad_ref_syntax.py | 145 + .../packages/cadpy/src/cadpy/catalog.py | 546 + .../packages/cadpy/src/cadpy/cli_logging.py | 58 + .../packages/cadpy/src/cadpy/file_metadata.py | 64 + .../packages/cadpy/src/cadpy/generation.py | 2323 ++ .../cadpy/src/cadpy/generation_status.py | 179 + .../scripts/packages/cadpy/src/cadpy/glb.py | 1124 + .../cadpy/src/cadpy/glb_mesh_payload.py | 431 + .../packages/cadpy/src/cadpy/glb_topology.py | 499 + .../packages/cadpy/src/cadpy/lookup.py | 243 + .../packages/cadpy/src/cadpy/metadata.py | 512 + .../scripts/packages/cadpy/src/cadpy/py.typed | 1 + .../packages/cadpy/src/cadpy/render.py | 97 + .../packages/cadpy/src/cadpy/reporting.py | 133 + .../cadpy/src/cadpy/selector_types.py | 18 + .../packages/cadpy/src/cadpy/source_hash.py | 264 + .../packages/cadpy/src/cadpy/step_artifact.py | 410 + .../cadpy/src/cadpy/step_artifacts.py | 247 + .../packages/cadpy/src/cadpy/step_export.py | 306 + .../packages/cadpy/src/cadpy/step_metadata.py | 333 + .../packages/cadpy/src/cadpy/step_scene.py | 2609 ++ .../packages/cadpy/src/cadpy/step_targets.py | 492 + .../scripts/packages/cadpy/src/cadpy/stl.py | 33 + .../packages/cadpy/src/cadpy/threemf.py | 557 + .../packages/cadpy/src/cadpy/validators.py | 119 + plugins/cad/skills/cad/scripts/snapshot | 20 + plugins/cad/skills/cad/scripts/step | 20 + plugins/cad/skills/gcode | 1 - plugins/cad/skills/gcode/LICENSE | 21 + plugins/cad/skills/gcode/SKILL.md | 137 + plugins/cad/skills/gcode/agents/openai.yaml | 4 + .../gcode/references/gcode-validation.md | 42 + .../gcode/references/slicer-backends.md | 81 + .../cad/skills/gcode/scripts/gcode_tool.py | 741 + .../skills/gcode/scripts/test_gcode_tool.py | 300 + plugins/cad/skills/sdf | 1 - plugins/cad/skills/sdf/LICENSE | 21 + plugins/cad/skills/sdf/SKILL.md | 104 + plugins/cad/skills/sdf/agents/openai.yaml | 4 + .../skills/sdf/references/builder-helpers.md | 136 + .../skills/sdf/references/design-ledger.md | 115 + plugins/cad/skills/sdf/references/examples.md | 148 + .../skills/sdf/references/frame-semantics.md | 87 + plugins/cad/skills/sdf/references/gen-sdf.md | 55 + .../sdf/references/generator-contract.md | 151 + .../sdf/references/implementation-notes.md | 56 + .../skills/sdf/references/interoperability.md | 76 + .../skills/sdf/references/llm-guardrails.md | 115 + .../cad/skills/sdf/references/sdf-workflow.md | 79 + .../cad/skills/sdf/references/smoke-tests.md | 98 + .../cad/skills/sdf/references/validation.md | 154 + plugins/cad/skills/sdf/requirements.txt | 1 + .../packages/cadpy_metadata/pyproject.toml | 17 + .../src/cadpy_metadata/__init__.py | 17 + .../src/cadpy_metadata/generator.py | 409 + .../src/cadpy_metadata/py.typed | 1 + .../cad/skills/sdf/scripts/sdf/__init__.py | 1 + .../cad/skills/sdf/scripts/sdf/__main__.py | 16 + plugins/cad/skills/sdf/scripts/sdf/builder.py | 405 + plugins/cad/skills/sdf/scripts/sdf/cli.py | 387 + .../cad/skills/sdf/scripts/sdf/external.py | 55 + .../cad/skills/sdf/scripts/sdf/findings.py | 61 + plugins/cad/skills/sdf/scripts/sdf/source.py | 309 + .../skills/sdf/scripts/sdf/tests/__init__.py | 1 + .../sdf/scripts/sdf/tests/test_builder.py | 47 + .../skills/sdf/scripts/sdf/tests/test_cli.py | 293 + .../sdf/scripts/sdf/tests/test_source.py | 294 + .../sdf/scripts/sdf/tests/test_validation.py | 338 + .../cad/skills/sdf/scripts/sdf/validation.py | 846 + plugins/cad/skills/sendcutsend | 1 - plugins/cad/skills/sendcutsend/LICENSE | 21 + plugins/cad/skills/sendcutsend/SKILL.md | 122 + .../cad/skills/sendcutsend/agents/openai.yaml | 4 + .../references/official-sources.md | 40 + .../sendcutsend/references/report-template.md | 42 + plugins/cad/skills/srdf | 1 - plugins/cad/skills/srdf/LICENSE | 21 + plugins/cad/skills/srdf/SKILL.md | 77 + plugins/cad/skills/srdf/agents/openai.yaml | 4 + .../srdf/references/disabled-collisions.md | 55 + .../skills/srdf/references/end-effectors.md | 73 + .../cad/skills/srdf/references/gen-srdf.md | 34 + .../srdf/references/generator-contract.md | 126 + .../srdf/references/implementation-notes.md | 37 + .../skills/srdf/references/planning-ledger.md | 102 + .../skills/srdf/references/srdf-workflow.md | 76 + .../cad/skills/srdf/references/validation.md | 117 + plugins/cad/skills/srdf/requirements.txt | 1 + .../packages/cadpy_metadata/pyproject.toml | 17 + .../src/cadpy_metadata/__init__.py | 17 + .../src/cadpy_metadata/generator.py | 409 + .../src/cadpy_metadata/py.typed | 1 + .../cad/skills/srdf/scripts/srdf/__init__.py | 1 + .../cad/skills/srdf/scripts/srdf/__main__.py | 16 + plugins/cad/skills/srdf/scripts/srdf/cli.py | 671 + .../cad/skills/srdf/scripts/srdf/source.py | 277 + .../srdf/scripts/srdf/tests/__init__.py | 1 + .../srdf/scripts/srdf/tests/test_cli.py | 265 + .../srdf/scripts/srdf/tests/test_source.py | 70 + plugins/cad/skills/step-parts | 1 - plugins/cad/skills/step-parts/LICENSE | 21 + plugins/cad/skills/step-parts/SKILL.md | 70 + .../cad/skills/step-parts/agents/openai.yaml | 4 + .../step-parts/references/step-parts-api.md | 74 + .../step-parts/scripts/download_step_part.py | 208 + plugins/cad/skills/urdf | 1 - plugins/cad/skills/urdf/LICENSE | 21 + plugins/cad/skills/urdf/SKILL.md | 66 + plugins/cad/skills/urdf/agents/openai.yaml | 4 + .../skills/urdf/references/design-ledger.md | 110 + .../skills/urdf/references/frame-semantics.md | 105 + .../cad/skills/urdf/references/gen-urdf.md | 46 + .../urdf/references/generator-contract.md | 105 + .../skills/urdf/references/urdf-workflow.md | 125 + .../cad/skills/urdf/references/validation.md | 156 + plugins/cad/skills/urdf/requirements.txt | 1 + .../packages/cadpy_metadata/pyproject.toml | 17 + .../src/cadpy_metadata/__init__.py | 17 + .../src/cadpy_metadata/generator.py | 409 + .../src/cadpy_metadata/py.typed | 1 + .../cad/skills/urdf/scripts/urdf/__init__.py | 1 + .../cad/skills/urdf/scripts/urdf/__main__.py | 16 + plugins/cad/skills/urdf/scripts/urdf/cli.py | 253 + .../cad/skills/urdf/scripts/urdf/source.py | 698 + .../urdf/scripts/urdf/tests/__init__.py | 1 + .../urdf/scripts/urdf/tests/test_cli.py | 260 + .../urdf/scripts/urdf/tests/test_source.py | 593 + skills/cad-viewer/scripts/viewer | 1 - skills/cad-viewer/scripts/viewer/.gitignore | 12 + .../scripts/viewer/backend/server.mjs | 26045 ++++++++++++++++ .../assets/BufferGeometryUtils-xu92ooFc.js | 2 + .../BufferGeometryUtils-xu92ooFc.js.map | 1 + .../viewer/dist/assets/GLTFLoader-B3ztFMBW.js | 2 + .../dist/assets/GLTFLoader-B3ztFMBW.js.map | 1 + .../viewer/dist/assets/STLLoader-C7hGonJR.js | 2 + .../dist/assets/STLLoader-C7hGonJR.js.map | 1 + .../viewer/dist/assets/favicon-DLqji3p4.ico | Bin 0 -> 98287 bytes .../dist/assets/glbMeshWorker-iyKraBym.js | 2 + .../dist/assets/glbMeshWorker-iyKraBym.js.map | 1 + .../viewer/dist/assets/index-ClRs8z4T.css | 1 + .../viewer/dist/assets/index-CxYr6aiy.js | 97 + .../viewer/dist/assets/index-CxYr6aiy.js.map | 1 + .../viewer/dist/assets/parseSdf-DaTRWVrj.js | 2 + .../dist/assets/parseSdf-DaTRWVrj.js.map | 1 + .../viewer/dist/assets/parseSrdf-5nF_MoHR.js | 2 + .../dist/assets/parseSrdf-5nF_MoHR.js.map | 1 + .../viewer/dist/assets/parseUrdf-DKAcUsKE.js | 2 + .../dist/assets/parseUrdf-DKAcUsKE.js.map | 1 + .../dist/assets/stlMeshWorker-0yVf-FuZ.js | 2 + .../dist/assets/stlMeshWorker-0yVf-FuZ.js.map | 1 + .../dist/assets/three.module-BB51Dq4E.js | 2 + .../dist/assets/three.module-BB51Dq4E.js.map | 1 + .../dist/assets/three.module-DJHaYUcg.js | 3683 +++ .../dist/assets/three.module-DJHaYUcg.js.map | 1 + .../dist/assets/vendor-icons-CG23pCZa.js | 2 + .../dist/assets/vendor-icons-CG23pCZa.js.map | 1 + .../dist/assets/vendor-react-7jnMmQ9s.js | 9 + .../dist/assets/vendor-react-7jnMmQ9s.js.map | 1 + .../dist/assets/vendor-three-zG29gTWo.js | 4053 +++ .../dist/assets/vendor-three-zG29gTWo.js.map | 1 + .../viewer/dist/assets/vendor-ui-CDgkaHGz.js | 52 + .../dist/assets/vendor-ui-CDgkaHGz.js.map | 1 + .../cad-viewer/scripts/viewer/dist/index.html | 39 + .../scripts/viewer/moveit2_server/__init__.py | 3 + .../moveit2_server/check-moveit2-server.sh | 14 + .../viewer/moveit2_server/conda-common.sh | 53 + .../viewer/moveit2_server/environment.yml | 14 + .../moveit2_server/moveit2_server/__init__.py | 1 + .../moveit2_server/moveit2_server/context.py | 904 + .../moveit2_server/dispatcher.py | 29 + .../moveit2_server/joint_state_seed.py | 61 + .../moveit2_server/moveit_py.py | 589 + .../moveit2_server/moveit2_server/protocol.py | 222 + .../moveit2_server/moveit2_server/server.py | 108 + .../moveit2_server/srdf_source.py | 261 + .../viewer/moveit2_server/pyproject.toml | 21 + .../moveit2_server/run-moveit2-server.sh | 19 + .../scripts/viewer/moveit2_server/setup.sh | 16 + skills/cad-viewer/scripts/viewer/package.json | 13 + .../viewer/packages/cadjs/package-lock.json | 28 + .../viewer/packages/cadjs/package.json | 23 + .../packages/cadjs/scripts/run-tests.mjs | 48 + .../packages/cadjs/src/common/cadScene.js | 1972 ++ .../packages/cadjs/src/common/camera.js | 337 + .../cadjs/src/common/displaySettings.js | 47 + .../cadjs/src/common/headlessRenderEntry.js | 256 + .../packages/cadjs/src/common/render.html | 29 + .../packages/cadjs/src/common/renderEdges.js | 641 + .../cadjs/src/common/renderMeshScene.js | 973 + .../packages/cadjs/src/common/renderModel.js | 223 + .../cadjs/src/common/renderOptions.js | 562 + .../packages/cadjs/src/common/source.js | 224 + .../packages/cadjs/src/common/stepModule.js | 518 + .../cadjs/src/common/stepModuleEffects.js | 323 + .../cadjs/src/common/stepParameters.js | 173 + .../cadjs/src/common/stepSidecars.mjs | 43 + .../cadjs/src/common/stepTopology.mjs | 103 + .../cadjs/src/common/themeSettings.js | 1807 ++ .../src/common/topologyDisplayEdgeRuntime.js | 197 + .../cadjs/src/common/topologyDisplayEdges.js | 434 + .../cadjs/src/common/webglRenderer.js | 39 + .../viewer/packages/cadjs/src/index.js | 4 + .../cadjs/src/lib/assembly/meshData.js | 472 + .../cadjs/src/lib/async/concurrency.js | 20 + .../cadjs/src/lib/cadDirectoryScanner.mjs | 2087 ++ .../cadjs/src/lib/cadManifestStore.js | 482 + .../viewer/packages/cadjs/src/lib/cadRefs.js | 180 + .../packages/cadjs/src/lib/displaySettings.js | 1 + .../cadjs/src/lib/dxf/buildPreviewMesh.js | 1278 + .../packages/cadjs/src/lib/dxf/parseDxf.js | 462 + .../packages/cadjs/src/lib/entryAssets.js | 171 + .../packages/cadjs/src/lib/fileFormats.js | 185 + .../cadjs/src/lib/gcode/buildPreviewMesh.js | 505 + .../cadjs/src/lib/gcode/parseGcode.js | 787 + .../cadjs/src/lib/generationStatus.mjs | 251 + .../packages/cadjs/src/lib/pathUtils.mjs | 56 + .../packages/cadjs/src/lib/perspective.js | 125 + .../cadjs/src/lib/render/glbMeshData.js | 479 + .../cadjs/src/lib/render/glbMeshWorker.js | 61 + .../src/lib/render/glbMeshWorkerClient.js | 94 + .../packages/cadjs/src/lib/render/meshCost.js | 68 + .../cadjs/src/lib/render/meshLoaders.js | 58 + .../cadjs/src/lib/render/meshTransfer.js | 13 + .../cadjs/src/lib/render/stlMeshData.js | 85 + .../cadjs/src/lib/render/stlMeshWorker.js | 61 + .../src/lib/render/stlMeshWorkerClient.js | 94 + .../cadjs/src/lib/render/threeMfMeshData.js | 577 + .../cadjs/src/lib/renderAssetClient.js | 618 + .../cadjs/src/lib/selectors/runtime.js | 849 + .../cadjs/src/lib/step/pythonStepArtifact.mjs | 226 + .../src/lib/step/stepArtifactCompiler.mjs | 273 + .../cadjs/src/lib/step/stepMetadata.mjs | 101 + .../packages/cadjs/src/lib/step/stepModule.js | 1 + .../packages/cadjs/src/lib/step/stepTree.js | 247 + .../cadjs/src/lib/stepRenderAssetClient.js | 402 + .../packages/cadjs/src/lib/themeSettings.js | 1 + .../cadjs/src/lib/urdf/jointAnimation.js | 127 + .../packages/cadjs/src/lib/urdf/kinematics.js | 682 + .../packages/cadjs/src/lib/urdf/motion.js | 161 + .../cadjs/src/lib/urdf/moveit2ServerClient.js | 237 + .../packages/cadjs/src/lib/urdf/parseSdf.js | 890 + .../packages/cadjs/src/lib/urdf/parseSrdf.js | 468 + .../packages/cadjs/src/lib/urdf/parseUrdf.js | 488 + .../cadjs/src/lib/viewer/clipPlane.js | 120 + .../cadjs/src/lib/viewer/constants.js | 6 + .../cadjs/src/lib/viewer/displayEdgePolicy.js | 32 + .../cadjs/src/lib/viewer/drawingCanvas.js | 801 + .../cadjs/src/lib/viewer/drawingGeometry.js | 169 + .../cadjs/src/lib/viewer/drawingTools.js | 11 + .../cadjs/src/lib/viewer/modelRuntime.js | 117 + .../cadjs/src/lib/viewer/partVisualState.js | 205 + .../cadjs/src/lib/viewer/pickingThresholds.js | 47 + .../cadjs/src/lib/viewer/referenceGeometry.js | 666 + .../cadjs/src/lib/viewer/renderQuality.js | 17 + .../cadjs/src/lib/viewer/sceneScale.js | 77 + .../cadjs/src/lib/viewer/screenshotCapture.js | 257 + .../src/lib/viewer/selectorPickGroups.js | 263 + .../cadjs/src/lib/viewer/stageGrid.js | 134 + .../cadjs/src/lib/viewer/stageTheme.js | 544 + .../src/lib/viewer/surfaceLineGeometry.js | 225 + .../cadjs/src/lib/viewer/surfaceMaterials.js | 198 + .../src/lib/viewer/topologyDisplayEdgeLine.js | 289 + .../cadjs/src/lib/viewer/urdfPosePicker.js | 458 + .../cadjs/src/lib/viewer/webglSupport.js | 33 + .../packages/cadjs/src/lib/viewerConfig.mjs | 56 + .../cadjs/src/lib/viewerServerInfo.mjs | 83 + .../cadjs/src/lib/viewerServerRegistry.mjs | 115 + .../viewer/packages/cadpy/pyproject.toml | 26 + .../packages/cadpy/src/cadpy/__init__.py | 14 + .../packages/cadpy/src/cadpy/analysis.py | 683 + .../viewer/packages/cadpy/src/cadpy/api.py | 6 + .../cadpy/src/cadpy/assembly_composition.py | 1269 + .../cadpy/src/cadpy/assembly_export.py | 1103 + .../cadpy/src/cadpy/assembly_flatten.py | 249 + .../packages/cadpy/src/cadpy/assembly_spec.py | 458 + .../cadpy/src/cadpy/cad_ref_syntax.py | 145 + .../packages/cadpy/src/cadpy/catalog.py | 546 + .../packages/cadpy/src/cadpy/cli_logging.py | 58 + .../packages/cadpy/src/cadpy/file_metadata.py | 64 + .../packages/cadpy/src/cadpy/generation.py | 2323 ++ .../cadpy/src/cadpy/generation_status.py | 179 + .../viewer/packages/cadpy/src/cadpy/glb.py | 1124 + .../cadpy/src/cadpy/glb_mesh_payload.py | 431 + .../packages/cadpy/src/cadpy/glb_topology.py | 499 + .../viewer/packages/cadpy/src/cadpy/lookup.py | 243 + .../packages/cadpy/src/cadpy/metadata.py | 512 + .../viewer/packages/cadpy/src/cadpy/py.typed | 1 + .../viewer/packages/cadpy/src/cadpy/render.py | 97 + .../packages/cadpy/src/cadpy/reporting.py | 133 + .../cadpy/src/cadpy/selector_types.py | 18 + .../packages/cadpy/src/cadpy/source_hash.py | 264 + .../packages/cadpy/src/cadpy/step_artifact.py | 410 + .../cadpy/src/cadpy/step_artifacts.py | 247 + .../packages/cadpy/src/cadpy/step_export.py | 306 + .../packages/cadpy/src/cadpy/step_metadata.py | 333 + .../packages/cadpy/src/cadpy/step_scene.py | 2609 ++ .../packages/cadpy/src/cadpy/step_targets.py | 492 + .../viewer/packages/cadpy/src/cadpy/stl.py | 33 + .../packages/cadpy/src/cadpy/threemf.py | 557 + .../packages/cadpy/src/cadpy/validators.py | 119 + .../scripts/viewer/requirements.txt | 1 + skills/cad/scripts/packages/cadpy | 1 - .../cad/scripts/packages/cadpy/pyproject.toml | 26 + .../packages/cadpy/src/cadpy/__init__.py | 14 + .../packages/cadpy/src/cadpy/analysis.py | 683 + .../scripts/packages/cadpy/src/cadpy/api.py | 6 + .../cadpy/src/cadpy/assembly_composition.py | 1269 + .../cadpy/src/cadpy/assembly_export.py | 1103 + .../cadpy/src/cadpy/assembly_flatten.py | 249 + .../packages/cadpy/src/cadpy/assembly_spec.py | 458 + .../cadpy/src/cadpy/cad_ref_syntax.py | 145 + .../packages/cadpy/src/cadpy/catalog.py | 546 + .../packages/cadpy/src/cadpy/cli_logging.py | 58 + .../packages/cadpy/src/cadpy/file_metadata.py | 64 + .../packages/cadpy/src/cadpy/generation.py | 2323 ++ .../cadpy/src/cadpy/generation_status.py | 179 + .../scripts/packages/cadpy/src/cadpy/glb.py | 1124 + .../cadpy/src/cadpy/glb_mesh_payload.py | 431 + .../packages/cadpy/src/cadpy/glb_topology.py | 499 + .../packages/cadpy/src/cadpy/lookup.py | 243 + .../packages/cadpy/src/cadpy/metadata.py | 512 + .../scripts/packages/cadpy/src/cadpy/py.typed | 1 + .../packages/cadpy/src/cadpy/render.py | 97 + .../packages/cadpy/src/cadpy/reporting.py | 133 + .../cadpy/src/cadpy/selector_types.py | 18 + .../packages/cadpy/src/cadpy/source_hash.py | 264 + .../packages/cadpy/src/cadpy/step_artifact.py | 410 + .../cadpy/src/cadpy/step_artifacts.py | 247 + .../packages/cadpy/src/cadpy/step_export.py | 306 + .../packages/cadpy/src/cadpy/step_metadata.py | 333 + .../packages/cadpy/src/cadpy/step_scene.py | 2609 ++ .../packages/cadpy/src/cadpy/step_targets.py | 492 + .../scripts/packages/cadpy/src/cadpy/stl.py | 33 + .../packages/cadpy/src/cadpy/threemf.py | 557 + .../packages/cadpy/src/cadpy/validators.py | 119 + skills/sdf/scripts/packages/cadpy_metadata | 1 - .../packages/cadpy_metadata/pyproject.toml | 17 + .../src/cadpy_metadata/__init__.py | 17 + .../src/cadpy_metadata/generator.py | 409 + .../src/cadpy_metadata/py.typed | 1 + skills/srdf/scripts/packages/cadpy_metadata | 1 - .../packages/cadpy_metadata/pyproject.toml | 17 + .../src/cadpy_metadata/__init__.py | 17 + .../src/cadpy_metadata/generator.py | 409 + .../src/cadpy_metadata/py.typed | 1 + skills/urdf/scripts/packages/cadpy_metadata | 1 - .../packages/cadpy_metadata/pyproject.toml | 17 + .../src/cadpy_metadata/__init__.py | 17 + .../src/cadpy_metadata/generator.py | 409 + .../src/cadpy_metadata/py.typed | 1 + viewer/packages/cadjs | 1 - viewer/packages/cadjs/README.md | 82 + viewer/packages/cadjs/docs/render-pipeline.md | 356 + viewer/packages/cadjs/package-lock.json | 28 + viewer/packages/cadjs/package.json | 23 + viewer/packages/cadjs/scripts/run-tests.mjs | 48 + viewer/packages/cadjs/src/common/cadScene.js | 1972 ++ .../cadjs/src/common/cadScene.test.js | 565 + viewer/packages/cadjs/src/common/camera.js | 337 + .../packages/cadjs/src/common/camera.test.js | 98 + .../cadjs/src/common/displaySettings.js | 47 + .../cadjs/src/common/displaySettings.test.js | 48 + .../cadjs/src/common/headlessRenderEntry.js | 256 + viewer/packages/cadjs/src/common/render.html | 29 + .../packages/cadjs/src/common/renderEdges.js | 641 + .../cadjs/src/common/renderEdges.test.js | 498 + .../cadjs/src/common/renderMeshScene.js | 973 + .../cadjs/src/common/renderMeshScene.test.js | 97 + .../packages/cadjs/src/common/renderModel.js | 223 + .../cadjs/src/common/renderOptions.js | 562 + .../cadjs/src/common/renderOptions.test.js | 165 + viewer/packages/cadjs/src/common/source.js | 224 + .../packages/cadjs/src/common/source.test.js | 90 + .../packages/cadjs/src/common/stepModule.js | 518 + .../cadjs/src/common/stepModuleEffects.js | 323 + .../cadjs/src/common/stepParameters.js | 173 + .../cadjs/src/common/stepSidecars.mjs | 43 + .../cadjs/src/common/stepTopology.mjs | 103 + .../cadjs/src/common/themeSettings.js | 1807 ++ .../src/common/topologyDisplayEdgeRuntime.js | 197 + .../common/topologyDisplayEdgeRuntime.test.js | 145 + .../cadjs/src/common/topologyDisplayEdges.js | 434 + .../src/common/topologyDisplayEdges.test.js | 205 + .../cadjs/src/common/webglRenderer.js | 39 + .../cadjs/src/common/webglRenderer.test.js | 28 + viewer/packages/cadjs/src/index.js | 4 + .../cadjs/src/lib/assembly/meshData.js | 472 + .../cadjs/src/lib/assembly/meshData.test.js | 526 + .../cadjs/src/lib/async/concurrency.js | 20 + .../cadjs/src/lib/async/concurrency.test.js | 34 + .../cadjs/src/lib/cadDirectoryScanner.mjs | 2087 ++ .../src/lib/cadDirectoryScanner.test.mjs | 1143 + .../cadjs/src/lib/cadManifestStore.js | 482 + .../cadjs/src/lib/cadManifestStore.test.js | 73 + viewer/packages/cadjs/src/lib/cadRefs.js | 180 + .../packages/cadjs/src/lib/displaySettings.js | 1 + .../cadjs/src/lib/dxf/buildPreviewMesh.js | 1278 + .../src/lib/dxf/buildPreviewMesh.test.js | 43 + viewer/packages/cadjs/src/lib/dxf/parseDxf.js | 462 + .../cadjs/src/lib/dxf/parseDxf.test.js | 74 + viewer/packages/cadjs/src/lib/entryAssets.js | 171 + .../cadjs/src/lib/entryAssets.test.js | 104 + viewer/packages/cadjs/src/lib/fileFormats.js | 185 + .../cadjs/src/lib/fileFormats.test.js | 79 + .../cadjs/src/lib/gcode/buildPreviewMesh.js | 505 + .../cadjs/src/lib/gcode/parseGcode.js | 787 + .../cadjs/src/lib/gcode/parseGcode.test.js | 201 + .../cadjs/src/lib/generationStatus.mjs | 251 + .../cadjs/src/lib/generationStatus.test.mjs | 123 + viewer/packages/cadjs/src/lib/pathUtils.mjs | 56 + .../packages/cadjs/src/lib/pathUtils.test.mjs | 15 + viewer/packages/cadjs/src/lib/perspective.js | 125 + .../cadjs/src/lib/perspective.test.js | 76 + .../cadjs/src/lib/render/glbMeshData.js | 479 + .../cadjs/src/lib/render/glbMeshData.test.js | 534 + .../cadjs/src/lib/render/glbMeshWorker.js | 61 + .../src/lib/render/glbMeshWorkerClient.js | 94 + .../lib/render/glbMeshWorkerClient.test.js | 24 + .../packages/cadjs/src/lib/render/meshCost.js | 68 + .../cadjs/src/lib/render/meshCost.test.js | 63 + .../cadjs/src/lib/render/meshLoaders.js | 58 + .../cadjs/src/lib/render/meshLoaders.test.js | 27 + .../cadjs/src/lib/render/meshTransfer.js | 13 + .../cadjs/src/lib/render/stlMeshData.js | 85 + .../cadjs/src/lib/render/stlMeshData.test.js | 41 + .../cadjs/src/lib/render/stlMeshWorker.js | 61 + .../src/lib/render/stlMeshWorkerClient.js | 94 + .../cadjs/src/lib/render/threeMfMeshData.js | 577 + .../src/lib/render/threeMfMeshData.test.js | 130 + .../cadjs/src/lib/renderAssetClient.js | 618 + .../cadjs/src/lib/renderAssetClient.test.js | 379 + .../cadjs/src/lib/selectors/runtime.js | 849 + .../cadjs/src/lib/selectors/runtime.test.js | 269 + .../cadjs/src/lib/step/pythonStepArtifact.mjs | 226 + .../src/lib/step/stepArtifactCompiler.mjs | 273 + .../lib/step/stepArtifactCompiler.test.mjs | 202 + .../cadjs/src/lib/step/stepMetadata.mjs | 101 + .../packages/cadjs/src/lib/step/stepModule.js | 1 + .../cadjs/src/lib/step/stepModule.test.js | 375 + .../packages/cadjs/src/lib/step/stepTree.js | 247 + .../cadjs/src/lib/step/stepTree.test.js | 199 + .../cadjs/src/lib/stepRenderAssetClient.js | 402 + .../packages/cadjs/src/lib/themeSettings.js | 1 + .../cadjs/src/lib/themeSettings.test.js | 727 + .../cadjs/src/lib/urdf/jointAnimation.js | 127 + .../cadjs/src/lib/urdf/jointAnimation.test.js | 112 + .../packages/cadjs/src/lib/urdf/kinematics.js | 682 + .../cadjs/src/lib/urdf/kinematics.test.js | 566 + viewer/packages/cadjs/src/lib/urdf/motion.js | 161 + .../cadjs/src/lib/urdf/motion.test.js | 135 + .../cadjs/src/lib/urdf/moveit2ServerClient.js | 237 + .../src/lib/urdf/moveit2ServerClient.test.js | 227 + .../packages/cadjs/src/lib/urdf/parseSdf.js | 890 + .../cadjs/src/lib/urdf/parseSdf.test.js | 464 + .../packages/cadjs/src/lib/urdf/parseSrdf.js | 468 + .../cadjs/src/lib/urdf/parseSrdf.test.js | 173 + .../packages/cadjs/src/lib/urdf/parseUrdf.js | 488 + .../cadjs/src/lib/urdf/parseUrdf.test.js | 163 + .../cadjs/src/lib/viewer/clipPlane.js | 120 + .../cadjs/src/lib/viewer/clipPlane.test.js | 89 + .../cadjs/src/lib/viewer/constants.js | 6 + .../cadjs/src/lib/viewer/displayEdgePolicy.js | 32 + .../src/lib/viewer/displayEdgePolicy.test.js | 41 + .../cadjs/src/lib/viewer/drawingCanvas.js | 801 + .../src/lib/viewer/drawingCanvas.test.js | 119 + .../cadjs/src/lib/viewer/drawingGeometry.js | 169 + .../src/lib/viewer/drawingGeometry.test.js | 106 + .../cadjs/src/lib/viewer/drawingTools.js | 11 + .../cadjs/src/lib/viewer/modelRuntime.js | 117 + .../cadjs/src/lib/viewer/modelRuntime.test.js | 140 + .../cadjs/src/lib/viewer/partVisualState.js | 205 + .../src/lib/viewer/partVisualState.test.js | 170 + .../cadjs/src/lib/viewer/pickingThresholds.js | 47 + .../cadjs/src/lib/viewer/referenceGeometry.js | 666 + .../src/lib/viewer/referenceGeometry.test.js | 347 + .../cadjs/src/lib/viewer/renderQuality.js | 17 + .../src/lib/viewer/renderQuality.test.js | 38 + .../cadjs/src/lib/viewer/sceneScale.js | 77 + .../cadjs/src/lib/viewer/sceneScale.test.js | 61 + .../cadjs/src/lib/viewer/screenshotCapture.js | 257 + .../src/lib/viewer/screenshotCapture.test.js | 258 + .../src/lib/viewer/selectorPickGroups.js | 263 + .../src/lib/viewer/selectorPickGroups.test.js | 227 + .../cadjs/src/lib/viewer/stageGrid.js | 134 + .../cadjs/src/lib/viewer/stageGrid.test.js | 135 + .../cadjs/src/lib/viewer/stageTheme.js | 544 + .../cadjs/src/lib/viewer/stageTheme.test.js | 150 + .../src/lib/viewer/surfaceLineGeometry.js | 225 + .../lib/viewer/surfaceLineGeometry.test.js | 110 + .../cadjs/src/lib/viewer/surfaceMaterials.js | 198 + .../src/lib/viewer/surfaceMaterials.test.js | 145 + .../src/lib/viewer/topologyDisplayEdgeLine.js | 289 + .../viewer/topologyDisplayEdgeLine.test.js | 211 + .../cadjs/src/lib/viewer/urdfPosePicker.js | 458 + .../src/lib/viewer/urdfPosePicker.test.js | 127 + .../cadjs/src/lib/viewer/webglSupport.js | 33 + .../cadjs/src/lib/viewer/webglSupport.test.js | 40 + .../packages/cadjs/src/lib/viewerConfig.mjs | 56 + .../cadjs/src/lib/viewerConfig.test.mjs | 51 + .../cadjs/src/lib/viewerServerInfo.mjs | 83 + .../cadjs/src/lib/viewerServerInfo.test.mjs | 85 + .../cadjs/src/lib/viewerServerRegistry.mjs | 115 + viewer/packages/cadpy | 1 - viewer/packages/cadpy/pyproject.toml | 26 + viewer/packages/cadpy/src/cadpy/__init__.py | 14 + viewer/packages/cadpy/src/cadpy/analysis.py | 683 + viewer/packages/cadpy/src/cadpy/api.py | 6 + .../cadpy/src/cadpy/assembly_composition.py | 1269 + .../cadpy/src/cadpy/assembly_export.py | 1103 + .../cadpy/src/cadpy/assembly_flatten.py | 249 + .../packages/cadpy/src/cadpy/assembly_spec.py | 458 + .../cadpy/src/cadpy/cad_ref_syntax.py | 145 + viewer/packages/cadpy/src/cadpy/catalog.py | 546 + .../packages/cadpy/src/cadpy/cli_logging.py | 58 + .../packages/cadpy/src/cadpy/file_metadata.py | 64 + viewer/packages/cadpy/src/cadpy/generation.py | 2323 ++ .../cadpy/src/cadpy/generation_status.py | 179 + viewer/packages/cadpy/src/cadpy/glb.py | 1124 + .../cadpy/src/cadpy/glb_mesh_payload.py | 431 + .../packages/cadpy/src/cadpy/glb_topology.py | 499 + viewer/packages/cadpy/src/cadpy/lookup.py | 243 + viewer/packages/cadpy/src/cadpy/metadata.py | 512 + viewer/packages/cadpy/src/cadpy/py.typed | 1 + viewer/packages/cadpy/src/cadpy/render.py | 97 + viewer/packages/cadpy/src/cadpy/reporting.py | 133 + .../cadpy/src/cadpy/selector_types.py | 18 + .../packages/cadpy/src/cadpy/source_hash.py | 264 + .../packages/cadpy/src/cadpy/step_artifact.py | 410 + .../cadpy/src/cadpy/step_artifacts.py | 247 + .../packages/cadpy/src/cadpy/step_export.py | 306 + .../packages/cadpy/src/cadpy/step_metadata.py | 333 + viewer/packages/cadpy/src/cadpy/step_scene.py | 2609 ++ .../packages/cadpy/src/cadpy/step_targets.py | 492 + viewer/packages/cadpy/src/cadpy/stl.py | 33 + viewer/packages/cadpy/src/cadpy/threemf.py | 557 + viewer/packages/cadpy/src/cadpy/validators.py | 119 + 815 files changed, 295996 insertions(+), 16 deletions(-) delete mode 120000 plugins/cad/skills/bambu-labs create mode 100644 plugins/cad/skills/bambu-labs/LICENSE create mode 100644 plugins/cad/skills/bambu-labs/SKILL.md create mode 100644 plugins/cad/skills/bambu-labs/agents/openai.yaml create mode 100644 plugins/cad/skills/bambu-labs/references/local-lan-protocol.md create mode 100644 plugins/cad/skills/bambu-labs/references/new-printer-onboarding.md create mode 100644 plugins/cad/skills/bambu-labs/references/real-printer-checklist.md create mode 100644 plugins/cad/skills/bambu-labs/scripts/bambu_lan_print.py create mode 100644 plugins/cad/skills/bambu-labs/scripts/test_bambu_lan_print.py delete mode 120000 plugins/cad/skills/cad delete mode 120000 plugins/cad/skills/cad-viewer create mode 100644 plugins/cad/skills/cad-viewer/LICENSE create mode 100644 plugins/cad/skills/cad-viewer/SKILL.md create mode 100644 plugins/cad/skills/cad-viewer/agents/openai.yaml create mode 100644 plugins/cad/skills/cad-viewer/references/development.md create mode 100644 plugins/cad/skills/cad-viewer/references/moveit2-server.md create mode 100644 plugins/cad/skills/cad-viewer/references/viewer-features.md create mode 100644 plugins/cad/skills/cad-viewer/requirements.txt create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/.gitignore create mode 100755 plugins/cad/skills/cad-viewer/scripts/viewer/backend/server.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/BufferGeometryUtils-xu92ooFc.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/BufferGeometryUtils-xu92ooFc.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/GLTFLoader-B3ztFMBW.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/GLTFLoader-B3ztFMBW.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/STLLoader-C7hGonJR.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/STLLoader-C7hGonJR.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/favicon-DLqji3p4.ico create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/glbMeshWorker-iyKraBym.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/glbMeshWorker-iyKraBym.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/index-ClRs8z4T.css create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/index-CxYr6aiy.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/index-CxYr6aiy.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/parseSdf-DaTRWVrj.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/parseSdf-DaTRWVrj.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/parseSrdf-5nF_MoHR.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/parseSrdf-5nF_MoHR.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/parseUrdf-DKAcUsKE.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/parseUrdf-DKAcUsKE.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/stlMeshWorker-0yVf-FuZ.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/stlMeshWorker-0yVf-FuZ.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/three.module-BB51Dq4E.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/three.module-BB51Dq4E.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/three.module-DJHaYUcg.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/three.module-DJHaYUcg.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/vendor-icons-CG23pCZa.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/vendor-icons-CG23pCZa.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/vendor-react-7jnMmQ9s.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/vendor-react-7jnMmQ9s.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/vendor-three-zG29gTWo.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/vendor-three-zG29gTWo.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/vendor-ui-CDgkaHGz.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/assets/vendor-ui-CDgkaHGz.js.map create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/dist/index.html create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/__init__.py create mode 100755 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/check-moveit2-server.sh create mode 100755 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/conda-common.sh create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/environment.yml create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/__init__.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/context.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/dispatcher.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/joint_state_seed.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/moveit_py.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/protocol.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/server.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/srdf_source.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/pyproject.toml create mode 100755 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/run-moveit2-server.sh create mode 100755 plugins/cad/skills/cad-viewer/scripts/viewer/moveit2_server/setup.sh create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/package.json create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/package-lock.json create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/package.json create mode 100755 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/scripts/run-tests.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/cadScene.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/camera.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/displaySettings.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/headlessRenderEntry.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/render.html create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/renderEdges.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/renderMeshScene.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/renderModel.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/renderOptions.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/source.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/stepModule.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/stepModuleEffects.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/stepParameters.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/stepSidecars.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/stepTopology.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/themeSettings.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/topologyDisplayEdgeRuntime.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/topologyDisplayEdges.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/webglRenderer.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/index.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/assembly/meshData.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/async/concurrency.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/cadDirectoryScanner.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/cadManifestStore.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/cadRefs.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/displaySettings.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/dxf/buildPreviewMesh.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/dxf/parseDxf.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/entryAssets.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/fileFormats.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/gcode/buildPreviewMesh.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/gcode/parseGcode.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/generationStatus.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/pathUtils.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/perspective.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/glbMeshData.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/glbMeshWorker.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/glbMeshWorkerClient.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/meshCost.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/meshLoaders.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/meshTransfer.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/stlMeshData.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/stlMeshWorker.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/stlMeshWorkerClient.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/threeMfMeshData.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/renderAssetClient.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/selectors/runtime.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/step/pythonStepArtifact.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/step/stepArtifactCompiler.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/step/stepMetadata.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/step/stepModule.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/step/stepTree.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/stepRenderAssetClient.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/themeSettings.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/jointAnimation.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/kinematics.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/motion.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/moveit2ServerClient.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/parseSdf.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/parseSrdf.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/parseUrdf.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/clipPlane.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/constants.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/displayEdgePolicy.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/drawingCanvas.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/drawingGeometry.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/drawingTools.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/modelRuntime.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/partVisualState.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/pickingThresholds.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/referenceGeometry.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/renderQuality.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/sceneScale.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/screenshotCapture.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/selectorPickGroups.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/stageGrid.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/stageTheme.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/surfaceLineGeometry.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/surfaceMaterials.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/topologyDisplayEdgeLine.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/urdfPosePicker.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/webglSupport.js create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewerConfig.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewerServerInfo.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewerServerRegistry.mjs create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/pyproject.toml create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/__init__.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/analysis.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/api.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/assembly_composition.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/assembly_export.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/assembly_flatten.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/assembly_spec.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/cad_ref_syntax.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/catalog.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/cli_logging.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/file_metadata.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/generation.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/generation_status.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/glb.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/glb_mesh_payload.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/glb_topology.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/lookup.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/metadata.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/py.typed create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/render.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/reporting.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/selector_types.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/source_hash.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_artifact.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_artifacts.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_export.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_metadata.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_scene.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_targets.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/stl.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/threemf.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/validators.py create mode 100644 plugins/cad/skills/cad-viewer/scripts/viewer/requirements.txt create mode 100644 plugins/cad/skills/cad/LICENSE create mode 100644 plugins/cad/skills/cad/SKILL.md create mode 100644 plugins/cad/skills/cad/agents/openai.yaml create mode 100644 plugins/cad/skills/cad/assets/design-brief-template.md create mode 100644 plugins/cad/skills/cad/references/build123d-modeling.md create mode 100644 plugins/cad/skills/cad/references/dxf.md create mode 100644 plugins/cad/skills/cad/references/inspection-and-validation.md create mode 100644 plugins/cad/skills/cad/references/natural-language-specs.md create mode 100644 plugins/cad/skills/cad/references/parameters.md create mode 100644 plugins/cad/skills/cad/references/positioning.md create mode 100644 plugins/cad/skills/cad/references/repair-loop.md create mode 100644 plugins/cad/skills/cad/references/snapshot-review.md create mode 100644 plugins/cad/skills/cad/references/step-generation.md create mode 100644 plugins/cad/skills/cad/references/supported-exports.md create mode 100644 plugins/cad/skills/cad/requirements.txt create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/__init__.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/assembly_composition.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/assembly_export.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/assembly_flatten.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/assembly_spec.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/cad_ref_syntax.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/catalog.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/cli_logging.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/generation.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/glb.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/glb_mesh_payload.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/glb_topology.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/inspect_imports.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/metadata.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/package_path.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/render.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/reporting.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/selector_types.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/source_hash.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/step_artifacts.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/step_export.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/step_metadata.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/step_scene.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/step_targets.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/stl.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/cad_test_roots.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/test_assembly_composition.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/test_assembly_export.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/test_assembly_flatten.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/test_assembly_spec.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/test_generation.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/test_glb.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/test_step_metadata.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/test_step_scene.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/test_stl.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/test_threemf.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/tests/tmp_root.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/threemf.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_common/validators.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_dxf/__init__.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_dxf/__main__.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_dxf/cli.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_dxf/render_payload.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_dxf/tests/test_cli.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_dxf/tests/test_render_payload.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_inspect/__main__.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_inspect/cli.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_inspect/inspect_refs/__init__.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_inspect/inspect_refs/analysis.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_inspect/inspect_refs/cli.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_inspect/inspect_refs/inspect.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_inspect/inspect_refs/lookup.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_inspect/inspect_refs/tests/test_refs_inspect.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_inspect/tests/test_cli.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_snapshot/__init__.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_snapshot/__main__.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_snapshot/runtime/render.html create mode 100644 plugins/cad/skills/cad/scripts/cadpy_snapshot/runtime/snapshot-render.js create mode 100644 plugins/cad/skills/cad/scripts/cadpy_snapshot/tests/test_cli.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_step/__init__.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_step/__main__.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_step/cli.py create mode 100644 plugins/cad/skills/cad/scripts/cadpy_step/tests/test_cli.py create mode 100644 plugins/cad/skills/cad/scripts/dxf create mode 100644 plugins/cad/skills/cad/scripts/inspect create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/pyproject.toml create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/__init__.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/analysis.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/api.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/assembly_composition.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/assembly_export.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/assembly_flatten.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/assembly_spec.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/cad_ref_syntax.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/catalog.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/cli_logging.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/file_metadata.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/generation.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/generation_status.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/glb.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/glb_mesh_payload.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/glb_topology.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/lookup.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/metadata.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/py.typed create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/render.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/reporting.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/selector_types.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/source_hash.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/step_artifact.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/step_artifacts.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/step_export.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/step_metadata.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/step_scene.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/step_targets.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/stl.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/threemf.py create mode 100644 plugins/cad/skills/cad/scripts/packages/cadpy/src/cadpy/validators.py create mode 100644 plugins/cad/skills/cad/scripts/snapshot create mode 100644 plugins/cad/skills/cad/scripts/step delete mode 120000 plugins/cad/skills/gcode create mode 100644 plugins/cad/skills/gcode/LICENSE create mode 100644 plugins/cad/skills/gcode/SKILL.md create mode 100644 plugins/cad/skills/gcode/agents/openai.yaml create mode 100644 plugins/cad/skills/gcode/references/gcode-validation.md create mode 100644 plugins/cad/skills/gcode/references/slicer-backends.md create mode 100644 plugins/cad/skills/gcode/scripts/gcode_tool.py create mode 100644 plugins/cad/skills/gcode/scripts/test_gcode_tool.py delete mode 120000 plugins/cad/skills/sdf create mode 100644 plugins/cad/skills/sdf/LICENSE create mode 100644 plugins/cad/skills/sdf/SKILL.md create mode 100644 plugins/cad/skills/sdf/agents/openai.yaml create mode 100644 plugins/cad/skills/sdf/references/builder-helpers.md create mode 100644 plugins/cad/skills/sdf/references/design-ledger.md create mode 100644 plugins/cad/skills/sdf/references/examples.md create mode 100644 plugins/cad/skills/sdf/references/frame-semantics.md create mode 100644 plugins/cad/skills/sdf/references/gen-sdf.md create mode 100644 plugins/cad/skills/sdf/references/generator-contract.md create mode 100644 plugins/cad/skills/sdf/references/implementation-notes.md create mode 100644 plugins/cad/skills/sdf/references/interoperability.md create mode 100644 plugins/cad/skills/sdf/references/llm-guardrails.md create mode 100644 plugins/cad/skills/sdf/references/sdf-workflow.md create mode 100644 plugins/cad/skills/sdf/references/smoke-tests.md create mode 100644 plugins/cad/skills/sdf/references/validation.md create mode 100644 plugins/cad/skills/sdf/requirements.txt create mode 100644 plugins/cad/skills/sdf/scripts/packages/cadpy_metadata/pyproject.toml create mode 100644 plugins/cad/skills/sdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/__init__.py create mode 100644 plugins/cad/skills/sdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/generator.py create mode 100644 plugins/cad/skills/sdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/py.typed create mode 100644 plugins/cad/skills/sdf/scripts/sdf/__init__.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/__main__.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/builder.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/cli.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/external.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/findings.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/source.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/tests/__init__.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/tests/test_builder.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/tests/test_cli.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/tests/test_source.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/tests/test_validation.py create mode 100644 plugins/cad/skills/sdf/scripts/sdf/validation.py delete mode 120000 plugins/cad/skills/sendcutsend create mode 100644 plugins/cad/skills/sendcutsend/LICENSE create mode 100644 plugins/cad/skills/sendcutsend/SKILL.md create mode 100644 plugins/cad/skills/sendcutsend/agents/openai.yaml create mode 100644 plugins/cad/skills/sendcutsend/references/official-sources.md create mode 100644 plugins/cad/skills/sendcutsend/references/report-template.md delete mode 120000 plugins/cad/skills/srdf create mode 100644 plugins/cad/skills/srdf/LICENSE create mode 100644 plugins/cad/skills/srdf/SKILL.md create mode 100644 plugins/cad/skills/srdf/agents/openai.yaml create mode 100644 plugins/cad/skills/srdf/references/disabled-collisions.md create mode 100644 plugins/cad/skills/srdf/references/end-effectors.md create mode 100644 plugins/cad/skills/srdf/references/gen-srdf.md create mode 100644 plugins/cad/skills/srdf/references/generator-contract.md create mode 100644 plugins/cad/skills/srdf/references/implementation-notes.md create mode 100644 plugins/cad/skills/srdf/references/planning-ledger.md create mode 100644 plugins/cad/skills/srdf/references/srdf-workflow.md create mode 100644 plugins/cad/skills/srdf/references/validation.md create mode 100644 plugins/cad/skills/srdf/requirements.txt create mode 100644 plugins/cad/skills/srdf/scripts/packages/cadpy_metadata/pyproject.toml create mode 100644 plugins/cad/skills/srdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/__init__.py create mode 100644 plugins/cad/skills/srdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/generator.py create mode 100644 plugins/cad/skills/srdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/py.typed create mode 100644 plugins/cad/skills/srdf/scripts/srdf/__init__.py create mode 100644 plugins/cad/skills/srdf/scripts/srdf/__main__.py create mode 100644 plugins/cad/skills/srdf/scripts/srdf/cli.py create mode 100644 plugins/cad/skills/srdf/scripts/srdf/source.py create mode 100644 plugins/cad/skills/srdf/scripts/srdf/tests/__init__.py create mode 100644 plugins/cad/skills/srdf/scripts/srdf/tests/test_cli.py create mode 100644 plugins/cad/skills/srdf/scripts/srdf/tests/test_source.py delete mode 120000 plugins/cad/skills/step-parts create mode 100644 plugins/cad/skills/step-parts/LICENSE create mode 100644 plugins/cad/skills/step-parts/SKILL.md create mode 100644 plugins/cad/skills/step-parts/agents/openai.yaml create mode 100644 plugins/cad/skills/step-parts/references/step-parts-api.md create mode 100755 plugins/cad/skills/step-parts/scripts/download_step_part.py delete mode 120000 plugins/cad/skills/urdf create mode 100644 plugins/cad/skills/urdf/LICENSE create mode 100644 plugins/cad/skills/urdf/SKILL.md create mode 100644 plugins/cad/skills/urdf/agents/openai.yaml create mode 100644 plugins/cad/skills/urdf/references/design-ledger.md create mode 100644 plugins/cad/skills/urdf/references/frame-semantics.md create mode 100644 plugins/cad/skills/urdf/references/gen-urdf.md create mode 100644 plugins/cad/skills/urdf/references/generator-contract.md create mode 100644 plugins/cad/skills/urdf/references/urdf-workflow.md create mode 100644 plugins/cad/skills/urdf/references/validation.md create mode 100644 plugins/cad/skills/urdf/requirements.txt create mode 100644 plugins/cad/skills/urdf/scripts/packages/cadpy_metadata/pyproject.toml create mode 100644 plugins/cad/skills/urdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/__init__.py create mode 100644 plugins/cad/skills/urdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/generator.py create mode 100644 plugins/cad/skills/urdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/py.typed create mode 100644 plugins/cad/skills/urdf/scripts/urdf/__init__.py create mode 100644 plugins/cad/skills/urdf/scripts/urdf/__main__.py create mode 100644 plugins/cad/skills/urdf/scripts/urdf/cli.py create mode 100644 plugins/cad/skills/urdf/scripts/urdf/source.py create mode 100644 plugins/cad/skills/urdf/scripts/urdf/tests/__init__.py create mode 100644 plugins/cad/skills/urdf/scripts/urdf/tests/test_cli.py create mode 100644 plugins/cad/skills/urdf/scripts/urdf/tests/test_source.py delete mode 120000 skills/cad-viewer/scripts/viewer create mode 100644 skills/cad-viewer/scripts/viewer/.gitignore create mode 100755 skills/cad-viewer/scripts/viewer/backend/server.mjs create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/BufferGeometryUtils-xu92ooFc.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/BufferGeometryUtils-xu92ooFc.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/GLTFLoader-B3ztFMBW.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/GLTFLoader-B3ztFMBW.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/STLLoader-C7hGonJR.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/STLLoader-C7hGonJR.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/favicon-DLqji3p4.ico create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/glbMeshWorker-iyKraBym.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/glbMeshWorker-iyKraBym.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/index-ClRs8z4T.css create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/index-CxYr6aiy.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/index-CxYr6aiy.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/parseSdf-DaTRWVrj.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/parseSdf-DaTRWVrj.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/parseSrdf-5nF_MoHR.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/parseSrdf-5nF_MoHR.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/parseUrdf-DKAcUsKE.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/parseUrdf-DKAcUsKE.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/stlMeshWorker-0yVf-FuZ.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/stlMeshWorker-0yVf-FuZ.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/three.module-BB51Dq4E.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/three.module-BB51Dq4E.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/three.module-DJHaYUcg.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/three.module-DJHaYUcg.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/vendor-icons-CG23pCZa.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/vendor-icons-CG23pCZa.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/vendor-react-7jnMmQ9s.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/vendor-react-7jnMmQ9s.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/vendor-three-zG29gTWo.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/vendor-three-zG29gTWo.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/vendor-ui-CDgkaHGz.js create mode 100644 skills/cad-viewer/scripts/viewer/dist/assets/vendor-ui-CDgkaHGz.js.map create mode 100644 skills/cad-viewer/scripts/viewer/dist/index.html create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/__init__.py create mode 100755 skills/cad-viewer/scripts/viewer/moveit2_server/check-moveit2-server.sh create mode 100755 skills/cad-viewer/scripts/viewer/moveit2_server/conda-common.sh create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/environment.yml create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/__init__.py create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/context.py create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/dispatcher.py create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/joint_state_seed.py create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/moveit_py.py create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/protocol.py create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/server.py create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/moveit2_server/srdf_source.py create mode 100644 skills/cad-viewer/scripts/viewer/moveit2_server/pyproject.toml create mode 100755 skills/cad-viewer/scripts/viewer/moveit2_server/run-moveit2-server.sh create mode 100755 skills/cad-viewer/scripts/viewer/moveit2_server/setup.sh create mode 100644 skills/cad-viewer/scripts/viewer/package.json create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/package-lock.json create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/package.json create mode 100755 skills/cad-viewer/scripts/viewer/packages/cadjs/scripts/run-tests.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/cadScene.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/camera.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/displaySettings.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/headlessRenderEntry.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/render.html create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/renderEdges.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/renderMeshScene.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/renderModel.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/renderOptions.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/source.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/stepModule.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/stepModuleEffects.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/stepParameters.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/stepSidecars.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/stepTopology.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/themeSettings.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/topologyDisplayEdgeRuntime.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/topologyDisplayEdges.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/common/webglRenderer.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/index.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/assembly/meshData.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/async/concurrency.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/cadDirectoryScanner.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/cadManifestStore.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/cadRefs.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/displaySettings.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/dxf/buildPreviewMesh.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/dxf/parseDxf.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/entryAssets.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/fileFormats.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/gcode/buildPreviewMesh.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/gcode/parseGcode.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/generationStatus.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/pathUtils.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/perspective.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/glbMeshData.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/glbMeshWorker.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/glbMeshWorkerClient.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/meshCost.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/meshLoaders.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/meshTransfer.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/stlMeshData.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/stlMeshWorker.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/stlMeshWorkerClient.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/render/threeMfMeshData.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/renderAssetClient.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/selectors/runtime.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/step/pythonStepArtifact.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/step/stepArtifactCompiler.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/step/stepMetadata.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/step/stepModule.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/step/stepTree.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/stepRenderAssetClient.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/themeSettings.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/jointAnimation.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/kinematics.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/motion.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/moveit2ServerClient.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/parseSdf.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/parseSrdf.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/urdf/parseUrdf.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/clipPlane.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/constants.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/displayEdgePolicy.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/drawingCanvas.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/drawingGeometry.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/drawingTools.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/modelRuntime.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/partVisualState.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/pickingThresholds.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/referenceGeometry.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/renderQuality.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/sceneScale.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/screenshotCapture.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/selectorPickGroups.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/stageGrid.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/stageTheme.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/surfaceLineGeometry.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/surfaceMaterials.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/topologyDisplayEdgeLine.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/urdfPosePicker.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewer/webglSupport.js create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewerConfig.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewerServerInfo.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadjs/src/lib/viewerServerRegistry.mjs create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/pyproject.toml create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/__init__.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/analysis.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/api.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/assembly_composition.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/assembly_export.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/assembly_flatten.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/assembly_spec.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/cad_ref_syntax.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/catalog.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/cli_logging.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/file_metadata.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/generation.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/generation_status.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/glb.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/glb_mesh_payload.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/glb_topology.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/lookup.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/metadata.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/py.typed create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/render.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/reporting.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/selector_types.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/source_hash.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_artifact.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_artifacts.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_export.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_metadata.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_scene.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/step_targets.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/stl.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/threemf.py create mode 100644 skills/cad-viewer/scripts/viewer/packages/cadpy/src/cadpy/validators.py create mode 100644 skills/cad-viewer/scripts/viewer/requirements.txt delete mode 120000 skills/cad/scripts/packages/cadpy create mode 100644 skills/cad/scripts/packages/cadpy/pyproject.toml create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/__init__.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/analysis.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/api.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/assembly_composition.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/assembly_export.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/assembly_flatten.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/assembly_spec.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/cad_ref_syntax.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/catalog.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/cli_logging.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/file_metadata.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/generation.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/generation_status.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/glb.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/glb_mesh_payload.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/glb_topology.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/lookup.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/metadata.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/py.typed create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/render.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/reporting.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/selector_types.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/source_hash.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/step_artifact.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/step_artifacts.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/step_export.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/step_metadata.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/step_scene.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/step_targets.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/stl.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/threemf.py create mode 100644 skills/cad/scripts/packages/cadpy/src/cadpy/validators.py delete mode 120000 skills/sdf/scripts/packages/cadpy_metadata create mode 100644 skills/sdf/scripts/packages/cadpy_metadata/pyproject.toml create mode 100644 skills/sdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/__init__.py create mode 100644 skills/sdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/generator.py create mode 100644 skills/sdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/py.typed delete mode 120000 skills/srdf/scripts/packages/cadpy_metadata create mode 100644 skills/srdf/scripts/packages/cadpy_metadata/pyproject.toml create mode 100644 skills/srdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/__init__.py create mode 100644 skills/srdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/generator.py create mode 100644 skills/srdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/py.typed delete mode 120000 skills/urdf/scripts/packages/cadpy_metadata create mode 100644 skills/urdf/scripts/packages/cadpy_metadata/pyproject.toml create mode 100644 skills/urdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/__init__.py create mode 100644 skills/urdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/generator.py create mode 100644 skills/urdf/scripts/packages/cadpy_metadata/src/cadpy_metadata/py.typed delete mode 120000 viewer/packages/cadjs create mode 100644 viewer/packages/cadjs/README.md create mode 100644 viewer/packages/cadjs/docs/render-pipeline.md create mode 100644 viewer/packages/cadjs/package-lock.json create mode 100644 viewer/packages/cadjs/package.json create mode 100755 viewer/packages/cadjs/scripts/run-tests.mjs create mode 100644 viewer/packages/cadjs/src/common/cadScene.js create mode 100644 viewer/packages/cadjs/src/common/cadScene.test.js create mode 100644 viewer/packages/cadjs/src/common/camera.js create mode 100644 viewer/packages/cadjs/src/common/camera.test.js create mode 100644 viewer/packages/cadjs/src/common/displaySettings.js create mode 100644 viewer/packages/cadjs/src/common/displaySettings.test.js create mode 100644 viewer/packages/cadjs/src/common/headlessRenderEntry.js create mode 100644 viewer/packages/cadjs/src/common/render.html create mode 100644 viewer/packages/cadjs/src/common/renderEdges.js create mode 100644 viewer/packages/cadjs/src/common/renderEdges.test.js create mode 100644 viewer/packages/cadjs/src/common/renderMeshScene.js create mode 100644 viewer/packages/cadjs/src/common/renderMeshScene.test.js create mode 100644 viewer/packages/cadjs/src/common/renderModel.js create mode 100644 viewer/packages/cadjs/src/common/renderOptions.js create mode 100644 viewer/packages/cadjs/src/common/renderOptions.test.js create mode 100644 viewer/packages/cadjs/src/common/source.js create mode 100644 viewer/packages/cadjs/src/common/source.test.js create mode 100644 viewer/packages/cadjs/src/common/stepModule.js create mode 100644 viewer/packages/cadjs/src/common/stepModuleEffects.js create mode 100644 viewer/packages/cadjs/src/common/stepParameters.js create mode 100644 viewer/packages/cadjs/src/common/stepSidecars.mjs create mode 100644 viewer/packages/cadjs/src/common/stepTopology.mjs create mode 100644 viewer/packages/cadjs/src/common/themeSettings.js create mode 100644 viewer/packages/cadjs/src/common/topologyDisplayEdgeRuntime.js create mode 100644 viewer/packages/cadjs/src/common/topologyDisplayEdgeRuntime.test.js create mode 100644 viewer/packages/cadjs/src/common/topologyDisplayEdges.js create mode 100644 viewer/packages/cadjs/src/common/topologyDisplayEdges.test.js create mode 100644 viewer/packages/cadjs/src/common/webglRenderer.js create mode 100644 viewer/packages/cadjs/src/common/webglRenderer.test.js create mode 100644 viewer/packages/cadjs/src/index.js create mode 100644 viewer/packages/cadjs/src/lib/assembly/meshData.js create mode 100644 viewer/packages/cadjs/src/lib/assembly/meshData.test.js create mode 100644 viewer/packages/cadjs/src/lib/async/concurrency.js create mode 100644 viewer/packages/cadjs/src/lib/async/concurrency.test.js create mode 100644 viewer/packages/cadjs/src/lib/cadDirectoryScanner.mjs create mode 100644 viewer/packages/cadjs/src/lib/cadDirectoryScanner.test.mjs create mode 100644 viewer/packages/cadjs/src/lib/cadManifestStore.js create mode 100644 viewer/packages/cadjs/src/lib/cadManifestStore.test.js create mode 100644 viewer/packages/cadjs/src/lib/cadRefs.js create mode 100644 viewer/packages/cadjs/src/lib/displaySettings.js create mode 100644 viewer/packages/cadjs/src/lib/dxf/buildPreviewMesh.js create mode 100644 viewer/packages/cadjs/src/lib/dxf/buildPreviewMesh.test.js create mode 100644 viewer/packages/cadjs/src/lib/dxf/parseDxf.js create mode 100644 viewer/packages/cadjs/src/lib/dxf/parseDxf.test.js create mode 100644 viewer/packages/cadjs/src/lib/entryAssets.js create mode 100644 viewer/packages/cadjs/src/lib/entryAssets.test.js create mode 100644 viewer/packages/cadjs/src/lib/fileFormats.js create mode 100644 viewer/packages/cadjs/src/lib/fileFormats.test.js create mode 100644 viewer/packages/cadjs/src/lib/gcode/buildPreviewMesh.js create mode 100644 viewer/packages/cadjs/src/lib/gcode/parseGcode.js create mode 100644 viewer/packages/cadjs/src/lib/gcode/parseGcode.test.js create mode 100644 viewer/packages/cadjs/src/lib/generationStatus.mjs create mode 100644 viewer/packages/cadjs/src/lib/generationStatus.test.mjs create mode 100644 viewer/packages/cadjs/src/lib/pathUtils.mjs create mode 100644 viewer/packages/cadjs/src/lib/pathUtils.test.mjs create mode 100644 viewer/packages/cadjs/src/lib/perspective.js create mode 100644 viewer/packages/cadjs/src/lib/perspective.test.js create mode 100644 viewer/packages/cadjs/src/lib/render/glbMeshData.js create mode 100644 viewer/packages/cadjs/src/lib/render/glbMeshData.test.js create mode 100644 viewer/packages/cadjs/src/lib/render/glbMeshWorker.js create mode 100644 viewer/packages/cadjs/src/lib/render/glbMeshWorkerClient.js create mode 100644 viewer/packages/cadjs/src/lib/render/glbMeshWorkerClient.test.js create mode 100644 viewer/packages/cadjs/src/lib/render/meshCost.js create mode 100644 viewer/packages/cadjs/src/lib/render/meshCost.test.js create mode 100644 viewer/packages/cadjs/src/lib/render/meshLoaders.js create mode 100644 viewer/packages/cadjs/src/lib/render/meshLoaders.test.js create mode 100644 viewer/packages/cadjs/src/lib/render/meshTransfer.js create mode 100644 viewer/packages/cadjs/src/lib/render/stlMeshData.js create mode 100644 viewer/packages/cadjs/src/lib/render/stlMeshData.test.js create mode 100644 viewer/packages/cadjs/src/lib/render/stlMeshWorker.js create mode 100644 viewer/packages/cadjs/src/lib/render/stlMeshWorkerClient.js create mode 100644 viewer/packages/cadjs/src/lib/render/threeMfMeshData.js create mode 100644 viewer/packages/cadjs/src/lib/render/threeMfMeshData.test.js create mode 100644 viewer/packages/cadjs/src/lib/renderAssetClient.js create mode 100644 viewer/packages/cadjs/src/lib/renderAssetClient.test.js create mode 100644 viewer/packages/cadjs/src/lib/selectors/runtime.js create mode 100644 viewer/packages/cadjs/src/lib/selectors/runtime.test.js create mode 100644 viewer/packages/cadjs/src/lib/step/pythonStepArtifact.mjs create mode 100644 viewer/packages/cadjs/src/lib/step/stepArtifactCompiler.mjs create mode 100644 viewer/packages/cadjs/src/lib/step/stepArtifactCompiler.test.mjs create mode 100644 viewer/packages/cadjs/src/lib/step/stepMetadata.mjs create mode 100644 viewer/packages/cadjs/src/lib/step/stepModule.js create mode 100644 viewer/packages/cadjs/src/lib/step/stepModule.test.js create mode 100644 viewer/packages/cadjs/src/lib/step/stepTree.js create mode 100644 viewer/packages/cadjs/src/lib/step/stepTree.test.js create mode 100644 viewer/packages/cadjs/src/lib/stepRenderAssetClient.js create mode 100644 viewer/packages/cadjs/src/lib/themeSettings.js create mode 100644 viewer/packages/cadjs/src/lib/themeSettings.test.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/jointAnimation.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/jointAnimation.test.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/kinematics.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/kinematics.test.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/motion.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/motion.test.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/moveit2ServerClient.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/moveit2ServerClient.test.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/parseSdf.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/parseSdf.test.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/parseSrdf.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/parseSrdf.test.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/parseUrdf.js create mode 100644 viewer/packages/cadjs/src/lib/urdf/parseUrdf.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/clipPlane.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/clipPlane.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/constants.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/displayEdgePolicy.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/displayEdgePolicy.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/drawingCanvas.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/drawingCanvas.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/drawingGeometry.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/drawingGeometry.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/drawingTools.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/modelRuntime.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/modelRuntime.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/partVisualState.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/partVisualState.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/pickingThresholds.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/referenceGeometry.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/referenceGeometry.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/renderQuality.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/renderQuality.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/sceneScale.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/sceneScale.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/screenshotCapture.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/screenshotCapture.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/selectorPickGroups.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/selectorPickGroups.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/stageGrid.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/stageGrid.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/stageTheme.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/stageTheme.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/surfaceLineGeometry.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/surfaceLineGeometry.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/surfaceMaterials.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/surfaceMaterials.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/topologyDisplayEdgeLine.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/topologyDisplayEdgeLine.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/urdfPosePicker.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/urdfPosePicker.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/webglSupport.js create mode 100644 viewer/packages/cadjs/src/lib/viewer/webglSupport.test.js create mode 100644 viewer/packages/cadjs/src/lib/viewerConfig.mjs create mode 100644 viewer/packages/cadjs/src/lib/viewerConfig.test.mjs create mode 100644 viewer/packages/cadjs/src/lib/viewerServerInfo.mjs create mode 100644 viewer/packages/cadjs/src/lib/viewerServerInfo.test.mjs create mode 100644 viewer/packages/cadjs/src/lib/viewerServerRegistry.mjs delete mode 120000 viewer/packages/cadpy create mode 100644 viewer/packages/cadpy/pyproject.toml create mode 100644 viewer/packages/cadpy/src/cadpy/__init__.py create mode 100644 viewer/packages/cadpy/src/cadpy/analysis.py create mode 100644 viewer/packages/cadpy/src/cadpy/api.py create mode 100644 viewer/packages/cadpy/src/cadpy/assembly_composition.py create mode 100644 viewer/packages/cadpy/src/cadpy/assembly_export.py create mode 100644 viewer/packages/cadpy/src/cadpy/assembly_flatten.py create mode 100644 viewer/packages/cadpy/src/cadpy/assembly_spec.py create mode 100644 viewer/packages/cadpy/src/cadpy/cad_ref_syntax.py create mode 100644 viewer/packages/cadpy/src/cadpy/catalog.py create mode 100644 viewer/packages/cadpy/src/cadpy/cli_logging.py create mode 100644 viewer/packages/cadpy/src/cadpy/file_metadata.py create mode 100644 viewer/packages/cadpy/src/cadpy/generation.py create mode 100644 viewer/packages/cadpy/src/cadpy/generation_status.py create mode 100644 viewer/packages/cadpy/src/cadpy/glb.py create mode 100644 viewer/packages/cadpy/src/cadpy/glb_mesh_payload.py create mode 100644 viewer/packages/cadpy/src/cadpy/glb_topology.py create mode 100644 viewer/packages/cadpy/src/cadpy/lookup.py create mode 100644 viewer/packages/cadpy/src/cadpy/metadata.py create mode 100644 viewer/packages/cadpy/src/cadpy/py.typed create mode 100644 viewer/packages/cadpy/src/cadpy/render.py create mode 100644 viewer/packages/cadpy/src/cadpy/reporting.py create mode 100644 viewer/packages/cadpy/src/cadpy/selector_types.py create mode 100644 viewer/packages/cadpy/src/cadpy/source_hash.py create mode 100644 viewer/packages/cadpy/src/cadpy/step_artifact.py create mode 100644 viewer/packages/cadpy/src/cadpy/step_artifacts.py create mode 100644 viewer/packages/cadpy/src/cadpy/step_export.py create mode 100644 viewer/packages/cadpy/src/cadpy/step_metadata.py create mode 100644 viewer/packages/cadpy/src/cadpy/step_scene.py create mode 100644 viewer/packages/cadpy/src/cadpy/step_targets.py create mode 100644 viewer/packages/cadpy/src/cadpy/stl.py create mode 100644 viewer/packages/cadpy/src/cadpy/threemf.py create mode 100644 viewer/packages/cadpy/src/cadpy/validators.py diff --git a/plugins/cad/skills/bambu-labs b/plugins/cad/skills/bambu-labs deleted file mode 120000 index 8ef6e683..00000000 --- a/plugins/cad/skills/bambu-labs +++ /dev/null @@ -1 +0,0 @@ -../../../skills/bambu-labs \ No newline at end of file diff --git a/plugins/cad/skills/bambu-labs/LICENSE b/plugins/cad/skills/bambu-labs/LICENSE new file mode 100644 index 00000000..eabcff2c --- /dev/null +++ b/plugins/cad/skills/bambu-labs/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 earthtojake + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/cad/skills/bambu-labs/SKILL.md b/plugins/cad/skills/bambu-labs/SKILL.md new file mode 100644 index 00000000..e9bc7154 --- /dev/null +++ b/plugins/cad/skills/bambu-labs/SKILL.md @@ -0,0 +1,209 @@ +--- +name: bambu-labs +description: Dry-run, upload, and cautiously initiate local Bambu Lab print jobs from validated plain `.gcode`, using Bambu LAN FTPS/MQTT handoffs. +--- + +# Bambu Labs + +Provenance: maintained in [earthtojake/text-to-cad](https://github.com/earthtojake/text-to-cad). +Use the installed local skill files as the runtime source of truth; the +repository link is only for provenance and release review. + +Use this skill for local-network Bambu Lab print handoffs after a plain `.gcode` +file already exists and has been validated. This skill does not slice models. + +## Safety Rules + +- Default to dry-run plans. Real printer traffic requires `--execute`. +- Never start a print without `--execute --confirm-start-print`. +- Pause and cancel controls are live printer requests; default to dry-run plans. + Canceling a print requires `--execute --confirm-cancel-print`. +- Treat an explicit user request to print or start a specific job as live-start + authorization; do not pause for a second confirmation solely for physical + checks. Still validate the G-code, inspect the dry-run payload, read printer + status, prefer upload-only before upload-start, state the physical checks, and + stop if validation/status/intent is unsafe or ambiguous. +- Do not ask for the printer serial by default; fetch it from the printer TLS certificate with `serial` or let `send` cache it. +- Prefer workspace-root `bambu-printers.json` over repeating access codes in commands. The file is local config and should be ignored by Git. +- Before a live start, state the physical checks: clear build plate, correct plate/filament/nozzle, safe surroundings, and operator nearby. +- Publishing MQTT is only a start request. Confirm acceptance with printer status/UI and physical observation. + +## CAD Viewer Handoff + +After completing Bambu work that creates or modifies a local supported print artifact such as `.gcode` or `.3mf`, you must ALWAYS hand the explicit file path to `$cad-viewer` when that skill is installed. `$cad-viewer` must start CAD Viewer if it is not already running and return link(s) to the relevant created or updated file(s); if `$cad-viewer` is unavailable or startup fails, report that instead of silently omitting the handoff. + +## Workflow + +1. Generate and validate plain G-code with `$gcode`. + If no slicer is installed, install OrcaSlicer and retry; do not treat the missing slicer as a blocker. On macOS, prefer `brew install --cask orcaslicer`. +2. Configure the printer. The user can either give the IP/access code in the thread and let the agent write JSON, or edit `bambu-printers.json` directly. + For a new printer setup or onboarding request, read + `references/new-printer-onboarding.md` first. Walk the user through the + model-specific touchscreen steps to find the IP and LAN access code, and make + **Enable LAN Only** plus **Enable Developer Mode** explicit before running + local start workflows. + +```bash +python scripts/bambu_lan_print.py config set \ + --printer a1-mini \ + --host 192.168.1.34 \ + --access-code 12345678 \ + --model a1-mini \ + --fetch-serial +``` + +Manual JSON shape: + +```json +{ + "printers": { + "a1-mini": { + "host": "192.168.1.34", + "access_code": "12345678", + "model": "a1-mini" + } + } +} +``` + +On A1/A1 Mini, find the IP and LAN access code on the printer touchscreen under +network/LAN settings. Enable LAN Only and Developer Mode when offered, then +power-cycle before retrying local start commands. + +3. Read status before live work: + +```bash +python scripts/bambu_lan_print.py status \ + --printer a1-mini \ + --push-all \ + --wait-seconds 10 +``` + +4. Dry-run the exact handoff, inspect the JSON payload, then run upload-only. +Only after upload succeeds should you run upload-start. If the user explicitly +asked to print or start the job, proceed to `upload-start --execute +--confirm-start-print` after the validation, status, and upload checks pass. If +the user only asked to prepare, slice, upload, or review, stop before the start +request. + +## Handoff Modes + +`--handoff template-project` is the validated A1 Mini path from this repo's LAN +debugging. It starts from validated plain `.gcode`, copies a known-good +same-printer `.gcode.3mf` template, replaces `Metadata/plate_N.gcode`, writes +the plate MD5, uploads the project to the FTPS root, and publishes +`print.project_file` with `url: ftp:///.gcode.3mf`. + +```bash +python scripts/bambu_lan_print.py send \ + --printer a1-mini \ + --gcode /tmp/job.gcode \ + --handoff template-project \ + --template-project /path/to/same-printer-template.gcode.3mf \ + --action upload-start +``` + +Execute after review when the user explicitly asked to print or start, or after +physical confirmation when intent is unclear: + +```bash +python scripts/bambu_lan_print.py send \ + --printer a1-mini \ + --gcode /tmp/job.gcode \ + --handoff template-project \ + --template-project /path/to/same-printer-template.gcode.3mf \ + --action upload-start \ + --execute \ + --confirm-start-print +``` + +`--handoff plain` uploads `cache/.gcode` and publishes +`print.gcode_file`. Keep it for diagnostics or printers/firmware where this is +known to work. On the tested A1 Mini, direct plain G-code was uploaded +successfully but `gcode_file` failed or was ignored, so do not use it as the +A1 Mini live-start path. + +`--handoff bambox-project` packages plain `.gcode` with `bambox`, uploads the +`.gcode.3mf` project to FTPS root, and publishes `print.project_file`. +Currently enabled only for `p1s-0.4` with `PLA`, `ASA`, or `PETG-CF`. +Known but disabled until validated profiles exist: `a1-mini-0.4`, `a1-0.4`, +`x1c-0.4`, and `p1p-0.4`. + +## Common Debugging Commands + +Fetch/cache serial: + +```bash +python scripts/bambu_lan_print.py serial \ + --printer a1-mini \ + --json +``` + +Clear a stale printer error after fixing the underlying cause: + +```bash +python scripts/bambu_lan_print.py clear-error \ + --printer a1-mini \ + --execute +``` + +Use `--mqtt-qos 1 --wait-after-publish 10` on `send` when debugging whether the +printer acknowledged the MQTT publish and what status it reported immediately +afterward. + +## Print Controls + +For a running print, use dedicated print-control commands rather than ad hoc +MQTT snippets. These commands publish only a control request; they do not upload +files or start a new job. Read status after execution to confirm the printer +state changed. + +Dry-run pause payload: + +```bash +python scripts/bambu_lan_print.py pause \ + --printer a1-mini +``` + +Execute pause and collect printer reports: + +```bash +python scripts/bambu_lan_print.py pause \ + --printer a1-mini \ + --execute \ + --mqtt-qos 1 \ + --wait-after-publish 10 +``` + +Dry-run cancel payload. The Bambu LAN command sent to the printer is `stop`: + +```bash +python scripts/bambu_lan_print.py cancel \ + --printer a1-mini +``` + +Execute cancel only when the user explicitly asks to cancel/stop the print or +after confirmation when intent is ambiguous: + +```bash +python scripts/bambu_lan_print.py cancel \ + --printer a1-mini \ + --execute \ + --confirm-cancel-print \ + --mqtt-qos 1 \ + --wait-after-publish 10 +``` + +## Failure Modes + +- `gcode_file` returns `result: fail` or leaves the printer `IDLE`: plain G-code upload worked, but the firmware rejected or ignored direct local start. For A1 Mini, switch to `template-project`. +- Project uploaded under `cache/` starts then fails with `print_error: 83935248` or `0500-C010`: clear the error, upload project handoffs to FTPS root, and use `ftp:///.gcode.3mf`. +- `file:///sdcard/cache/...` or local HTTP URLs appear accepted but nothing starts: stop using those URL forms for this workflow. +- Bambu Studio or OrcaSlicer project export crashes on macOS: do not keep retrying GUI-backed project export. Use OrcaSlicer for plain `.gcode`, then this skill for handoff. +- Stale `gcode_state: FAILED` or HMS after enabling Developer Mode: clear the printer error and power-cycle before retrying. +- FTPS login works but upload fails with `553` or missing `cache/`: check printer storage/SD card status before MQTT start. +- MQTT status works but start does not: confirm serial, access code, Developer Mode/LAN Only status, and the exact handoff payload before retrying. + +Read `references/new-printer-onboarding.md` for new printer setup, +`references/local-lan-protocol.md` for protocol details, and +`references/real-printer-checklist.md` before first live use on a new printer. diff --git a/plugins/cad/skills/bambu-labs/agents/openai.yaml b/plugins/cad/skills/bambu-labs/agents/openai.yaml new file mode 100644 index 00000000..53d49ceb --- /dev/null +++ b/plugins/cad/skills/bambu-labs/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Bambu Labs" + short_description: "Dry-run and start local Bambu G-code handoffs" + default_prompt: "Use $bambu-labs to dry-run a validated plain G-code handoff before starting it." diff --git a/plugins/cad/skills/bambu-labs/references/local-lan-protocol.md b/plugins/cad/skills/bambu-labs/references/local-lan-protocol.md new file mode 100644 index 00000000..fe4802a9 --- /dev/null +++ b/plugins/cad/skills/bambu-labs/references/local-lan-protocol.md @@ -0,0 +1,123 @@ +# Bambu Lab Local LAN Protocol Notes + +Use this reference only when planning or debugging against a real local printer. +Bambu does not provide this skill with a stable public local-print API +contract, so treat these as observed FTPS/MQTT behaviors. + +## Required Inputs + +- Validated plain `.gcode`. +- Printer LAN IP/hostname. +- Printer access code. +- Printer serial for MQTT topic `device/{serial}/request`; fetch it from the + printer TLS certificate with `serial` or let `send` fetch/cache it. +- Handoff mode: `template-project`, `plain`, or `bambox-project`. + +Workspace-root `bambu-printers.json` stores printer IDs, hostnames, access codes, models, +and cached serials. It is local config and should be ignored by Git. + +## Transport + +- FTPS upload: implicit TLS on port `990`. +- MQTT control/status: TLS on port `8883`. +- Username: `bblp`. +- Password: printer access code. +- TLS verification is off by default because local printers commonly use + device/self-signed certificates. +- The helper rejects public IPs/hostnames unless `--allow-nonprivate-host` is + set. +- FTPS data connections may require TLS session reuse. The helper reuses the + control TLS session for uploads and listings. + +## MQTT Topics + +- Request topic: `device/{serial}/request`. +- Report topic: `device/{serial}/report`. +- `status --push-all` subscribes to reports, then publishes `pushing.pushall` + to request a full state report. +- Publishing a start payload is a request, not proof of accepted motion. + +## Handoff Payloads + +### Template Project + +Validated on an A1 Mini during local LAN debugging: + +1. Start from a validated plain `.gcode`. +2. Copy a known-good same-printer `.gcode.3mf` template. +3. Replace `Metadata/plate_N.gcode` and update `Metadata/plate_N.gcode.md5`. +4. Upload the resulting `.gcode.3mf` to FTPS root, not `cache/`. +5. Publish `print.project_file` with root FTP URL. + +Representative payload: + +```json +{ + "print": { + "command": "project_file", + "param": "Metadata/plate_1.gcode", + "project_id": "0", + "profile_id": "0", + "task_id": "0", + "subtask_id": "0", + "subtask_name": "job", + "url": "ftp:///job.gcode.3mf", + "md5": "PROJECT_MD5_UPPERCASE", + "timelapse": false, + "bed_type": "auto", + "bed_levelling": true, + "flow_cali": true, + "vibration_cali": false, + "layer_inspect": true, + "use_ams": false, + "ams_mapping": "" + } +} +``` + +### Plain G-code + +The plain path uploads `cache/.gcode` and publishes: + +```json +{ + "print": { + "command": "gcode_file", + "param": "cache/job.gcode" + } +} +``` + +On the tested A1 Mini, byte-for-byte verified uploads still produced +`gcode_file` failure/idle behavior. Use this path only for diagnostics or +printer firmware where it has been validated. + +### Bambox Project + +The optional `bambox-project` path packages plain G-code into `.gcode.3mf` for +enabled profiles, validates the archive, uploads it to FTPS root, and publishes +the same `project_file` shape as template projects. Current enabled profile is +`p1s-0.4`; A1/A1 Mini are disabled until a validated bambox profile exists. + +## Observed Failure Modes + +- **Direct G-code rejected:** MQTT report after `gcode_file` may include + `{"command":"gcode_file","result":"fail","reason":"error string"}`. Stop and + use a project handoff. +- **Direct G-code ignored:** uploaded file exists, HMS is empty, target + temperatures stay at zero, and `gcode_state` remains `IDLE`. Do not keep + cycling path variants. +- **Project in `cache/` fails:** `project_file` can be accepted and then fail + with `print_error: 83935248` / `0500-C010`. Clear the error and upload project + files to FTPS root with `ftp:///.gcode.3mf`. +- **HTTP/file URLs inert:** `file:///sdcard/cache/...` and local HTTP URLs may + be accepted without fetching or starting. Do not use them for this workflow. +- **Bambu/Orca project export crash:** GUI-backed CLI project export on macOS + can crash inside AppKit/BambuStudio. Use slicer CLI only for plain `.gcode`. +- **Stale printer state:** after LAN Only/Developer Mode changes, clear errors + and power-cycle. Status can retain stale `FAILED`/HMS values. +- **Storage unavailable:** if FTPS auth works but upload fails with `553`, or + status reports no SD/storage, resolve storage before MQTT start. + +Use `clear-error --execute` only after the underlying cause is fixed. It +publishes `print.clean_print_error` and does not start motion. diff --git a/plugins/cad/skills/bambu-labs/references/new-printer-onboarding.md b/plugins/cad/skills/bambu-labs/references/new-printer-onboarding.md new file mode 100644 index 00000000..6538124c --- /dev/null +++ b/plugins/cad/skills/bambu-labs/references/new-printer-onboarding.md @@ -0,0 +1,139 @@ +# New Printer Onboarding + +Use this reference whenever the user asks to set up, add, pair, configure, or +test a new Bambu Lab printer for local LAN handoff. The goal is a calm, +step-by-step setup where the user always knows what is safe, what is private, +and what the agent will do next. + +## Agent Flow + +1. Start by confirming this is setup only. Say that no upload or print will + happen during onboarding unless the user explicitly asks later. +2. Ask for the printer model or family if it is not already known. Use a stable + local printer id such as `a1-mini`, `a1`, `p1s`, `p1p`, `x1c`, or `h2d`. +3. Tell the user you need two values from the printer touchscreen: + printer IP address and LAN access code. Explain that the serial is fetched + from the printer certificate and should not be requested by default. +4. Immediately give the model-specific touchscreen steps below. Do not just ask + for the IP and access code without helping the user find them. +5. Make the LAN prerequisites very explicit: the user must **Enable LAN Only** + and **Enable Developer Mode** before live local start commands. If either + option exists and is off, stop setup and ask them to enable it first. +6. After the user provides the IP and access code, store them with `config set` + in workspace-root `bambu-printers.json`, using `--fetch-serial`. Do not repeat the + access code in the final response. +7. Run `status --push-all --wait-seconds 10` and summarize the result in plain + language: reachable or not, idle/running/error, SD/storage present, and any + `print_error` or HMS entries. +8. If setup succeeds, offer the next safe step as a dry-run handoff plan. Do not + upload or start anything during onboarding unless the user explicitly asks. + +## What To Say First + +Use a short, reassuring prompt like this: + +```text +I can set this up safely. I need the printer's LAN IP address and LAN access +code from the touchscreen. Before you send them, please enable LAN Only and +Developer Mode; local starts often fail or become read-only if Developer Mode is +off. I will store the code only in the workspace-local ignored config and fetch the +serial from the printer automatically. +``` + +Then give the matching steps for their printer family. + +## Touchscreen Steps By Printer Family + +### A1 / A1 Mini + +1. On the printer touchscreen, open **Settings**. +2. Open **Network** or **WLAN**. +3. Connect the printer to the same trusted local network as this computer. +4. **Enable LAN Only**. +5. **Enable Developer Mode** in the same network/LAN area when shown. +6. Record the IPv4 address shown on the network screen. +7. Record the LAN access code shown near the LAN Only or Developer Mode + controls. If it is all zeros, refresh/regenerate it or toggle LAN Only off + and on, then record the new code. +8. Power-cycle the printer after changing LAN Only or Developer Mode. + +### P1P / P1S + +1. On the printer screen, open **Settings**. +2. Open **Network** or **WLAN**. +3. Confirm the printer is on the same trusted local network as this computer. +4. **Enable LAN Only**. +5. **Enable Developer Mode**. If it is not visible, update firmware or stop + before live local start workflows. +6. Record the printer IPv4 address. +7. Record the LAN access code. If the code is all zeros or blank, refresh it or + toggle LAN Only off and on, then record the new code. +8. Power-cycle the printer before the first local status check. + +### X1 / X1C / X1E + +1. On the printer touchscreen, open **Settings**. +2. Open **Network** or **WLAN**. +3. Confirm the printer is connected to the same trusted local network. +4. **Enable LAN Only**. +5. **Enable Developer Mode**. If it is not visible, update firmware or stop + before live local start workflows. +6. Record the IPv4 address. +7. Record the LAN access code from the LAN/network screen. +8. Power-cycle the printer after changing LAN settings. + +### H2D / Newer Bambu Printers + +1. Open **Settings** on the printer touchscreen. +2. Open **Network**, **WLAN**, or the printer's LAN settings panel. +3. Confirm local network connectivity. +4. **Enable LAN Only**. +5. **Enable Developer Mode**. +6. Record the IPv4 address and LAN access code. +7. Power-cycle after changing LAN settings. + +For an unknown Bambu model, guide the user to the printer's network/WLAN +settings, then require the same four items before continuing: same local +network, **Enable LAN Only**, **Enable Developer Mode**, and collect IP plus +LAN access code. + +## Agent Commands + +Use the active Python environment: + +```bash +python scripts/bambu_lan_print.py config set \ + --printer a1-mini \ + --host 192.168.1.34 \ + --access-code 12345678 \ + --model a1-mini \ + --fetch-serial +``` + +Then check status: + +```bash +python scripts/bambu_lan_print.py status \ + --printer a1-mini \ + --push-all \ + --wait-seconds 10 +``` + +Use the model-specific printer id in both commands. If sandboxing blocks local +network access, rerun the same command with permission to contact the printer. + +## Smooth Failure Handling + +- If the printer is unreachable, ask the user to confirm the IP, same Wi-Fi or + VLAN reachability, and that the printer is awake. +- If MQTT status fails but TLS serial fetch worked, first confirm **Developer + Mode** is enabled, then power-cycle and retry status. +- If the access code is rejected or all zeros, ask the user to refresh the LAN + access code on the printer and rerun `config set --fetch-serial`. +- If status returns stale `FAILED`, `print_error`, or HMS entries after enabling + LAN Only or Developer Mode, stop. Ask the user to resolve the physical issue, + power-cycle, then retry status. Use `clear-error --execute` only after the + underlying cause is fixed. +- If setup succeeds, do not imply that live printing is validated. Say that LAN + connectivity is configured and status works; live printing still requires the + real-printer checklist, a dry-run plan, upload-only, and supervised start. diff --git a/plugins/cad/skills/bambu-labs/references/real-printer-checklist.md b/plugins/cad/skills/bambu-labs/references/real-printer-checklist.md new file mode 100644 index 00000000..362ff4b3 --- /dev/null +++ b/plugins/cad/skills/bambu-labs/references/real-printer-checklist.md @@ -0,0 +1,56 @@ +# Real Printer Checklist + +Use this before any `--execute` run against a physical Bambu Lab printer. + +## Credentials And Network + +- Confirm the printer IP/hostname is on the trusted local network. +- Confirm LAN Only/Developer Mode is enabled when the printer exposes it, + especially on A1/A1 Mini. +- Store the access code in workspace-root `bambu-printers.json` with `config set`; do not + print it in final messages. +- Fetch/cache serial with `serial` or `config set --fetch-serial`. +- Run `status --push-all` and verify the intended printer responds. +- If LAN settings changed after failed starts, clear stale errors and + power-cycle before retrying. + +## Job + +- Confirm `$gcode` generated and validated the plain `.gcode`. +- Confirm scale, orientation, supports, material profile, nozzle, and bed type. +- For A1 Mini LAN start, prefer `--handoff template-project` with a known-good + same-printer `.gcode.3mf` template. +- Use `--handoff plain` only for diagnostics or firmware where `gcode_file` is + already validated. +- Use `--handoff bambox-project` only when the exact printer/nozzle profile is + enabled by the script. +- For project handoffs, upload to FTPS root and use `ftp:///.gcode.3mf`. + +## Physical Printer + +If the current user request explicitly asks to print or start the job, treat that +request as live-start authorization for this checklist. State these physical +checks before the live command and proceed if automated validation and printer +status are healthy. Ask for another confirmation only when the request intent is +ambiguous or a validation/status check raises concern. + +- Build plate is installed, clear, clean, and appropriate for the material. +- No failed-print remnants, loose tools, tape scraps, or debris are in the + printer. +- Filament is loaded and appropriate for the sliced file. +- Operator is nearby for heat-up, homing, and first-layer observation. +- Camera or direct observation is available. + +## First Live Sequence + +1. Run the exact `send` command without `--execute` and inspect the plan. +2. Run `send --action upload --execute` first. +3. Check status/UI/storage if possible. +4. Re-run the dry `send --action upload-start` plan. +5. Run `send --action upload-start --execute --confirm-start-print` when the + user explicitly asked to print/start, or after confirmation when intent is + unclear. +6. Poll status and watch the printer until the first layer is clearly normal. + +If status reports `print_error` or HMS after a failed attempt, stop. Resolve the +cause, optionally run `clear-error --execute`, then poll status before retrying. diff --git a/plugins/cad/skills/bambu-labs/scripts/bambu_lan_print.py b/plugins/cad/skills/bambu-labs/scripts/bambu_lan_print.py new file mode 100644 index 00000000..f5da8fd8 --- /dev/null +++ b/plugins/cad/skills/bambu-labs/scripts/bambu_lan_print.py @@ -0,0 +1,1771 @@ +#!/usr/bin/env python3 +"""Dry-run-first helpers for local Bambu Lab print workflows. + +The default behavior is non-networked. Start from a validated plain .gcode file, +then either upload/start it directly with the printer's gcode_file command or, +for explicitly supported printer profiles, package it with bambox into a +.gcode.3mf project and start that with project_file. +""" + +from __future__ import annotations + +import argparse +import ftplib +import hashlib +import ipaddress +import json +import os +import re +import shutil +import socket +import ssl +import subprocess +import sys +import tempfile +import time +import zipfile +from dataclasses import asdict, dataclass +from pathlib import Path +from typing import Any, Union + + +BAMBU_USERNAME = "bblp" +DEFAULT_FTPS_PORT = 990 +DEFAULT_MQTT_PORT = 8883 +DEFAULT_REMOTE_DIR = "cache" +PLATE_RE = re.compile(r"^Metadata/plate_(\d+)\.gcode$") +IPAddress = Union[ipaddress.IPv4Address, ipaddress.IPv6Address] + + +def default_workspace_root() -> Path: + init_cwd = str(os.environ.get("INIT_CWD") or "").strip() + return Path(init_cwd).expanduser().resolve() if init_cwd else Path.cwd().resolve() + + +DEFAULT_CONFIG_PATH = default_workspace_root() / "bambu-printers.json" + + +class BambuPrintError(RuntimeError): + """Raised for expected user-facing workflow errors.""" + + +@dataclass(frozen=True) +class GCodeInspection: + path: str + size_bytes: int + md5: str + + +@dataclass(frozen=True) +class PlateInfo: + index: int + path: str + size_bytes: int + + +@dataclass(frozen=True) +class ProjectInspection: + path: str + size_bytes: int + md5: str + plates: list[PlateInfo] + + +@dataclass(frozen=True) +class BamboxProfile: + key: str + machine: str + nozzle_diameter: str + enabled: bool + reason: str + allowed_filaments: set[str] + + +BAMBOX_PROFILES: dict[str, BamboxProfile] = { + "p1s-0.4": BamboxProfile( + key="p1s-0.4", + machine="p1s", + nozzle_diameter="0.4", + enabled=True, + reason="bambox 0.5.0 bundles and hardware-validates the Bambu Lab P1S 0.4 profile.", + allowed_filaments={"PLA", "ASA", "PETG-CF"}, + ), + "a1-mini-0.4": BamboxProfile( + key="a1-mini-0.4", + machine="a1-mini", + nozzle_diameter="0.4", + enabled=False, + reason="no validated bambox A1 Mini profile is present.", + allowed_filaments=set(), + ), + "a1-0.4": BamboxProfile( + key="a1-0.4", + machine="a1", + nozzle_diameter="0.4", + enabled=False, + reason="no validated bambox A1 profile is present.", + allowed_filaments=set(), + ), + "x1c-0.4": BamboxProfile( + key="x1c-0.4", + machine="x1c", + nozzle_diameter="0.4", + enabled=False, + reason="no validated bambox X1C profile is present.", + allowed_filaments=set(), + ), + "p1p-0.4": BamboxProfile( + key="p1p-0.4", + machine="p1p", + nozzle_diameter="0.4", + enabled=False, + reason="no validated bambox P1P profile is present.", + allowed_filaments=set(), + ), +} + + +class ImplicitFTP_TLS(ftplib.FTP_TLS): + """FTP_TLS variant for implicit FTPS servers such as Bambu printers.""" + + def connect(self, host: str = "", port: int = 0, timeout: float | None = -999, source_address=None): + if host: + self.host = host + if port: + self.port = port + if timeout != -999: + self.timeout = timeout + if source_address is not None: + self.source_address = source_address + raw_sock = socket.create_connection( + (self.host, self.port), + self.timeout, + source_address=self.source_address, + ) + self.af = raw_sock.family + self.sock = self.context.wrap_socket(raw_sock, server_hostname=self.host) + self.file = self.sock.makefile("r", encoding=self.encoding) + self.welcome = self.getresp() + return self.welcome + + def ntransfercmd(self, cmd: str, rest: Any = None): + conn, size = ftplib.FTP.ntransfercmd(self, cmd, rest) + if self._prot_p: + conn = self.context.wrap_socket(conn, server_hostname=self.host, session=self.sock.session) + return conn, size + + +def config_path_from_args(args: argparse.Namespace) -> Path: + return Path(getattr(args, "config", None) or DEFAULT_CONFIG_PATH).expanduser().resolve() + + +def load_config(path: Path) -> dict[str, Any]: + if not path.is_file(): + return {"printers": {}} + try: + data = json.loads(path.read_text(encoding="utf-8")) + except json.JSONDecodeError as exc: + raise BambuPrintError(f"Printer config is not valid JSON: {path}: {exc}") from exc + if not isinstance(data, dict): + raise BambuPrintError(f"Printer config must be a JSON object: {path}") + printers = data.setdefault("printers", {}) + if not isinstance(printers, dict): + raise BambuPrintError("Printer config field printers must be an object.") + return data + + +def save_config(path: Path, data: dict[str, Any]) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(data, indent=2, sort_keys=True) + "\n", encoding="utf-8") + + +def sanitized_printer_entry(entry: dict[str, Any]) -> dict[str, Any]: + return {key: value for key, value in entry.items() if key != "access_code"} + + +def printer_entry(data: dict[str, Any], printer_id: str) -> dict[str, Any]: + printers = data.get("printers", {}) + entry = printers.get(printer_id) + if not isinstance(entry, dict): + known = ", ".join(sorted(printers)) or "" + raise BambuPrintError(f"Printer {printer_id!r} is not configured. Known printers: {known}") + return entry + + +def apply_printer_config(args: argparse.Namespace) -> None: + printer_id = getattr(args, "printer", "") or "" + if not printer_id: + return + data = load_config(config_path_from_args(args)) + entry = printer_entry(data, printer_id) + for attr, key in ( + ("host", "host"), + ("access_code", "access_code"), + ("serial", "serial"), + ("model", "model"), + ): + if hasattr(args, attr) and not getattr(args, attr, "") and entry.get(key): + setattr(args, attr, str(entry[key])) + + +def cache_printer_serial(args: argparse.Namespace, serial: str) -> None: + printer_id = getattr(args, "printer", "") or "" + if not printer_id: + return + path = config_path_from_args(args) + data = load_config(path) + entry = printer_entry(data, printer_id) + if entry.get("serial") == serial: + return + entry["serial"] = serial + entry["serial_source"] = "printer_tls_certificate_common_name" + entry["updated_at"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) + save_config(path, data) + + +def md5_and_size(path: Path) -> tuple[str, int]: + digest = hashlib.md5() + size = 0 + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + size += len(chunk) + digest.update(chunk) + return digest.hexdigest(), size + + +def inspect_gcode_file(path: Path) -> GCodeInspection: + if not path.is_file(): + raise BambuPrintError(f"G-code input file does not exist: {path}") + name = path.name.lower() + if name.endswith(".gcode.3mf") or path.suffix.lower() == ".3mf": + raise BambuPrintError("Expected plain .gcode, not a Bambu .gcode.3mf or .3mf archive.") + if path.suffix.lower() != ".gcode": + raise BambuPrintError(f"Expected a plain .gcode input, got: {path.name}") + md5, size = md5_and_size(path) + if size == 0: + raise BambuPrintError(f"G-code input is empty: {path}") + return GCodeInspection(path=str(path), size_bytes=size, md5=md5) + + +def inspect_sliced_3mf(path: Path) -> ProjectInspection: + if not path.is_file(): + raise BambuPrintError(f"Packaged project file does not exist: {path}") + + md5, size = md5_and_size(path) + try: + archive = zipfile.ZipFile(path) + except zipfile.BadZipFile as exc: + raise BambuPrintError(f"Packaged project is not a readable 3MF/ZIP archive: {path}") from exc + + plates: list[PlateInfo] = [] + with archive: + for info in archive.infolist(): + match = PLATE_RE.match(info.filename) + if match: + plates.append( + PlateInfo( + index=int(match.group(1)), + path=info.filename, + size_bytes=info.file_size, + ) + ) + + if not plates: + raise BambuPrintError("Packaged project has no Metadata/plate_N.gcode entries.") + + plates.sort(key=lambda item: item.index) + return ProjectInspection(path=str(path), size_bytes=size, md5=md5, plates=plates) + + +def sanitize_remote_name(name: str) -> str: + base = Path(name).name.strip() + if not base: + raise BambuPrintError("Remote filename cannot be empty.") + return re.sub(r"[^A-Za-z0-9._+-]", "_", base) + + +def join_remote_path(remote_dir: str, remote_name: str) -> str: + clean_dir = remote_dir.strip("/") + clean_name = sanitize_remote_name(remote_name) + return f"{clean_dir}/{clean_name}" if clean_dir else clean_name + + +def default_project_name(gcode_path: Path) -> str: + if gcode_path.name.lower().endswith(".gcode"): + return f"{gcode_path.name}.3mf" + return f"{gcode_path.name}.gcode.3mf" + + +def project_subtask_name(remote_path: str) -> str: + name = Path(remote_path).name + for suffix in (".gcode.3mf", ".3mf", ".gcode"): + if name.lower().endswith(suffix): + name = name[: -len(suffix)] + return name or "local_print" + + +def is_local_address(address: IPAddress) -> bool: + return address.is_private or address.is_loopback or address.is_link_local + + +def resolve_host_addresses(host: str) -> list[IPAddress]: + clean_host = host.strip("[]") + try: + return [ipaddress.ip_address(clean_host)] + except ValueError: + pass + + try: + results = socket.getaddrinfo(clean_host, None, type=socket.SOCK_STREAM) + except socket.gaierror as exc: + raise BambuPrintError(f"Could not resolve printer host {host!r}: {exc}") from exc + + addresses = sorted({ipaddress.ip_address(item[4][0]) for item in results}, key=str) + if not addresses: + raise BambuPrintError(f"Could not resolve printer host {host!r}.") + return addresses + + +def validate_local_host(host: str, allow_nonprivate: bool) -> None: + if not host: + raise BambuPrintError("Printer host/IP is required for network actions.") + if allow_nonprivate: + return + + addresses = resolve_host_addresses(host) + nonprivate = [str(address) for address in addresses if not is_local_address(address)] + if nonprivate: + raise BambuPrintError( + f"{host} resolves to non-private address(es): {', '.join(nonprivate)}. " + "Refusing unless --allow-nonprivate-host is set." + ) + + +def common_name_from_decoded_cert(decoded: dict[str, Any]) -> str: + for subject_item in decoded.get("subject", ()): + for key, value in subject_item: + if key == "commonName": + return str(value) + return "" + + +def decode_der_certificate(der_cert: bytes) -> dict[str, Any]: + pem = ssl.DER_cert_to_PEM_cert(der_cert) + temp_path = "" + try: + with tempfile.NamedTemporaryFile("w", encoding="utf-8", suffix=".pem", delete=False) as handle: + temp_path = handle.name + handle.write(pem) + return ssl._ssl._test_decode_cert(temp_path) # type: ignore[attr-defined] + finally: + if temp_path: + try: + Path(temp_path).unlink() + except FileNotFoundError: + pass + + +def discover_printer_serial( + *, + host: str, + port: int = DEFAULT_MQTT_PORT, + timeout: float = 20.0, + tls_verify: bool = False, + allow_nonprivate_host: bool = False, +) -> str: + validate_local_host(host, allow_nonprivate_host) + context = ssl.create_default_context() + if not tls_verify: + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + with socket.create_connection((host, port), timeout=timeout) as raw_sock: + with context.wrap_socket(raw_sock, server_hostname=host) as sock: + der_cert = sock.getpeercert(binary_form=True) + if not der_cert: + raise BambuPrintError("Printer did not provide a TLS certificate for serial discovery.") + serial = common_name_from_decoded_cert(decode_der_certificate(der_cert)).strip() + if not serial: + raise BambuPrintError("Could not find printer serial in the local TLS certificate common name.") + return serial + + +def ensure_printer_serial(args: argparse.Namespace) -> str: + if getattr(args, "serial", ""): + return args.serial + if not getattr(args, "host", ""): + return "" + args.serial = discover_printer_serial( + host=args.host, + port=args.mqtt_port, + timeout=args.timeout, + tls_verify=args.tls_verify, + allow_nonprivate_host=args.allow_nonprivate_host, + ) + cache_printer_serial(args, args.serial) + return args.serial + + +def selected_plate(inspection: ProjectInspection, requested: int | None) -> PlateInfo: + if requested is None: + return inspection.plates[0] + for plate in inspection.plates: + if plate.index == requested: + return plate + available = ", ".join(str(plate.index) for plate in inspection.plates) + raise BambuPrintError(f"Plate {requested} not found. Available plates: {available}") + + +def sequence_id(value: str | None) -> str: + if value: + return value + return str(int(time.time() * 1000)) + + +def build_gcode_file_payload(*, remote_path: str, args: argparse.Namespace) -> dict[str, Any]: + return { + "print": { + "sequence_id": sequence_id(args.sequence_id), + "command": "gcode_file", + "param": args.gcode_param or remote_path, + } + } + + +def build_clean_print_error_payload(args: argparse.Namespace) -> dict[str, Any]: + return { + "print": { + "sequence_id": sequence_id(args.sequence_id), + "command": "clean_print_error", + } + } + + +def build_print_control_payload(args: argparse.Namespace) -> dict[str, Any]: + command = "stop" if args.action == "cancel" else args.action + payload = { + "print": { + "sequence_id": sequence_id(args.sequence_id), + "command": command, + } + } + if command == "stop": + payload["print"]["param"] = "" + return payload + + +def build_project_file_payload( + *, + plate: PlateInfo, + remote_path: str, + remote_url: str, + md5: str | None, + args: argparse.Namespace, +) -> dict[str, Any]: + return { + "print": { + "sequence_id": sequence_id(args.sequence_id), + "command": "project_file", + "param": plate.path, + "project_id": "0", + "profile_id": "0", + "task_id": "0", + "subtask_id": "0", + "subtask_name": project_subtask_name(remote_path), + "url": remote_url, + "md5": md5.upper() if md5 else None, + "timelapse": False, + "bed_type": "auto", + "bed_levelling": True, + "flow_cali": True, + "vibration_cali": False, + "layer_inspect": True, + "use_ams": False, + "ams_mapping": "", + } + } + + +def bambox_profile(profile_key: str) -> BamboxProfile: + try: + profile = BAMBOX_PROFILES[profile_key] + except KeyError as exc: + known = ", ".join(sorted(BAMBOX_PROFILES)) + raise BambuPrintError(f"Unknown bambox profile {profile_key!r}. Known profiles: {known}") from exc + if not profile.enabled: + raise BambuPrintError(f"{profile.key} is not enabled because {profile.reason}") + return profile + + +def bambox_profile_payload(profile: BamboxProfile) -> dict[str, Any]: + return { + "key": profile.key, + "machine": profile.machine, + "nozzle_diameter": profile.nozzle_diameter, + "enabled": profile.enabled, + "reason": profile.reason, + "allowed_filaments": sorted(profile.allowed_filaments), + } + + +def bambox_filament_type(spec: str) -> str: + parts = spec.split(":") + if len(parts) >= 2 and parts[0].isdigit(): + value = parts[1] + else: + value = parts[0] + return value.strip().upper() + + +def validate_bambox_filaments(profile: BamboxProfile, filaments: list[str] | None) -> list[str]: + if not filaments: + raise BambuPrintError("At least one --filament is required for bambox packaging.") + for spec in filaments: + filament_type = bambox_filament_type(spec) + if filament_type not in profile.allowed_filaments: + allowed = ", ".join(sorted(profile.allowed_filaments)) + raise BambuPrintError( + f"Filament {filament_type!r} is not enabled for {profile.key}. Allowed filaments: {allowed}" + ) + return filaments + + +def resolve_bambox_bin(requested: str | None, *, require_exists: bool) -> str: + candidate = requested or os.environ.get("BAMBOX_BIN") or "bambox" + if not require_exists: + return candidate + resolved = shutil.which(candidate) if Path(candidate).name == candidate else candidate + if not resolved or not Path(resolved).exists(): + raise BambuPrintError("bambox CLI was not found. Install it separately or set BAMBOX_BIN.") + return resolved + + +def build_bambox_pack_command( + *, + gcode_path: Path, + output_path: Path, + profile_key: str, + filaments: list[str] | None, + bambox_bin: str | None = None, + require_bambox: bool = False, +) -> list[str]: + profile = bambox_profile(profile_key) + safe_filaments = validate_bambox_filaments(profile, filaments) + command = [ + resolve_bambox_bin(bambox_bin, require_exists=require_bambox), + "pack", + str(gcode_path), + "-o", + str(output_path), + "-m", + profile.machine, + "--nozzle-diameter", + profile.nozzle_diameter, + ] + for filament in safe_filaments: + command.extend(["-f", filament]) + return command + + +def build_bambox_validate_command(*, project_path: Path, bambox_bin: str | None = None, require_bambox: bool = False) -> list[str]: + return [ + resolve_bambox_bin(bambox_bin, require_exists=require_bambox), + "validate", + str(project_path), + "--json", + "--strict", + ] + + +def run_checked_command(command: list[str], label: str) -> dict[str, Any]: + result = subprocess.run(command, check=False, capture_output=True, text=True) + payload: dict[str, Any] = {"command": command, "returncode": result.returncode} + if result.stdout: + payload["stdout_tail"] = tail_text(result.stdout) + if result.stderr: + payload["stderr_tail"] = tail_text(result.stderr) + if result.returncode != 0: + raise BambuPrintError(f"{label} failed: {json.dumps(payload, indent=2)}") + return payload + + +def package_with_bambox(args: argparse.Namespace, output_path: Path) -> dict[str, Any]: + gcode_path = Path(args.gcode).expanduser().resolve() + inspect_gcode_file(gcode_path) + pack_command = build_bambox_pack_command( + gcode_path=gcode_path, + output_path=output_path, + profile_key=args.bambox_profile, + filaments=args.filament, + bambox_bin=args.bambox_bin, + require_bambox=True, + ) + validate_command = build_bambox_validate_command( + project_path=output_path, + bambox_bin=args.bambox_bin, + require_bambox=True, + ) + pack_result = run_checked_command(pack_command, "bambox pack") + if not output_path.is_file(): + raise BambuPrintError(f"bambox pack did not create expected output: {output_path}") + project_inspection = inspect_sliced_3mf(output_path) + validate_result = run_checked_command(validate_command, "bambox validate") + return { + "pack": pack_result, + "validate": validate_result, + "project": asdict(project_inspection), + } + + +def package_with_template_project(args: argparse.Namespace, output_path: Path) -> dict[str, Any]: + gcode_path = Path(args.gcode).expanduser().resolve() + inspection = inspect_gcode_file(gcode_path) + if not args.template_project: + raise BambuPrintError("--template-project is required for template-project packaging.") + template_path = Path(args.template_project).expanduser().resolve() + template_inspection = inspect_sliced_3mf(template_path) + plate = selected_plate(template_inspection, args.plate) + + output_path.parent.mkdir(parents=True, exist_ok=True) + gcode_bytes = gcode_path.read_bytes() + gcode_md5 = hashlib.md5(gcode_bytes).hexdigest().upper() + md5_path = f"{plate.path}.md5" + found_plate = False + found_md5 = False + + with zipfile.ZipFile(template_path, "r") as source, zipfile.ZipFile( + output_path, "w", compression=zipfile.ZIP_DEFLATED + ) as target: + for info in source.infolist(): + data = source.read(info.filename) + if info.filename == plate.path: + data = gcode_bytes + found_plate = True + elif info.filename == md5_path: + data = gcode_md5.encode("ascii") + found_md5 = True + target.writestr(info, data) + if not found_md5: + target.writestr(md5_path, gcode_md5) + + if not found_plate: + raise BambuPrintError(f"Template project plate G-code entry not found: {plate.path}") + + project_inspection = inspect_sliced_3mf(output_path) + return { + "pack": { + "template": str(template_path), + "output": str(output_path), + "replaced_plate": plate.path, + "plate_gcode_md5": gcode_md5, + "input": asdict(inspection), + }, + "project": asdict(project_inspection), + } + + +def build_package_plan(args: argparse.Namespace) -> dict[str, Any]: + gcode_path = Path(args.gcode).expanduser().resolve() + inspection = inspect_gcode_file(gcode_path) + output_path = Path(args.output).expanduser().resolve() + pack_command = build_bambox_pack_command( + gcode_path=gcode_path, + output_path=output_path, + profile_key=args.bambox_profile, + filaments=args.filament, + bambox_bin=args.bambox_bin, + require_bambox=False, + ) + validate_command = build_bambox_validate_command( + project_path=output_path, + bambox_bin=args.bambox_bin, + require_bambox=False, + ) + return { + "dry_run": not args.execute, + "action": "package", + "input": asdict(inspection), + "output": str(output_path), + "bambox": { + "profile": bambox_profile_payload(bambox_profile(args.bambox_profile)), + "filaments": args.filament, + "pack_command": pack_command, + "validate_command": validate_command, + }, + "notes": [ + "bambox is optional and must be installed separately.", + "Only enabled bambox profiles can be packaged.", + "A1 Mini is intentionally disabled until a validated bambox profile is available.", + ], + } + + +def build_plain_send_plan(args: argparse.Namespace) -> dict[str, Any]: + gcode_path = Path(args.gcode).expanduser().resolve() + inspection = inspect_gcode_file(gcode_path) + remote_name = sanitize_remote_name(args.remote_name or gcode_path.name) + remote_path = join_remote_path(args.remote_dir or DEFAULT_REMOTE_DIR, remote_name) + payload = build_gcode_file_payload(remote_path=remote_path, args=args) + return build_common_send_plan( + args=args, + input_payload={**asdict(inspection), "kind": "plain_gcode"}, + local_path=str(gcode_path), + remote_path=remote_path, + remote_url=None, + payload=payload, + ) + + +def build_bambox_project_send_plan(args: argparse.Namespace, project_path: Path | None = None) -> dict[str, Any]: + gcode_path = Path(args.gcode).expanduser().resolve() + inspection = inspect_gcode_file(gcode_path) + remote_name = sanitize_remote_name(args.remote_name or default_project_name(gcode_path)) + remote_path = join_remote_path(args.remote_dir or "", remote_name) + remote_url = f"ftp:///{remote_path}" + output_path = project_path or Path(tempfile.gettempdir()) / default_project_name(gcode_path) + pack_command = build_bambox_pack_command( + gcode_path=gcode_path, + output_path=output_path, + profile_key=args.bambox_profile, + filaments=args.filament, + bambox_bin=args.bambox_bin, + require_bambox=False, + ) + validate_command = build_bambox_validate_command( + project_path=output_path, + bambox_bin=args.bambox_bin, + require_bambox=False, + ) + + project: dict[str, Any] | None = None + payload: dict[str, Any] + if project_path is not None: + project_inspection = inspect_sliced_3mf(project_path) + plate = selected_plate(project_inspection, args.plate) + project = {**asdict(project_inspection), "selected_plate": asdict(plate)} + payload = build_project_file_payload( + plate=plate, + remote_path=remote_path, + remote_url=remote_url, + md5=project_inspection.md5, + args=args, + ) + else: + payload = build_project_file_payload( + plate=PlateInfo(index=1, path="Metadata/plate_1.gcode", size_bytes=0), + remote_path=remote_path, + remote_url=remote_url, + md5=None, + args=args, + ) + + return build_common_send_plan( + args=args, + input_payload={ + **asdict(inspection), + "kind": "plain_gcode", + "bambox_project": project, + "bambox": { + "profile": bambox_profile_payload(bambox_profile(args.bambox_profile)), + "filaments": args.filament, + "pack_command": pack_command, + "validate_command": validate_command, + }, + }, + local_path=str(project_path) if project_path is not None else None, + remote_path=remote_path, + remote_url=remote_url, + payload=payload, + ) + + +def build_template_project_send_plan(args: argparse.Namespace, project_path: Path | None = None) -> dict[str, Any]: + gcode_path = Path(args.gcode).expanduser().resolve() + inspection = inspect_gcode_file(gcode_path) + template_path = Path(args.template_project).expanduser().resolve() if args.template_project else None + if template_path is None: + raise BambuPrintError("--template-project is required for --handoff template-project.") + inspect_sliced_3mf(template_path) + remote_name = sanitize_remote_name(args.remote_name or default_project_name(gcode_path)) + remote_path = join_remote_path(args.remote_dir or "", remote_name) + remote_url = f"ftp:///{remote_path}" + output_path = project_path or Path(tempfile.gettempdir()) / default_project_name(gcode_path) + + project: dict[str, Any] | None = None + if project_path is not None: + project_inspection = inspect_sliced_3mf(project_path) + plate = selected_plate(project_inspection, args.plate) + project = {**asdict(project_inspection), "selected_plate": asdict(plate)} + payload = build_project_file_payload( + plate=plate, + remote_path=remote_path, + remote_url=remote_url, + md5=project_inspection.md5, + args=args, + ) + else: + payload = build_project_file_payload( + plate=PlateInfo(index=1, path="Metadata/plate_1.gcode", size_bytes=0), + remote_path=remote_path, + remote_url=remote_url, + md5=None, + args=args, + ) + + return build_common_send_plan( + args=args, + input_payload={ + **asdict(inspection), + "kind": "plain_gcode", + "template_project": { + "template": str(template_path), + "output": str(output_path), + "packaged_project": project, + "note": "Experimental A1/A1 Mini path: replaces Metadata/plate_1.gcode in a same-printer template project.", + }, + }, + local_path=str(project_path) if project_path is not None else None, + remote_path=remote_path, + remote_url=remote_url, + payload=payload, + ) + + +def build_common_send_plan( + *, + args: argparse.Namespace, + input_payload: dict[str, Any], + local_path: str | None, + remote_path: str, + remote_url: str | None, + payload: dict[str, Any], +) -> dict[str, Any]: + serial = getattr(args, "serial", "") or "" + topic = f"device/{serial}/request" if serial else None + will_upload = args.action in {"upload", "upload-start"} + will_publish = args.action in {"start", "upload-start"} + + ftps: dict[str, Any] = { + "host": args.host, + "port": args.ftps_port, + "username": BAMBU_USERNAME, + "remote_path": remote_path, + "will_upload": will_upload, + } + if remote_url: + ftps["url"] = remote_url + + return { + "dry_run": not args.execute, + "action": args.action, + "handoff": args.handoff, + "input": input_payload, + "local_upload_path": local_path, + "ftps": ftps, + "mqtt": { + "host": args.host, + "port": args.mqtt_port, + "username": BAMBU_USERNAME, + "topic": topic, + "payload": payload, + "will_publish": will_publish, + }, + "safety": [ + "Dry-run is the default; network actions require --execute.", + "Starting a print requires --confirm-start-print.", + "MQTT start publishes a request only; watch the printer UI/state for acceptance and progress.", + "Verify the build plate is clear, filament/path are correct, and the printer is physically safe before execution.", + ], + } + + +def build_clear_error_plan(args: argparse.Namespace) -> dict[str, Any]: + serial = getattr(args, "serial", "") or "" + topic = f"device/{serial}/request" if serial else None + return { + "dry_run": not args.execute, + "action": "clear-error", + "printer": args.printer or None, + "host": args.host, + "mqtt": { + "host": args.host, + "port": args.mqtt_port, + "username": BAMBU_USERNAME, + "topic": topic, + "payload": build_clean_print_error_payload(args), + "will_publish": bool(args.execute), + }, + "notes": [ + "This publishes clean_print_error only; it does not upload files or start a print.", + "Use after resolving the underlying cause of a stale printer error, then read status before retrying.", + ], + } + + +def build_print_control_plan(args: argparse.Namespace) -> dict[str, Any]: + serial = getattr(args, "serial", "") or "" + topic = f"device/{serial}/request" if serial else None + return { + "dry_run": not args.execute, + "action": args.action, + "printer": args.printer or None, + "host": args.host, + "mqtt": { + "host": args.host, + "port": args.mqtt_port, + "username": BAMBU_USERNAME, + "topic": topic, + "payload": build_print_control_payload(args), + "will_publish": bool(args.execute), + }, + "notes": [ + "This publishes a print-control request only; it does not upload files or start a print.", + "Read printer status after publishing to confirm the state changed as intended.", + ], + } + + +def build_send_plan(args: argparse.Namespace, project_path: Path | None = None) -> dict[str, Any]: + apply_printer_config(args) + if args.handoff == "plain": + return build_plain_send_plan(args) + if args.handoff == "bambox-project": + return build_bambox_project_send_plan(args, project_path=project_path) + if args.handoff == "template-project": + return build_template_project_send_plan(args, project_path=project_path) + raise BambuPrintError(f"Unsupported handoff: {args.handoff}") + + +def upload_ftps(args: argparse.Namespace, local_path: Path, remote_path: str) -> None: + access_code = access_code_from_args(args) + validate_local_host(args.host, args.allow_nonprivate_host) + context = ssl.create_default_context() + if not args.tls_verify: + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + ftp = ImplicitFTP_TLS(context=context, timeout=args.timeout) + ftp.connect(args.host, args.ftps_port) + try: + ftp.login(BAMBU_USERNAME, access_code) + ftp.prot_p() + remote_dir = remote_path.rsplit("/", 1)[0] if "/" in remote_path else "" + remote_name = Path(remote_path).name + if remote_dir: + try: + ftp.cwd(remote_dir) + except ftplib.error_perm: + ftp.mkd(remote_dir) + ftp.cwd(remote_dir) + with local_path.open("rb") as handle: + storbinary_with_bambu_timeout_tolerance(ftp, f"STOR {remote_name}", handle) + finally: + try: + ftp.quit() + except Exception: + ftp.close() + + +def storbinary_with_bambu_timeout_tolerance(ftp: ftplib.FTP_TLS, command: str, handle: Any) -> None: + try: + ftp.storbinary(command, handle) + except socket.timeout as exc: + try: + ftp.voidresp() + except Exception as confirm_exc: + raise BambuPrintError( + "FTPS upload timed out before the printer confirmed completion. " + "The file may be partially uploaded; retry upload-only after checking printer storage." + ) from confirm_exc + # Some Bambu FTPS firmware completes STOR but does not close the TLS data + # channel the way Python's ftplib expects. A 226 control response is enough. + + +def encode_mqtt_string(value: str) -> bytes: + encoded = value.encode("utf-8") + if len(encoded) > 65535: + raise BambuPrintError("MQTT string is too long.") + return len(encoded).to_bytes(2, "big") + encoded + + +def encode_remaining_length(length: int) -> bytes: + out = bytearray() + while True: + byte = length % 128 + length //= 128 + if length: + byte |= 0x80 + out.append(byte) + if not length: + return bytes(out) + + +def read_exact(sock: ssl.SSLSocket, size: int) -> bytes: + chunks = bytearray() + while len(chunks) < size: + chunk = sock.recv(size - len(chunks)) + if not chunk: + raise BambuPrintError("MQTT connection closed unexpectedly.") + chunks.extend(chunk) + return bytes(chunks) + + +def read_mqtt_packet(sock: ssl.SSLSocket) -> tuple[int, bytes]: + header = read_exact(sock, 1)[0] + multiplier = 1 + remaining = 0 + while True: + digit = read_exact(sock, 1)[0] + remaining += (digit & 127) * multiplier + if not digit & 128: + break + multiplier *= 128 + if multiplier > 128 * 128 * 128: + raise BambuPrintError("Malformed MQTT remaining length.") + return header, read_exact(sock, remaining) + + +def mqtt_connect_packet(client_id: str, username: str, password: str, keepalive: int = 30) -> bytes: + variable = encode_mqtt_string("MQTT") + bytes([4, 0xC2]) + keepalive.to_bytes(2, "big") + payload = encode_mqtt_string(client_id) + encode_mqtt_string(username) + encode_mqtt_string(password) + remaining = variable + payload + return bytes([0x10]) + encode_remaining_length(len(remaining)) + remaining + + +def mqtt_publish_packet(topic: str, payload: bytes, *, qos: int = 0, packet_id: int = 1) -> bytes: + if qos not in {0, 1}: + raise BambuPrintError("Only MQTT QoS 0 and QoS 1 are supported.") + variable = encode_mqtt_string(topic) + if qos: + variable += packet_id.to_bytes(2, "big") + remaining = variable + payload + return bytes([0x30 | (qos << 1)]) + encode_remaining_length(len(remaining)) + remaining + + +def mqtt_subscribe_packet(packet_id: int, topic: str) -> bytes: + variable = packet_id.to_bytes(2, "big") + payload = encode_mqtt_string(topic) + bytes([0]) + remaining = variable + payload + return bytes([0x82]) + encode_remaining_length(len(remaining)) + remaining + + +def parse_mqtt_publish(header: int, body: bytes) -> tuple[str, bytes]: + if header & 0xF0 != 0x30: + raise BambuPrintError(f"Expected MQTT PUBLISH packet, got header=0x{header:02x}.") + if len(body) < 2: + raise BambuPrintError("Malformed MQTT PUBLISH packet.") + topic_length = int.from_bytes(body[:2], "big") + topic_start = 2 + topic_end = topic_start + topic_length + topic = body[topic_start:topic_end].decode("utf-8", errors="replace") + payload_start = topic_end + qos = (header & 0x06) >> 1 + if qos: + payload_start += 2 + return topic, body[payload_start:] + + +def format_hms_code(attr: Any, code: Any) -> str: + try: + attr_int = int(attr) + code_int = int(code) + except (TypeError, ValueError) as exc: + raise BambuPrintError("HMS attr/code values must be integers.") from exc + return f"{(attr_int >> 16) & 0xFFFF:04X}-{attr_int & 0xFFFF:04X}-{(code_int >> 16) & 0xFFFF:04X}-{code_int & 0xFFFF:04X}" + + +def annotate_hms_codes(message: dict[str, Any]) -> None: + payload = message.get("json") + if not isinstance(payload, dict): + return + print_payload = payload.get("print") + if not isinstance(print_payload, dict): + return + hms_items = print_payload.get("hms") + if not isinstance(hms_items, list): + return + decoded: list[dict[str, Any]] = [] + for item in hms_items: + if not isinstance(item, dict) or "attr" not in item or "code" not in item: + continue + decoded.append({**item, "hms_code": format_hms_code(item["attr"], item["code"])}) + if decoded: + message["hms"] = decoded + + +def mqtt_puback_packet(packet_id: int) -> bytes: + return bytes([0x40, 0x02]) + packet_id.to_bytes(2, "big") + + +def read_mqtt_reports_until( + sock: ssl.SSLSocket, + *, + deadline: float, + timeout: float, + expected_puback_packet_id: int | None = None, + stop_after_puback: bool = False, +) -> dict[str, Any]: + messages: list[dict[str, Any]] = [] + puback_received = expected_puback_packet_id is None + while time.monotonic() < deadline: + sock.settimeout(max(0.1, min(timeout, deadline - time.monotonic()))) + try: + header, body = read_mqtt_packet(sock) + except socket.timeout: + break + if header == 0x40: + packet_id = int.from_bytes(body[:2], "big") if len(body) >= 2 else None + if packet_id == expected_puback_packet_id: + puback_received = True + if stop_after_puback: + break + continue + if header & 0xF0 != 0x30: + continue + message_topic, report_payload = parse_mqtt_publish(header, body) + text = report_payload.decode("utf-8", errors="replace") + item: dict[str, Any] = {"topic": message_topic, "payload": text} + try: + item["json"] = json.loads(text) + except json.JSONDecodeError: + pass + annotate_hms_codes(item) + messages.append(item) + qos = (header & 0x06) >> 1 + if qos == 1: + topic_length = int.from_bytes(body[:2], "big") + publish_packet_id_start = 2 + topic_length + packet_id = int.from_bytes(body[publish_packet_id_start : publish_packet_id_start + 2], "big") + sock.sendall(mqtt_puback_packet(packet_id)) + return {"puback_received": puback_received, "messages": messages} + + +def publish_mqtt( + args: argparse.Namespace, + topic: str, + payload: dict[str, Any], + *, + report_topic: str | None = None, +) -> dict[str, Any]: + access_code = access_code_from_args(args) + validate_local_host(args.host, args.allow_nonprivate_host) + context = ssl.create_default_context() + if not args.tls_verify: + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + payload_bytes = json.dumps(payload, separators=(",", ":"), ensure_ascii=False).encode("utf-8") + client_id = args.client_id or args.serial or f"codex-bambu-{int(time.time())}" + raw_mqtt_qos = getattr(args, "mqtt_qos", 0) + if not isinstance(raw_mqtt_qos, (int, float, str)): + raw_mqtt_qos = 0 + mqtt_qos = int(raw_mqtt_qos) + publish_packet_id = 2 + raw_wait_after_publish = getattr(args, "wait_after_publish", 0.0) + if not isinstance(raw_wait_after_publish, (int, float, str)): + raw_wait_after_publish = 0.0 + wait_after_publish = float(raw_wait_after_publish or 0.0) + diagnostics: dict[str, Any] = { + "qos": mqtt_qos, + "puback_required": mqtt_qos == 1, + "puback_received": mqtt_qos == 0, + "report_topic": report_topic if wait_after_publish and report_topic else None, + "messages": [], + } + with socket.create_connection((args.host, args.mqtt_port), timeout=args.timeout) as raw_sock: + with context.wrap_socket(raw_sock, server_hostname=args.host) as sock: + sock.sendall(mqtt_connect_packet(client_id, BAMBU_USERNAME, access_code)) + header, body = read_mqtt_packet(sock) + if header != 0x20 or len(body) != 2 or body[1] != 0: + raise BambuPrintError(f"MQTT CONNACK failed: header=0x{header:02x} body={body.hex()}") + if wait_after_publish and report_topic: + sock.sendall(mqtt_subscribe_packet(1, report_topic)) + header, body = read_mqtt_packet(sock) + if header != 0x90 or len(body) < 3 or body[-1] == 0x80: + raise BambuPrintError(f"MQTT SUBACK failed: header=0x{header:02x} body={body.hex()}") + sock.sendall(mqtt_publish_packet(topic, payload_bytes, qos=mqtt_qos, packet_id=publish_packet_id)) + if mqtt_qos == 1 or wait_after_publish: + wait_seconds = wait_after_publish if wait_after_publish else args.timeout + observed = read_mqtt_reports_until( + sock, + deadline=time.monotonic() + wait_seconds, + timeout=args.timeout, + expected_puback_packet_id=publish_packet_id if mqtt_qos == 1 else None, + stop_after_puback=mqtt_qos == 1 and not wait_after_publish, + ) + diagnostics.update(observed) + sock.sendall(bytes([0xE0, 0x00])) + return diagnostics + + +def subscribe_mqtt_reports( + args: argparse.Namespace, + topic: str, + wait_seconds: float, + *, + push_all_topic: str | None = None, + max_messages: int = 1, +) -> list[dict[str, Any]]: + access_code = access_code_from_args(args) + validate_local_host(args.host, args.allow_nonprivate_host) + context = ssl.create_default_context() + if not args.tls_verify: + context.check_hostname = False + context.verify_mode = ssl.CERT_NONE + client_id = args.client_id or args.serial or f"codex-bambu-status-{int(time.time())}" + messages: list[dict[str, Any]] = [] + deadline = time.monotonic() + wait_seconds + with socket.create_connection((args.host, args.mqtt_port), timeout=args.timeout) as raw_sock: + with context.wrap_socket(raw_sock, server_hostname=args.host) as sock: + sock.sendall(mqtt_connect_packet(client_id, BAMBU_USERNAME, access_code)) + header, body = read_mqtt_packet(sock) + if header != 0x20 or len(body) != 2 or body[1] != 0: + raise BambuPrintError(f"MQTT CONNACK failed: header=0x{header:02x} body={body.hex()}") + sock.sendall(mqtt_subscribe_packet(1, topic)) + header, body = read_mqtt_packet(sock) + if header != 0x90 or len(body) < 3 or body[-1] == 0x80: + raise BambuPrintError(f"MQTT SUBACK failed: header=0x{header:02x} body={body.hex()}") + if push_all_topic: + payload = { + "pushing": { + "sequence_id": sequence_id(args.sequence_id), + "command": "pushall", + "version": 1, + "push_target": 1, + } + } + sock.sendall(mqtt_publish_packet(push_all_topic, json.dumps(payload, separators=(",", ":")).encode())) + while time.monotonic() < deadline: + sock.settimeout(max(0.1, min(args.timeout, deadline - time.monotonic()))) + try: + header, body = read_mqtt_packet(sock) + except socket.timeout: + break + if header & 0xF0 != 0x30: + continue + message_topic, payload = parse_mqtt_publish(header, body) + text = payload.decode("utf-8", errors="replace") + item: dict[str, Any] = {"topic": message_topic, "payload": text} + try: + item["json"] = json.loads(text) + except json.JSONDecodeError: + pass + annotate_hms_codes(item) + messages.append(item) + if len(messages) >= max_messages: + break + payload_json = item.get("json") + if ( + push_all_topic + and isinstance(payload_json, dict) + and isinstance(payload_json.get("print"), dict) + and payload_json["print"].get("command") == "push_status" + and payload_json["print"].get("msg") == 0 + ): + break + sock.sendall(bytes([0xE0, 0x00])) + return messages + + +def access_code_from_args(args: argparse.Namespace) -> str: + access_code = args.access_code or "" + if not access_code: + raise BambuPrintError("Access code is required for --execute. Configure --printer with config set or pass --access-code.") + if set(access_code) == {"0"}: + raise BambuPrintError("Access code is all zeros; refresh the printer access code before execution.") + return access_code + + +def tail_text(value: str, *, max_lines: int = 80) -> str: + lines = value.splitlines() + if len(lines) <= max_lines: + return value + return "\n".join(lines[-max_lines:]) + + +def package_main(args: argparse.Namespace) -> int: + plan = build_package_plan(args) + if not args.execute: + print(json.dumps(plan, indent=2)) + return 0 + + output_path = Path(args.output).expanduser().resolve() + result = package_with_bambox(args, output_path) + plan["dry_run"] = False + plan["executed"] = ["bambox_pack", "bambox_validate"] + plan["result"] = result + print(json.dumps(plan, indent=2)) + return 0 + + +def config_set_main(args: argparse.Namespace) -> int: + path = config_path_from_args(args) + data = load_config(path) + printers = data.setdefault("printers", {}) + entry = printers.get(args.printer) + if not isinstance(entry, dict): + entry = {} + printers[args.printer] = entry + if args.host: + entry["host"] = args.host + if args.access_code: + entry["access_code"] = args.access_code + if args.model: + entry["model"] = args.model + if args.notes: + entry["notes"] = args.notes + serial = args.serial or "" + if args.fetch_serial: + host = args.host or str(entry.get("host") or "") + if not host: + raise BambuPrintError("Cannot fetch serial without --host or an existing host in the printer config.") + serial = discover_printer_serial( + host=host, + port=args.mqtt_port, + timeout=args.timeout, + tls_verify=args.tls_verify, + allow_nonprivate_host=args.allow_nonprivate_host, + ) + entry["serial_source"] = "printer_tls_certificate_common_name" + if serial: + entry["serial"] = serial + entry["updated_at"] = time.strftime("%Y-%m-%dT%H:%M:%SZ", time.gmtime()) + save_config(path, data) + print(json.dumps({"ok": True, "config": str(path), "printer": args.printer, "entry": sanitized_printer_entry(entry)}, indent=2)) + return 0 + + +def config_list_main(args: argparse.Namespace) -> int: + path = config_path_from_args(args) + data = load_config(path) + printers = data.get("printers", {}) + payload = { + "config": str(path), + "printers": {printer_id: sanitized_printer_entry(entry) for printer_id, entry in sorted(printers.items())}, + } + print(json.dumps(payload, indent=2)) + return 0 + + +def config_show_main(args: argparse.Namespace) -> int: + path = config_path_from_args(args) + data = load_config(path) + entry = printer_entry(data, args.printer) + print(json.dumps({"config": str(path), "printer": args.printer, "entry": sanitized_printer_entry(entry)}, indent=2)) + return 0 + + +def serial_main(args: argparse.Namespace) -> int: + apply_printer_config(args) + serial = discover_printer_serial( + host=args.host, + port=args.mqtt_port, + timeout=args.timeout, + tls_verify=args.tls_verify, + allow_nonprivate_host=args.allow_nonprivate_host, + ) + args.serial = serial + cache_printer_serial(args, serial) + payload = { + "ok": True, + "printer": args.printer or None, + "host": args.host, + "config": str(config_path_from_args(args)) if args.printer else None, + "port": args.mqtt_port, + "serial": serial, + "source": "printer_tls_certificate_common_name", + } + if args.json: + print(json.dumps(payload, indent=2)) + else: + print(serial) + return 0 + + +def status_main(args: argparse.Namespace) -> int: + apply_printer_config(args) + serial = ensure_printer_serial(args) + if not serial: + raise BambuPrintError("Printer serial is required for status; configure --printer or pass --serial.") + topic = args.topic or f"device/{serial}/report" + push_all_topic = f"device/{serial}/request" if args.push_all else None + messages = subscribe_mqtt_reports( + args, + topic, + args.wait_seconds, + push_all_topic=push_all_topic, + max_messages=args.max_messages, + ) + payload = { + "ok": bool(messages), + "printer": args.printer or None, + "host": args.host, + "topic": topic, + "push_all_requested": bool(args.push_all), + "messages": messages, + } + if not messages: + payload["warning"] = f"No report message received within {args.wait_seconds:g} seconds." + print(json.dumps(payload, indent=2)) + return 0 if messages else 1 + + +def clear_error_main(args: argparse.Namespace) -> int: + apply_printer_config(args) + if args.execute and not ensure_printer_serial(args): + raise BambuPrintError("Printer serial is required to publish clean_print_error.") + plan = build_clear_error_plan(args) + if not args.execute: + print(json.dumps(plan, indent=2)) + return 0 + publish_result = publish_mqtt( + args, + plan["mqtt"]["topic"], + plan["mqtt"]["payload"], + report_topic=f"device/{args.serial}/report" if getattr(args, "serial", "") else None, + ) + plan["dry_run"] = False + plan["executed"] = ["publish_clean_print_error"] + plan["mqtt_publish_result"] = publish_result + print(json.dumps(plan, indent=2)) + return 0 + + +def print_control_main(args: argparse.Namespace) -> int: + apply_printer_config(args) + if args.execute and args.action == "cancel" and not args.confirm_cancel_print: + raise BambuPrintError("Canceling a print requires --confirm-cancel-print.") + if args.execute and not ensure_printer_serial(args): + raise BambuPrintError("Printer serial is required to publish a print-control command.") + plan = build_print_control_plan(args) + if not args.execute: + print(json.dumps(plan, indent=2)) + return 0 + publish_result = publish_mqtt( + args, + plan["mqtt"]["topic"], + plan["mqtt"]["payload"], + report_topic=f"device/{args.serial}/report" if getattr(args, "serial", "") else None, + ) + plan["dry_run"] = False + plan["executed"] = [f"publish_{args.action}_request"] + plan["mqtt_publish_result"] = publish_result + print(json.dumps(plan, indent=2)) + return 0 + + +def send_main(args: argparse.Namespace) -> int: + apply_printer_config(args) + if args.execute and args.action == "plan": + raise BambuPrintError("--execute has no effect with --action plan.") + if args.execute and args.action in {"start", "upload-start"} and not args.confirm_start_print: + raise BambuPrintError("Starting a print requires --confirm-start-print.") + if args.execute and args.action in {"start", "upload-start"} and not ensure_printer_serial(args): + raise BambuPrintError("Printer serial is required to publish a start command.") + plan = build_send_plan(args) + + if args.handoff == "plain": + local_path = Path(args.gcode).expanduser().resolve() + if not args.execute: + print(json.dumps(plan, indent=2)) + return 0 + return execute_send(args, plan, local_path) + + if not args.execute: + print(json.dumps(plan, indent=2)) + return 0 + + if args.handoff == "template-project": + with tempfile.TemporaryDirectory(prefix="bambu-template-project-") as tmp: + project_path = Path(tmp) / default_project_name(Path(args.gcode).expanduser()) + package_result = package_with_template_project(args, project_path) + plan = build_send_plan(args, project_path=project_path) + plan["template_project_execution"] = package_result + return execute_send(args, plan, project_path) + + with tempfile.TemporaryDirectory(prefix="bambu-bambox-") as tmp: + project_path = Path(tmp) / default_project_name(Path(args.gcode).expanduser()) + package_result = package_with_bambox(args, project_path) + plan = build_send_plan(args, project_path=project_path) + plan["bambox_execution"] = package_result + return execute_send(args, plan, project_path) + + +def execute_send(args: argparse.Namespace, plan: dict[str, Any], local_path: Path) -> int: + executed: list[str] = [] + if args.action in {"upload", "upload-start"}: + upload_ftps(args, local_path, plan["ftps"]["remote_path"]) + executed.append("upload") + if args.action in {"start", "upload-start"}: + publish_result = publish_mqtt( + args, + plan["mqtt"]["topic"], + plan["mqtt"]["payload"], + report_topic=f"device/{args.serial}/report" if getattr(args, "serial", "") else None, + ) + if isinstance(publish_result, dict): + plan["mqtt_publish_result"] = publish_result + executed.append("publish_start_request") + plan["dry_run"] = False + plan["local_upload_path"] = str(local_path) + plan["executed"] = executed + if "publish_start_request" in executed: + plan["execution_notes"] = [ + "MQTT start was published as a request; this helper does not confirm printer acceptance or print progress." + ] + print(json.dumps(plan, indent=2)) + return 0 + + +def add_package_parser(subparsers: argparse._SubParsersAction) -> None: + parser = subparsers.add_parser("package", help="Package plain G-code into a supported bambox .gcode.3mf project.") + parser.add_argument("--gcode", required=True, help="Validated plain .gcode input.") + parser.add_argument("--output", required=True, help="Output .gcode.3mf path.") + parser.add_argument("--bambox-profile", required=True, help="Enabled bambox compatibility profile such as p1s-0.4.") + parser.add_argument("--filament", action="append", help="bambox filament spec. Repeat for multi-filament jobs.") + parser.add_argument("--bambox-bin", help="Path to bambox CLI. Defaults to BAMBOX_BIN or bambox on PATH.") + mode = parser.add_mutually_exclusive_group() + mode.add_argument("--dry-run", dest="execute", action="store_false", help="Print the packaging plan without running bambox.") + mode.add_argument("--execute", dest="execute", action="store_true", help="Run bambox pack and bambox validate.") + parser.set_defaults(execute=False, func=package_main) + + +def add_config_parser(subparsers: argparse._SubParsersAction) -> None: + parser = subparsers.add_parser("config", help="Read and write local Bambu printer JSON config.") + parser.add_argument("--config", default=str(DEFAULT_CONFIG_PATH), help="Printer config JSON path.") + config_subparsers = parser.add_subparsers(dest="config_command", required=True) + + set_parser = config_subparsers.add_parser("set", help="Create or update a configured printer.") + set_parser.add_argument("--printer", required=True, help="Local printer id, for example a1-mini.") + set_parser.add_argument("--host", help="Printer LAN IP or hostname.") + set_parser.add_argument("--access-code", help="Printer LAN access code.") + set_parser.add_argument("--model", help="Printer model, for example a1-mini.") + set_parser.add_argument("--serial", help="Printer serial. Usually omitted; use --fetch-serial.") + set_parser.add_argument("--notes", help="Optional operator notes.") + set_parser.add_argument("--fetch-serial", action="store_true", help="Fetch and cache serial from the printer TLS certificate.") + set_parser.add_argument("--mqtt-port", type=int, default=DEFAULT_MQTT_PORT) + set_parser.add_argument("--timeout", type=float, default=20.0) + set_parser.add_argument("--tls-verify", action="store_true", help="Verify printer TLS certificates.") + set_parser.add_argument( + "--allow-nonprivate-host", + action="store_true", + help="Allow printer hosts that resolve outside private/link-local/loopback ranges.", + ) + set_parser.set_defaults(func=config_set_main) + + list_parser = config_subparsers.add_parser("list", help="List configured printers.") + list_parser.set_defaults(func=config_list_main) + + show_parser = config_subparsers.add_parser("show", help="Show one configured printer without printing the access code.") + show_parser.add_argument("--printer", required=True) + show_parser.set_defaults(func=config_show_main) + + +def add_serial_parser(subparsers: argparse._SubParsersAction) -> None: + parser = subparsers.add_parser("serial", help="Fetch the printer serial from its local TLS certificate.") + parser.add_argument("--config", default=str(DEFAULT_CONFIG_PATH), help="Printer config JSON path.") + parser.add_argument("--printer", help="Configured printer id.") + parser.add_argument("--host", default="", help="Printer LAN IP or hostname.") + parser.add_argument("--mqtt-port", type=int, default=DEFAULT_MQTT_PORT) + parser.add_argument("--timeout", type=float, default=20.0) + parser.add_argument("--tls-verify", action="store_true", help="Verify printer TLS certificates.") + parser.add_argument( + "--allow-nonprivate-host", + action="store_true", + help="Allow printer hosts that resolve outside private/link-local/loopback ranges.", + ) + parser.add_argument("--json", action="store_true") + parser.set_defaults(func=serial_main) + + +def add_status_parser(subparsers: argparse._SubParsersAction) -> None: + parser = subparsers.add_parser("status", help="Read one MQTT report message from a configured local printer.") + parser.add_argument("--config", default=str(DEFAULT_CONFIG_PATH), help="Printer config JSON path.") + parser.add_argument("--printer", help="Configured printer id.") + parser.add_argument("--host", default="", help="Printer LAN IP or hostname.") + parser.add_argument( + "--serial", + default="", + help="Printer serial number for MQTT topic. Usually loaded from config or fetched automatically.", + ) + parser.add_argument("--access-code", help="Printer access code for one-off use. Prefer --printer config.") + parser.add_argument("--topic", help="MQTT report topic. Defaults to device/{serial}/report.") + parser.add_argument("--push-all", action="store_true", help="Request a full status report after subscribing.") + parser.add_argument("--wait-seconds", type=float, default=10.0) + parser.add_argument("--max-messages", type=int, default=1, help="Maximum report messages to collect before returning.") + parser.add_argument("--sequence-id", help="MQTT sequence id for --push-all. Defaults to current timestamp milliseconds.") + parser.add_argument("--mqtt-port", type=int, default=DEFAULT_MQTT_PORT) + parser.add_argument("--timeout", type=float, default=20.0) + parser.add_argument("--tls-verify", action="store_true", help="Verify printer TLS certificates.") + parser.add_argument( + "--allow-nonprivate-host", + action="store_true", + help="Allow printer hosts that resolve outside private/link-local/loopback ranges.", + ) + parser.add_argument("--client-id", help="MQTT client id. Defaults to the printer serial.") + parser.set_defaults(func=status_main) + + +def add_clear_error_parser(subparsers: argparse._SubParsersAction) -> None: + parser = subparsers.add_parser("clear-error", help="Publish Bambu clean_print_error; dry-run by default.") + parser.add_argument("--config", default=str(DEFAULT_CONFIG_PATH), help="Printer config JSON path.") + parser.add_argument("--printer", help="Configured printer id.") + parser.add_argument("--host", default="", help="Printer LAN IP or hostname.") + parser.add_argument( + "--serial", + default="", + help="Printer serial number for MQTT topic. Usually loaded from config or fetched automatically.", + ) + parser.add_argument("--access-code", help="Printer access code for one-off use. Prefer --printer config.") + parser.add_argument("--execute", action="store_true", help="Publish clean_print_error to the printer.") + parser.add_argument("--mqtt-port", type=int, default=DEFAULT_MQTT_PORT) + parser.add_argument("--timeout", type=float, default=20.0) + parser.add_argument("--tls-verify", action="store_true", help="Verify printer TLS certificates.") + parser.add_argument( + "--allow-nonprivate-host", + action="store_true", + help="Allow printer hosts that resolve outside private/link-local/loopback ranges.", + ) + parser.add_argument("--client-id", help="MQTT client id. Defaults to the printer serial.") + parser.add_argument("--sequence-id", help="MQTT sequence id. Defaults to current timestamp milliseconds.") + parser.add_argument( + "--mqtt-qos", + type=int, + choices=[0, 1], + default=0, + help="MQTT publish QoS. Default 0; use 1 for protocol diagnostics.", + ) + parser.add_argument( + "--wait-after-publish", + type=float, + default=0.0, + help="After publishing, stay connected for this many seconds and capture report messages.", + ) + parser.set_defaults(func=clear_error_main) + + +def add_print_control_parser(subparsers: argparse._SubParsersAction, action: str) -> None: + help_text = "Pause the active local print; dry-run by default." if action == "pause" else "Cancel the active local print; dry-run by default." + parser = subparsers.add_parser(action, help=help_text) + parser.add_argument("--config", default=str(DEFAULT_CONFIG_PATH), help="Printer config JSON path.") + parser.add_argument("--printer", help="Configured printer id.") + parser.add_argument("--host", default="", help="Printer LAN IP or hostname.") + parser.add_argument( + "--serial", + default="", + help="Printer serial number for MQTT topic. Usually loaded from config or fetched automatically.", + ) + parser.add_argument("--access-code", help="Printer access code for one-off use. Prefer --printer config.") + parser.add_argument("--execute", action="store_true", help=f"Publish the {action} request to the printer.") + if action == "cancel": + parser.add_argument( + "--confirm-cancel-print", + action="store_true", + help="Required with --execute because canceling stops the active print job.", + ) + parser.add_argument("--mqtt-port", type=int, default=DEFAULT_MQTT_PORT) + parser.add_argument("--timeout", type=float, default=20.0) + parser.add_argument("--tls-verify", action="store_true", help="Verify printer TLS certificates.") + parser.add_argument( + "--allow-nonprivate-host", + action="store_true", + help="Allow printer hosts that resolve outside private/link-local/loopback ranges.", + ) + parser.add_argument("--client-id", help="MQTT client id. Defaults to the printer serial.") + parser.add_argument("--sequence-id", help="MQTT sequence id. Defaults to current timestamp milliseconds.") + parser.add_argument( + "--mqtt-qos", + type=int, + choices=[0, 1], + default=0, + help="MQTT publish QoS. Default 0; use 1 for protocol diagnostics.", + ) + parser.add_argument( + "--wait-after-publish", + type=float, + default=0.0, + help="After publishing, stay connected for this many seconds and capture report messages.", + ) + parser.set_defaults(action=action, func=print_control_main) + + +def add_send_parser(subparsers: argparse._SubParsersAction) -> None: + parser = subparsers.add_parser("send", help="Inspect, upload, and optionally start a validated plain G-code job.") + parser.add_argument("--config", default=str(DEFAULT_CONFIG_PATH), help="Printer config JSON path.") + parser.add_argument("--printer", help="Configured printer id. Preferred over repeating host/access-code flags.") + parser.add_argument("--gcode", required=True, help="Validated plain .gcode input.") + parser.add_argument("--handoff", choices=["plain", "bambox-project", "template-project"], default="plain") + parser.add_argument("--host", default="", help="Printer LAN IP or hostname.") + parser.add_argument( + "--serial", + default="", + help="Printer serial number for MQTT topic. Usually omitted; the helper fetches it from the printer TLS certificate.", + ) + parser.add_argument("--access-code", help="Printer access code for one-off use. Prefer --printer config for repeated use.") + parser.add_argument("--action", choices=["plan", "upload", "start", "upload-start"], default="plan") + parser.add_argument("--execute", action="store_true", help="Perform network action selected by --action.") + parser.add_argument("--confirm-start-print", action="store_true", help="Required for --action start or upload-start with --execute.") + parser.add_argument( + "--remote-dir", + default=None, + help="Remote directory. Defaults to cache for plain G-code and printer root for project handoffs.", + ) + parser.add_argument("--remote-name", help="Filename to store on the printer.") + parser.add_argument("--gcode-param", help="Override MQTT gcode_file param. Defaults to the uploaded remote path.") + parser.add_argument("--plate", type=int, help="Plate number for packaged projects. Defaults to the first plate.") + parser.add_argument("--bambox-profile", default="p1s-0.4", help="Enabled bambox profile for --handoff bambox-project.") + parser.add_argument("--filament", action="append", help="bambox filament spec. Repeat for multi-filament jobs.") + parser.add_argument("--bambox-bin", help="Path to bambox CLI. Defaults to BAMBOX_BIN or bambox on PATH.") + parser.add_argument( + "--template-project", + help="Same-printer sliced .gcode.3mf template for --handoff template-project.", + ) + parser.add_argument("--ftps-port", type=int, default=DEFAULT_FTPS_PORT) + parser.add_argument("--mqtt-port", type=int, default=DEFAULT_MQTT_PORT) + parser.add_argument("--timeout", type=float, default=20.0) + parser.add_argument("--tls-verify", action="store_true", help="Verify printer TLS certificates.") + parser.add_argument( + "--allow-nonprivate-host", + action="store_true", + help="Allow printer hosts that resolve outside private/link-local/loopback ranges.", + ) + parser.add_argument("--client-id", help="MQTT client id. Defaults to the printer serial for start commands.") + parser.add_argument("--sequence-id", help="MQTT sequence id. Defaults to current timestamp milliseconds.") + parser.add_argument( + "--mqtt-qos", + type=int, + choices=[0, 1], + default=0, + help="MQTT publish QoS for start commands. Default 0; use 1 for protocol diagnostics.", + ) + parser.add_argument( + "--wait-after-publish", + type=float, + default=0.0, + help="After publishing a start command, stay connected for this many seconds and capture report messages.", + ) + parser.set_defaults(func=send_main) + + +def parse_args(argv: list[str]) -> argparse.Namespace: + parser = argparse.ArgumentParser(description=__doc__) + subparsers = parser.add_subparsers(dest="command", required=True) + add_package_parser(subparsers) + add_config_parser(subparsers) + add_serial_parser(subparsers) + add_status_parser(subparsers) + add_clear_error_parser(subparsers) + add_print_control_parser(subparsers, "pause") + add_print_control_parser(subparsers, "cancel") + add_send_parser(subparsers) + return parser.parse_args(argv) + + +def main(argv: list[str] | None = None) -> int: + args = parse_args(argv if argv is not None else sys.argv[1:]) + try: + return args.func(args) + except BambuPrintError as exc: + print(json.dumps({"error": str(exc)}, indent=2), file=sys.stderr) + return 2 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/plugins/cad/skills/bambu-labs/scripts/test_bambu_lan_print.py b/plugins/cad/skills/bambu-labs/scripts/test_bambu_lan_print.py new file mode 100644 index 00000000..95bb19e6 --- /dev/null +++ b/plugins/cad/skills/bambu-labs/scripts/test_bambu_lan_print.py @@ -0,0 +1,981 @@ +#!/usr/bin/env python3 + +from __future__ import annotations + +import json +import hashlib +import os +import stat +import sys +import tempfile +import textwrap +import unittest +import zipfile +from pathlib import Path +from unittest import mock + +sys.path.insert(0, str(Path(__file__).resolve().parent)) + +import bambu_lan_print as bambu + + +def write_gcode(path: Path, body: str = "M104 S220\nM140 S65\nG1 X1 Y1 Z0.2 E0.1\n") -> None: + path.write_text(body, encoding="utf-8") + + +def write_sliced_3mf(path: Path) -> None: + with zipfile.ZipFile(path, "w") as archive: + archive.writestr("[Content_Types].xml", "") + archive.writestr("Metadata/plate_1.gcode", "; plate 1\nG1 X1\n") + + +def write_fake_bambox(path: Path) -> None: + script = textwrap.dedent( + """\ + #!/usr/bin/env python3 + import json + import sys + import zipfile + from pathlib import Path + + args = sys.argv[1:] + if args[0] == "pack": + output = Path(args[args.index("-o") + 1]) + with zipfile.ZipFile(output, "w") as archive: + archive.writestr("[Content_Types].xml", "") + archive.writestr("Metadata/plate_1.gcode", "G1 X1 E0.1\\n") + print(json.dumps({"packed": str(output)})) + raise SystemExit(0) + if args[0] == "validate": + print(json.dumps({"ok": True})) + raise SystemExit(0) + raise SystemExit(2) + """ + ) + path.write_text(script, encoding="utf-8") + path.chmod(path.stat().st_mode | stat.S_IXUSR) + + +class BambuLanPrintTests(unittest.TestCase): + def test_new_printer_onboarding_reference_is_linked_and_specific(self) -> None: + skill_root = Path(__file__).resolve().parents[1] + skill_text = (skill_root / "SKILL.md").read_text(encoding="utf-8") + onboarding_path = skill_root / "references" / "new-printer-onboarding.md" + onboarding = onboarding_path.read_text(encoding="utf-8") + + self.assertIn("references/new-printer-onboarding.md", skill_text) + for required in [ + "Enable LAN Only", + "Enable Developer Mode", + "A1 / A1 Mini", + "P1P / P1S", + "X1 / X1C / X1E", + "H2D / Newer Bambu Printers", + "printer IP address and LAN access code", + ]: + with self.subTest(required=required): + self.assertIn(required, onboarding) + + def test_explicit_print_request_policy_is_documented(self) -> None: + skill_root = Path(__file__).resolve().parents[1] + skill_text = (skill_root / "SKILL.md").read_text(encoding="utf-8") + checklist = (skill_root / "references" / "real-printer-checklist.md").read_text(encoding="utf-8") + + self.assertIn("explicit user request to print or start", skill_text) + self.assertIn("do not pause for a second confirmation", skill_text) + self.assertIn("live-start authorization for this checklist", checklist) + + def test_default_config_uses_workspace_root_not_skill_root(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + workspace_root = Path(tmp) / "workspace" + workspace_root.mkdir() + with mock.patch.dict(os.environ, {"INIT_CWD": str(workspace_root)}): + self.assertEqual(workspace_root.resolve(), bambu.default_workspace_root()) + + skill_root = Path(__file__).resolve().parents[1] + self.assertNotEqual(skill_root.resolve(), bambu.DEFAULT_CONFIG_PATH.parent) + + def test_inspects_plain_gcode(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + job = Path(tmp) / "job.gcode" + write_gcode(job) + + inspection = bambu.inspect_gcode_file(job) + + self.assertEqual(inspection.size_bytes, job.stat().st_size) + self.assertRegex(inspection.md5, r"^[0-9a-f]{32}$") + self.assertEqual(inspection.path, str(job)) + + def test_rejects_non_plain_gcode_inputs(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + missing = root / "missing.gcode" + empty = root / "empty.gcode" + empty.write_text("", encoding="utf-8") + sliced = root / "job.gcode.3mf" + write_sliced_3mf(sliced) + mesh = root / "part.stl" + mesh.write_text("solid part\nendsolid part\n", encoding="utf-8") + + cases = [ + (missing, "does not exist"), + (empty, "empty"), + (sliced, "Expected plain .gcode"), + (mesh, "Expected a plain .gcode"), + ] + for path, message in cases: + with self.subTest(path=path): + with self.assertRaisesRegex(bambu.BambuPrintError, message): + bambu.inspect_gcode_file(path) + + def test_plain_send_plan_uses_gcode_file(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + job = Path(tmp) / "job 01.gcode" + write_gcode(job) + args = bambu.parse_args( + [ + "send", + "--gcode", + str(job), + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--action", + "upload-start", + "--sequence-id", + "seq-1", + "--remote-name", + "job 01.gcode", + ] + ) + + plan = bambu.build_send_plan(args) + + self.assertTrue(plan["dry_run"]) + self.assertEqual(plan["handoff"], "plain") + self.assertTrue(plan["ftps"]["will_upload"]) + self.assertTrue(plan["mqtt"]["will_publish"]) + self.assertEqual(plan["ftps"]["remote_path"], "cache/job_01.gcode") + self.assertEqual(plan["mqtt"]["topic"], "device/00M00A000000000/request") + payload = plan["mqtt"]["payload"]["print"] + self.assertEqual(payload["command"], "gcode_file") + self.assertEqual(payload["param"], "cache/job_01.gcode") + self.assertEqual(payload["sequence_id"], "seq-1") + + def test_gcode_param_override_is_allowed_for_plain_handoff(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + job = Path(tmp) / "job.gcode" + write_gcode(job) + args = bambu.parse_args( + [ + "send", + "--gcode", + str(job), + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--gcode-param", + "/cache/job.gcode", + ] + ) + + plan = bambu.build_send_plan(args) + + self.assertEqual(plan["mqtt"]["payload"]["print"]["param"], "/cache/job.gcode") + + def test_config_set_writes_printer_json_without_echoing_access_code(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + config = root / "printers.json" + args = bambu.parse_args( + [ + "config", + "--config", + str(config), + "set", + "--printer", + "a1-mini", + "--host", + "192.168.1.34", + "--access-code", + "12345678", + "--model", + "a1-mini", + "--serial", + "0309CA4C0901107", + ] + ) + + with mock.patch("builtins.print") as mocked_print: + code = bambu.config_set_main(args) + + self.assertEqual(code, 0) + data = json.loads(config.read_text(encoding="utf-8")) + self.assertEqual(data["printers"]["a1-mini"]["access_code"], "12345678") + payload = json.loads(mocked_print.call_args.args[0]) + self.assertEqual(payload["entry"]["host"], "192.168.1.34") + self.assertNotIn("access_code", payload["entry"]) + + def test_send_parser_loads_printer_defaults_from_json_config(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + job = root / "job.gcode" + config = root / "printers.json" + write_gcode(job) + config.write_text( + json.dumps( + { + "printers": { + "a1-mini": { + "host": "192.168.1.34", + "access_code": "12345678", + "serial": "0309CA4C0901107", + "model": "a1-mini", + } + } + } + ), + encoding="utf-8", + ) + + args = bambu.parse_args(["send", "--config", str(config), "--printer", "a1-mini", "--gcode", str(job)]) + plan = bambu.build_send_plan(args) + + self.assertEqual(args.host, "192.168.1.34") + self.assertEqual(args.serial, "0309CA4C0901107") + self.assertEqual(bambu.access_code_from_args(args), "12345678") + self.assertEqual(plan["mqtt"]["topic"], "device/0309CA4C0901107/request") + + def test_dry_run_send_plan_does_not_discover_serial_when_omitted(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + job = root / "job.gcode" + config = root / "printers.json" + write_gcode(job) + config.write_text( + json.dumps({"printers": {"a1-mini": {"host": "192.168.1.34", "access_code": "12345678"}}}), + encoding="utf-8", + ) + args = bambu.parse_args( + [ + "send", + "--config", + str(config), + "--printer", + "a1-mini", + "--gcode", + str(job), + "--action", + "upload-start", + ] + ) + + with mock.patch.object( + bambu, + "discover_printer_serial", + side_effect=AssertionError("dry-run plans must not perform network discovery"), + ) as mocked_discover: + plan = bambu.build_send_plan(args) + + mocked_discover.assert_not_called() + self.assertEqual(args.serial, "") + self.assertIsNone(plan["mqtt"]["topic"]) + cached = json.loads(config.read_text(encoding="utf-8")) + self.assertNotIn("serial", cached["printers"]["a1-mini"]) + + def test_execute_send_discovers_serial_from_printer_certificate_when_omitted(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + job = root / "job.gcode" + config = root / "printers.json" + write_gcode(job) + config.write_text( + json.dumps({"printers": {"a1-mini": {"host": "192.168.1.34", "access_code": "12345678"}}}), + encoding="utf-8", + ) + args = bambu.parse_args( + [ + "send", + "--config", + str(config), + "--printer", + "a1-mini", + "--gcode", + str(job), + "--action", + "upload-start", + "--execute", + "--confirm-start-print", + ] + ) + + with ( + mock.patch.object(bambu, "discover_printer_serial", return_value="0309CA4C0901107") as mocked_discover, + mock.patch.object(bambu, "upload_ftps") as mocked_upload, + mock.patch.object(bambu, "publish_mqtt") as mocked_publish, + mock.patch("builtins.print") as mocked_print, + ): + code = bambu.send_main(args) + + self.assertEqual(code, 0) + mocked_discover.assert_called_once() + mocked_upload.assert_called_once() + mocked_publish.assert_called_once() + self.assertEqual(args.serial, "0309CA4C0901107") + payload = json.loads(mocked_print.call_args.args[0]) + self.assertEqual(payload["mqtt"]["topic"], "device/0309CA4C0901107/request") + cached = json.loads(config.read_text(encoding="utf-8")) + self.assertEqual(cached["printers"]["a1-mini"]["serial"], "0309CA4C0901107") + + def test_serial_command_reports_tls_certificate_serial(self) -> None: + args = bambu.parse_args(["serial", "--host", "192.168.1.34", "--json"]) + + with mock.patch.object(bambu, "discover_printer_serial", return_value="0309CA4C0901107"), mock.patch( + "builtins.print" + ) as mocked_print: + code = bambu.serial_main(args) + + self.assertEqual(code, 0) + payload = json.loads(mocked_print.call_args.args[0]) + self.assertEqual(payload["serial"], "0309CA4C0901107") + self.assertEqual(payload["source"], "printer_tls_certificate_common_name") + + def test_bambox_project_refuses_unsupported_a1_mini_profile(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + job = Path(tmp) / "job.gcode" + write_gcode(job) + args = bambu.parse_args( + [ + "send", + "--gcode", + str(job), + "--handoff", + "bambox-project", + "--bambox-profile", + "a1-mini-0.4", + "--filament", + "PLA", + ] + ) + + with self.assertRaisesRegex(bambu.BambuPrintError, "a1-mini-0.4 is not enabled"): + bambu.build_send_plan(args) + + def test_bambox_project_builds_pack_command_without_running_bambox(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + job = Path(tmp) / "job.gcode" + write_gcode(job) + args = bambu.parse_args( + [ + "send", + "--gcode", + str(job), + "--handoff", + "bambox-project", + "--bambox-profile", + "p1s-0.4", + "--filament", + "PLA", + "--bambox-bin", + "/usr/local/bin/bambox", + "--action", + "upload-start", + ] + ) + + plan = bambu.build_send_plan(args) + + command = plan["input"]["bambox"]["pack_command"] + self.assertEqual(command[:3], ["/usr/local/bin/bambox", "pack", str(job.resolve())]) + self.assertIn("-m", command) + self.assertIn("p1s", command) + self.assertIn("--nozzle-diameter", command) + self.assertIn("0.4", command) + self.assertIn("-f", command) + self.assertIn("PLA", command) + self.assertEqual(plan["mqtt"]["payload"]["print"]["command"], "project_file") + self.assertIsNone(plan["mqtt"]["payload"]["print"]["md5"]) + self.assertEqual(plan["mqtt"]["payload"]["print"]["subtask_name"], "job") + self.assertTrue(plan["mqtt"]["payload"]["print"]["bed_levelling"]) + self.assertFalse(plan["mqtt"]["payload"]["print"]["use_ams"]) + self.assertEqual(plan["ftps"]["remote_path"], "job.gcode.3mf") + self.assertEqual(plan["ftps"]["url"], "ftp:///job.gcode.3mf") + + def test_package_execute_uses_fake_bambox_and_validates_archive(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + job = root / "job.gcode" + output = root / "job.gcode.3mf" + fake_bambox = root / "bambox" + write_gcode(job) + write_fake_bambox(fake_bambox) + args = bambu.parse_args( + [ + "package", + "--gcode", + str(job), + "--output", + str(output), + "--bambox-profile", + "p1s-0.4", + "--filament", + "PLA", + "--bambox-bin", + str(fake_bambox), + "--execute", + ] + ) + + with mock.patch("builtins.print") as mocked_print: + code = bambu.package_main(args) + + self.assertEqual(code, 0) + self.assertTrue(output.exists()) + payload = json.loads(mocked_print.call_args.args[0]) + self.assertEqual(payload["executed"], ["bambox_pack", "bambox_validate"]) + self.assertEqual(payload["result"]["project"]["plates"][0]["path"], "Metadata/plate_1.gcode") + + def test_template_project_pack_replaces_plate_gcode_and_md5(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + job = root / "job.gcode" + template = root / "template.gcode.3mf" + output = root / "job.gcode.3mf" + write_gcode(job, "M104 S220\nM140 S65\nG1 X2 Y2 Z0.2 E0.2\n") + write_sliced_3mf(template) + args = bambu.parse_args( + [ + "send", + "--gcode", + str(job), + "--handoff", + "template-project", + "--template-project", + str(template), + ] + ) + + result = bambu.package_with_template_project(args, output) + + self.assertEqual(result["pack"]["replaced_plate"], "Metadata/plate_1.gcode") + with zipfile.ZipFile(output) as archive: + self.assertEqual(archive.read("Metadata/plate_1.gcode"), job.read_bytes()) + self.assertEqual( + archive.read("Metadata/plate_1.gcode.md5").decode("ascii"), + hashlib.md5(job.read_bytes()).hexdigest().upper(), + ) + + def test_template_project_upload_start_execute_uses_root_project_file(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + job = root / "job.gcode" + template = root / "template.gcode.3mf" + write_gcode(job) + write_sliced_3mf(template) + args = bambu.parse_args( + [ + "send", + "--gcode", + str(job), + "--handoff", + "template-project", + "--template-project", + str(template), + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--access-code", + "12345678", + "--action", + "upload-start", + "--execute", + "--confirm-start-print", + ] + ) + + with ( + mock.patch.object(bambu, "upload_ftps") as mocked_upload, + mock.patch.object(bambu, "publish_mqtt") as mocked_publish, + mock.patch("builtins.print") as mocked_print, + ): + code = bambu.send_main(args) + + self.assertEqual(code, 0) + mocked_upload.assert_called_once() + self.assertEqual(mocked_upload.call_args.args[2], "job.gcode.3mf") + mocked_publish.assert_called_once() + payload = json.loads(mocked_print.call_args.args[0]) + self.assertEqual(payload["handoff"], "template-project") + self.assertEqual(payload["ftps"]["remote_path"], "job.gcode.3mf") + self.assertEqual(payload["ftps"]["url"], "ftp:///job.gcode.3mf") + self.assertEqual(payload["mqtt"]["payload"]["print"]["command"], "project_file") + self.assertEqual(payload["mqtt"]["payload"]["print"]["url"], "ftp:///job.gcode.3mf") + self.assertEqual(payload["mqtt"]["payload"]["print"]["subtask_name"], "job") + self.assertTrue(payload["mqtt"]["payload"]["print"]["flow_cali"]) + self.assertRegex(payload["mqtt"]["payload"]["print"]["md5"], r"^[0-9A-F]{32}$") + + def test_bambox_upload_start_execute_packages_then_uses_project_file(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + job = root / "job.gcode" + fake_bambox = root / "bambox" + write_gcode(job) + write_fake_bambox(fake_bambox) + args = bambu.parse_args( + [ + "send", + "--gcode", + str(job), + "--handoff", + "bambox-project", + "--bambox-profile", + "p1s-0.4", + "--filament", + "PLA", + "--bambox-bin", + str(fake_bambox), + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--access-code", + "12345678", + "--action", + "upload-start", + "--execute", + "--confirm-start-print", + ] + ) + + with ( + mock.patch.object(bambu, "upload_ftps") as mocked_upload, + mock.patch.object(bambu, "publish_mqtt") as mocked_publish, + mock.patch("builtins.print") as mocked_print, + ): + code = bambu.send_main(args) + + self.assertEqual(code, 0) + mocked_upload.assert_called_once() + mocked_publish.assert_called_once() + payload = json.loads(mocked_print.call_args.args[0]) + self.assertEqual(payload["executed"], ["upload", "publish_start_request"]) + self.assertEqual(payload["mqtt"]["payload"]["print"]["command"], "project_file") + self.assertEqual(payload["mqtt"]["payload"]["print"]["param"], "Metadata/plate_1.gcode") + self.assertEqual(payload["mqtt"]["payload"]["print"]["url"], "ftp:///job.gcode.3mf") + self.assertEqual(payload["mqtt"]["payload"]["print"]["subtask_name"], "job") + self.assertRegex(payload["mqtt"]["payload"]["print"]["md5"], r"^[0-9A-F]{32}$") + + def test_implicit_ftps_reuses_control_tls_session_for_data_connection(self) -> None: + context = mock.Mock() + control_socket = mock.Mock() + control_socket.session = "session-token" + data_socket = mock.Mock() + wrapped_data_socket = mock.Mock() + context.wrap_socket.return_value = wrapped_data_socket + ftp = bambu.ImplicitFTP_TLS(context=context) + ftp.sock = control_socket + ftp.host = "printer.local" + ftp._prot_p = True + + with mock.patch.object(bambu.ftplib.FTP, "ntransfercmd", return_value=(data_socket, 123)): + conn, size = ftp.ntransfercmd("STOR job.gcode") + + self.assertIs(conn, wrapped_data_socket) + self.assertEqual(size, 123) + context.wrap_socket.assert_called_once_with( + data_socket, + server_hostname="printer.local", + session="session-token", + ) + + def test_ftps_upload_accepts_timeout_when_control_channel_confirms_completion(self) -> None: + ftp = mock.Mock() + ftp.storbinary.side_effect = bambu.socket.timeout("data channel shutdown timed out") + ftp.voidresp.return_value = "226 Transfer complete" + + bambu.storbinary_with_bambu_timeout_tolerance(ftp, "STOR job.gcode", mock.Mock()) + + ftp.storbinary.assert_called_once() + ftp.voidresp.assert_called_once() + + def test_start_execute_requires_confirmation_before_network_use(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + job = Path(tmp) / "job.gcode" + write_gcode(job) + args = bambu.parse_args( + [ + "send", + "--gcode", + str(job), + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--action", + "start", + "--execute", + ] + ) + + with self.assertRaisesRegex(bambu.BambuPrintError, "confirm-start-print"): + bambu.send_main(args) + + def test_validate_local_host_accepts_hostname_resolving_to_private_address(self) -> None: + with mock.patch.object( + bambu.socket, + "getaddrinfo", + return_value=[ + ( + bambu.socket.AF_INET, + bambu.socket.SOCK_STREAM, + 0, + "", + ("192.168.1.50", 0), + ) + ], + ): + bambu.validate_local_host("printer.local", allow_nonprivate=False) + + def test_validate_local_host_rejects_hostname_resolving_to_public_address(self) -> None: + with mock.patch.object( + bambu.socket, + "getaddrinfo", + return_value=[ + ( + bambu.socket.AF_INET, + bambu.socket.SOCK_STREAM, + 0, + "", + ("8.8.8.8", 0), + ) + ], + ): + with self.assertRaisesRegex(bambu.BambuPrintError, "non-private"): + bambu.validate_local_host("printer.example.com", allow_nonprivate=False) + + def test_validate_local_host_does_not_resolve_when_nonprivate_hosts_are_allowed(self) -> None: + with mock.patch.object(bambu.socket, "getaddrinfo") as mocked_getaddrinfo: + bambu.validate_local_host("printer.example.com", allow_nonprivate=True) + + mocked_getaddrinfo.assert_not_called() + + def test_validate_local_host_rejects_literal_public_address(self) -> None: + with self.assertRaisesRegex(bambu.BambuPrintError, "non-private"): + bambu.validate_local_host("8.8.8.8", allow_nonprivate=False) + + def test_upload_start_reports_published_start_request_not_confirmed_start(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + job = Path(tmp) / "job.gcode" + write_gcode(job) + args = bambu.parse_args( + [ + "send", + "--gcode", + str(job), + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--access-code", + "12345678", + "--action", + "upload-start", + "--execute", + "--confirm-start-print", + ] + ) + + with ( + mock.patch.object(bambu, "upload_ftps") as mocked_upload, + mock.patch.object(bambu, "publish_mqtt") as mocked_publish, + mock.patch("builtins.print") as mocked_print, + ): + code = bambu.send_main(args) + + self.assertEqual(code, 0) + mocked_upload.assert_called_once() + mocked_publish.assert_called_once() + payload = json.loads(mocked_print.call_args.args[0]) + self.assertEqual(payload["executed"], ["upload", "publish_start_request"]) + self.assertEqual(payload["mqtt"]["payload"]["print"]["command"], "gcode_file") + self.assertIn("does not confirm printer acceptance", payload["execution_notes"][0]) + + def test_mqtt_client_id_defaults_to_serial(self) -> None: + args = mock.Mock() + args.access_code = "12345678" + args.host = "192.168.1.50" + args.mqtt_port = 8883 + args.timeout = 20.0 + args.tls_verify = False + args.allow_nonprivate_host = True + args.client_id = "" + args.serial = "00M00A000000000" + sent = bytearray() + connack = bytearray(b"\x20\x02\x00\x00") + + class FakeSocket: + def __enter__(self): + return self + + def __exit__(self, exc_type, exc, tb): + return False + + def sendall(self, data): + sent.extend(data) + + def recv(self, size): + chunk = bytes(connack[:size]) + del connack[:size] + return chunk + + fake_context = mock.Mock() + fake_context.wrap_socket.return_value = FakeSocket() + with ( + mock.patch.object(bambu.ssl, "create_default_context", return_value=fake_context), + mock.patch.object(bambu.socket, "create_connection", return_value=FakeSocket()), + ): + bambu.publish_mqtt(args, "device/00M00A000000000/request", {"print": {}}) + + self.assertIn(b"00M00A000000000", bytes(sent)) + + def test_mqtt_qos1_publish_waits_for_puback(self) -> None: + args = mock.Mock() + args.access_code = "12345678" + args.host = "192.168.1.50" + args.mqtt_port = 8883 + args.timeout = 20.0 + args.tls_verify = False + args.allow_nonprivate_host = True + args.client_id = "" + args.serial = "00M00A000000000" + args.mqtt_qos = 1 + args.wait_after_publish = 0.0 + sent = bytearray() + incoming = bytearray(b"\x20\x02\x00\x00\x40\x02\x00\x02") + + class FakeSocket: + def __enter__(self): + return self + + def __exit__(self, exc_type, exc, tb): + return False + + def sendall(self, data): + sent.extend(data) + + def recv(self, size): + chunk = bytes(incoming[:size]) + del incoming[:size] + return chunk + + def settimeout(self, timeout): + self.timeout = timeout + + fake_context = mock.Mock() + fake_context.wrap_socket.return_value = FakeSocket() + with ( + mock.patch.object(bambu.ssl, "create_default_context", return_value=fake_context), + mock.patch.object(bambu.socket, "create_connection", return_value=FakeSocket()), + ): + result = bambu.publish_mqtt(args, "device/00M00A000000000/request", {"print": {}}) + + self.assertTrue(result["puback_received"]) + self.assertIn(b"\x32", bytes(sent)) + + def test_mqtt_packet_encoding(self) -> None: + self.assertEqual(bambu.encode_remaining_length(0), b"\x00") + self.assertEqual(bambu.encode_remaining_length(321), b"\xc1\x02") + packet = bambu.mqtt_publish_packet("device/abc/request", json.dumps({"print": {}}).encode()) + self.assertEqual(packet[0], 0x30) + self.assertIn(b"device/abc/request", packet) + qos_packet = bambu.mqtt_publish_packet( + "device/abc/request", + json.dumps({"print": {}}).encode(), + qos=1, + packet_id=7, + ) + self.assertEqual(qos_packet[0], 0x32) + self.assertIn(b"\x00\x07", qos_packet) + subscribe = bambu.mqtt_subscribe_packet(1, "device/abc/report") + self.assertEqual(subscribe[0], 0x82) + self.assertIn(b"device/abc/report", subscribe) + + def test_status_command_uses_configured_printer_report_topic(self) -> None: + with tempfile.TemporaryDirectory() as tmp: + root = Path(tmp) + config = root / "printers.json" + config.write_text( + json.dumps( + { + "printers": { + "a1-mini": { + "host": "192.168.1.34", + "access_code": "12345678", + "serial": "0309CA4C0901107", + } + } + } + ), + encoding="utf-8", + ) + args = bambu.parse_args(["status", "--config", str(config), "--printer", "a1-mini", "--wait-seconds", "0.1"]) + + with mock.patch.object( + bambu, + "subscribe_mqtt_reports", + return_value=[{"topic": "device/0309CA4C0901107/report", "json": {"print": {"gcode_state": "RUNNING"}}}], + ) as mocked_status, mock.patch("builtins.print") as mocked_print: + code = bambu.status_main(args) + + self.assertEqual(code, 0) + mocked_status.assert_called_once() + self.assertEqual(mocked_status.call_args.args[1], "device/0309CA4C0901107/report") + payload = json.loads(mocked_print.call_args.args[0]) + self.assertTrue(payload["ok"]) + + def test_clear_error_dry_run_builds_clean_print_error_payload(self) -> None: + args = bambu.parse_args( + [ + "clear-error", + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--sequence-id", + "seq-1", + ] + ) + + plan = bambu.build_clear_error_plan(args) + + self.assertTrue(plan["dry_run"]) + self.assertEqual(plan["mqtt"]["topic"], "device/00M00A000000000/request") + self.assertEqual(plan["mqtt"]["payload"]["print"]["command"], "clean_print_error") + self.assertEqual(plan["mqtt"]["payload"]["print"]["sequence_id"], "seq-1") + + def test_clear_error_execute_publishes_without_start_confirmation(self) -> None: + args = bambu.parse_args( + [ + "clear-error", + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--access-code", + "12345678", + "--execute", + ] + ) + + with mock.patch.object(bambu, "publish_mqtt", return_value={"puback_received": True}) as mocked_publish, mock.patch( + "builtins.print" + ) as mocked_print: + code = bambu.clear_error_main(args) + + self.assertEqual(code, 0) + mocked_publish.assert_called_once() + payload = json.loads(mocked_print.call_args.args[0]) + self.assertEqual(payload["executed"], ["publish_clean_print_error"]) + self.assertEqual(payload["mqtt"]["payload"]["print"]["command"], "clean_print_error") + + def test_pause_dry_run_builds_pause_payload(self) -> None: + args = bambu.parse_args( + [ + "pause", + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--sequence-id", + "seq-1", + ] + ) + + plan = bambu.build_print_control_plan(args) + + self.assertTrue(plan["dry_run"]) + self.assertEqual(plan["action"], "pause") + self.assertEqual(plan["mqtt"]["topic"], "device/00M00A000000000/request") + self.assertFalse(plan["mqtt"]["will_publish"]) + payload = plan["mqtt"]["payload"]["print"] + self.assertEqual(payload["command"], "pause") + self.assertEqual(payload["sequence_id"], "seq-1") + + def test_cancel_dry_run_maps_to_bambu_stop_payload(self) -> None: + args = bambu.parse_args( + [ + "cancel", + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--sequence-id", + "seq-2", + ] + ) + + plan = bambu.build_print_control_plan(args) + + self.assertTrue(plan["dry_run"]) + self.assertEqual(plan["action"], "cancel") + payload = plan["mqtt"]["payload"]["print"] + self.assertEqual(payload["command"], "stop") + self.assertEqual(payload["param"], "") + self.assertEqual(payload["sequence_id"], "seq-2") + + def test_cancel_execute_requires_cancel_confirmation(self) -> None: + args = bambu.parse_args( + [ + "cancel", + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--access-code", + "12345678", + "--execute", + ] + ) + + with self.assertRaisesRegex(bambu.BambuPrintError, "--confirm-cancel-print"): + bambu.print_control_main(args) + + def test_cancel_execute_publishes_stop_after_confirmation(self) -> None: + args = bambu.parse_args( + [ + "cancel", + "--host", + "192.168.1.50", + "--serial", + "00M00A000000000", + "--access-code", + "12345678", + "--execute", + "--confirm-cancel-print", + ] + ) + + with mock.patch.object(bambu, "publish_mqtt", return_value={"puback_received": True}) as mocked_publish, mock.patch( + "builtins.print" + ) as mocked_print: + code = bambu.print_control_main(args) + + self.assertEqual(code, 0) + mocked_publish.assert_called_once() + payload = json.loads(mocked_print.call_args.args[0]) + self.assertEqual(payload["executed"], ["publish_cancel_request"]) + self.assertEqual(payload["mqtt"]["payload"]["print"]["command"], "stop") + + def test_formats_hms_codes_from_status_payload(self) -> None: + message = {"json": {"print": {"hms": [{"attr": 83887360, "code": 65543, "action": 0}]}}} + + bambu.annotate_hms_codes(message) + + self.assertEqual(message["hms"][0]["hms_code"], "0500-0500-0001-0007") + + +if __name__ == "__main__": + unittest.main() diff --git a/plugins/cad/skills/cad b/plugins/cad/skills/cad deleted file mode 120000 index 2081dcdf..00000000 --- a/plugins/cad/skills/cad +++ /dev/null @@ -1 +0,0 @@ -../../../skills/cad \ No newline at end of file diff --git a/plugins/cad/skills/cad-viewer b/plugins/cad/skills/cad-viewer deleted file mode 120000 index ee8c5061..00000000 --- a/plugins/cad/skills/cad-viewer +++ /dev/null @@ -1 +0,0 @@ -../../../skills/cad-viewer \ No newline at end of file diff --git a/plugins/cad/skills/cad-viewer/LICENSE b/plugins/cad/skills/cad-viewer/LICENSE new file mode 100644 index 00000000..eabcff2c --- /dev/null +++ b/plugins/cad/skills/cad-viewer/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 earthtojake + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/cad/skills/cad-viewer/SKILL.md b/plugins/cad/skills/cad-viewer/SKILL.md new file mode 100644 index 00000000..9860cf80 --- /dev/null +++ b/plugins/cad/skills/cad-viewer/SKILL.md @@ -0,0 +1,127 @@ +--- +name: cad-viewer +description: Start or reuse CAD Viewer and return review links for explicit CAD, robot-description, and G-code files. Use when visually reviewing `.step`, `.stp`, `.glb`, `.stl`, `.3mf`, `.gcode`, `.dxf`, `.urdf`, `.srdf`, or `.sdf` files, especially when handed off from CAD, G-code, URDF, SRDF, or SDF generation skills. +--- + +# CAD Viewer + +Provenance: maintained in [earthtojake/text-to-cad](https://github.com/earthtojake/text-to-cad). +Use the installed local skill files as the runtime source of truth; the +repository link is only for provenance and release review. + +Use this skill to open existing or newly generated CAD, robot-description, DXF, or plain FDM G-code files in CAD Viewer and hand back live review links. The expected input is one or more explicit file paths. + +## Start Viewer + +Start or reuse one local CAD Viewer with `npm run agent:start`, then select +local files by URL. The launcher uses Vite dev mode when this skill's +`scripts/viewer` path is a development symlink, and the packaged `dist/` server +for production skill installs. Every Viewer link returned from this skill MUST +include `?dir=` with an absolute path. Set `?dir=` to the workspace-local +artifact root that owns the model files and related sidecars, usually the +project `models/` directory, such as `/Users/name/project/models`. This root +should be the shared directory containing STEP/STL/GLB/URDF/SRDF/SDF/G-code/DXF +files, not a relative path and not just the selected file's parent when a +broader model workspace root exists. Always begin at port `4178`. + +Probe each candidate port with `GET /__cad/server`. If the response is JSON +with `app: "cad-viewer"`, `dynamicRoot: true`, and `serverApiVersion >= 2`, +reuse that base URL. The response also includes `viewerVersion` for sanity +checking the running build. If the response is a legacy root-bound CAD Viewer +without those fields, treat it as incompatible and try the next port because +returned links must use absolute `?dir=` and `?file=` values. If the port is +occupied by something else, increment the port and probe again. If the port is +closed, start the Viewer launcher on that port. + +Legacy fixed-root startup flags and old local root environment variables have +been removed. Do not use fixed-root startup configuration; use absolute `?dir=` +links instead. + +Always start new local Viewer servers with `--shutdown-after 12h` so forgotten +review servers clean themselves up. Do not rely on a default shutdown; the +server stays alive until stopped unless this flag or `VIEWER_SERVER_LIFETIME_MS` +is set. + +If the user has a Viewer URL open, treat that port as the first reuse candidate. +Return a URL on that same port whenever it can serve the requested absolute +`?dir=`/`?file=`. Do not start a separate Viewer just to change directories; +the same local server can scan a new absolute `?dir=`. + +Run from this skill directory: + +```bash +npm --prefix scripts/viewer run agent:start -- --host 127.0.0.1 --port 4178 --shutdown-after 12h +``` + +Use the printed base URL and append query parameters: + +```bash +http://127.0.0.1:4178/?dir=/absolute/workspace/models&file=/absolute/workspace/models/path/to/model.step +``` + +If a non-Viewer process occupies the candidate port, rerun `agent:start` with +the next available `--port `. In sandboxed agent environments, local +binding failures such as `EPERM` or `EACCES` can be expected; rerun the same +command with the needed permission/escalation. + +## Claude Preview + +When running in Claude Code Desktop, check the workspace `.claude/launch.json`. +If it does not already contain a CAD Viewer preview configuration, add one and +preserve every existing configuration. The preview config should start this +Viewer launcher, use the same selected port as the returned links, and keep +`autoPort: false` so Claude does not silently move the Viewer to a different +port. Use an absolute path to this skill's `scripts/viewer` directory in +`npm --prefix`, or set the preview `cwd` to this skill directory before running +the same `npm --prefix scripts/viewer run agent:start -- --host 127.0.0.1 --port + --shutdown-after 12h` command. + +Example configuration entry: + +```json +{ + "name": "cad-viewer", + "runtimeExecutable": "npm", + "runtimeArgs": [ + "--prefix", + "/absolute/path/to/cad-viewer/scripts/viewer", + "run", + "agent:start", + "--", + "--host", + "127.0.0.1", + "--port", + "4178", + "--shutdown-after", + "12h" + ], + "port": 4178, + "autoPort": false +} +``` + +## Links + +- Return the printed Viewer link for each requested file. +- If a compatible Viewer server is already running, reuse its port and vary the + `?dir=`/`?file=` query only. +- ALWAYS include `?dir=` on every returned Viewer link. + This is mandatory for cad-viewer handoffs: do not omit it for convenience, do + not use a relative path, and do not rely on the Viewer's session-storage + `?dir=` fallback. +- Choose `?dir=` as the absolute workspace folder that contains the model + artifacts, commonly `/models` or the consuming project's equivalent + model directory. +- Include `file=` for each requested file, one URL per file. For + directory-only review links, include `?dir=` without `file=`. +- Return file-only links with no `?dir=` only when the user explicitly asks to + test the Viewer's no-directory/file-only mode. +- Do not stop an existing Viewer server unless the user asks. +- If Viewer startup fails, report the failure and continue with the owning skill's non-GUI validation or artifacts. + +## References + +- Read `references/development.md` when the user asks to modify, debug, or + iterate on CAD Viewer source. +- Read `references/viewer-features.md` when you need supported file types, Viewer controls, or file-specific feature details. +- Read `references/moveit2-server.md` only when the user specifically needs optional SRDF MoveIt2 IK or path-planning controls. diff --git a/plugins/cad/skills/cad-viewer/agents/openai.yaml b/plugins/cad/skills/cad-viewer/agents/openai.yaml new file mode 100644 index 00000000..e754081f --- /dev/null +++ b/plugins/cad/skills/cad-viewer/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "CAD Viewer" + short_description: "Open CAD, G-code, and robot files in Viewer." + default_prompt: "Use $cad-viewer to start CAD Viewer and return review links for explicit CAD, G-code, or robot-description files." diff --git a/plugins/cad/skills/cad-viewer/references/development.md b/plugins/cad/skills/cad-viewer/references/development.md new file mode 100644 index 00000000..e9d5c04a --- /dev/null +++ b/plugins/cad/skills/cad-viewer/references/development.md @@ -0,0 +1,12 @@ +# CAD Viewer Development + +Use this reference only when the user asks to modify, debug, or iterate on CAD +Viewer source. + +CAD Viewer source development happens in the root +source workspace, not inside this generated skill runtime. + +If you are not currently working directly in the editable source workspace, ask +the user for the correct checkout and run the agent from that repository. + +Once inside the repository, read root `AGENTS.md` for guidance on modifying and running the Viewer. diff --git a/plugins/cad/skills/cad-viewer/references/moveit2-server.md b/plugins/cad/skills/cad-viewer/references/moveit2-server.md new file mode 100644 index 00000000..b2208e12 --- /dev/null +++ b/plugins/cad/skills/cad-viewer/references/moveit2-server.md @@ -0,0 +1,29 @@ +# MoveIt2 Server + +Load this only when the user specifically needs CAD Viewer's optional SRDF IK or path-planning controls. Plain SRDF review and normal Viewer links do not require MoveIt2. + +## Start + +Run from the `cad-viewer` skill directory: + +```bash +npm --prefix scripts/viewer run moveit2:setup +npm --prefix scripts/viewer run moveit2:check +npm --prefix scripts/viewer run moveit2:serve +``` + +The server defaults to `ws://127.0.0.1:8765/ws`. CAD Viewer connects to that URL when `VIEWER_MOVEIT2_WS_URL` or the browser `?moveit2Ws=` query points at it. + +Use the configured ROS 2 / MoveIt2 environment. Do not install ROS 2 or MoveIt2 packages into the repository CAD `.venv`. + +## Viewer Controls + +Open an `.srdf` file, expand the right-side `MoveIt2` sheet, and use: + +- Status: linked SRDF and MoveIt2 server status. +- Target: planning group, end effector, target frame, and X/Y/Z target coordinates. +- Solver: IK timeout, attempts, and tolerance. +- Planning: pipeline, planner ID, plan time, velocity scale, and acceleration scale. +- Actions: select pose from the model, reset to the current pose, solve pose, or plan to pose. + +Report whether the environment check passed, whether pose solving/planning worked, and any viewer/server error text. diff --git a/plugins/cad/skills/cad-viewer/references/viewer-features.md b/plugins/cad/skills/cad-viewer/references/viewer-features.md new file mode 100644 index 00000000..343a2aee --- /dev/null +++ b/plugins/cad/skills/cad-viewer/references/viewer-features.md @@ -0,0 +1,22 @@ +# CAD Viewer Features + +Load this only when a task needs Viewer file-support details or UI control guidance. + +## Supported Files + +- `.step`, `.stp`: STEP/STP review through hidden GLB sidecars; supports assembly trees, part hide/show, inspect/focus, face/edge/vertex/part selection, copied `@cad[...]` references, display modes, clip planes, and optional STEP module parameters/animations when a sidecar module exists. +- `.stl`, `.3mf`, `.glb`: mesh viewing with orbit/pan/zoom, screenshots, appearance controls, and solid/wireframe display where available. +- `.dxf`: read-only flat-pattern viewing, plus plate thickness and bend direction/angle controls when bend preview data is available. +- `.gcode`: diagnostic toolpath preview; shows layer-colored extrusion ribbons, optional travel moves, visible-layer and detail controls, feature markers, movement stats, bounds, and parser warnings. It does not reslice, simulate firmware, or replace G-code validation. +- `.urdf`: robot link/mesh viewing with movable joint sliders, reset pose, and copied joint values. +- `.srdf`: linked-URDF viewing with planning groups, group-state presets, joint controls, and optional MoveIt2 IK/planning controls. +- `.sdf`: SDF model/world viewing with metadata, counts, warnings, and joint controls when available. + +## Controls + +- Navigation: left-drag to orbit, right/middle-drag to pan, wheel or pinch to zoom, and Arrow/WASD keys to orbit. Use the view sphere for top/bottom/front/back/left/right views; click its center for the default isometric view. +- File browser: toggle the left CAD Viewer sidebar, search files/ids/paths, expand folders, select entries, or switch files from the breadcrumb menus. +- Floating toolbar: `Select` copies STEP topology references, `Draw` opens annotation tools, `Select Pose` appears for robot target picking when available, `Open orbit preview` starts an auto-rotating preview, and the copy/download buttons capture screenshots. +- Drawing tools: freehand, line, arrow, expand, rectangle, circle, fill, erase, undo, redo, and clear. +- File sheet: open the right sheet for file-specific controls such as STEP tree/parameters, G-code layers/detail/travel, DXF thickness/bends, URDF/SRDF/SDF joints and metadata, plus display and appearance controls. +- Display/appearance: use the file sheet and theme menu for solid/wireframe mode, STEP clipping, surface colors, edge visibility/detail, highlight styling, backdrop, floor/grid, lighting, theme presets, and color mode. diff --git a/plugins/cad/skills/cad-viewer/requirements.txt b/plugins/cad/skills/cad-viewer/requirements.txt new file mode 100644 index 00000000..271f36ff --- /dev/null +++ b/plugins/cad/skills/cad-viewer/requirements.txt @@ -0,0 +1 @@ +--editable ./scripts/viewer/packages/cadpy diff --git a/plugins/cad/skills/cad-viewer/scripts/viewer/.gitignore b/plugins/cad/skills/cad-viewer/scripts/viewer/.gitignore new file mode 100644 index 00000000..92dad316 --- /dev/null +++ b/plugins/cad/skills/cad-viewer/scripts/viewer/.gitignore @@ -0,0 +1,12 @@ +node_modules +.env +.env.* +!.env.example +!.env.*.example +__pycache__ +*.py[cod] +.pytest_cache +tmp + +!dist +!dist/** diff --git a/plugins/cad/skills/cad-viewer/scripts/viewer/backend/server.mjs b/plugins/cad/skills/cad-viewer/scripts/viewer/backend/server.mjs new file mode 100755 index 00000000..02843573 --- /dev/null +++ b/plugins/cad/skills/cad-viewer/scripts/viewer/backend/server.mjs @@ -0,0 +1,26045 @@ +#!/usr/bin/env node +var __create = Object.create; +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, { + get: (a, b) => (typeof require !== "undefined" ? require : a)[b] +}) : x)(function(x) { + if (typeof require !== "undefined") return require.apply(this, arguments); + throw Error('Dynamic require of "' + x + '" is not supported'); +}); +var __esm = (fn, res) => function __init() { + return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res; +}; +var __commonJS = (cb, mod) => function __require2() { + return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( + // If the importer is in node compatibility mode or this is not an ESM + // file that has been converted to a CommonJS file using a Babel- + // compatible transform (i.e. "__esModule" has not been set), then set + // "default" to the CommonJS "module.exports" for node compatibility. + isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, + mod +)); + +// viewer/node_modules/is-node-process/lib/index.mjs +function isNodeProcess() { + if (typeof navigator !== "undefined" && navigator.product === "ReactNative") { + return true; + } + if (typeof process !== "undefined") { + const type = process.type; + if (type === "renderer" || type === "worker") { + return false; + } + return !!(process.versions && process.versions.node); + } + return false; +} +var init_lib = __esm({ + "viewer/node_modules/is-node-process/lib/index.mjs"() { + } +}); + +// viewer/node_modules/is-buffer/index.js +var require_is_buffer = __commonJS({ + "viewer/node_modules/is-buffer/index.js"(exports, module) { + module.exports = function isBuffer2(obj) { + return obj != null && obj.constructor != null && typeof obj.constructor.isBuffer === "function" && obj.constructor.isBuffer(obj); + }; + } +}); + +// viewer/node_modules/retry/lib/retry_operation.js +var require_retry_operation = __commonJS({ + "viewer/node_modules/retry/lib/retry_operation.js"(exports, module) { + function RetryOperation(timeouts, options) { + if (typeof options === "boolean") { + options = { forever: options }; + } + this._originalTimeouts = JSON.parse(JSON.stringify(timeouts)); + this._timeouts = timeouts; + this._options = options || {}; + this._maxRetryTime = options && options.maxRetryTime || Infinity; + this._fn = null; + this._errors = []; + this._attempts = 1; + this._operationTimeout = null; + this._operationTimeoutCb = null; + this._timeout = null; + this._operationStart = null; + this._timer = null; + if (this._options.forever) { + this._cachedTimeouts = this._timeouts.slice(0); + } + } + module.exports = RetryOperation; + RetryOperation.prototype.reset = function() { + this._attempts = 1; + this._timeouts = this._originalTimeouts.slice(0); + }; + RetryOperation.prototype.stop = function() { + if (this._timeout) { + clearTimeout(this._timeout); + } + if (this._timer) { + clearTimeout(this._timer); + } + this._timeouts = []; + this._cachedTimeouts = null; + }; + RetryOperation.prototype.retry = function(err) { + if (this._timeout) { + clearTimeout(this._timeout); + } + if (!err) { + return false; + } + var currentTime = (/* @__PURE__ */ new Date()).getTime(); + if (err && currentTime - this._operationStart >= this._maxRetryTime) { + this._errors.push(err); + this._errors.unshift(new Error("RetryOperation timeout occurred")); + return false; + } + this._errors.push(err); + var timeout = this._timeouts.shift(); + if (timeout === void 0) { + if (this._cachedTimeouts) { + this._errors.splice(0, this._errors.length - 1); + timeout = this._cachedTimeouts.slice(-1); + } else { + return false; + } + } + var self = this; + this._timer = setTimeout(function() { + self._attempts++; + if (self._operationTimeoutCb) { + self._timeout = setTimeout(function() { + self._operationTimeoutCb(self._attempts); + }, self._operationTimeout); + if (self._options.unref) { + self._timeout.unref(); + } + } + self._fn(self._attempts); + }, timeout); + if (this._options.unref) { + this._timer.unref(); + } + return true; + }; + RetryOperation.prototype.attempt = function(fn, timeoutOps) { + this._fn = fn; + if (timeoutOps) { + if (timeoutOps.timeout) { + this._operationTimeout = timeoutOps.timeout; + } + if (timeoutOps.cb) { + this._operationTimeoutCb = timeoutOps.cb; + } + } + var self = this; + if (this._operationTimeoutCb) { + this._timeout = setTimeout(function() { + self._operationTimeoutCb(); + }, self._operationTimeout); + } + this._operationStart = (/* @__PURE__ */ new Date()).getTime(); + this._fn(this._attempts); + }; + RetryOperation.prototype.try = function(fn) { + console.log("Using RetryOperation.try() is deprecated"); + this.attempt(fn); + }; + RetryOperation.prototype.start = function(fn) { + console.log("Using RetryOperation.start() is deprecated"); + this.attempt(fn); + }; + RetryOperation.prototype.start = RetryOperation.prototype.try; + RetryOperation.prototype.errors = function() { + return this._errors; + }; + RetryOperation.prototype.attempts = function() { + return this._attempts; + }; + RetryOperation.prototype.mainError = function() { + if (this._errors.length === 0) { + return null; + } + var counts = {}; + var mainError = null; + var mainErrorCount = 0; + for (var i = 0; i < this._errors.length; i++) { + var error = this._errors[i]; + var message = error.message; + var count = (counts[message] || 0) + 1; + counts[message] = count; + if (count >= mainErrorCount) { + mainError = error; + mainErrorCount = count; + } + } + return mainError; + }; + } +}); + +// viewer/node_modules/retry/lib/retry.js +var require_retry = __commonJS({ + "viewer/node_modules/retry/lib/retry.js"(exports) { + var RetryOperation = require_retry_operation(); + exports.operation = function(options) { + var timeouts = exports.timeouts(options); + return new RetryOperation(timeouts, { + forever: options && (options.forever || options.retries === Infinity), + unref: options && options.unref, + maxRetryTime: options && options.maxRetryTime + }); + }; + exports.timeouts = function(options) { + if (options instanceof Array) { + return [].concat(options); + } + var opts = { + retries: 10, + factor: 2, + minTimeout: 1 * 1e3, + maxTimeout: Infinity, + randomize: false + }; + for (var key in options) { + opts[key] = options[key]; + } + if (opts.minTimeout > opts.maxTimeout) { + throw new Error("minTimeout is greater than maxTimeout"); + } + var timeouts = []; + for (var i = 0; i < opts.retries; i++) { + timeouts.push(this.createTimeout(i, opts)); + } + if (options && options.forever && !timeouts.length) { + timeouts.push(this.createTimeout(i, opts)); + } + timeouts.sort(function(a, b) { + return a - b; + }); + return timeouts; + }; + exports.createTimeout = function(attempt, opts) { + var random = opts.randomize ? Math.random() + 1 : 1; + var timeout = Math.round(random * Math.max(opts.minTimeout, 1) * Math.pow(opts.factor, attempt)); + timeout = Math.min(timeout, opts.maxTimeout); + return timeout; + }; + exports.wrap = function(obj, options, methods) { + if (options instanceof Array) { + methods = options; + options = null; + } + if (!methods) { + methods = []; + for (var key in obj) { + if (typeof obj[key] === "function") { + methods.push(key); + } + } + } + for (var i = 0; i < methods.length; i++) { + var method = methods[i]; + var original = obj[method]; + obj[method] = function retryWrapper(original2) { + var op = exports.operation(options); + var args = Array.prototype.slice.call(arguments, 1); + var callback = args.pop(); + args.push(function(err) { + if (op.retry(err)) { + return; + } + if (err) { + arguments[0] = op.mainError(); + } + callback.apply(this, arguments); + }); + op.attempt(function() { + original2.apply(obj, args); + }); + }.bind(obj, original); + obj[method].options = options; + } + }; + } +}); + +// viewer/node_modules/retry/index.js +var require_retry2 = __commonJS({ + "viewer/node_modules/retry/index.js"(exports, module) { + module.exports = require_retry(); + } +}); + +// viewer/node_modules/async-retry/lib/index.js +var require_lib = __commonJS({ + "viewer/node_modules/async-retry/lib/index.js"(exports, module) { + var retrier = require_retry2(); + function retry2(fn, opts) { + function run(resolve, reject) { + var options = opts || {}; + var op; + if (!("randomize" in options)) { + options.randomize = true; + } + op = retrier.operation(options); + function bail(err) { + reject(err || new Error("Aborted")); + } + function onError(err, num) { + if (err.bail) { + bail(err); + return; + } + if (!op.retry(err)) { + reject(op.mainError()); + } else if (options.onRetry) { + options.onRetry(err, num); + } + } + function runAttempt(num) { + var val; + try { + val = fn(bail, num); + } catch (err) { + onError(err, num); + return; + } + Promise.resolve(val).then(resolve).catch(function catchIt(err) { + onError(err, num); + }); + } + op.attempt(runAttempt); + } + return new Promise(run); + } + module.exports = retry2; + } +}); + +// viewer/node_modules/undici/lib/core/symbols.js +var require_symbols = __commonJS({ + "viewer/node_modules/undici/lib/core/symbols.js"(exports, module) { + module.exports = { + kClose: /* @__PURE__ */ Symbol("close"), + kDestroy: /* @__PURE__ */ Symbol("destroy"), + kDispatch: /* @__PURE__ */ Symbol("dispatch"), + kUrl: /* @__PURE__ */ Symbol("url"), + kWriting: /* @__PURE__ */ Symbol("writing"), + kResuming: /* @__PURE__ */ Symbol("resuming"), + kQueue: /* @__PURE__ */ Symbol("queue"), + kConnect: /* @__PURE__ */ Symbol("connect"), + kConnecting: /* @__PURE__ */ Symbol("connecting"), + kKeepAliveDefaultTimeout: /* @__PURE__ */ Symbol("default keep alive timeout"), + kKeepAliveMaxTimeout: /* @__PURE__ */ Symbol("max keep alive timeout"), + kKeepAliveTimeoutThreshold: /* @__PURE__ */ Symbol("keep alive timeout threshold"), + kKeepAliveTimeoutValue: /* @__PURE__ */ Symbol("keep alive timeout"), + kKeepAlive: /* @__PURE__ */ Symbol("keep alive"), + kHeadersTimeout: /* @__PURE__ */ Symbol("headers timeout"), + kBodyTimeout: /* @__PURE__ */ Symbol("body timeout"), + kServerName: /* @__PURE__ */ Symbol("server name"), + kLocalAddress: /* @__PURE__ */ Symbol("local address"), + kHost: /* @__PURE__ */ Symbol("host"), + kNoRef: /* @__PURE__ */ Symbol("no ref"), + kBodyUsed: /* @__PURE__ */ Symbol("used"), + kBody: /* @__PURE__ */ Symbol("abstracted request body"), + kRunning: /* @__PURE__ */ Symbol("running"), + kBlocking: /* @__PURE__ */ Symbol("blocking"), + kPending: /* @__PURE__ */ Symbol("pending"), + kSize: /* @__PURE__ */ Symbol("size"), + kBusy: /* @__PURE__ */ Symbol("busy"), + kQueued: /* @__PURE__ */ Symbol("queued"), + kFree: /* @__PURE__ */ Symbol("free"), + kConnected: /* @__PURE__ */ Symbol("connected"), + kClosed: /* @__PURE__ */ Symbol("closed"), + kNeedDrain: /* @__PURE__ */ Symbol("need drain"), + kReset: /* @__PURE__ */ Symbol("reset"), + kDestroyed: /* @__PURE__ */ Symbol.for("nodejs.stream.destroyed"), + kResume: /* @__PURE__ */ Symbol("resume"), + kOnError: /* @__PURE__ */ Symbol("on error"), + kMaxHeadersSize: /* @__PURE__ */ Symbol("max headers size"), + kRunningIdx: /* @__PURE__ */ Symbol("running index"), + kPendingIdx: /* @__PURE__ */ Symbol("pending index"), + kError: /* @__PURE__ */ Symbol("error"), + kClients: /* @__PURE__ */ Symbol("clients"), + kClient: /* @__PURE__ */ Symbol("client"), + kParser: /* @__PURE__ */ Symbol("parser"), + kOnDestroyed: /* @__PURE__ */ Symbol("destroy callbacks"), + kPipelining: /* @__PURE__ */ Symbol("pipelining"), + kSocket: /* @__PURE__ */ Symbol("socket"), + kHostHeader: /* @__PURE__ */ Symbol("host header"), + kConnector: /* @__PURE__ */ Symbol("connector"), + kStrictContentLength: /* @__PURE__ */ Symbol("strict content length"), + kMaxRedirections: /* @__PURE__ */ Symbol("maxRedirections"), + kMaxRequests: /* @__PURE__ */ Symbol("maxRequestsPerClient"), + kProxy: /* @__PURE__ */ Symbol("proxy agent options"), + kCounter: /* @__PURE__ */ Symbol("socket request counter"), + kInterceptors: /* @__PURE__ */ Symbol("dispatch interceptors"), + kMaxResponseSize: /* @__PURE__ */ Symbol("max response size"), + kHTTP2Session: /* @__PURE__ */ Symbol("http2Session"), + kHTTP2SessionState: /* @__PURE__ */ Symbol("http2Session state"), + kRetryHandlerDefaultRetry: /* @__PURE__ */ Symbol("retry agent default retry"), + kConstruct: /* @__PURE__ */ Symbol("constructable"), + kListeners: /* @__PURE__ */ Symbol("listeners"), + kHTTPContext: /* @__PURE__ */ Symbol("http context"), + kMaxConcurrentStreams: /* @__PURE__ */ Symbol("max concurrent streams"), + kNoProxyAgent: /* @__PURE__ */ Symbol("no proxy agent"), + kHttpProxyAgent: /* @__PURE__ */ Symbol("http proxy agent"), + kHttpsProxyAgent: /* @__PURE__ */ Symbol("https proxy agent") + }; + } +}); + +// viewer/node_modules/undici/lib/core/errors.js +var require_errors = __commonJS({ + "viewer/node_modules/undici/lib/core/errors.js"(exports, module) { + "use strict"; + var kUndiciError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR"); + var UndiciError = class extends Error { + constructor(message) { + super(message); + this.name = "UndiciError"; + this.code = "UND_ERR"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kUndiciError] === true; + } + [kUndiciError] = true; + }; + var kConnectTimeoutError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_CONNECT_TIMEOUT"); + var ConnectTimeoutError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "ConnectTimeoutError"; + this.message = message || "Connect Timeout Error"; + this.code = "UND_ERR_CONNECT_TIMEOUT"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kConnectTimeoutError] === true; + } + [kConnectTimeoutError] = true; + }; + var kHeadersTimeoutError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_HEADERS_TIMEOUT"); + var HeadersTimeoutError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "HeadersTimeoutError"; + this.message = message || "Headers Timeout Error"; + this.code = "UND_ERR_HEADERS_TIMEOUT"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kHeadersTimeoutError] === true; + } + [kHeadersTimeoutError] = true; + }; + var kHeadersOverflowError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_HEADERS_OVERFLOW"); + var HeadersOverflowError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "HeadersOverflowError"; + this.message = message || "Headers Overflow Error"; + this.code = "UND_ERR_HEADERS_OVERFLOW"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kHeadersOverflowError] === true; + } + [kHeadersOverflowError] = true; + }; + var kBodyTimeoutError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_BODY_TIMEOUT"); + var BodyTimeoutError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "BodyTimeoutError"; + this.message = message || "Body Timeout Error"; + this.code = "UND_ERR_BODY_TIMEOUT"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kBodyTimeoutError] === true; + } + [kBodyTimeoutError] = true; + }; + var kResponseStatusCodeError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_RESPONSE_STATUS_CODE"); + var ResponseStatusCodeError = class extends UndiciError { + constructor(message, statusCode, headers, body) { + super(message); + this.name = "ResponseStatusCodeError"; + this.message = message || "Response Status Code Error"; + this.code = "UND_ERR_RESPONSE_STATUS_CODE"; + this.body = body; + this.status = statusCode; + this.statusCode = statusCode; + this.headers = headers; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kResponseStatusCodeError] === true; + } + [kResponseStatusCodeError] = true; + }; + var kInvalidArgumentError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_INVALID_ARG"); + var InvalidArgumentError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "InvalidArgumentError"; + this.message = message || "Invalid Argument Error"; + this.code = "UND_ERR_INVALID_ARG"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kInvalidArgumentError] === true; + } + [kInvalidArgumentError] = true; + }; + var kInvalidReturnValueError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_INVALID_RETURN_VALUE"); + var InvalidReturnValueError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "InvalidReturnValueError"; + this.message = message || "Invalid Return Value Error"; + this.code = "UND_ERR_INVALID_RETURN_VALUE"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kInvalidReturnValueError] === true; + } + [kInvalidReturnValueError] = true; + }; + var kAbortError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_ABORT"); + var AbortError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "AbortError"; + this.message = message || "The operation was aborted"; + this.code = "UND_ERR_ABORT"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kAbortError] === true; + } + [kAbortError] = true; + }; + var kRequestAbortedError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_ABORTED"); + var RequestAbortedError = class extends AbortError { + constructor(message) { + super(message); + this.name = "AbortError"; + this.message = message || "Request aborted"; + this.code = "UND_ERR_ABORTED"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kRequestAbortedError] === true; + } + [kRequestAbortedError] = true; + }; + var kInformationalError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_INFO"); + var InformationalError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "InformationalError"; + this.message = message || "Request information"; + this.code = "UND_ERR_INFO"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kInformationalError] === true; + } + [kInformationalError] = true; + }; + var kRequestContentLengthMismatchError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_REQ_CONTENT_LENGTH_MISMATCH"); + var RequestContentLengthMismatchError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "RequestContentLengthMismatchError"; + this.message = message || "Request body length does not match content-length header"; + this.code = "UND_ERR_REQ_CONTENT_LENGTH_MISMATCH"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kRequestContentLengthMismatchError] === true; + } + [kRequestContentLengthMismatchError] = true; + }; + var kResponseContentLengthMismatchError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_RES_CONTENT_LENGTH_MISMATCH"); + var ResponseContentLengthMismatchError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "ResponseContentLengthMismatchError"; + this.message = message || "Response body length does not match content-length header"; + this.code = "UND_ERR_RES_CONTENT_LENGTH_MISMATCH"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kResponseContentLengthMismatchError] === true; + } + [kResponseContentLengthMismatchError] = true; + }; + var kClientDestroyedError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_DESTROYED"); + var ClientDestroyedError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "ClientDestroyedError"; + this.message = message || "The client is destroyed"; + this.code = "UND_ERR_DESTROYED"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kClientDestroyedError] === true; + } + [kClientDestroyedError] = true; + }; + var kClientClosedError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_CLOSED"); + var ClientClosedError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "ClientClosedError"; + this.message = message || "The client is closed"; + this.code = "UND_ERR_CLOSED"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kClientClosedError] === true; + } + [kClientClosedError] = true; + }; + var kSocketError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_SOCKET"); + var SocketError = class extends UndiciError { + constructor(message, socket) { + super(message); + this.name = "SocketError"; + this.message = message || "Socket error"; + this.code = "UND_ERR_SOCKET"; + this.socket = socket; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kSocketError] === true; + } + [kSocketError] = true; + }; + var kNotSupportedError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_NOT_SUPPORTED"); + var NotSupportedError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "NotSupportedError"; + this.message = message || "Not supported error"; + this.code = "UND_ERR_NOT_SUPPORTED"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kNotSupportedError] === true; + } + [kNotSupportedError] = true; + }; + var kBalancedPoolMissingUpstreamError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_BPL_MISSING_UPSTREAM"); + var BalancedPoolMissingUpstreamError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "MissingUpstreamError"; + this.message = message || "No upstream has been added to the BalancedPool"; + this.code = "UND_ERR_BPL_MISSING_UPSTREAM"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kBalancedPoolMissingUpstreamError] === true; + } + [kBalancedPoolMissingUpstreamError] = true; + }; + var kHTTPParserError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_HTTP_PARSER"); + var HTTPParserError = class extends Error { + constructor(message, code, data) { + super(message); + this.name = "HTTPParserError"; + this.code = code ? `HPE_${code}` : void 0; + this.data = data ? data.toString() : void 0; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kHTTPParserError] === true; + } + [kHTTPParserError] = true; + }; + var kResponseExceededMaxSizeError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_RES_EXCEEDED_MAX_SIZE"); + var ResponseExceededMaxSizeError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "ResponseExceededMaxSizeError"; + this.message = message || "Response content exceeded max size"; + this.code = "UND_ERR_RES_EXCEEDED_MAX_SIZE"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kResponseExceededMaxSizeError] === true; + } + [kResponseExceededMaxSizeError] = true; + }; + var kRequestRetryError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_REQ_RETRY"); + var RequestRetryError = class extends UndiciError { + constructor(message, code, { headers, data }) { + super(message); + this.name = "RequestRetryError"; + this.message = message || "Request retry error"; + this.code = "UND_ERR_REQ_RETRY"; + this.statusCode = code; + this.data = data; + this.headers = headers; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kRequestRetryError] === true; + } + [kRequestRetryError] = true; + }; + var kResponseError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_RESPONSE"); + var ResponseError = class extends UndiciError { + constructor(message, code, { headers, data }) { + super(message); + this.name = "ResponseError"; + this.message = message || "Response error"; + this.code = "UND_ERR_RESPONSE"; + this.statusCode = code; + this.data = data; + this.headers = headers; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kResponseError] === true; + } + [kResponseError] = true; + }; + var kSecureProxyConnectionError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_PRX_TLS"); + var SecureProxyConnectionError = class extends UndiciError { + constructor(cause, message, options) { + super(message, { cause, ...options ?? {} }); + this.name = "SecureProxyConnectionError"; + this.message = message || "Secure Proxy Connection failed"; + this.code = "UND_ERR_PRX_TLS"; + this.cause = cause; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kSecureProxyConnectionError] === true; + } + [kSecureProxyConnectionError] = true; + }; + var kMessageSizeExceededError = /* @__PURE__ */ Symbol.for("undici.error.UND_ERR_WS_MESSAGE_SIZE_EXCEEDED"); + var MessageSizeExceededError = class extends UndiciError { + constructor(message) { + super(message); + this.name = "MessageSizeExceededError"; + this.message = message || "Max decompressed message size exceeded"; + this.code = "UND_ERR_WS_MESSAGE_SIZE_EXCEEDED"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kMessageSizeExceededError] === true; + } + get [kMessageSizeExceededError]() { + return true; + } + }; + module.exports = { + AbortError, + HTTPParserError, + UndiciError, + HeadersTimeoutError, + HeadersOverflowError, + BodyTimeoutError, + RequestContentLengthMismatchError, + ConnectTimeoutError, + ResponseStatusCodeError, + InvalidArgumentError, + InvalidReturnValueError, + RequestAbortedError, + ClientDestroyedError, + ClientClosedError, + InformationalError, + SocketError, + NotSupportedError, + ResponseContentLengthMismatchError, + BalancedPoolMissingUpstreamError, + ResponseExceededMaxSizeError, + RequestRetryError, + ResponseError, + SecureProxyConnectionError, + MessageSizeExceededError + }; + } +}); + +// viewer/node_modules/undici/lib/core/constants.js +var require_constants = __commonJS({ + "viewer/node_modules/undici/lib/core/constants.js"(exports, module) { + "use strict"; + var headerNameLowerCasedRecord = {}; + var wellknownHeaderNames = [ + "Accept", + "Accept-Encoding", + "Accept-Language", + "Accept-Ranges", + "Access-Control-Allow-Credentials", + "Access-Control-Allow-Headers", + "Access-Control-Allow-Methods", + "Access-Control-Allow-Origin", + "Access-Control-Expose-Headers", + "Access-Control-Max-Age", + "Access-Control-Request-Headers", + "Access-Control-Request-Method", + "Age", + "Allow", + "Alt-Svc", + "Alt-Used", + "Authorization", + "Cache-Control", + "Clear-Site-Data", + "Connection", + "Content-Disposition", + "Content-Encoding", + "Content-Language", + "Content-Length", + "Content-Location", + "Content-Range", + "Content-Security-Policy", + "Content-Security-Policy-Report-Only", + "Content-Type", + "Cookie", + "Cross-Origin-Embedder-Policy", + "Cross-Origin-Opener-Policy", + "Cross-Origin-Resource-Policy", + "Date", + "Device-Memory", + "Downlink", + "ECT", + "ETag", + "Expect", + "Expect-CT", + "Expires", + "Forwarded", + "From", + "Host", + "If-Match", + "If-Modified-Since", + "If-None-Match", + "If-Range", + "If-Unmodified-Since", + "Keep-Alive", + "Last-Modified", + "Link", + "Location", + "Max-Forwards", + "Origin", + "Permissions-Policy", + "Pragma", + "Proxy-Authenticate", + "Proxy-Authorization", + "RTT", + "Range", + "Referer", + "Referrer-Policy", + "Refresh", + "Retry-After", + "Sec-WebSocket-Accept", + "Sec-WebSocket-Extensions", + "Sec-WebSocket-Key", + "Sec-WebSocket-Protocol", + "Sec-WebSocket-Version", + "Server", + "Server-Timing", + "Service-Worker-Allowed", + "Service-Worker-Navigation-Preload", + "Set-Cookie", + "SourceMap", + "Strict-Transport-Security", + "Supports-Loading-Mode", + "TE", + "Timing-Allow-Origin", + "Trailer", + "Transfer-Encoding", + "Upgrade", + "Upgrade-Insecure-Requests", + "User-Agent", + "Vary", + "Via", + "WWW-Authenticate", + "X-Content-Type-Options", + "X-DNS-Prefetch-Control", + "X-Frame-Options", + "X-Permitted-Cross-Domain-Policies", + "X-Powered-By", + "X-Requested-With", + "X-XSS-Protection" + ]; + for (let i = 0; i < wellknownHeaderNames.length; ++i) { + const key = wellknownHeaderNames[i]; + const lowerCasedKey = key.toLowerCase(); + headerNameLowerCasedRecord[key] = headerNameLowerCasedRecord[lowerCasedKey] = lowerCasedKey; + } + Object.setPrototypeOf(headerNameLowerCasedRecord, null); + module.exports = { + wellknownHeaderNames, + headerNameLowerCasedRecord + }; + } +}); + +// viewer/node_modules/undici/lib/core/tree.js +var require_tree = __commonJS({ + "viewer/node_modules/undici/lib/core/tree.js"(exports, module) { + "use strict"; + var { + wellknownHeaderNames, + headerNameLowerCasedRecord + } = require_constants(); + var TstNode = class _TstNode { + /** @type {any} */ + value = null; + /** @type {null | TstNode} */ + left = null; + /** @type {null | TstNode} */ + middle = null; + /** @type {null | TstNode} */ + right = null; + /** @type {number} */ + code; + /** + * @param {string} key + * @param {any} value + * @param {number} index + */ + constructor(key, value, index) { + if (index === void 0 || index >= key.length) { + throw new TypeError("Unreachable"); + } + const code = this.code = key.charCodeAt(index); + if (code > 127) { + throw new TypeError("key must be ascii string"); + } + if (key.length !== ++index) { + this.middle = new _TstNode(key, value, index); + } else { + this.value = value; + } + } + /** + * @param {string} key + * @param {any} value + */ + add(key, value) { + const length = key.length; + if (length === 0) { + throw new TypeError("Unreachable"); + } + let index = 0; + let node = this; + while (true) { + const code = key.charCodeAt(index); + if (code > 127) { + throw new TypeError("key must be ascii string"); + } + if (node.code === code) { + if (length === ++index) { + node.value = value; + break; + } else if (node.middle !== null) { + node = node.middle; + } else { + node.middle = new _TstNode(key, value, index); + break; + } + } else if (node.code < code) { + if (node.left !== null) { + node = node.left; + } else { + node.left = new _TstNode(key, value, index); + break; + } + } else if (node.right !== null) { + node = node.right; + } else { + node.right = new _TstNode(key, value, index); + break; + } + } + } + /** + * @param {Uint8Array} key + * @return {TstNode | null} + */ + search(key) { + const keylength = key.length; + let index = 0; + let node = this; + while (node !== null && index < keylength) { + let code = key[index]; + if (code <= 90 && code >= 65) { + code |= 32; + } + while (node !== null) { + if (code === node.code) { + if (keylength === ++index) { + return node; + } + node = node.middle; + break; + } + node = node.code < code ? node.left : node.right; + } + } + return null; + } + }; + var TernarySearchTree = class { + /** @type {TstNode | null} */ + node = null; + /** + * @param {string} key + * @param {any} value + * */ + insert(key, value) { + if (this.node === null) { + this.node = new TstNode(key, value, 0); + } else { + this.node.add(key, value); + } + } + /** + * @param {Uint8Array} key + * @return {any} + */ + lookup(key) { + return this.node?.search(key)?.value ?? null; + } + }; + var tree = new TernarySearchTree(); + for (let i = 0; i < wellknownHeaderNames.length; ++i) { + const key = headerNameLowerCasedRecord[wellknownHeaderNames[i]]; + tree.insert(key, key); + } + module.exports = { + TernarySearchTree, + tree + }; + } +}); + +// viewer/node_modules/undici/lib/core/util.js +var require_util = __commonJS({ + "viewer/node_modules/undici/lib/core/util.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var { kDestroyed, kBodyUsed, kListeners, kBody } = require_symbols(); + var { IncomingMessage } = __require("node:http"); + var stream = __require("node:stream"); + var net = __require("node:net"); + var { Blob: Blob2 } = __require("node:buffer"); + var nodeUtil = __require("node:util"); + var { stringify } = __require("node:querystring"); + var { EventEmitter: EE } = __require("node:events"); + var { InvalidArgumentError } = require_errors(); + var { headerNameLowerCasedRecord } = require_constants(); + var { tree } = require_tree(); + var [nodeMajor, nodeMinor] = process.versions.node.split(".").map((v) => Number(v)); + var BodyAsyncIterable = class { + constructor(body) { + this[kBody] = body; + this[kBodyUsed] = false; + } + async *[Symbol.asyncIterator]() { + assert(!this[kBodyUsed], "disturbed"); + this[kBodyUsed] = true; + yield* this[kBody]; + } + }; + function wrapRequestBody(body) { + if (isStream2(body)) { + if (bodyLength(body) === 0) { + body.on("data", function() { + assert(false); + }); + } + if (typeof body.readableDidRead !== "boolean") { + body[kBodyUsed] = false; + EE.prototype.on.call(body, "data", function() { + this[kBodyUsed] = true; + }); + } + return body; + } else if (body && typeof body.pipeTo === "function") { + return new BodyAsyncIterable(body); + } else if (body && typeof body !== "string" && !ArrayBuffer.isView(body) && isIterable(body)) { + return new BodyAsyncIterable(body); + } else { + return body; + } + } + function nop() { + } + function isStream2(obj) { + return obj && typeof obj === "object" && typeof obj.pipe === "function" && typeof obj.on === "function"; + } + function isBlobLike(object) { + if (object === null) { + return false; + } else if (object instanceof Blob2) { + return true; + } else if (typeof object !== "object") { + return false; + } else { + const sTag = object[Symbol.toStringTag]; + return (sTag === "Blob" || sTag === "File") && ("stream" in object && typeof object.stream === "function" || "arrayBuffer" in object && typeof object.arrayBuffer === "function"); + } + } + function buildURL(url, queryParams) { + if (url.includes("?") || url.includes("#")) { + throw new Error('Query params cannot be passed when url already contains "?" or "#".'); + } + const stringified = stringify(queryParams); + if (stringified) { + url += "?" + stringified; + } + return url; + } + function isValidPort(port2) { + const value = parseInt(port2, 10); + return value === Number(port2) && value >= 0 && value <= 65535; + } + function isHttpOrHttpsPrefixed(value) { + return value != null && value[0] === "h" && value[1] === "t" && value[2] === "t" && value[3] === "p" && (value[4] === ":" || value[4] === "s" && value[5] === ":"); + } + function parseURL(url) { + if (typeof url === "string") { + url = new URL(url); + if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) { + throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`."); + } + return url; + } + if (!url || typeof url !== "object") { + throw new InvalidArgumentError("Invalid URL: The URL argument must be a non-null object."); + } + if (!(url instanceof URL)) { + if (url.port != null && url.port !== "" && isValidPort(url.port) === false) { + throw new InvalidArgumentError("Invalid URL: port must be a valid integer or a string representation of an integer."); + } + if (url.path != null && typeof url.path !== "string") { + throw new InvalidArgumentError("Invalid URL path: the path must be a string or null/undefined."); + } + if (url.pathname != null && typeof url.pathname !== "string") { + throw new InvalidArgumentError("Invalid URL pathname: the pathname must be a string or null/undefined."); + } + if (url.hostname != null && typeof url.hostname !== "string") { + throw new InvalidArgumentError("Invalid URL hostname: the hostname must be a string or null/undefined."); + } + if (url.origin != null && typeof url.origin !== "string") { + throw new InvalidArgumentError("Invalid URL origin: the origin must be a string or null/undefined."); + } + if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) { + throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`."); + } + const port2 = url.port != null ? url.port : url.protocol === "https:" ? 443 : 80; + let origin = url.origin != null ? url.origin : `${url.protocol || ""}//${url.hostname || ""}:${port2}`; + let path12 = url.path != null ? url.path : `${url.pathname || ""}${url.search || ""}`; + if (origin[origin.length - 1] === "/") { + origin = origin.slice(0, origin.length - 1); + } + if (path12 && path12[0] !== "/") { + path12 = `/${path12}`; + } + return new URL(`${origin}${path12}`); + } + if (!isHttpOrHttpsPrefixed(url.origin || url.protocol)) { + throw new InvalidArgumentError("Invalid URL protocol: the URL must start with `http:` or `https:`."); + } + return url; + } + function parseOrigin(url) { + url = parseURL(url); + if (url.pathname !== "/" || url.search || url.hash) { + throw new InvalidArgumentError("invalid url"); + } + return url; + } + function getHostname(host2) { + if (host2[0] === "[") { + const idx2 = host2.indexOf("]"); + assert(idx2 !== -1); + return host2.substring(1, idx2); + } + const idx = host2.indexOf(":"); + if (idx === -1) return host2; + return host2.substring(0, idx); + } + function getServerName(host2) { + if (!host2) { + return null; + } + assert(typeof host2 === "string"); + const servername = getHostname(host2); + if (net.isIP(servername)) { + return ""; + } + return servername; + } + function deepClone(obj) { + return JSON.parse(JSON.stringify(obj)); + } + function isAsyncIterable(obj) { + return !!(obj != null && typeof obj[Symbol.asyncIterator] === "function"); + } + function isIterable(obj) { + return !!(obj != null && (typeof obj[Symbol.iterator] === "function" || typeof obj[Symbol.asyncIterator] === "function")); + } + function bodyLength(body) { + if (body == null) { + return 0; + } else if (isStream2(body)) { + const state = body._readableState; + return state && state.objectMode === false && state.ended === true && Number.isFinite(state.length) ? state.length : null; + } else if (isBlobLike(body)) { + return body.size != null ? body.size : null; + } else if (isBuffer2(body)) { + return body.byteLength; + } + return null; + } + function isDestroyed(body) { + return body && !!(body.destroyed || body[kDestroyed] || stream.isDestroyed?.(body)); + } + function destroy(stream2, err) { + if (stream2 == null || !isStream2(stream2) || isDestroyed(stream2)) { + return; + } + if (typeof stream2.destroy === "function") { + if (Object.getPrototypeOf(stream2).constructor === IncomingMessage) { + stream2.socket = null; + } + stream2.destroy(err); + } else if (err) { + queueMicrotask(() => { + stream2.emit("error", err); + }); + } + if (stream2.destroyed !== true) { + stream2[kDestroyed] = true; + } + } + var KEEPALIVE_TIMEOUT_EXPR = /timeout=(\d+)/; + function parseKeepAliveTimeout(val) { + const m = val.toString().match(KEEPALIVE_TIMEOUT_EXPR); + return m ? parseInt(m[1], 10) * 1e3 : null; + } + function headerNameToString(value) { + return typeof value === "string" ? headerNameLowerCasedRecord[value] ?? value.toLowerCase() : tree.lookup(value) ?? value.toString("latin1").toLowerCase(); + } + function bufferToLowerCasedHeaderName(value) { + return tree.lookup(value) ?? value.toString("latin1").toLowerCase(); + } + function parseHeaders(headers, obj) { + if (obj === void 0) obj = {}; + for (let i = 0; i < headers.length; i += 2) { + const key = headerNameToString(headers[i]); + let val = obj[key]; + if (val) { + if (typeof val === "string") { + val = [val]; + obj[key] = val; + } + val.push(headers[i + 1].toString("utf8")); + } else { + const headersValue = headers[i + 1]; + if (typeof headersValue === "string") { + obj[key] = headersValue; + } else { + obj[key] = Array.isArray(headersValue) ? headersValue.map((x) => x.toString("utf8")) : headersValue.toString("utf8"); + } + } + } + if ("content-length" in obj && "content-disposition" in obj) { + obj["content-disposition"] = Buffer.from(obj["content-disposition"]).toString("latin1"); + } + return obj; + } + function parseRawHeaders(headers) { + const len = headers.length; + const ret = new Array(len); + let hasContentLength = false; + let contentDispositionIdx = -1; + let key; + let val; + let kLen = 0; + for (let n = 0; n < headers.length; n += 2) { + key = headers[n]; + val = headers[n + 1]; + typeof key !== "string" && (key = key.toString()); + typeof val !== "string" && (val = val.toString("utf8")); + kLen = key.length; + if (kLen === 14 && key[7] === "-" && (key === "content-length" || key.toLowerCase() === "content-length")) { + hasContentLength = true; + } else if (kLen === 19 && key[7] === "-" && (key === "content-disposition" || key.toLowerCase() === "content-disposition")) { + contentDispositionIdx = n + 1; + } + ret[n] = key; + ret[n + 1] = val; + } + if (hasContentLength && contentDispositionIdx !== -1) { + ret[contentDispositionIdx] = Buffer.from(ret[contentDispositionIdx]).toString("latin1"); + } + return ret; + } + function isBuffer2(buffer) { + return buffer instanceof Uint8Array || Buffer.isBuffer(buffer); + } + function validateHandler(handler, method, upgrade) { + if (!handler || typeof handler !== "object") { + throw new InvalidArgumentError("handler must be an object"); + } + if (typeof handler.onConnect !== "function") { + throw new InvalidArgumentError("invalid onConnect method"); + } + if (typeof handler.onError !== "function") { + throw new InvalidArgumentError("invalid onError method"); + } + if (typeof handler.onBodySent !== "function" && handler.onBodySent !== void 0) { + throw new InvalidArgumentError("invalid onBodySent method"); + } + if (upgrade || method === "CONNECT") { + if (typeof handler.onUpgrade !== "function") { + throw new InvalidArgumentError("invalid onUpgrade method"); + } + } else { + if (typeof handler.onHeaders !== "function") { + throw new InvalidArgumentError("invalid onHeaders method"); + } + if (typeof handler.onData !== "function") { + throw new InvalidArgumentError("invalid onData method"); + } + if (typeof handler.onComplete !== "function") { + throw new InvalidArgumentError("invalid onComplete method"); + } + } + } + function isDisturbed(body) { + return !!(body && (stream.isDisturbed(body) || body[kBodyUsed])); + } + function isErrored(body) { + return !!(body && stream.isErrored(body)); + } + function isReadable(body) { + return !!(body && stream.isReadable(body)); + } + function getSocketInfo(socket) { + return { + localAddress: socket.localAddress, + localPort: socket.localPort, + remoteAddress: socket.remoteAddress, + remotePort: socket.remotePort, + remoteFamily: socket.remoteFamily, + timeout: socket.timeout, + bytesWritten: socket.bytesWritten, + bytesRead: socket.bytesRead + }; + } + function ReadableStreamFrom(iterable) { + let iterator; + return new ReadableStream( + { + async start() { + iterator = iterable[Symbol.asyncIterator](); + }, + async pull(controller) { + const { done, value } = await iterator.next(); + if (done) { + queueMicrotask(() => { + controller.close(); + controller.byobRequest?.respond(0); + }); + } else { + const buf = Buffer.isBuffer(value) ? value : Buffer.from(value); + if (buf.byteLength) { + controller.enqueue(new Uint8Array(buf)); + } + } + return controller.desiredSize > 0; + }, + async cancel(reason) { + await iterator.return(); + }, + type: "bytes" + } + ); + } + function isFormDataLike(object) { + return object && typeof object === "object" && typeof object.append === "function" && typeof object.delete === "function" && typeof object.get === "function" && typeof object.getAll === "function" && typeof object.has === "function" && typeof object.set === "function" && object[Symbol.toStringTag] === "FormData"; + } + function addAbortListener(signal, listener) { + if ("addEventListener" in signal) { + signal.addEventListener("abort", listener, { once: true }); + return () => signal.removeEventListener("abort", listener); + } + signal.addListener("abort", listener); + return () => signal.removeListener("abort", listener); + } + var hasToWellFormed = typeof String.prototype.toWellFormed === "function"; + var hasIsWellFormed = typeof String.prototype.isWellFormed === "function"; + function toUSVString(val) { + return hasToWellFormed ? `${val}`.toWellFormed() : nodeUtil.toUSVString(val); + } + function isUSVString(val) { + return hasIsWellFormed ? `${val}`.isWellFormed() : toUSVString(val) === `${val}`; + } + function isTokenCharCode(c) { + switch (c) { + case 34: + case 40: + case 41: + case 44: + case 47: + case 58: + case 59: + case 60: + case 61: + case 62: + case 63: + case 64: + case 91: + case 92: + case 93: + case 123: + case 125: + return false; + default: + return c >= 33 && c <= 126; + } + } + function isValidHTTPToken(characters) { + if (characters.length === 0) { + return false; + } + for (let i = 0; i < characters.length; ++i) { + if (!isTokenCharCode(characters.charCodeAt(i))) { + return false; + } + } + return true; + } + var headerCharRegex = /[^\t\x20-\x7e\x80-\xff]/; + function isValidHeaderValue(characters) { + return !headerCharRegex.test(characters); + } + function parseRangeHeader(range) { + if (range == null || range === "") return { start: 0, end: null, size: null }; + const m = range ? range.match(/^bytes (\d+)-(\d+)\/(\d+)?$/) : null; + return m ? { + start: parseInt(m[1]), + end: m[2] ? parseInt(m[2]) : null, + size: m[3] ? parseInt(m[3]) : null + } : null; + } + function addListener(obj, name, listener) { + const listeners = obj[kListeners] ??= []; + listeners.push([name, listener]); + obj.on(name, listener); + return obj; + } + function removeAllListeners(obj) { + for (const [name, listener] of obj[kListeners] ?? []) { + obj.removeListener(name, listener); + } + obj[kListeners] = null; + } + function errorRequest(client, request, err) { + try { + request.onError(err); + assert(request.aborted); + } catch (err2) { + client.emit("error", err2); + } + } + var kEnumerableProperty = /* @__PURE__ */ Object.create(null); + kEnumerableProperty.enumerable = true; + var normalizedMethodRecordsBase = { + delete: "DELETE", + DELETE: "DELETE", + get: "GET", + GET: "GET", + head: "HEAD", + HEAD: "HEAD", + options: "OPTIONS", + OPTIONS: "OPTIONS", + post: "POST", + POST: "POST", + put: "PUT", + PUT: "PUT" + }; + var normalizedMethodRecords = { + ...normalizedMethodRecordsBase, + patch: "patch", + PATCH: "PATCH" + }; + Object.setPrototypeOf(normalizedMethodRecordsBase, null); + Object.setPrototypeOf(normalizedMethodRecords, null); + module.exports = { + kEnumerableProperty, + nop, + isDisturbed, + isErrored, + isReadable, + toUSVString, + isUSVString, + isBlobLike, + parseOrigin, + parseURL, + getServerName, + isStream: isStream2, + isIterable, + isAsyncIterable, + isDestroyed, + headerNameToString, + bufferToLowerCasedHeaderName, + addListener, + removeAllListeners, + errorRequest, + parseRawHeaders, + parseHeaders, + parseKeepAliveTimeout, + destroy, + bodyLength, + deepClone, + ReadableStreamFrom, + isBuffer: isBuffer2, + validateHandler, + getSocketInfo, + isFormDataLike, + buildURL, + addAbortListener, + isValidHTTPToken, + isValidHeaderValue, + isTokenCharCode, + parseRangeHeader, + normalizedMethodRecordsBase, + normalizedMethodRecords, + isValidPort, + isHttpOrHttpsPrefixed, + nodeMajor, + nodeMinor, + safeHTTPMethods: ["GET", "HEAD", "OPTIONS", "TRACE"], + wrapRequestBody + }; + } +}); + +// viewer/node_modules/undici/lib/core/diagnostics.js +var require_diagnostics = __commonJS({ + "viewer/node_modules/undici/lib/core/diagnostics.js"(exports, module) { + "use strict"; + var diagnosticsChannel = __require("node:diagnostics_channel"); + var util = __require("node:util"); + var undiciDebugLog = util.debuglog("undici"); + var fetchDebuglog = util.debuglog("fetch"); + var websocketDebuglog = util.debuglog("websocket"); + var isClientSet = false; + var channels = { + // Client + beforeConnect: diagnosticsChannel.channel("undici:client:beforeConnect"), + connected: diagnosticsChannel.channel("undici:client:connected"), + connectError: diagnosticsChannel.channel("undici:client:connectError"), + sendHeaders: diagnosticsChannel.channel("undici:client:sendHeaders"), + // Request + create: diagnosticsChannel.channel("undici:request:create"), + bodySent: diagnosticsChannel.channel("undici:request:bodySent"), + headers: diagnosticsChannel.channel("undici:request:headers"), + trailers: diagnosticsChannel.channel("undici:request:trailers"), + error: diagnosticsChannel.channel("undici:request:error"), + // WebSocket + open: diagnosticsChannel.channel("undici:websocket:open"), + close: diagnosticsChannel.channel("undici:websocket:close"), + socketError: diagnosticsChannel.channel("undici:websocket:socket_error"), + ping: diagnosticsChannel.channel("undici:websocket:ping"), + pong: diagnosticsChannel.channel("undici:websocket:pong") + }; + if (undiciDebugLog.enabled || fetchDebuglog.enabled) { + const debuglog = fetchDebuglog.enabled ? fetchDebuglog : undiciDebugLog; + diagnosticsChannel.channel("undici:client:beforeConnect").subscribe((evt) => { + const { + connectParams: { version, protocol, port: port2, host: host2 } + } = evt; + debuglog( + "connecting to %s using %s%s", + `${host2}${port2 ? `:${port2}` : ""}`, + protocol, + version + ); + }); + diagnosticsChannel.channel("undici:client:connected").subscribe((evt) => { + const { + connectParams: { version, protocol, port: port2, host: host2 } + } = evt; + debuglog( + "connected to %s using %s%s", + `${host2}${port2 ? `:${port2}` : ""}`, + protocol, + version + ); + }); + diagnosticsChannel.channel("undici:client:connectError").subscribe((evt) => { + const { + connectParams: { version, protocol, port: port2, host: host2 }, + error + } = evt; + debuglog( + "connection to %s using %s%s errored - %s", + `${host2}${port2 ? `:${port2}` : ""}`, + protocol, + version, + error.message + ); + }); + diagnosticsChannel.channel("undici:client:sendHeaders").subscribe((evt) => { + const { + request: { method, path: path12, origin } + } = evt; + debuglog("sending request to %s %s/%s", method, origin, path12); + }); + diagnosticsChannel.channel("undici:request:headers").subscribe((evt) => { + const { + request: { method, path: path12, origin }, + response: { statusCode } + } = evt; + debuglog( + "received response to %s %s/%s - HTTP %d", + method, + origin, + path12, + statusCode + ); + }); + diagnosticsChannel.channel("undici:request:trailers").subscribe((evt) => { + const { + request: { method, path: path12, origin } + } = evt; + debuglog("trailers received from %s %s/%s", method, origin, path12); + }); + diagnosticsChannel.channel("undici:request:error").subscribe((evt) => { + const { + request: { method, path: path12, origin }, + error + } = evt; + debuglog( + "request to %s %s/%s errored - %s", + method, + origin, + path12, + error.message + ); + }); + isClientSet = true; + } + if (websocketDebuglog.enabled) { + if (!isClientSet) { + const debuglog = undiciDebugLog.enabled ? undiciDebugLog : websocketDebuglog; + diagnosticsChannel.channel("undici:client:beforeConnect").subscribe((evt) => { + const { + connectParams: { version, protocol, port: port2, host: host2 } + } = evt; + debuglog( + "connecting to %s%s using %s%s", + host2, + port2 ? `:${port2}` : "", + protocol, + version + ); + }); + diagnosticsChannel.channel("undici:client:connected").subscribe((evt) => { + const { + connectParams: { version, protocol, port: port2, host: host2 } + } = evt; + debuglog( + "connected to %s%s using %s%s", + host2, + port2 ? `:${port2}` : "", + protocol, + version + ); + }); + diagnosticsChannel.channel("undici:client:connectError").subscribe((evt) => { + const { + connectParams: { version, protocol, port: port2, host: host2 }, + error + } = evt; + debuglog( + "connection to %s%s using %s%s errored - %s", + host2, + port2 ? `:${port2}` : "", + protocol, + version, + error.message + ); + }); + diagnosticsChannel.channel("undici:client:sendHeaders").subscribe((evt) => { + const { + request: { method, path: path12, origin } + } = evt; + debuglog("sending request to %s %s/%s", method, origin, path12); + }); + } + diagnosticsChannel.channel("undici:websocket:open").subscribe((evt) => { + const { + address: { address, port: port2 } + } = evt; + websocketDebuglog("connection opened %s%s", address, port2 ? `:${port2}` : ""); + }); + diagnosticsChannel.channel("undici:websocket:close").subscribe((evt) => { + const { websocket, code, reason } = evt; + websocketDebuglog( + "closed connection to %s - %s %s", + websocket.url, + code, + reason + ); + }); + diagnosticsChannel.channel("undici:websocket:socket_error").subscribe((err) => { + websocketDebuglog("connection errored - %s", err.message); + }); + diagnosticsChannel.channel("undici:websocket:ping").subscribe((evt) => { + websocketDebuglog("ping received"); + }); + diagnosticsChannel.channel("undici:websocket:pong").subscribe((evt) => { + websocketDebuglog("pong received"); + }); + } + module.exports = { + channels + }; + } +}); + +// viewer/node_modules/undici/lib/core/request.js +var require_request = __commonJS({ + "viewer/node_modules/undici/lib/core/request.js"(exports, module) { + "use strict"; + var { + InvalidArgumentError, + NotSupportedError + } = require_errors(); + var assert = __require("node:assert"); + var { + isValidHTTPToken, + isValidHeaderValue, + isStream: isStream2, + destroy, + isBuffer: isBuffer2, + isFormDataLike, + isIterable, + isBlobLike, + buildURL, + validateHandler, + getServerName, + normalizedMethodRecords + } = require_util(); + var { channels } = require_diagnostics(); + var { headerNameLowerCasedRecord } = require_constants(); + var invalidPathRegex = /[^\u0021-\u00ff]/; + var kHandler = /* @__PURE__ */ Symbol("handler"); + var Request2 = class { + constructor(origin, { + path: path12, + method, + body, + headers, + query, + idempotent, + blocking, + upgrade, + headersTimeout, + bodyTimeout, + reset, + throwOnError, + expectContinue, + servername + }, handler) { + if (typeof path12 !== "string") { + throw new InvalidArgumentError("path must be a string"); + } else if (path12[0] !== "/" && !(path12.startsWith("http://") || path12.startsWith("https://")) && method !== "CONNECT") { + throw new InvalidArgumentError("path must be an absolute URL or start with a slash"); + } else if (invalidPathRegex.test(path12)) { + throw new InvalidArgumentError("invalid request path"); + } + if (typeof method !== "string") { + throw new InvalidArgumentError("method must be a string"); + } else if (normalizedMethodRecords[method] === void 0 && !isValidHTTPToken(method)) { + throw new InvalidArgumentError("invalid request method"); + } + if (upgrade && typeof upgrade !== "string") { + throw new InvalidArgumentError("upgrade must be a string"); + } + if (upgrade && !isValidHeaderValue(upgrade)) { + throw new InvalidArgumentError("invalid upgrade header"); + } + if (headersTimeout != null && (!Number.isFinite(headersTimeout) || headersTimeout < 0)) { + throw new InvalidArgumentError("invalid headersTimeout"); + } + if (bodyTimeout != null && (!Number.isFinite(bodyTimeout) || bodyTimeout < 0)) { + throw new InvalidArgumentError("invalid bodyTimeout"); + } + if (reset != null && typeof reset !== "boolean") { + throw new InvalidArgumentError("invalid reset"); + } + if (expectContinue != null && typeof expectContinue !== "boolean") { + throw new InvalidArgumentError("invalid expectContinue"); + } + this.headersTimeout = headersTimeout; + this.bodyTimeout = bodyTimeout; + this.throwOnError = throwOnError === true; + this.method = method; + this.abort = null; + if (body == null) { + this.body = null; + } else if (isStream2(body)) { + this.body = body; + const rState = this.body._readableState; + if (!rState || !rState.autoDestroy) { + this.endHandler = function autoDestroy() { + destroy(this); + }; + this.body.on("end", this.endHandler); + } + this.errorHandler = (err) => { + if (this.abort) { + this.abort(err); + } else { + this.error = err; + } + }; + this.body.on("error", this.errorHandler); + } else if (isBuffer2(body)) { + this.body = body.byteLength ? body : null; + } else if (ArrayBuffer.isView(body)) { + this.body = body.buffer.byteLength ? Buffer.from(body.buffer, body.byteOffset, body.byteLength) : null; + } else if (body instanceof ArrayBuffer) { + this.body = body.byteLength ? Buffer.from(body) : null; + } else if (typeof body === "string") { + this.body = body.length ? Buffer.from(body) : null; + } else if (isFormDataLike(body) || isIterable(body) || isBlobLike(body)) { + this.body = body; + } else { + throw new InvalidArgumentError("body must be a string, a Buffer, a Readable stream, an iterable, or an async iterable"); + } + this.completed = false; + this.aborted = false; + this.upgrade = upgrade || null; + this.path = query ? buildURL(path12, query) : path12; + this.origin = origin; + this.idempotent = idempotent == null ? method === "HEAD" || method === "GET" : idempotent; + this.blocking = blocking == null ? false : blocking; + this.reset = reset == null ? null : reset; + this.host = null; + this.contentLength = null; + this.contentType = null; + this.headers = []; + this.expectContinue = expectContinue != null ? expectContinue : false; + if (Array.isArray(headers)) { + if (headers.length % 2 !== 0) { + throw new InvalidArgumentError("headers array must be even"); + } + for (let i = 0; i < headers.length; i += 2) { + processHeader(this, headers[i], headers[i + 1]); + } + } else if (headers && typeof headers === "object") { + if (headers[Symbol.iterator]) { + for (const header of headers) { + if (!Array.isArray(header) || header.length !== 2) { + throw new InvalidArgumentError("headers must be in key-value pair format"); + } + processHeader(this, header[0], header[1]); + } + } else { + const keys = Object.keys(headers); + for (let i = 0; i < keys.length; ++i) { + processHeader(this, keys[i], headers[keys[i]]); + } + } + } else if (headers != null) { + throw new InvalidArgumentError("headers must be an object or an array"); + } + validateHandler(handler, method, upgrade); + this.servername = servername || getServerName(this.host); + this[kHandler] = handler; + if (channels.create.hasSubscribers) { + channels.create.publish({ request: this }); + } + } + onBodySent(chunk) { + if (this[kHandler].onBodySent) { + try { + return this[kHandler].onBodySent(chunk); + } catch (err) { + this.abort(err); + } + } + } + onRequestSent() { + if (channels.bodySent.hasSubscribers) { + channels.bodySent.publish({ request: this }); + } + if (this[kHandler].onRequestSent) { + try { + return this[kHandler].onRequestSent(); + } catch (err) { + this.abort(err); + } + } + } + onConnect(abort) { + assert(!this.aborted); + assert(!this.completed); + if (this.error) { + abort(this.error); + } else { + this.abort = abort; + return this[kHandler].onConnect(abort); + } + } + onResponseStarted() { + return this[kHandler].onResponseStarted?.(); + } + onHeaders(statusCode, headers, resume, statusText) { + assert(!this.aborted); + assert(!this.completed); + if (channels.headers.hasSubscribers) { + channels.headers.publish({ request: this, response: { statusCode, headers, statusText } }); + } + try { + return this[kHandler].onHeaders(statusCode, headers, resume, statusText); + } catch (err) { + this.abort(err); + } + } + onData(chunk) { + assert(!this.aborted); + assert(!this.completed); + try { + return this[kHandler].onData(chunk); + } catch (err) { + this.abort(err); + return false; + } + } + onUpgrade(statusCode, headers, socket) { + assert(!this.aborted); + assert(!this.completed); + return this[kHandler].onUpgrade(statusCode, headers, socket); + } + onComplete(trailers) { + this.onFinally(); + assert(!this.aborted); + this.completed = true; + if (channels.trailers.hasSubscribers) { + channels.trailers.publish({ request: this, trailers }); + } + try { + return this[kHandler].onComplete(trailers); + } catch (err) { + this.onError(err); + } + } + onError(error) { + this.onFinally(); + if (channels.error.hasSubscribers) { + channels.error.publish({ request: this, error }); + } + if (this.aborted) { + return; + } + this.aborted = true; + return this[kHandler].onError(error); + } + onFinally() { + if (this.errorHandler) { + this.body.off("error", this.errorHandler); + this.errorHandler = null; + } + if (this.endHandler) { + this.body.off("end", this.endHandler); + this.endHandler = null; + } + } + addHeader(key, value) { + processHeader(this, key, value); + return this; + } + }; + function processHeader(request, key, val) { + if (val && (typeof val === "object" && !Array.isArray(val))) { + throw new InvalidArgumentError(`invalid ${key} header`); + } else if (val === void 0) { + return; + } + let headerName = headerNameLowerCasedRecord[key]; + if (headerName === void 0) { + headerName = key.toLowerCase(); + if (headerNameLowerCasedRecord[headerName] === void 0 && !isValidHTTPToken(headerName)) { + throw new InvalidArgumentError("invalid header key"); + } + } + if (Array.isArray(val)) { + const arr = []; + for (let i = 0; i < val.length; i++) { + if (typeof val[i] === "string") { + if (!isValidHeaderValue(val[i])) { + throw new InvalidArgumentError(`invalid ${key} header`); + } + arr.push(val[i]); + } else if (val[i] === null) { + arr.push(""); + } else if (typeof val[i] === "object") { + throw new InvalidArgumentError(`invalid ${key} header`); + } else { + arr.push(`${val[i]}`); + } + } + val = arr; + } else if (typeof val === "string") { + if (!isValidHeaderValue(val)) { + throw new InvalidArgumentError(`invalid ${key} header`); + } + } else if (val === null) { + val = ""; + } else { + val = `${val}`; + } + if (headerName === "host") { + if (request.host !== null) { + throw new InvalidArgumentError("duplicate host header"); + } + if (typeof val !== "string") { + throw new InvalidArgumentError("invalid host header"); + } + request.host = val; + } else if (headerName === "content-length") { + if (request.contentLength !== null) { + throw new InvalidArgumentError("duplicate content-length header"); + } + request.contentLength = parseInt(val, 10); + if (!Number.isFinite(request.contentLength)) { + throw new InvalidArgumentError("invalid content-length header"); + } + } else if (request.contentType === null && headerName === "content-type") { + request.contentType = val; + request.headers.push(key, val); + } else if (headerName === "transfer-encoding" || headerName === "keep-alive" || headerName === "upgrade") { + throw new InvalidArgumentError(`invalid ${headerName} header`); + } else if (headerName === "connection") { + const value = typeof val === "string" ? val.toLowerCase() : null; + if (value !== "close" && value !== "keep-alive") { + throw new InvalidArgumentError("invalid connection header"); + } + if (value === "close") { + request.reset = true; + } + } else if (headerName === "expect") { + throw new NotSupportedError("expect header not supported"); + } else { + request.headers.push(key, val); + } + } + module.exports = Request2; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/dispatcher.js +var require_dispatcher = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/dispatcher.js"(exports, module) { + "use strict"; + var EventEmitter = __require("node:events"); + var Dispatcher = class extends EventEmitter { + dispatch() { + throw new Error("not implemented"); + } + close() { + throw new Error("not implemented"); + } + destroy() { + throw new Error("not implemented"); + } + compose(...args) { + const interceptors = Array.isArray(args[0]) ? args[0] : args; + let dispatch = this.dispatch.bind(this); + for (const interceptor of interceptors) { + if (interceptor == null) { + continue; + } + if (typeof interceptor !== "function") { + throw new TypeError(`invalid interceptor, expected function received ${typeof interceptor}`); + } + dispatch = interceptor(dispatch); + if (dispatch == null || typeof dispatch !== "function" || dispatch.length !== 2) { + throw new TypeError("invalid interceptor"); + } + } + return new ComposedDispatcher(this, dispatch); + } + }; + var ComposedDispatcher = class extends Dispatcher { + #dispatcher = null; + #dispatch = null; + constructor(dispatcher, dispatch) { + super(); + this.#dispatcher = dispatcher; + this.#dispatch = dispatch; + } + dispatch(...args) { + this.#dispatch(...args); + } + close(...args) { + return this.#dispatcher.close(...args); + } + destroy(...args) { + return this.#dispatcher.destroy(...args); + } + }; + module.exports = Dispatcher; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/dispatcher-base.js +var require_dispatcher_base = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/dispatcher-base.js"(exports, module) { + "use strict"; + var Dispatcher = require_dispatcher(); + var { + ClientDestroyedError, + ClientClosedError, + InvalidArgumentError + } = require_errors(); + var { kDestroy, kClose, kClosed, kDestroyed, kDispatch, kInterceptors } = require_symbols(); + var kOnDestroyed = /* @__PURE__ */ Symbol("onDestroyed"); + var kOnClosed = /* @__PURE__ */ Symbol("onClosed"); + var kInterceptedDispatch = /* @__PURE__ */ Symbol("Intercepted Dispatch"); + var kWebSocketOptions = /* @__PURE__ */ Symbol("webSocketOptions"); + var DispatcherBase = class extends Dispatcher { + constructor(opts) { + super(); + this[kDestroyed] = false; + this[kOnDestroyed] = null; + this[kClosed] = false; + this[kOnClosed] = []; + this[kWebSocketOptions] = opts?.webSocket ?? {}; + } + get webSocketOptions() { + return { + maxPayloadSize: this[kWebSocketOptions].maxPayloadSize ?? 128 * 1024 * 1024 + }; + } + get destroyed() { + return this[kDestroyed]; + } + get closed() { + return this[kClosed]; + } + get interceptors() { + return this[kInterceptors]; + } + set interceptors(newInterceptors) { + if (newInterceptors) { + for (let i = newInterceptors.length - 1; i >= 0; i--) { + const interceptor = this[kInterceptors][i]; + if (typeof interceptor !== "function") { + throw new InvalidArgumentError("interceptor must be an function"); + } + } + } + this[kInterceptors] = newInterceptors; + } + close(callback) { + if (callback === void 0) { + return new Promise((resolve, reject) => { + this.close((err, data) => { + return err ? reject(err) : resolve(data); + }); + }); + } + if (typeof callback !== "function") { + throw new InvalidArgumentError("invalid callback"); + } + if (this[kDestroyed]) { + queueMicrotask(() => callback(new ClientDestroyedError(), null)); + return; + } + if (this[kClosed]) { + if (this[kOnClosed]) { + this[kOnClosed].push(callback); + } else { + queueMicrotask(() => callback(null, null)); + } + return; + } + this[kClosed] = true; + this[kOnClosed].push(callback); + const onClosed = () => { + const callbacks = this[kOnClosed]; + this[kOnClosed] = null; + for (let i = 0; i < callbacks.length; i++) { + callbacks[i](null, null); + } + }; + this[kClose]().then(() => this.destroy()).then(() => { + queueMicrotask(onClosed); + }); + } + destroy(err, callback) { + if (typeof err === "function") { + callback = err; + err = null; + } + if (callback === void 0) { + return new Promise((resolve, reject) => { + this.destroy(err, (err2, data) => { + return err2 ? ( + /* istanbul ignore next: should never error */ + reject(err2) + ) : resolve(data); + }); + }); + } + if (typeof callback !== "function") { + throw new InvalidArgumentError("invalid callback"); + } + if (this[kDestroyed]) { + if (this[kOnDestroyed]) { + this[kOnDestroyed].push(callback); + } else { + queueMicrotask(() => callback(null, null)); + } + return; + } + if (!err) { + err = new ClientDestroyedError(); + } + this[kDestroyed] = true; + this[kOnDestroyed] = this[kOnDestroyed] || []; + this[kOnDestroyed].push(callback); + const onDestroyed = () => { + const callbacks = this[kOnDestroyed]; + this[kOnDestroyed] = null; + for (let i = 0; i < callbacks.length; i++) { + callbacks[i](null, null); + } + }; + this[kDestroy](err).then(() => { + queueMicrotask(onDestroyed); + }); + } + [kInterceptedDispatch](opts, handler) { + if (!this[kInterceptors] || this[kInterceptors].length === 0) { + this[kInterceptedDispatch] = this[kDispatch]; + return this[kDispatch](opts, handler); + } + let dispatch = this[kDispatch].bind(this); + for (let i = this[kInterceptors].length - 1; i >= 0; i--) { + dispatch = this[kInterceptors][i](dispatch); + } + this[kInterceptedDispatch] = dispatch; + return dispatch(opts, handler); + } + dispatch(opts, handler) { + if (!handler || typeof handler !== "object") { + throw new InvalidArgumentError("handler must be an object"); + } + try { + if (!opts || typeof opts !== "object") { + throw new InvalidArgumentError("opts must be an object."); + } + if (this[kDestroyed] || this[kOnDestroyed]) { + throw new ClientDestroyedError(); + } + if (this[kClosed]) { + throw new ClientClosedError(); + } + return this[kInterceptedDispatch](opts, handler); + } catch (err) { + if (typeof handler.onError !== "function") { + throw new InvalidArgumentError("invalid onError method"); + } + handler.onError(err); + return false; + } + } + }; + module.exports = DispatcherBase; + } +}); + +// viewer/node_modules/undici/lib/util/timers.js +var require_timers = __commonJS({ + "viewer/node_modules/undici/lib/util/timers.js"(exports, module) { + "use strict"; + var fastNow = 0; + var RESOLUTION_MS = 1e3; + var TICK_MS = (RESOLUTION_MS >> 1) - 1; + var fastNowTimeout; + var kFastTimer = /* @__PURE__ */ Symbol("kFastTimer"); + var fastTimers = []; + var NOT_IN_LIST = -2; + var TO_BE_CLEARED = -1; + var PENDING = 0; + var ACTIVE = 1; + function onTick() { + fastNow += TICK_MS; + let idx = 0; + let len = fastTimers.length; + while (idx < len) { + const timer = fastTimers[idx]; + if (timer._state === PENDING) { + timer._idleStart = fastNow - TICK_MS; + timer._state = ACTIVE; + } else if (timer._state === ACTIVE && fastNow >= timer._idleStart + timer._idleTimeout) { + timer._state = TO_BE_CLEARED; + timer._idleStart = -1; + timer._onTimeout(timer._timerArg); + } + if (timer._state === TO_BE_CLEARED) { + timer._state = NOT_IN_LIST; + if (--len !== 0) { + fastTimers[idx] = fastTimers[len]; + } + } else { + ++idx; + } + } + fastTimers.length = len; + if (fastTimers.length !== 0) { + refreshTimeout(); + } + } + function refreshTimeout() { + if (fastNowTimeout) { + fastNowTimeout.refresh(); + } else { + clearTimeout(fastNowTimeout); + fastNowTimeout = setTimeout(onTick, TICK_MS); + if (fastNowTimeout.unref) { + fastNowTimeout.unref(); + } + } + } + var FastTimer = class { + [kFastTimer] = true; + /** + * The state of the timer, which can be one of the following: + * - NOT_IN_LIST (-2) + * - TO_BE_CLEARED (-1) + * - PENDING (0) + * - ACTIVE (1) + * + * @type {-2|-1|0|1} + * @private + */ + _state = NOT_IN_LIST; + /** + * The number of milliseconds to wait before calling the callback. + * + * @type {number} + * @private + */ + _idleTimeout = -1; + /** + * The time in milliseconds when the timer was started. This value is used to + * calculate when the timer should expire. + * + * @type {number} + * @default -1 + * @private + */ + _idleStart = -1; + /** + * The function to be executed when the timer expires. + * @type {Function} + * @private + */ + _onTimeout; + /** + * The argument to be passed to the callback when the timer expires. + * + * @type {*} + * @private + */ + _timerArg; + /** + * @constructor + * @param {Function} callback A function to be executed after the timer + * expires. + * @param {number} delay The time, in milliseconds that the timer should wait + * before the specified function or code is executed. + * @param {*} arg + */ + constructor(callback, delay, arg) { + this._onTimeout = callback; + this._idleTimeout = delay; + this._timerArg = arg; + this.refresh(); + } + /** + * Sets the timer's start time to the current time, and reschedules the timer + * to call its callback at the previously specified duration adjusted to the + * current time. + * Using this on a timer that has already called its callback will reactivate + * the timer. + * + * @returns {void} + */ + refresh() { + if (this._state === NOT_IN_LIST) { + fastTimers.push(this); + } + if (!fastNowTimeout || fastTimers.length === 1) { + refreshTimeout(); + } + this._state = PENDING; + } + /** + * The `clear` method cancels the timer, preventing it from executing. + * + * @returns {void} + * @private + */ + clear() { + this._state = TO_BE_CLEARED; + this._idleStart = -1; + } + }; + module.exports = { + /** + * The setTimeout() method sets a timer which executes a function once the + * timer expires. + * @param {Function} callback A function to be executed after the timer + * expires. + * @param {number} delay The time, in milliseconds that the timer should + * wait before the specified function or code is executed. + * @param {*} [arg] An optional argument to be passed to the callback function + * when the timer expires. + * @returns {NodeJS.Timeout|FastTimer} + */ + setTimeout(callback, delay, arg) { + return delay <= RESOLUTION_MS ? setTimeout(callback, delay, arg) : new FastTimer(callback, delay, arg); + }, + /** + * The clearTimeout method cancels an instantiated Timer previously created + * by calling setTimeout. + * + * @param {NodeJS.Timeout|FastTimer} timeout + */ + clearTimeout(timeout) { + if (timeout[kFastTimer]) { + timeout.clear(); + } else { + clearTimeout(timeout); + } + }, + /** + * The setFastTimeout() method sets a fastTimer which executes a function once + * the timer expires. + * @param {Function} callback A function to be executed after the timer + * expires. + * @param {number} delay The time, in milliseconds that the timer should + * wait before the specified function or code is executed. + * @param {*} [arg] An optional argument to be passed to the callback function + * when the timer expires. + * @returns {FastTimer} + */ + setFastTimeout(callback, delay, arg) { + return new FastTimer(callback, delay, arg); + }, + /** + * The clearTimeout method cancels an instantiated FastTimer previously + * created by calling setFastTimeout. + * + * @param {FastTimer} timeout + */ + clearFastTimeout(timeout) { + timeout.clear(); + }, + /** + * The now method returns the value of the internal fast timer clock. + * + * @returns {number} + */ + now() { + return fastNow; + }, + /** + * Trigger the onTick function to process the fastTimers array. + * Exported for testing purposes only. + * Marking as deprecated to discourage any use outside of testing. + * @deprecated + * @param {number} [delay=0] The delay in milliseconds to add to the now value. + */ + tick(delay = 0) { + fastNow += delay - RESOLUTION_MS + 1; + onTick(); + onTick(); + }, + /** + * Reset FastTimers. + * Exported for testing purposes only. + * Marking as deprecated to discourage any use outside of testing. + * @deprecated + */ + reset() { + fastNow = 0; + fastTimers.length = 0; + clearTimeout(fastNowTimeout); + fastNowTimeout = null; + }, + /** + * Exporting for testing purposes only. + * Marking as deprecated to discourage any use outside of testing. + * @deprecated + */ + kFastTimer + }; + } +}); + +// viewer/node_modules/undici/lib/core/connect.js +var require_connect = __commonJS({ + "viewer/node_modules/undici/lib/core/connect.js"(exports, module) { + "use strict"; + var net = __require("node:net"); + var assert = __require("node:assert"); + var util = require_util(); + var { InvalidArgumentError, ConnectTimeoutError } = require_errors(); + var timers = require_timers(); + function noop() { + } + var tls; + var SessionCache; + if (global.FinalizationRegistry && !(process.env.NODE_V8_COVERAGE || process.env.UNDICI_NO_FG)) { + SessionCache = class WeakSessionCache { + constructor(maxCachedSessions) { + this._maxCachedSessions = maxCachedSessions; + this._sessionCache = /* @__PURE__ */ new Map(); + this._sessionRegistry = new global.FinalizationRegistry((key) => { + if (this._sessionCache.size < this._maxCachedSessions) { + return; + } + const ref = this._sessionCache.get(key); + if (ref !== void 0 && ref.deref() === void 0) { + this._sessionCache.delete(key); + } + }); + } + get(sessionKey) { + const ref = this._sessionCache.get(sessionKey); + return ref ? ref.deref() : null; + } + set(sessionKey, session) { + if (this._maxCachedSessions === 0) { + return; + } + this._sessionCache.set(sessionKey, new WeakRef(session)); + this._sessionRegistry.register(session, sessionKey); + } + }; + } else { + SessionCache = class SimpleSessionCache { + constructor(maxCachedSessions) { + this._maxCachedSessions = maxCachedSessions; + this._sessionCache = /* @__PURE__ */ new Map(); + } + get(sessionKey) { + return this._sessionCache.get(sessionKey); + } + set(sessionKey, session) { + if (this._maxCachedSessions === 0) { + return; + } + if (this._sessionCache.size >= this._maxCachedSessions) { + const { value: oldestKey } = this._sessionCache.keys().next(); + this._sessionCache.delete(oldestKey); + } + this._sessionCache.set(sessionKey, session); + } + }; + } + function buildConnector({ allowH2, maxCachedSessions, socketPath, timeout, session: customSession, ...opts }) { + if (maxCachedSessions != null && (!Number.isInteger(maxCachedSessions) || maxCachedSessions < 0)) { + throw new InvalidArgumentError("maxCachedSessions must be a positive integer or zero"); + } + const options = { path: socketPath, ...opts }; + const sessionCache = new SessionCache(maxCachedSessions == null ? 100 : maxCachedSessions); + timeout = timeout == null ? 1e4 : timeout; + allowH2 = allowH2 != null ? allowH2 : false; + return function connect({ hostname, host: host2, protocol, port: port2, servername, localAddress, httpSocket }, callback) { + let socket; + if (protocol === "https:") { + if (!tls) { + tls = __require("node:tls"); + } + servername = servername || options.servername || util.getServerName(host2) || null; + const sessionKey = servername || hostname; + assert(sessionKey); + const session = customSession || sessionCache.get(sessionKey) || null; + port2 = port2 || 443; + socket = tls.connect({ + highWaterMark: 16384, + // TLS in node can't have bigger HWM anyway... + ...options, + servername, + session, + localAddress, + // TODO(HTTP/2): Add support for h2c + ALPNProtocols: allowH2 ? ["http/1.1", "h2"] : ["http/1.1"], + socket: httpSocket, + // upgrade socket connection + port: port2, + host: hostname + }); + socket.on("session", function(session2) { + sessionCache.set(sessionKey, session2); + }); + } else { + assert(!httpSocket, "httpSocket can only be sent on TLS update"); + port2 = port2 || 80; + socket = net.connect({ + highWaterMark: 64 * 1024, + // Same as nodejs fs streams. + ...options, + localAddress, + port: port2, + host: hostname + }); + } + if (options.keepAlive == null || options.keepAlive) { + const keepAliveInitialDelay = options.keepAliveInitialDelay === void 0 ? 6e4 : options.keepAliveInitialDelay; + socket.setKeepAlive(true, keepAliveInitialDelay); + } + const clearConnectTimeout = setupConnectTimeout(new WeakRef(socket), { timeout, hostname, port: port2 }); + socket.setNoDelay(true).once(protocol === "https:" ? "secureConnect" : "connect", function() { + queueMicrotask(clearConnectTimeout); + if (callback) { + const cb = callback; + callback = null; + cb(null, this); + } + }).on("error", function(err) { + queueMicrotask(clearConnectTimeout); + if (callback) { + const cb = callback; + callback = null; + cb(err); + } + }); + return socket; + }; + } + var setupConnectTimeout = process.platform === "win32" ? (socketWeakRef, opts) => { + if (!opts.timeout) { + return noop; + } + let s1 = null; + let s2 = null; + const fastTimer = timers.setFastTimeout(() => { + s1 = setImmediate(() => { + s2 = setImmediate(() => onConnectTimeout(socketWeakRef.deref(), opts)); + }); + }, opts.timeout); + return () => { + timers.clearFastTimeout(fastTimer); + clearImmediate(s1); + clearImmediate(s2); + }; + } : (socketWeakRef, opts) => { + if (!opts.timeout) { + return noop; + } + let s1 = null; + const fastTimer = timers.setFastTimeout(() => { + s1 = setImmediate(() => { + onConnectTimeout(socketWeakRef.deref(), opts); + }); + }, opts.timeout); + return () => { + timers.clearFastTimeout(fastTimer); + clearImmediate(s1); + }; + }; + function onConnectTimeout(socket, opts) { + if (socket == null) { + return; + } + let message = "Connect Timeout Error"; + if (Array.isArray(socket.autoSelectFamilyAttemptedAddresses)) { + message += ` (attempted addresses: ${socket.autoSelectFamilyAttemptedAddresses.join(", ")},`; + } else { + message += ` (attempted address: ${opts.hostname}:${opts.port},`; + } + message += ` timeout: ${opts.timeout}ms)`; + util.destroy(socket, new ConnectTimeoutError(message)); + } + module.exports = buildConnector; + } +}); + +// viewer/node_modules/undici/lib/llhttp/utils.js +var require_utils = __commonJS({ + "viewer/node_modules/undici/lib/llhttp/utils.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.enumToMap = void 0; + function enumToMap(obj) { + const res = {}; + Object.keys(obj).forEach((key) => { + const value = obj[key]; + if (typeof value === "number") { + res[key] = value; + } + }); + return res; + } + exports.enumToMap = enumToMap; + } +}); + +// viewer/node_modules/undici/lib/llhttp/constants.js +var require_constants2 = __commonJS({ + "viewer/node_modules/undici/lib/llhttp/constants.js"(exports) { + "use strict"; + Object.defineProperty(exports, "__esModule", { value: true }); + exports.SPECIAL_HEADERS = exports.HEADER_STATE = exports.MINOR = exports.MAJOR = exports.CONNECTION_TOKEN_CHARS = exports.HEADER_CHARS = exports.TOKEN = exports.STRICT_TOKEN = exports.HEX = exports.URL_CHAR = exports.STRICT_URL_CHAR = exports.USERINFO_CHARS = exports.MARK = exports.ALPHANUM = exports.NUM = exports.HEX_MAP = exports.NUM_MAP = exports.ALPHA = exports.FINISH = exports.H_METHOD_MAP = exports.METHOD_MAP = exports.METHODS_RTSP = exports.METHODS_ICE = exports.METHODS_HTTP = exports.METHODS = exports.LENIENT_FLAGS = exports.FLAGS = exports.TYPE = exports.ERROR = void 0; + var utils_1 = require_utils(); + var ERROR; + (function(ERROR2) { + ERROR2[ERROR2["OK"] = 0] = "OK"; + ERROR2[ERROR2["INTERNAL"] = 1] = "INTERNAL"; + ERROR2[ERROR2["STRICT"] = 2] = "STRICT"; + ERROR2[ERROR2["LF_EXPECTED"] = 3] = "LF_EXPECTED"; + ERROR2[ERROR2["UNEXPECTED_CONTENT_LENGTH"] = 4] = "UNEXPECTED_CONTENT_LENGTH"; + ERROR2[ERROR2["CLOSED_CONNECTION"] = 5] = "CLOSED_CONNECTION"; + ERROR2[ERROR2["INVALID_METHOD"] = 6] = "INVALID_METHOD"; + ERROR2[ERROR2["INVALID_URL"] = 7] = "INVALID_URL"; + ERROR2[ERROR2["INVALID_CONSTANT"] = 8] = "INVALID_CONSTANT"; + ERROR2[ERROR2["INVALID_VERSION"] = 9] = "INVALID_VERSION"; + ERROR2[ERROR2["INVALID_HEADER_TOKEN"] = 10] = "INVALID_HEADER_TOKEN"; + ERROR2[ERROR2["INVALID_CONTENT_LENGTH"] = 11] = "INVALID_CONTENT_LENGTH"; + ERROR2[ERROR2["INVALID_CHUNK_SIZE"] = 12] = "INVALID_CHUNK_SIZE"; + ERROR2[ERROR2["INVALID_STATUS"] = 13] = "INVALID_STATUS"; + ERROR2[ERROR2["INVALID_EOF_STATE"] = 14] = "INVALID_EOF_STATE"; + ERROR2[ERROR2["INVALID_TRANSFER_ENCODING"] = 15] = "INVALID_TRANSFER_ENCODING"; + ERROR2[ERROR2["CB_MESSAGE_BEGIN"] = 16] = "CB_MESSAGE_BEGIN"; + ERROR2[ERROR2["CB_HEADERS_COMPLETE"] = 17] = "CB_HEADERS_COMPLETE"; + ERROR2[ERROR2["CB_MESSAGE_COMPLETE"] = 18] = "CB_MESSAGE_COMPLETE"; + ERROR2[ERROR2["CB_CHUNK_HEADER"] = 19] = "CB_CHUNK_HEADER"; + ERROR2[ERROR2["CB_CHUNK_COMPLETE"] = 20] = "CB_CHUNK_COMPLETE"; + ERROR2[ERROR2["PAUSED"] = 21] = "PAUSED"; + ERROR2[ERROR2["PAUSED_UPGRADE"] = 22] = "PAUSED_UPGRADE"; + ERROR2[ERROR2["PAUSED_H2_UPGRADE"] = 23] = "PAUSED_H2_UPGRADE"; + ERROR2[ERROR2["USER"] = 24] = "USER"; + })(ERROR = exports.ERROR || (exports.ERROR = {})); + var TYPE; + (function(TYPE2) { + TYPE2[TYPE2["BOTH"] = 0] = "BOTH"; + TYPE2[TYPE2["REQUEST"] = 1] = "REQUEST"; + TYPE2[TYPE2["RESPONSE"] = 2] = "RESPONSE"; + })(TYPE = exports.TYPE || (exports.TYPE = {})); + var FLAGS; + (function(FLAGS2) { + FLAGS2[FLAGS2["CONNECTION_KEEP_ALIVE"] = 1] = "CONNECTION_KEEP_ALIVE"; + FLAGS2[FLAGS2["CONNECTION_CLOSE"] = 2] = "CONNECTION_CLOSE"; + FLAGS2[FLAGS2["CONNECTION_UPGRADE"] = 4] = "CONNECTION_UPGRADE"; + FLAGS2[FLAGS2["CHUNKED"] = 8] = "CHUNKED"; + FLAGS2[FLAGS2["UPGRADE"] = 16] = "UPGRADE"; + FLAGS2[FLAGS2["CONTENT_LENGTH"] = 32] = "CONTENT_LENGTH"; + FLAGS2[FLAGS2["SKIPBODY"] = 64] = "SKIPBODY"; + FLAGS2[FLAGS2["TRAILING"] = 128] = "TRAILING"; + FLAGS2[FLAGS2["TRANSFER_ENCODING"] = 512] = "TRANSFER_ENCODING"; + })(FLAGS = exports.FLAGS || (exports.FLAGS = {})); + var LENIENT_FLAGS; + (function(LENIENT_FLAGS2) { + LENIENT_FLAGS2[LENIENT_FLAGS2["HEADERS"] = 1] = "HEADERS"; + LENIENT_FLAGS2[LENIENT_FLAGS2["CHUNKED_LENGTH"] = 2] = "CHUNKED_LENGTH"; + LENIENT_FLAGS2[LENIENT_FLAGS2["KEEP_ALIVE"] = 4] = "KEEP_ALIVE"; + })(LENIENT_FLAGS = exports.LENIENT_FLAGS || (exports.LENIENT_FLAGS = {})); + var METHODS; + (function(METHODS2) { + METHODS2[METHODS2["DELETE"] = 0] = "DELETE"; + METHODS2[METHODS2["GET"] = 1] = "GET"; + METHODS2[METHODS2["HEAD"] = 2] = "HEAD"; + METHODS2[METHODS2["POST"] = 3] = "POST"; + METHODS2[METHODS2["PUT"] = 4] = "PUT"; + METHODS2[METHODS2["CONNECT"] = 5] = "CONNECT"; + METHODS2[METHODS2["OPTIONS"] = 6] = "OPTIONS"; + METHODS2[METHODS2["TRACE"] = 7] = "TRACE"; + METHODS2[METHODS2["COPY"] = 8] = "COPY"; + METHODS2[METHODS2["LOCK"] = 9] = "LOCK"; + METHODS2[METHODS2["MKCOL"] = 10] = "MKCOL"; + METHODS2[METHODS2["MOVE"] = 11] = "MOVE"; + METHODS2[METHODS2["PROPFIND"] = 12] = "PROPFIND"; + METHODS2[METHODS2["PROPPATCH"] = 13] = "PROPPATCH"; + METHODS2[METHODS2["SEARCH"] = 14] = "SEARCH"; + METHODS2[METHODS2["UNLOCK"] = 15] = "UNLOCK"; + METHODS2[METHODS2["BIND"] = 16] = "BIND"; + METHODS2[METHODS2["REBIND"] = 17] = "REBIND"; + METHODS2[METHODS2["UNBIND"] = 18] = "UNBIND"; + METHODS2[METHODS2["ACL"] = 19] = "ACL"; + METHODS2[METHODS2["REPORT"] = 20] = "REPORT"; + METHODS2[METHODS2["MKACTIVITY"] = 21] = "MKACTIVITY"; + METHODS2[METHODS2["CHECKOUT"] = 22] = "CHECKOUT"; + METHODS2[METHODS2["MERGE"] = 23] = "MERGE"; + METHODS2[METHODS2["M-SEARCH"] = 24] = "M-SEARCH"; + METHODS2[METHODS2["NOTIFY"] = 25] = "NOTIFY"; + METHODS2[METHODS2["SUBSCRIBE"] = 26] = "SUBSCRIBE"; + METHODS2[METHODS2["UNSUBSCRIBE"] = 27] = "UNSUBSCRIBE"; + METHODS2[METHODS2["PATCH"] = 28] = "PATCH"; + METHODS2[METHODS2["PURGE"] = 29] = "PURGE"; + METHODS2[METHODS2["MKCALENDAR"] = 30] = "MKCALENDAR"; + METHODS2[METHODS2["LINK"] = 31] = "LINK"; + METHODS2[METHODS2["UNLINK"] = 32] = "UNLINK"; + METHODS2[METHODS2["SOURCE"] = 33] = "SOURCE"; + METHODS2[METHODS2["PRI"] = 34] = "PRI"; + METHODS2[METHODS2["DESCRIBE"] = 35] = "DESCRIBE"; + METHODS2[METHODS2["ANNOUNCE"] = 36] = "ANNOUNCE"; + METHODS2[METHODS2["SETUP"] = 37] = "SETUP"; + METHODS2[METHODS2["PLAY"] = 38] = "PLAY"; + METHODS2[METHODS2["PAUSE"] = 39] = "PAUSE"; + METHODS2[METHODS2["TEARDOWN"] = 40] = "TEARDOWN"; + METHODS2[METHODS2["GET_PARAMETER"] = 41] = "GET_PARAMETER"; + METHODS2[METHODS2["SET_PARAMETER"] = 42] = "SET_PARAMETER"; + METHODS2[METHODS2["REDIRECT"] = 43] = "REDIRECT"; + METHODS2[METHODS2["RECORD"] = 44] = "RECORD"; + METHODS2[METHODS2["FLUSH"] = 45] = "FLUSH"; + })(METHODS = exports.METHODS || (exports.METHODS = {})); + exports.METHODS_HTTP = [ + METHODS.DELETE, + METHODS.GET, + METHODS.HEAD, + METHODS.POST, + METHODS.PUT, + METHODS.CONNECT, + METHODS.OPTIONS, + METHODS.TRACE, + METHODS.COPY, + METHODS.LOCK, + METHODS.MKCOL, + METHODS.MOVE, + METHODS.PROPFIND, + METHODS.PROPPATCH, + METHODS.SEARCH, + METHODS.UNLOCK, + METHODS.BIND, + METHODS.REBIND, + METHODS.UNBIND, + METHODS.ACL, + METHODS.REPORT, + METHODS.MKACTIVITY, + METHODS.CHECKOUT, + METHODS.MERGE, + METHODS["M-SEARCH"], + METHODS.NOTIFY, + METHODS.SUBSCRIBE, + METHODS.UNSUBSCRIBE, + METHODS.PATCH, + METHODS.PURGE, + METHODS.MKCALENDAR, + METHODS.LINK, + METHODS.UNLINK, + METHODS.PRI, + // TODO(indutny): should we allow it with HTTP? + METHODS.SOURCE + ]; + exports.METHODS_ICE = [ + METHODS.SOURCE + ]; + exports.METHODS_RTSP = [ + METHODS.OPTIONS, + METHODS.DESCRIBE, + METHODS.ANNOUNCE, + METHODS.SETUP, + METHODS.PLAY, + METHODS.PAUSE, + METHODS.TEARDOWN, + METHODS.GET_PARAMETER, + METHODS.SET_PARAMETER, + METHODS.REDIRECT, + METHODS.RECORD, + METHODS.FLUSH, + // For AirPlay + METHODS.GET, + METHODS.POST + ]; + exports.METHOD_MAP = utils_1.enumToMap(METHODS); + exports.H_METHOD_MAP = {}; + Object.keys(exports.METHOD_MAP).forEach((key) => { + if (/^H/.test(key)) { + exports.H_METHOD_MAP[key] = exports.METHOD_MAP[key]; + } + }); + var FINISH; + (function(FINISH2) { + FINISH2[FINISH2["SAFE"] = 0] = "SAFE"; + FINISH2[FINISH2["SAFE_WITH_CB"] = 1] = "SAFE_WITH_CB"; + FINISH2[FINISH2["UNSAFE"] = 2] = "UNSAFE"; + })(FINISH = exports.FINISH || (exports.FINISH = {})); + exports.ALPHA = []; + for (let i = "A".charCodeAt(0); i <= "Z".charCodeAt(0); i++) { + exports.ALPHA.push(String.fromCharCode(i)); + exports.ALPHA.push(String.fromCharCode(i + 32)); + } + exports.NUM_MAP = { + 0: 0, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7, + 8: 8, + 9: 9 + }; + exports.HEX_MAP = { + 0: 0, + 1: 1, + 2: 2, + 3: 3, + 4: 4, + 5: 5, + 6: 6, + 7: 7, + 8: 8, + 9: 9, + A: 10, + B: 11, + C: 12, + D: 13, + E: 14, + F: 15, + a: 10, + b: 11, + c: 12, + d: 13, + e: 14, + f: 15 + }; + exports.NUM = [ + "0", + "1", + "2", + "3", + "4", + "5", + "6", + "7", + "8", + "9" + ]; + exports.ALPHANUM = exports.ALPHA.concat(exports.NUM); + exports.MARK = ["-", "_", ".", "!", "~", "*", "'", "(", ")"]; + exports.USERINFO_CHARS = exports.ALPHANUM.concat(exports.MARK).concat(["%", ";", ":", "&", "=", "+", "$", ","]); + exports.STRICT_URL_CHAR = [ + "!", + '"', + "$", + "%", + "&", + "'", + "(", + ")", + "*", + "+", + ",", + "-", + ".", + "/", + ":", + ";", + "<", + "=", + ">", + "@", + "[", + "\\", + "]", + "^", + "_", + "`", + "{", + "|", + "}", + "~" + ].concat(exports.ALPHANUM); + exports.URL_CHAR = exports.STRICT_URL_CHAR.concat([" ", "\f"]); + for (let i = 128; i <= 255; i++) { + exports.URL_CHAR.push(i); + } + exports.HEX = exports.NUM.concat(["a", "b", "c", "d", "e", "f", "A", "B", "C", "D", "E", "F"]); + exports.STRICT_TOKEN = [ + "!", + "#", + "$", + "%", + "&", + "'", + "*", + "+", + "-", + ".", + "^", + "_", + "`", + "|", + "~" + ].concat(exports.ALPHANUM); + exports.TOKEN = exports.STRICT_TOKEN.concat([" "]); + exports.HEADER_CHARS = [" "]; + for (let i = 32; i <= 255; i++) { + if (i !== 127) { + exports.HEADER_CHARS.push(i); + } + } + exports.CONNECTION_TOKEN_CHARS = exports.HEADER_CHARS.filter((c) => c !== 44); + exports.MAJOR = exports.NUM_MAP; + exports.MINOR = exports.MAJOR; + var HEADER_STATE; + (function(HEADER_STATE2) { + HEADER_STATE2[HEADER_STATE2["GENERAL"] = 0] = "GENERAL"; + HEADER_STATE2[HEADER_STATE2["CONNECTION"] = 1] = "CONNECTION"; + HEADER_STATE2[HEADER_STATE2["CONTENT_LENGTH"] = 2] = "CONTENT_LENGTH"; + HEADER_STATE2[HEADER_STATE2["TRANSFER_ENCODING"] = 3] = "TRANSFER_ENCODING"; + HEADER_STATE2[HEADER_STATE2["UPGRADE"] = 4] = "UPGRADE"; + HEADER_STATE2[HEADER_STATE2["CONNECTION_KEEP_ALIVE"] = 5] = "CONNECTION_KEEP_ALIVE"; + HEADER_STATE2[HEADER_STATE2["CONNECTION_CLOSE"] = 6] = "CONNECTION_CLOSE"; + HEADER_STATE2[HEADER_STATE2["CONNECTION_UPGRADE"] = 7] = "CONNECTION_UPGRADE"; + HEADER_STATE2[HEADER_STATE2["TRANSFER_ENCODING_CHUNKED"] = 8] = "TRANSFER_ENCODING_CHUNKED"; + })(HEADER_STATE = exports.HEADER_STATE || (exports.HEADER_STATE = {})); + exports.SPECIAL_HEADERS = { + "connection": HEADER_STATE.CONNECTION, + "content-length": HEADER_STATE.CONTENT_LENGTH, + "proxy-connection": HEADER_STATE.CONNECTION, + "transfer-encoding": HEADER_STATE.TRANSFER_ENCODING, + "upgrade": HEADER_STATE.UPGRADE + }; + } +}); + +// viewer/node_modules/undici/lib/llhttp/llhttp-wasm.js +var require_llhttp_wasm = __commonJS({ + "viewer/node_modules/undici/lib/llhttp/llhttp-wasm.js"(exports, module) { + "use strict"; + var { Buffer: Buffer2 } = __require("node:buffer"); + module.exports = Buffer2.from("AGFzbQEAAAABJwdgAX8Bf2ADf39/AX9gAX8AYAJ/fwBgBH9/f38Bf2AAAGADf39/AALLAQgDZW52GHdhc21fb25faGVhZGVyc19jb21wbGV0ZQAEA2VudhV3YXNtX29uX21lc3NhZ2VfYmVnaW4AAANlbnYLd2FzbV9vbl91cmwAAQNlbnYOd2FzbV9vbl9zdGF0dXMAAQNlbnYUd2FzbV9vbl9oZWFkZXJfZmllbGQAAQNlbnYUd2FzbV9vbl9oZWFkZXJfdmFsdWUAAQNlbnYMd2FzbV9vbl9ib2R5AAEDZW52GHdhc21fb25fbWVzc2FnZV9jb21wbGV0ZQAAAy0sBQYAAAIAAAAAAAACAQIAAgICAAADAAAAAAMDAwMBAQEBAQEBAQEAAAIAAAAEBQFwARISBQMBAAIGCAF/AUGA1AQLB9EFIgZtZW1vcnkCAAtfaW5pdGlhbGl6ZQAIGV9faW5kaXJlY3RfZnVuY3Rpb25fdGFibGUBAAtsbGh0dHBfaW5pdAAJGGxsaHR0cF9zaG91bGRfa2VlcF9hbGl2ZQAvDGxsaHR0cF9hbGxvYwALBm1hbGxvYwAxC2xsaHR0cF9mcmVlAAwEZnJlZQAMD2xsaHR0cF9nZXRfdHlwZQANFWxsaHR0cF9nZXRfaHR0cF9tYWpvcgAOFWxsaHR0cF9nZXRfaHR0cF9taW5vcgAPEWxsaHR0cF9nZXRfbWV0aG9kABAWbGxodHRwX2dldF9zdGF0dXNfY29kZQAREmxsaHR0cF9nZXRfdXBncmFkZQASDGxsaHR0cF9yZXNldAATDmxsaHR0cF9leGVjdXRlABQUbGxodHRwX3NldHRpbmdzX2luaXQAFQ1sbGh0dHBfZmluaXNoABYMbGxodHRwX3BhdXNlABcNbGxodHRwX3Jlc3VtZQAYG2xsaHR0cF9yZXN1bWVfYWZ0ZXJfdXBncmFkZQAZEGxsaHR0cF9nZXRfZXJybm8AGhdsbGh0dHBfZ2V0X2Vycm9yX3JlYXNvbgAbF2xsaHR0cF9zZXRfZXJyb3JfcmVhc29uABwUbGxodHRwX2dldF9lcnJvcl9wb3MAHRFsbGh0dHBfZXJybm9fbmFtZQAeEmxsaHR0cF9tZXRob2RfbmFtZQAfEmxsaHR0cF9zdGF0dXNfbmFtZQAgGmxsaHR0cF9zZXRfbGVu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PgtBhwEMPQtBiAEMPAtBiQEMOwtBigEMOgtBiwEMOQtBjAEMOAtBjQEMNwtBjgEMNgtBjwEMNQtBkAEMNAtBkQEMMwtBkgEMMgtBkwEMMQtBlAEMMAtBlQEMLwtBlgEMLgtBlwEMLQtBmAEMLAtBmQEMKwtBmgEMKgtBmwEMKQtBnAEMKAtBnQEMJwtBngEMJgtBnwEMJQtBoAEMJAtBoQEMIwtBogEMIgtBowEMIQtBpAEMIAtBpQEMHwtBpgEMHgtBpwEMHQtBqAEMHAtBqQEMGwtBqgEMGgtBqwEMGQtBrAEMGAtBrQEMFwtBrgEMFgtBAQwVC0GvAQwUC0GwAQwTC0GxAQwSC0GzAQwRC0GyAQwQC0G0AQwPC0G1AQwOC0G2AQwNC0G3AQwMC0G4AQwLC0G5AQwKC0G6AQwJC0G7AQwIC0HGAQwHC0G8AQwGC0G9AQwFC0G+AQwEC0G/AQwDC0HAAQwCC0HCAQwBC0HBAQshAwNAAkACQAJAAkACQAJAAkACQAJAIAICfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJ/AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAgJ/AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACQAJAAn8CQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQCADDsYBAAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHyAhIyUmKCorLC8wMTIzNDU2Nzk6Ozw9lANAQkRFRklLTk9QUVJTVFVWWFpbXF1eX2BhYmNkZWZnaGpsb3Bxc3V2eHl6e3x/gAGBAYIBgwGEAYUBhgGHAYgBiQGKAYsBjAGNAY4BjwGQAZEBkgGTAZQBlQGWAZcBmAGZAZoBmwGcAZ0BngGfAaABoQGiAaMBpAGlAaYBpwGoAakBqgGrAawBrQGuAa8BsAGxAbIBswG0AbUBtgG3AbgBuQG6AbsBvAG9Ab4BvwHAAcEBwgHDAcQBxQHGAccByAHJAcsBzAHNAc4BzwGKA4kDiAOHA4QDgwOAA/sC+gL5AvgC9wL0AvMC8gLLAsECsALZAQsgASAERw3wAkHdASEDDLMDCyABIARHDcgBQcMBIQMMsgMLIAEgBEcNe0H3ACEDDLEDCyABIARHDXBB7wAhAwywAwsgASAERw1pQeoAIQMMrwMLIAEgBEcNZUHoACEDDK4DCyABIARHDWJB5gAhAwytAwsgASAERw0aQRghAwysAwsgASAERw0VQRIhAwyrAwsgASAERw1CQcUAIQMMqgMLIAEgBEcNNEE/IQMMqQMLIAEgBEcNMkE8IQMMqAMLIAEgBEcNK0ExIQMMpwMLIAItAC5BAUYNnwMMwQILQQAhAAJAAkACQCACLQAqRQ0AIAItACtFDQAgAi8BMCIDQQJxRQ0BDAILIAIvATAiA0EBcUUNAQtBASEAIAItAChBAUYNACACLwEyIgVB5ABrQeQASQ0AIAVBzAFGDQAgBUGwAkYNACADQcAAcQ0AQQAhACADQYgEcUGABEYNACADQShxQQBHIQALIAJBADsBMCACQQA6AC8gAEUN3wIgAkIANwMgDOACC0EAIQACQCACKAI4IgNFDQAgAygCLCIDRQ0AIAIgAxEAACEACyAARQ3MASAAQRVHDd0CIAJBBDYCHCACIAE2AhQgAkGwGDYCECACQRU2AgxBACEDDKQDCyABIARGBEBBBiEDDKQDCyABQQFqIQFBACEAAkAgAigCOCIDRQ0AIAMoAlQiA0UNACACIAMRAAAhAAsgAA3ZAgwcCyACQgA3AyBBEiEDDIkDCyABIARHDRZBHSEDDKEDCyABIARHBEAgAUEBaiEBQRAhAwyIAwtBByEDDKADCyACIAIpAyAiCiAEIAFrrSILfSIMQgAgCiAMWhs3AyAgCiALWA3UAkEIIQMMnwMLIAEgBEcEQCACQQk2AgggAiABNgIEQRQhAwyGAwtBCSEDDJ4DCyACKQMgQgBSDccBIAIgAi8BMEGAAXI7ATAMQgsgASAERw0/QdAAIQMMnAMLIAEgBEYEQEELIQMMnAMLIAFBAWohAUEAIQACQCACKAI4IgNFDQAgAygCUCIDRQ0AIAIgAxEAACEACyAADc8CDMYBC0EAIQACQCACKAI4IgNFDQAgAygCSCIDRQ0AIAIgAxEAACEACyAARQ3GASAAQRVHDc0CIAJBCzYCHCACIAE2AhQgAkGCGTYCECACQRU2AgxBACEDDJoDC0EAIQACQCACKAI4IgNFDQAgAygCSCIDRQ0AIAIgAxEAACEACyAARQ0MIABBFUcNygIgAkEaNgIcIAIgATYCFCACQYIZNgIQIAJBFTYCDEEAIQMMmQMLQQAhAAJAIAIoAjgiA0UNACADKAJMIgNFDQAgAiADEQAAIQALIABFDcQBIABBFUcNxwIgAkELNgIcIAIgATYCFCACQZEXNgIQIAJBFTYCDEEAIQMMmAMLIAEgBEYEQEEPIQMMmAMLIAEtAAAiAEE7Rg0HIABBDUcNxAIgAUEBaiEBDMMBC0EAIQACQCACKAI4IgNFDQAgAygCTCIDRQ0AIAIgAxEAACEACyAARQ3DASAAQRVHDcICIAJBDzYCHCACIAE2AhQgAkGRFzYCECACQRU2AgxBACEDDJYDCwNAIAEtAABB8DVqLQAAIgBBAUcEQCAAQQJHDcECIAIoAgQhAEEAIQMgAkEANgIEIAIgACABQQFqIgEQLSIADcICDMUBCyAEIAFBAWoiAUcNAAtBEiEDDJUDC0EAIQACQCACKAI4IgNFDQAgAygCTCIDRQ0AIAIgAxEAACEACyAARQ3FASAAQRVHDb0CIAJBGzYCHCACIAE2AhQgAkGRFzYCECACQRU2AgxBACEDDJQDCyABIARGBEBBFiEDDJQDCyACQQo2AgggAiABNgIEQQAhAAJAIAIoAjgiA0UNACADKAJIIgNFDQAgAiADEQAAIQALIABFDcIBIABBFUcNuQIgAkEVNgIcIAIgATYCFCACQYIZNgIQIAJBFTYCDEEAIQMMkwMLIAEgBEcEQANAIAEtAABB8DdqLQAAIgBBAkcEQAJAIABBAWsOBMQCvQIAvgK9AgsgAUEBaiEBQQghAwz8AgsgBCABQQFqIgFHDQALQRUhAwyTAwtBFSEDDJIDCwNAIAEtAABB8DlqLQAAIgBBAkcEQCAAQQFrDgTFArcCwwK4ArcCCyAEIAFBAWoiAUcNAAtBGCEDDJEDCyABIARHBEAgAkELNgIIIAIgATYCBEEHIQMM+AILQRkhAwyQAwsgAUEBaiEBDAILIAEgBEYEQEEaIQMMjwMLAkAgAS0AAEENaw4UtQG/Ab8BvwG/Ab8BvwG/Ab8BvwG/Ab8BvwG/Ab8BvwG/Ab8BvwEAvwELQQAhAyACQQA2AhwgAkGvCzYCECACQQI2AgwgAiABQQFqNgIUDI4DCyABIARGBEBBGyEDDI4DCyABLQAAIgBBO0cEQCAAQQ1HDbECIAFBAWohAQy6AQsgAUEBaiEBC0EiIQMM8wILIAEgBEYEQEEcIQMMjAMLQgAhCgJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAS0AAEEwaw43wQLAAgABAgMEBQYH0AHQAdAB0AHQAdAB0AEICQoLDA3QAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdABDg8QERIT0AELQgIhCgzAAgtCAyEKDL8CC0IEIQoMvgILQgUhCgy9AgtCBiEKDLwCC0IHIQoMuwILQgghCgy6AgtCCSEKDLkCC0IKIQoMuAILQgshCgy3AgtCDCEKDLYCC0INIQoMtQILQg4hCgy0AgtCDyEKDLMCC0IKIQoMsgILQgshCgyxAgtCDCEKDLACC0INIQoMrwILQg4hCgyuAgtCDyEKDK0CC0IAIQoCQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIAEtAABBMGsON8ACvwIAAQIDBAUGB74CvgK+Ar4CvgK+Ar4CCAkKCwwNvgK+Ar4CvgK+Ar4CvgK+Ar4CvgK+Ar4CvgK+Ar4CvgK+Ar4CvgK+Ar4CvgK+Ar4CvgK+Ag4PEBESE74CC0ICIQoMvwILQgMhCgy+AgtCBCEKDL0CC0IFIQoMvAILQgYhCgy7AgtCByEKDLoCC0IIIQoMuQILQgkhCgy4AgtCCiEKDLcCC0ILIQoMtgILQgwhCgy1AgtCDSEKDLQCC0IOIQoMswILQg8hCgyyAgtCCiEKDLECC0ILIQoMsAILQgwhCgyvAgtCDSEKDK4CC0IOIQoMrQILQg8hCgysAgsgAiACKQMgIgogBCABa60iC30iDEIAIAogDFobNwMgIAogC1gNpwJBHyEDDIkDCyABIARHBEAgAkEJNgIIIAIgATYCBEElIQMM8AILQSAhAwyIAwtBASEFIAIvATAiA0EIcUUEQCACKQMgQgBSIQULAkAgAi0ALgRAQQEhACACLQApQQVGDQEgA0HAAHFFIAVxRQ0BC0EAIQAgA0HAAHENAEECIQAgA0EIcQ0AIANBgARxBEACQCACLQAoQQFHDQAgAi0ALUEKcQ0AQQUhAAwCC0EEIQAMAQsgA0EgcUUEQAJAIAItAChBAUYNACACLwEyIgBB5ABrQeQASQ0AIABBzAFGDQAgAEGwAkYNAEEEIQAgA0EocUUNAiADQYgEcUGABEYNAgtBACEADAELQQBBAyACKQMgUBshAAsgAEEBaw4FvgIAsAEBpAKhAgtBESEDDO0CCyACQQE6AC8MhAMLIAEgBEcNnQJBJCEDDIQDCyABIARHDRxBxgAhAwyDAwtBACEAAkAgAigCOCIDRQ0AIAMoAkQiA0UNACACIAMRAAAhAAsgAEUNJyAAQRVHDZgCIAJB0AA2AhwgAiABNgIUIAJBkRg2AhAgAkEVNgIMQQAhAwyCAwsgASAERgRAQSghAwyCAwtBACEDIAJBADYCBCACQQw2AgggAiABIAEQKiIARQ2UAiACQSc2AhwgAiABNgIUIAIgADYCDAyBAwsgASAERgRAQSkhAwyBAwsgAS0AACIAQSBGDRMgAEEJRw2VAiABQQFqIQEMFAsgASAERwRAIAFBAWohAQwWC0EqIQMM/wILIAEgBEYEQEErIQMM/wILIAEtAAAiAEEJRyAAQSBHcQ2QAiACLQAsQQhHDd0CIAJBADoALAzdAgsgASAERgRAQSwhAwz+AgsgAS0AAEEKRw2OAiABQQFqIQEMsAELIAEgBEcNigJBLyEDDPwCCwNAIAEtAAAiAEEgRwRAIABBCmsOBIQCiAKIAoQChgILIAQgAUEBaiIBRw0AC0ExIQMM+wILQTIhAyABIARGDfoCIAIoAgAiACAEIAFraiEHIAEgAGtBA2ohBgJAA0AgAEHwO2otAAAgAS0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDQEgAEEDRgRAQQYhAQziAgsgAEEBaiEAIAQgAUEBaiIBRw0ACyACIAc2AgAM+wILIAJBADYCAAyGAgtBMyEDIAQgASIARg35AiAEIAFrIAIoAgAiAWohByAAIAFrQQhqIQYCQANAIAFB9DtqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0BIAFBCEYEQEEFIQEM4QILIAFBAWohASAEIABBAWoiAEcNAAsgAiAHNgIADPoCCyACQQA2AgAgACEBDIUCC0E0IQMgBCABIgBGDfgCIAQgAWsgAigCACIBaiEHIAAgAWtBBWohBgJAA0AgAUHQwgBqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw0BIAFBBUYEQEEHIQEM4AILIAFBAWohASAEIABBAWoiAEcNAAsgAiAHNgIADPkCCyACQQA2AgAgACEBDIQCCyABIARHBEADQCABLQAAQYA+ai0AACIAQQFHBEAgAEECRg0JDIECCyAEIAFBAWoiAUcNAAtBMCEDDPgCC0EwIQMM9wILIAEgBEcEQANAIAEtAAAiAEEgRwRAIABBCmsOBP8B/gH+Af8B/gELIAQgAUEBaiIBRw0AC0E4IQMM9wILQTghAwz2AgsDQCABLQAAIgBBIEcgAEEJR3EN9gEgBCABQQFqIgFHDQALQTwhAwz1AgsDQCABLQAAIgBBIEcEQAJAIABBCmsOBPkBBAT5AQALIABBLEYN9QEMAwsgBCABQQFqIgFHDQALQT8hAwz0AgtBwAAhAyABIARGDfMCIAIoAgAiACAEIAFraiEFIAEgAGtBBmohBgJAA0AgAEGAQGstAAAgAS0AAEEgckcNASAAQQZGDdsCIABBAWohACAEIAFBAWoiAUcNAAsgAiAFNgIADPQCCyACQQA2AgALQTYhAwzZAgsgASAERgRAQcEAIQMM8gILIAJBDDYCCCACIAE2AgQgAi0ALEEBaw4E+wHuAewB6wHUAgsgAUEBaiEBDPoBCyABIARHBEADQAJAIAEtAAAiAEEgciAAIABBwQBrQf8BcUEaSRtB/wFxIgBBCUYNACAAQSBGDQACQAJAAkACQCAAQeMAaw4TAAMDAwMDAwMBAwMDAwMDAwMDAgMLIAFBAWohAUExIQMM3AILIAFBAWohAUEyIQMM2wILIAFBAWohAUEzIQMM2gILDP4BCyAEIAFBAWoiAUcNAAtBNSEDDPACC0E1IQMM7wILIAEgBEcEQANAIAEtAABBgDxqLQAAQQFHDfcBIAQgAUEBaiIBRw0AC0E9IQMM7wILQT0hAwzuAgtBACEAAkAgAigCOCIDRQ0AIAMoAkAiA0UNACACIAMRAAAhAAsgAEUNASAAQRVHDeYBIAJBwgA2AhwgAiABNgIUIAJB4xg2AhAgAkEVNgIMQQAhAwztAgsgAUEBaiEBC0E8IQMM0gILIAEgBEYEQEHCACEDDOsCCwJAA0ACQCABLQAAQQlrDhgAAswCzALRAswCzALMAswCzALMAswCzALMAswCzALMAswCzALMAswCzALMAgDMAgsgBCABQQFqIgFHDQALQcIAIQMM6wILIAFBAWohASACLQAtQQFxRQ3+AQtBLCEDDNACCyABIARHDd4BQcQAIQMM6AILA0AgAS0AAEGQwABqLQAAQQFHDZwBIAQgAUEBaiIBRw0AC0HFACEDDOcCCyABLQAAIgBBIEYN/gEgAEE6Rw3AAiACKAIEIQBBACEDIAJBADYCBCACIAAgARApIgAN3gEM3QELQccAIQMgBCABIgBGDeUCIAQgAWsgAigCACIBaiEHIAAgAWtBBWohBgNAIAFBkMIAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNvwIgAUEFRg3CAiABQQFqIQEgBCAAQQFqIgBHDQALIAIgBzYCAAzlAgtByAAhAyAEIAEiAEYN5AIgBCABayACKAIAIgFqIQcgACABa0EJaiEGA0AgAUGWwgBqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw2+AkECIAFBCUYNwgIaIAFBAWohASAEIABBAWoiAEcNAAsgAiAHNgIADOQCCyABIARGBEBByQAhAwzkAgsCQAJAIAEtAAAiAEEgciAAIABBwQBrQf8BcUEaSRtB/wFxQe4Aaw4HAL8CvwK/Ar8CvwIBvwILIAFBAWohAUE+IQMMywILIAFBAWohAUE/IQMMygILQcoAIQMgBCABIgBGDeICIAQgAWsgAigCACIBaiEGIAAgAWtBAWohBwNAIAFBoMIAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNvAIgAUEBRg2+AiABQQFqIQEgBCAAQQFqIgBHDQALIAIgBjYCAAziAgtBywAhAyAEIAEiAEYN4QIgBCABayACKAIAIgFqIQcgACABa0EOaiEGA0AgAUGiwgBqLQAAIAAtAAAiBUEgciAFIAVBwQBrQf8BcUEaSRtB/wFxRw27AiABQQ5GDb4CIAFBAWohASAEIABBAWoiAEcNAAsgAiAHNgIADOECC0HMACEDIAQgASIARg3gAiAEIAFrIAIoAgAiAWohByAAIAFrQQ9qIQYDQCABQcDCAGotAAAgAC0AACIFQSByIAUgBUHBAGtB/wFxQRpJG0H/AXFHDboCQQMgAUEPRg2+AhogAUEBaiEBIAQgAEEBaiIARw0ACyACIAc2AgAM4AILQc0AIQMgBCABIgBGDd8CIAQgAWsgAigCACIBaiEHIAAgAWtBBWohBgNAIAFB0MIAai0AACAALQAAIgVBIHIgBSAFQcEAa0H/AXFBGkkbQf8BcUcNuQJBBCABQQVGDb0CGiABQQFqIQEgBCAAQQFqIgBHDQALIAIgBzYCAAzfAgsgASAERgRAQc4AIQMM3wILAkACQAJAAkAgAS0AACIAQSByIAAgAEHBAGtB/wFxQRpJG0H/AXFB4wBrDhMAvAK8ArwCvAK8ArwCvAK8ArwCvAK8ArwCAbwCvAK8AgIDvAILIAFBAWohAUHBACEDDMgCCyABQQFqIQFBwgAhAwzHAgsgAUEBaiEBQcMAIQMMxgILIAFBAWohAUHEACEDDMUCCyABIARHBEAgAkENNgIIIAIgATYCBEHFACEDDMUCC0HPACEDDN0CCwJAAkAgAS0AAEEKaw4EAZABkAEAkAELIAFBAWohAQtBKCEDDMMCCyABIARGBEBB0QAhAwzcAgsgAS0AAEEgRw0AIAFBAWohASACLQAtQQFxRQ3QAQtBFyEDDMECCyABIARHDcsBQdIAIQMM2QILQdMAIQMgASAERg3YAiACKAIAIgAgBCABa2ohBiABIABrQQFqIQUDQCABLQAAIABB1sIAai0AAEcNxwEgAEEBRg3KASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBjYCAAzYAgsgASAERgRAQdUAIQMM2AILIAEtAABBCkcNwgEgAUEBaiEBDMoBCyABIARGBEBB1gAhAwzXAgsCQAJAIAEtAABBCmsOBADDAcMBAcMBCyABQQFqIQEMygELIAFBAWohAUHKACEDDL0CC0EAIQACQCACKAI4IgNFDQAgAygCPCIDRQ0AIAIgAxEAACEACyAADb8BQc0AIQMMvAILIAItAClBIkYNzwIMiQELIAQgASIFRgRAQdsAIQMM1AILQQAhAEEBIQFBASEGQQAhAwJAAn8CQAJAAkACQAJAAkACQCAFLQAAQTBrDgrFAcQBAAECAwQFBgjDAQtBAgwGC0EDDAULQQQMBAtBBQwDC0EGDAILQQcMAQtBCAshA0EAIQFBACEGDL0BC0EJIQNBASEAQQAhAUEAIQYMvAELIAEgBEYEQEHdACEDDNMCCyABLQAAQS5HDbgBIAFBAWohAQyIAQsgASAERw22AUHfACEDDNECCyABIARHBEAgAkEONgIIIAIgATYCBEHQACEDDLgCC0HgACEDDNACC0HhACEDIAEgBEYNzwIgAigCACIAIAQgAWtqIQUgASAAa0EDaiEGA0AgAS0AACAAQeLCAGotAABHDbEBIABBA0YNswEgAEEBaiEAIAQgAUEBaiIBRw0ACyACIAU2AgAMzwILQeIAIQMgASAERg3OAiACKAIAIgAgBCABa2ohBSABIABrQQJqIQYDQCABLQAAIABB5sIAai0AAEcNsAEgAEECRg2vASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAzOAgtB4wAhAyABIARGDc0CIAIoAgAiACAEIAFraiEFIAEgAGtBA2ohBgNAIAEtAAAgAEHpwgBqLQAARw2vASAAQQNGDa0BIABBAWohACAEIAFBAWoiAUcNAAsgAiAFNgIADM0CCyABIARGBEBB5QAhAwzNAgsgAUEBaiEBQQAhAAJAIAIoAjgiA0UNACADKAIwIgNFDQAgAiADEQAAIQALIAANqgFB1gAhAwyzAgsgASAERwRAA0AgAS0AACIAQSBHBEACQAJAAkAgAEHIAGsOCwABswGzAbMBswGzAbMBswGzAQKzAQsgAUEBaiEBQdIAIQMMtwILIAFBAWohAUHTACEDDLYCCyABQQFqIQFB1AAhAwy1AgsgBCABQQFqIgFHDQALQeQAIQMMzAILQeQAIQMMywILA0AgAS0AAEHwwgBqLQAAIgBBAUcEQCAAQQJrDgOnAaYBpQGkAQsgBCABQQFqIgFHDQALQeYAIQMMygILIAFBAWogASAERw0CGkHnACEDDMkCCwNAIAEtAABB8MQAai0AACIAQQFHBEACQCAAQQJrDgSiAaEBoAEAnwELQdcAIQMMsQILIAQgAUEBaiIBRw0AC0HoACEDDMgCCyABIARGBEBB6QAhAwzIAgsCQCABLQAAIgBBCmsOGrcBmwGbAbQBmwGbAZsBmwGbAZsBmwGbAZsBmwGbAZsBmwGbAZsBmwGbAZsBpAGbAZsBAJkBCyABQQFqCyEBQQYhAwytAgsDQCABLQAAQfDGAGotAABBAUcNfSAEIAFBAWoiAUcNAAtB6gAhAwzFAgsgAUEBaiABIARHDQIaQesAIQMMxAILIAEgBEYEQEHsACEDDMQCCyABQQFqDAELIAEgBEYEQEHtACEDDMMCCyABQQFqCyEBQQQhAwyoAgsgASAERgRAQe4AIQMMwQILAkACQAJAIAEtAABB8MgAai0AAEEBaw4HkAGPAY4BAHwBAo0BCyABQQFqIQEMCwsgAUEBagyTAQtBACEDIAJBADYCHCACQZsSNgIQIAJBBzYCDCACIAFBAWo2AhQMwAILAkADQCABLQAAQfDIAGotAAAiAEEERwRAAkACQCAAQQFrDgeUAZMBkgGNAQAEAY0BC0HaACEDDKoCCyABQQFqIQFB3AAhAwypAgsgBCABQQFqIgFHDQALQe8AIQMMwAILIAFBAWoMkQELIAQgASIARgRAQfAAIQMMvwILIAAtAABBL0cNASAAQQFqIQEMBwsgBCABIgBGBEBB8QAhAwy+AgsgAC0AACIBQS9GBEAgAEEBaiEBQd0AIQMMpQILIAFBCmsiA0EWSw0AIAAhAUEBIAN0QYmAgAJxDfkBC0EAIQMgAkEANgIcIAIgADYCFCACQYwcNgIQIAJBBzYCDAy8AgsgASAERwRAIAFBAWohAUHeACEDDKMCC0HyACEDDLsCCyABIARGBEBB9AAhAwy7AgsCQCABLQAAQfDMAGotAABBAWsOA/cBcwCCAQtB4QAhAwyhAgsgASAERwRAA0AgAS0AAEHwygBqLQAAIgBBA0cEQAJAIABBAWsOAvkBAIUBC0HfACEDDKMCCyAEIAFBAWoiAUcNAAtB8wAhAwy6AgtB8wAhAwy5AgsgASAERwRAIAJBDzYCCCACIAE2AgRB4AAhAwygAgtB9QAhAwy4AgsgASAERgRAQfYAIQMMuAILIAJBDzYCCCACIAE2AgQLQQMhAwydAgsDQCABLQAAQSBHDY4CIAQgAUEBaiIBRw0AC0H3ACEDDLUCCyABIARGBEBB+AAhAwy1AgsgAS0AAEEgRw16IAFBAWohAQxbC0EAIQACQCACKAI4IgNFDQAgAygCOCIDRQ0AIAIgAxEAACEACyAADXgMgAILIAEgBEYEQEH6ACEDDLMCCyABLQAAQcwARw10IAFBAWohAUETDHYLQfsAIQMgASAERg2xAiACKAIAIgAgBCABa2ohBSABIABrQQVqIQYDQCABLQAAIABB8M4Aai0AAEcNcyAAQQVGDXUgAEEBaiEAIAQgAUEBaiIBRw0ACyACIAU2AgAMsQILIAEgBEYEQEH8ACEDDLECCwJAAkAgAS0AAEHDAGsODAB0dHR0dHR0dHR0AXQLIAFBAWohAUHmACEDDJgCCyABQQFqIQFB5wAhAwyXAgtB/QAhAyABIARGDa8CIAIoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQe3PAGotAABHDXIgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAiAFNgIADLACCyACQQA2AgAgBkEBaiEBQRAMcwtB/gAhAyABIARGDa4CIAIoAgAiACAEIAFraiEFIAEgAGtBBWohBgJAA0AgAS0AACAAQfbOAGotAABHDXEgAEEFRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAiAFNgIADK8CCyACQQA2AgAgBkEBaiEBQRYMcgtB/wAhAyABIARGDa0CIAIoAgAiACAEIAFraiEFIAEgAGtBA2ohBgJAA0AgAS0AACAAQfzOAGotAABHDXAgAEEDRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAiAFNgIADK4CCyACQQA2AgAgBkEBaiEBQQUMcQsgASAERgRAQYABIQMMrQILIAEtAABB2QBHDW4gAUEBaiEBQQgMcAsgASAERgRAQYEBIQMMrAILAkACQCABLQAAQc4Aaw4DAG8BbwsgAUEBaiEBQesAIQMMkwILIAFBAWohAUHsACEDDJICCyABIARGBEBBggEhAwyrAgsCQAJAIAEtAABByABrDggAbm5ubm5uAW4LIAFBAWohAUHqACEDDJICCyABQQFqIQFB7QAhAwyRAgtBgwEhAyABIARGDakCIAIoAgAiACAEIAFraiEFIAEgAGtBAmohBgJAA0AgAS0AACAAQYDPAGotAABHDWwgAEECRg0BIABBAWohACAEIAFBAWoiAUcNAAsgAiAFNgIADKoCCyACQQA2AgAgBkEBaiEBQQAMbQtBhAEhAyABIARGDagCIAIoAgAiACAEIAFraiEFIAEgAGtBBGohBgJAA0AgAS0AACAAQYPPAGotAABHDWsgAEEERg0BIABBAWohACAEIAFBAWoiAUcNAAsgAiAFNgIADKkCCyACQQA2AgAgBkEBaiEBQSMMbAsgASAERgRAQYUBIQMMqAILAkACQCABLQAAQcwAaw4IAGtra2trawFrCyABQQFqIQFB7wAhAwyPAgsgAUEBaiEBQfAAIQMMjgILIAEgBEYEQEGGASEDDKcCCyABLQAAQcUARw1oIAFBAWohAQxgC0GHASEDIAEgBEYNpQIgAigCACIAIAQgAWtqIQUgASAAa0EDaiEGAkADQCABLQAAIABBiM8Aai0AAEcNaCAAQQNGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyACIAU2AgAMpgILIAJBADYCACAGQQFqIQFBLQxpC0GIASEDIAEgBEYNpAIgAigCACIAIAQgAWtqIQUgASAAa0EIaiEGAkADQCABLQAAIABB0M8Aai0AAEcNZyAAQQhGDQEgAEEBaiEAIAQgAUEBaiIBRw0ACyACIAU2AgAMpQILIAJBADYCACAGQQFqIQFBKQxoCyABIARGBEBBiQEhAwykAgtBASABLQAAQd8ARw1nGiABQQFqIQEMXgtBigEhAyABIARGDaICIAIoAgAiACAEIAFraiEFIAEgAGtBAWohBgNAIAEtAAAgAEGMzwBqLQAARw1kIABBAUYN+gEgAEEBaiEAIAQgAUEBaiIBRw0ACyACIAU2AgAMogILQYsBIQMgASAERg2hAiACKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGOzwBqLQAARw1kIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAyiAgsgAkEANgIAIAZBAWohAUECDGULQYwBIQMgASAERg2gAiACKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHwzwBqLQAARw1jIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAyhAgsgAkEANgIAIAZBAWohAUEfDGQLQY0BIQMgASAERg2fAiACKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHyzwBqLQAARw1iIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAygAgsgAkEANgIAIAZBAWohAUEJDGMLIAEgBEYEQEGOASEDDJ8CCwJAAkAgAS0AAEHJAGsOBwBiYmJiYgFiCyABQQFqIQFB+AAhAwyGAgsgAUEBaiEBQfkAIQMMhQILQY8BIQMgASAERg2dAiACKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEGRzwBqLQAARw1gIABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAyeAgsgAkEANgIAIAZBAWohAUEYDGELQZABIQMgASAERg2cAiACKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGXzwBqLQAARw1fIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAydAgsgAkEANgIAIAZBAWohAUEXDGALQZEBIQMgASAERg2bAiACKAIAIgAgBCABa2ohBSABIABrQQZqIQYCQANAIAEtAAAgAEGazwBqLQAARw1eIABBBkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAycAgsgAkEANgIAIAZBAWohAUEV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JSIARQ0RIAJB5QA2AhwgAiABNgIUIAIgADYCDEEAIQMMtAELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0gIAJB0wA2AhwgAiABNgIUIAIgADYCDEEAIQMMswELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0iIAJB0gA2AhwgAiABNgIUIAIgADYCDEEAIQMMsgELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0OIAJB5QA2AhwgAiABNgIUIAIgADYCDEEAIQMMsQELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0dIAJB0wA2AhwgAiABNgIUIAIgADYCDEEAIQMMsAELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0fIAJB0gA2AhwgAiABNgIUIAIgADYCDEEAIQMMrwELIABBP0cNASABQQFqCyEBQQUhAwyUAQtBACEDIAJBADYCHCACIAE2AhQgAkH9EjYCECACQQc2AgwMrAELIAJBADYCHCACIAE2AhQgAkHcCDYCECACQQc2AgxBACEDDKsBCyACKAIEIQAgAkEANgIEIAIgACABECUiAEUNByACQeUANgIcIAIgATYCFCACIAA2AgxBACEDDKoBCyACKAIEIQAgAkEANgIEIAIgACABECUiAEUNFiACQdMANgIcIAIgATYCFCACIAA2AgxBACEDDKkBCyACKAIEIQAgAkEANgIEIAIgACABECUiAEUNGCACQdIANgIcIAIgATYCFCACIAA2AgxBACEDDKgBCyACQQA2AhwgAiABNgIUIAJBxgo2AhAgAkEHNgIMQQAhAwynAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDQMgAkHlADYCHCACIAE2AhQgAiAANgIMQQAhAwymAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDRIgAkHTADYCHCACIAE2AhQgAiAANgIMQQAhAwylAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDRQgAkHSADYCHCACIAE2AhQgAiAANgIMQQAhAwykAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDQAgAkHlADYCHCACIAE2AhQgAiAANgIMQQAhAwyjAQtB1QAhAwyJAQsgAEEVRwRAIAJBADYCHCACIAE2AhQgAkG5DTYCECACQRo2AgxB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AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIABB5ABrDvQDY2IAAWFhYWFhYQIDBAVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhBgcICQoLDA0OD2FhYWFhEGFhYWFhYWFhYWFhEWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYRITFBUWFxgZGhthYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2YTc4OTphYWFhYWFhYTthYWE8YWFhYT0+P2FhYWFhYWFhQGFhQWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYUJDREVGR0hJSktMTU5PUFFSU2FhYWFhYWFhVFVWV1hZWlthXF1hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFeYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhX2BhC0HhJw8LQaQhDwtByywPC0H+MQ8LQcAkDwtBqyQPC0GNKA8LQeImDwtBgDAPC0G5Lw8LQdckDwtB7x8PC0HhHw8LQfofDwtB8iAPC0GoLw8LQa4yDwtBiDAPC0HsJw8LQYIiDwtBjh0PC0HQLg8LQcojDwtBxTIPC0HfHA8LQdIcDwtBxCAPC0HXIA8LQaIfDwtB7S4PC0GrMA8LQdQlDwtBzC4PC0H6Lg8LQfwrDwtB0jAPC0HxHQ8LQbsgDwtB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CABB3AgLii1JbnZhbGlkIGNoYXIgaW4gdXJsIHF1ZXJ5AFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fYm9keQBDb250ZW50LUxlbmd0aCBvdmVyZmxvdwBDaHVuayBzaXplIG92ZXJmbG93AFJlc3BvbnNlIG92ZXJmbG93AEludmFsaWQgbWV0aG9kIGZvciBIVFRQL3gueCByZXF1ZXN0AEludmFsaWQgbWV0aG9kIGZvciBSVFNQL3gueCByZXF1ZXN0AEV4cGVjdGVkIFNPVVJDRSBtZXRob2QgZm9yIElDRS94LnggcmVxdWVzdABJbnZhbGlkIGNoYXIgaW4gdXJsIGZyYWdtZW50IHN0YXJ0AEV4cGVjdGVkIGRvdABTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3N0YXR1cwBJbnZhbGlkIHJlc3BvbnNlIHN0YXR1cwBJbnZhbGlkIGNoYXJhY3RlciBpbiBjaHVuayBleHRlbnNpb25zAFVzZXIgY2FsbGJhY2sgZXJyb3IAYG9uX3Jlc2V0YCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfaGVhZGVyYCBjYWxsYmFjayBlcnJvcgBgb25fbWVzc2FnZV9iZWdpbmAgY2FsbGJhY2sgZXJyb3IAYG9uX2NodW5rX2V4dGVuc2lvbl92YWx1ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3N0YXR1c19jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX3ZlcnNpb25fY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl91cmxfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9jaHVua19jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX2hlYWRlcl92YWx1ZV9jb21wbGV0ZWAgY2FsbGJhY2sgZXJyb3IAYG9uX21lc3NhZ2VfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXRob2RfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9oZWFkZXJfZmllbGRfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9jaHVua19leHRlbnNpb25fbmFtZWAgY2FsbGJhY2sgZXJyb3IAVW5leHBlY3RlZCBjaGFyIGluIHVybCBzZXJ2ZXIASW52YWxpZCBoZWFkZXIgdmFsdWUgY2hhcgBJbnZhbGlkIGhlYWRlciBmaWVsZCBjaGFyAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fdmVyc2lvbgBJbnZhbGlkIG1pbm9yIHZlcnNpb24ASW52YWxpZCBtYWpvciB2ZXJzaW9uAEV4cGVjdGVkIHNwYWNlIGFmdGVyIHZlcnNpb24ARXhwZWN0ZWQgQ1JMRiBhZnRlciB2ZXJzaW9uAEludmFsaWQgSFRUUCB2ZXJzaW9uAEludmFsaWQgaGVhZGVyIHRva2VuAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fdXJsAEludmFsaWQgY2hhcmFjdGVycyBpbiB1cmwAVW5leHBlY3RlZCBzdGFydCBjaGFyIGluIHVybABEb3VibGUgQCBpbiB1cmwARW1wdHkgQ29udGVudC1MZW5ndGgASW52YWxpZCBjaGFyYWN0ZXIgaW4gQ29udGVudC1MZW5ndGgARHVwbGljYXRlIENvbnRlbnQtTGVuZ3RoAEludmFsaWQgY2hhciBpbiB1cmwgcGF0aABDb250ZW50LUxlbmd0aCBjYW4ndCBiZSBwcmVzZW50IHdpdGggVHJhbnNmZXItRW5jb2RpbmcASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgc2l6ZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX2hlYWRlcl92YWx1ZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX2NodW5rX2V4dGVuc2lvbl92YWx1ZQBJbnZhbGlkIGNoYXJhY3RlciBpbiBjaHVuayBleHRlbnNpb25zIHZhbHVlAE1pc3NpbmcgZXhwZWN0ZWQgTEYgYWZ0ZXIgaGVhZGVyIHZhbHVlAEludmFsaWQgYFRyYW5zZmVyLUVuY29kaW5nYCBoZWFkZXIgdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBxdW90ZSB2YWx1ZQBJbnZhbGlkIGNoYXJhY3RlciBpbiBjaHVuayBleHRlbnNpb25zIHF1b3RlZCB2YWx1ZQBQYXVzZWQgYnkgb25faGVhZGVyc19jb21wbGV0ZQBJbnZhbGlkIEVPRiBzdGF0ZQBvbl9yZXNldCBwYXVzZQBvbl9jaHVua19oZWFkZXIgcGF1c2UAb25fbWVzc2FnZV9iZWdpbiBwYXVzZQBvbl9jaHVua19leHRlbnNpb25fdmFsdWUgcGF1c2UAb25fc3RhdHVzX2NvbXBsZXRlIHBhdXNlAG9uX3ZlcnNpb25fY29tcGxldGUgcGF1c2UAb25fdXJsX2NvbXBsZXRlIHBhdXNlAG9uX2NodW5rX2NvbXBsZXRlIHBhdXNlAG9uX2hlYWRlcl92YWx1ZV9jb21wbGV0ZSBwYXVzZQBvbl9tZXNzYWdlX2NvbXBsZXRlIHBhdXNlAG9uX21ldGhvZF9jb21wbGV0ZSBwYXVzZQBvbl9oZWFkZXJfZmllbGRfY29tcGxldGUgcGF1c2UAb25fY2h1bmtfZXh0ZW5zaW9uX25hbWUgcGF1c2UAVW5leHBlY3RlZCBzcGFjZSBhZnRlciBzdGFydCBsaW5lAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fY2h1bmtfZXh0ZW5zaW9uX25hbWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBuYW1lAFBhdXNlIG9uIENPTk5FQ1QvVXBncmFkZQBQYXVzZSBvbiBQUkkvVXBncmFkZQBFeHBlY3RlZCBIVFRQLzIgQ29ubmVjdGlvbiBQcmVmYWNlAFNwYW4gY2FsbGJhY2sgZXJyb3IgaW4gb25fbWV0aG9kAEV4cGVjdGVkIHNwYWNlIGFmdGVyIG1ldGhvZABTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX2hlYWRlcl9maWVsZABQYXVzZWQASW52YWxpZCB3b3JkIGVuY291bnRlcmVkAEludmFsaWQgbWV0aG9kIGVuY291bnRlcmVkAFVuZXhwZWN0ZWQgY2hhciBpbiB1cmwgc2NoZW1hAFJlcXVlc3QgaGFzIGludmFsaWQgYFRyYW5zZmVyLUVuY29kaW5nYABTV0lUQ0hfUFJPWFkAVVNFX1BST1hZAE1LQUNUSVZJVFkAVU5QUk9DRVNTQUJMRV9FTlRJVFkAQ09QWQBNT1ZFRF9QRVJNQU5FTlRMWQBUT09fRUFSTFkATk9USUZZAEZBSUxFRF9ERVBFTkRFTkNZAEJBRF9HQVRFV0FZAFBMQVkAUFVUAENIRUNLT1VUAEdBVEVXQVlfVElNRU9VVABSRVFVRVNUX1RJTUVPVVQATkVUV09SS19DT05ORUNUX1RJTUVPVVQAQ09OTkVDVElPTl9USU1FT1VUAExPR0lOX1RJTUVPVVQATkVUV09SS19SRUFEX1RJTUVPVVQAUE9TVABNSVNESVJFQ1RFRF9SRVFVRVNUAENMSUVOVF9DTE9TRURfUkVRVUVTVABDTElFTlRfQ0xPU0VEX0xPQURfQkFMQU5DRURfUkVRVUVTVABCQURfUkVRVUVTVABIVFRQX1JFUVVFU1RfU0VOVF9UT19IVFRQU19QT1JUAFJFUE9SVABJTV9BX1RFQVBPVABSRVNFVF9DT05URU5UAE5PX0NPTlRFTlQAUEFSVElBTF9DT05URU5UAEhQRV9JTlZBTElEX0NPTlNUQU5UAEhQRV9DQl9SRVNFVABHRVQASFBFX1NUUklDVABDT05GTElDVABURU1QT1JBUllfUkVESVJFQ1QAUEVSTUFORU5UX1JFRElSRUNUAENPTk5FQ1QATVVMVElfU1RBVFVTAEhQRV9JTlZBTElEX1NUQVRVUwBUT09fTUFOWV9SRVFVRVNUUwBFQVJMWV9ISU5UUwBVTkFWQUlMQUJMRV9GT1JfTEVHQUxfUkVBU09OUwBPUFRJT05TAFNXSVRDSElOR19QUk9UT0NPTFMAVkFSSUFOVF9BTFNPX05FR09USUFURVMATVVMVElQTEVfQ0hPSUNFUwBJTlRFUk5BTF9TRVJWRVJfRVJST1IAV0VCX1NFUlZFUl9VTktOT1dOX0VSUk9SAFJBSUxHVU5fRVJST1IASURFTlRJVFlfUFJPVklERVJfQVVUSEVOVElDQVRJT05fRVJST1IAU1NMX0NFUlRJRklDQVRFX0VSUk9SAElOVkFMSURfWF9GT1JXQVJERURfRk9SAFNFVF9QQVJBTUVURVIAR0VUX1BBUkFNRVRFUgBIUEVfVVNFUgBTRUVfT1RIRVIASFBFX0NCX0NIVU5LX0hFQURFUgBNS0NBTEVOREFSAFNFVFVQAFdFQl9TRVJWRVJfSVNfRE9XTgBURUFSRE9XTgBIUEVfQ0xPU0VEX0NPTk5FQ1RJT04ASEVVUklTVElDX0VYUElSQVRJT04ARElTQ09OTkVDVEVEX09QRVJBVElPTgBOT05fQVVUSE9SSVRBVElWRV9JTkZPUk1BVElPTgBIUEVfSU5WQUxJRF9WRVJTSU9OAEhQRV9DQl9NRVNTQUdFX0JFR0lOAFNJVEVfSVNfRlJPWkVOAEhQRV9JTlZBTElEX0hFQURFUl9UT0tFTgBJTlZBTElEX1RPS0VOAEZPUkJJRERFTgBFTkhBTkNFX1lPVVJfQ0FMTQBIUEVfSU5WQUxJRF9VUkwAQkxPQ0tFRF9CWV9QQVJFTlRBTF9DT05UUk9MAE1LQ09MAEFDTABIUEVfSU5URVJOQUwAUkVRVUVTVF9IRUFERVJfRklFTERTX1RPT19MQVJHRV9VTk9GRklDSUFMAEhQRV9PSwBVTkxJTksAVU5MT0NLAFBSSQBSRVRSWV9XSVRIAEhQRV9JTlZBTElEX0NPTlRFTlRfTEVOR1RIAEhQRV9VTkVYUEVDVEVEX0NPTlRFTlRfTEVOR1RIAEZMVVNIAFBST1BQQVRDSABNLVNFQVJDSABVUklfVE9PX0xPTkcAUFJPQ0VTU0lORwBNSVNDRUxMQU5FT1VTX1BFUlNJU1RFTlRfV0FSTklORwBNSVNDRUxMQU5FT1VTX1dBUk5JTkcASFBFX0lOVkFMSURfVFJBTlNGRVJfRU5DT0RJTkcARXhwZWN0ZWQgQ1JMRgBIUEVfSU5WQUxJRF9DSFVOS19TSVpFAE1PVkUAQ09OVElOVUUASFBFX0NCX1NUQVRVU19DT01QTEVURQBIUEVfQ0JfSEVBREVSU19DT01QTEVURQBIUEVfQ0JfVkVSU0lPTl9DT01QTEVURQBIUEVfQ0JfVVJMX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19DT01QTEVURQBIUEVfQ0JfSEVBREVSX1ZBTFVFX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19FWFRFTlNJT05fVkFMVUVfQ09NUExFVEUASFBFX0NCX0NIVU5LX0VYVEVOU0lPTl9OQU1FX0NPTVBMRVRFAEhQRV9DQl9NRVNTQUdFX0NPTVBMRVRFAEhQRV9DQl9NRVRIT0RfQ09NUExFVEUASFBFX0NCX0hFQURFUl9GSUVMRF9DT01QTEVURQBERUxFVEUASFBFX0lOVkFMSURfRU9GX1NUQVRFAElOVkFMSURfU1NMX0NFUlRJRklDQVRFAFBBVVNFAE5PX1JFU1BPTlNFAFVOU1VQUE9SVEVEX01FRElBX1RZUEUAR09ORQBOT1RfQUNDRVBUQUJMRQBTRVJWSUNFX1VOQVZBSUxBQkxFAFJBTkdFX05PVF9TQVRJU0ZJQUJMRQBPUklHSU5fSVNfVU5SRUFDSEFCTEUAUkVTUE9OU0VfSVNfU1RBTEUAUFVSR0UATUVSR0UAUkVRVUVTVF9IRUFERVJfRklFTERTX1RPT19MQVJHRQBSRVFVRVNUX0hFQURFUl9UT09fTEFSR0UAUEFZTE9BRF9UT09fTEFSR0UASU5TVUZGSUNJRU5UX1NUT1JBR0UASFBFX1BBVVNFRF9VUEdSQURFAEhQRV9QQVVTRURfSDJfVVBHUkFERQBTT1VSQ0UAQU5OT1VOQ0UAVFJBQ0UASFBFX1VORVhQRUNURURfU1BBQ0UAREVTQ1JJQkUAVU5TVUJTQ1JJQkUAUkVDT1JEAEhQRV9JTlZBTElEX01FVEhPRABOT1RfRk9VTkQAUFJPUEZJTkQAVU5CSU5EAFJFQklORABVTkFVVEhPUklaRUQATUVUSE9EX05PVF9BTExPV0VEAEhUVFBfVkVSU0lPTl9OT1RfU1VQUE9SVEVEAEFMUkVBRFlfUkVQT1JURUQAQUNDRVBURUQATk9UX0lNUExFTUVOVEVEAExPT1BfREVURUNURUQASFBFX0NSX0VYUEVDVEVEAEhQRV9MRl9FWFBFQ1RFRABDUkVBVEVEAElNX1VTRUQASFBFX1BBVVNFRABUSU1FT1VUX09DQ1VSRUQAUEFZTUVOVF9SRVFVSVJFRABQUkVDT05ESVRJT05fUkVRVUlSRUQAUFJPWFlfQVVUSEVOVElDQVRJT05fUkVRVUlSRUQATkVUV09SS19BVVRIRU5USUNBVElPTl9SRVFVSVJFRABMRU5HVEhfUkVRVUlSRUQAU1NMX0NFUlRJRklDQVRFX1JFUVVJUkVEAFVQR1JBREVfUkVRVUlSRUQAUEFHRV9FWFBJUkVEAFBSRUNPTkRJVElPTl9GQUlMRUQARVhQRUNUQVRJT05fRkFJTEVEAFJFVkFMSURBVElPTl9GQUlMRUQAU1NMX0hBTkRTSEFLRV9GQUlMRUQATE9DS0VEAFRSQU5TRk9STUFUSU9OX0FQUExJRUQATk9UX01PRElGSUVEAE5PVF9FWFRFTkRFRABCQU5EV0lEVEhfTElNSVRfRVhDRUVERUQAU0lURV9JU19PVkVSTE9BREVEAEhFQUQARXhwZWN0ZWQgSFRUUC8AAF4TAAAmEwAAMBAAAPAXAACdEwAAFRIAADkXAADwEgAAChAAAHUSAACtEgAAghMAAE8UAAB/EAAAoBUAACMUAACJEgAAixQAAE0VAADUEQAAzxQAABAYAADJFgAA3BYAAMERAADgFwAAuxQAAHQUAAB8FQAA5RQAAAgXAAAfEAAAZRUAAKMUAAAoFQAAAhUAAJkVAAAsEAAAixkAAE8PAADUDgAAahAAAM4QAAACFwAAiQ4AAG4TAAAcEwAAZhQAAFYXAADBEwAAzRMAAGwTAABoFwAAZhcAAF8XAAAiEwAAzg8AAGkOAADYDgAAYxYAAMsTAACqDgAAKBcAACYXAADFEwAAXRYAAOgRAABnEwAAZRMAAPIWAABzEwAAHRcAAPkWAADzEQAAzw4AAM4VAAAMEgAAsxEAAKURAABhEAAAMhcAALsTAEH5NQsBAQBBkDYL4AEBAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBB/TcLAQEAQZE4C14CAwICAgICAAACAgACAgACAgICAgICAgICAAQAAAAAAAICAgICAgICAgICAgICAgICAgICAgICAgICAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAAgACAEH9OQsBAQBBkToLXgIAAgICAgIAAAICAAICAAICAgICAgICAgIAAwAEAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgIAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgICAgACAAIAQfA7Cw1sb3NlZWVwLWFsaXZlAEGJPAsBAQBBoDwL4AEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBBiT4LAQEAQaA+C+cBAQEBAQEBAQEBAQEBAgEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQFjaHVua2VkAEGwwAALXwEBAAEBAQEBAAABAQABAQABAQEBAQEBAQEBAAAAAAAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQABAEGQwgALIWVjdGlvbmVudC1sZW5ndGhvbnJveHktY29ubmVjdGlvbgBBwMIACy1yYW5zZmVyLWVuY29kaW5ncGdyYWRlDQoNCg0KU00NCg0KVFRQL0NFL1RTUC8AQfnCAAsFAQIAAQMAQZDDAAvgAQQBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAEH5xAALBQECAAEDAEGQxQAL4AEEAQEFAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBB+cYACwQBAAABAEGRxwAL3wEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAEH6yAALBAEAAAIAQZDJAAtfAwQAAAQEBAQEBAQEBAQEBQQEBAQEBAQEBAQEBAAEAAYHBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQABAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAAAAQAQfrKAAsEAQAAAQBBkMsACwEBAEGqywALQQIAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwAAAAAAAAMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAEH6zAALBAEAAAEAQZDNAAsBAQBBms0ACwYCAAAAAAIAQbHNAAs6AwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBB8M4AC5YBTk9VTkNFRUNLT1VUTkVDVEVURUNSSUJFTFVTSEVURUFEU0VBUkNIUkdFQ1RJVklUWUxFTkRBUlZFT1RJRllQVElPTlNDSFNFQVlTVEFUQ0hHRU9SRElSRUNUT1JUUkNIUEFSQU1FVEVSVVJDRUJTQ1JJQkVBUkRPV05BQ0VJTkROS0NLVUJTQ1JJQkVIVFRQL0FEVFAv", "base64"); + } +}); + +// viewer/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js +var require_llhttp_simd_wasm = __commonJS({ + "viewer/node_modules/undici/lib/llhttp/llhttp_simd-wasm.js"(exports, module) { + "use strict"; + var { Buffer: Buffer2 } = __require("node:buffer"); + module.exports = Buffer2.from("AGFzbQEAAAABJwdgAX8Bf2ADf39/AX9gAX8AYAJ/fwBgBH9/f38Bf2AAAGADf39/AALLAQgDZW52GHdhc21fb25faGVhZGVyc19jb21wbGV0ZQAEA2VudhV3YXNtX29uX21lc3NhZ2VfYmVnaW4AAANlbnYLd2FzbV9vbl91cmwAAQNlbnYOd2FzbV9vbl9zdGF0dXMAAQNlbnYUd2FzbV9vbl9oZWFkZXJfZmllbGQAAQNlbnYUd2FzbV9vbl9oZWFkZXJfdmFsdWUAAQNlbnYMd2FzbV9vbl9ib2R5AAEDZW52GHdhc21fb25fbWVzc2FnZV9jb21wbGV0ZQAAAy0sBQYAAAIAAAAAAAACAQIAAgICAAADAAAAAAMDAwMBAQEBAQEBAQEAAAIAAAAEBQFwARISBQMBAAIGCAF/AUGA1AQLB9EFIgZtZW1vcnkCAAtfaW5pdGlhbGl6ZQAIGV9faW5kaXJlY3RfZnVuY3Rpb25fdGFibGUBAAtsbGh0dHBfaW5pdAAJGGxsaHR0cF9zaG91bGRfa2VlcF9hbGl2ZQAvDGxsaHR0cF9hbGxvYwALBm1hbGxvYwAxC2xsaHR0cF9mcmVlAAwEZnJlZQAMD2xsaHR0cF9nZXRfdHlwZQANFWxsaHR0cF9nZXRfaHR0cF9tYWpvcgAOFWxsaHR0cF9nZXRfaHR0cF9taW5vcgAPEWxsaHR0cF9nZXRfbWV0aG9kABAWbGxodHRwX2dldF9zdGF0dXNfY29kZQAREmxsaHR0cF9nZXRfdXBncmFkZQASDGxsaHR0cF9yZXNldAATDmxsaHR0cF9leGVjdXRlABQUbGxodHRwX3NldHRpbmdzX2luaXQAFQ1sbGh0dHBfZmluaXNoABYMbGxodHRwX3BhdXNlABcNbGxodHRwX3Jlc3VtZQAYG2xsaHR0cF9yZXN1bWVfYWZ0ZXJfdXBncmFkZQAZEGxsaHR0cF9nZXRfZXJybm8AGhdsbGh0dHBfZ2V0X2Vycm9yX3JlYXNvbgAbF2xsaHR0cF9zZXRfZXJyb3JfcmVhc29uABwUbGxodHRwX2dldF9lcnJvcl9wb3MAHRFsbGh0dHBfZXJybm9fbmFtZQAeEmxsaHR0cF9tZXRob2RfbmFtZQAfEmxsaHR0cF9zdGF0dXNfbmFtZQAgGmxsaHR0cF9zZXRfbGVu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PgtBhwEMPQtBiAEMPAtBiQEMOwtBigEMOgtBiwEMOQtBjAEMOAtBjQEMNwtBjgEMNgtBjwEMNQtBkAEMNAtBkQEMMwtBkgEMMgtBkwEMMQtBlAEMMAtBlQEMLwtBlgEMLgtBlwEMLQtBmAEMLAtBmQEMKwtBmgEMKgtBmwEMKQtBnAEMKAtBnQEMJwtBngEMJgtBnwEMJQtBoAEMJAtBoQEMIwtBogEMIgtBowEMIQtBpAEMIAtBpQEMHwtBpgEMHgtBpwEMHQtBqAEMHAtBqQEMGwtBqgEMGgtBqwEMGQtBrAEMGAtBrQEMFwtBrgEMFgtBAQwVC0GvAQwUC0GwAQwTC0GxAQwSC0GzAQwRC0GyAQwQC0G0AQwPC0G1AQwOC0G2AQwNC0G3AQwMC0G4AQwLC0G5AQwKC0G6AQwJC0G7AQwIC0HGAQwHC0G8AQwGC0G9AQwFC0G+AQwEC0G/AQwDC0HAAQwCC0HCAQwBC0HBAQshAwNAAkACQAJAAkACQAJAAkACQAJAIAICfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJ/AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAgAgJ/AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACfwJAAkACfwJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkAC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iQEhAwykAgtBASABLQAAQd8ARw1nGiABQQFqIQEMXgtBigEhAyABIARGDaICIAIoAgAiACAEIAFraiEFIAEgAGtBAWohBgNAIAEtAAAgAEGMzwBqLQAARw1kIABBAUYN+gEgAEEBaiEAIAQgAUEBaiIBRw0ACyACIAU2AgAMogILQYsBIQMgASAERg2hAiACKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGOzwBqLQAARw1kIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAyiAgsgAkEANgIAIAZBAWohAUECDGULQYwBIQMgASAERg2gAiACKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHwzwBqLQAARw1jIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAyhAgsgAkEANgIAIAZBAWohAUEfDGQLQY0BIQMgASAERg2fAiACKAIAIgAgBCABa2ohBSABIABrQQFqIQYCQANAIAEtAAAgAEHyzwBqLQAARw1iIABBAUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAygAgsgAkEANgIAIAZBAWohAUEJDGMLIAEgBEYEQEGOASEDDJ8CCwJAAkAgAS0AAEHJAGsOBwBiYmJiYgFiCyABQQFqIQFB+AAhAwyGAgsgAUEBaiEBQfkAIQMMhQILQY8BIQMgASAERg2dAiACKAIAIgAgBCABa2ohBSABIABrQQVqIQYCQANAIAEtAAAgAEGRzwBqLQAARw1gIABBBUYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAyeAgsgAkEANgIAIAZBAWohAUEYDGELQZABIQMgASAERg2cAiACKAIAIgAgBCABa2ohBSABIABrQQJqIQYCQANAIAEtAAAgAEGXzwBqLQAARw1fIABBAkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAydAgsgAkEANgIAIAZBAWohAUEXDGALQZEBIQMgASAERg2bAiACKAIAIgAgBCABa2ohBSABIABrQQZqIQYCQANAIAEtAAAgAEGazwBqLQAARw1eIABBBkYNASAAQQFqIQAgBCABQQFqIgFHDQALIAIgBTYCAAycAgsgAkEANgIAIAZBAWohAUEV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JSIARQ0RIAJB5QA2AhwgAiABNgIUIAIgADYCDEEAIQMMtAELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0gIAJB0wA2AhwgAiABNgIUIAIgADYCDEEAIQMMswELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0iIAJB0gA2AhwgAiABNgIUIAIgADYCDEEAIQMMsgELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0OIAJB5QA2AhwgAiABNgIUIAIgADYCDEEAIQMMsQELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0dIAJB0wA2AhwgAiABNgIUIAIgADYCDEEAIQMMsAELIAIoAgQhACACQQA2AgQgAiAAIAEQJSIARQ0fIAJB0gA2AhwgAiABNgIUIAIgADYCDEEAIQMMrwELIABBP0cNASABQQFqCyEBQQUhAwyUAQtBACEDIAJBADYCHCACIAE2AhQgAkH9EjYCECACQQc2AgwMrAELIAJBADYCHCACIAE2AhQgAkHcCDYCECACQQc2AgxBACEDDKsBCyACKAIEIQAgAkEANgIEIAIgACABECUiAEUNByACQeUANgIcIAIgATYCFCACIAA2AgxBACEDDKoBCyACKAIEIQAgAkEANgIEIAIgACABECUiAEUNFiACQdMANgIcIAIgATYCFCACIAA2AgxBACEDDKkBCyACKAIEIQAgAkEANgIEIAIgACABECUiAEUNGCACQdIANgIcIAIgATYCFCACIAA2AgxBACEDDKgBCyACQQA2AhwgAiABNgIUIAJBxgo2AhAgAkEHNgIMQQAhAwynAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDQMgAkHlADYCHCACIAE2AhQgAiAANgIMQQAhAwymAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDRIgAkHTADYCHCACIAE2AhQgAiAANgIMQQAhAwylAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDRQgAkHSADYCHCACIAE2AhQgAiAANgIMQQAhAwykAQsgAigCBCEAIAJBADYCBCACIAAgARAlIgBFDQAgAkHlADYCHCACIAE2AhQgAiAANgIMQQAhAwyjAQtB1QAhAwyJAQsgAEEVRwRAIAJBADYCHCACIAE2AhQgAkG5DTYCECACQRo2AgxB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AkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAAkACQAJAIABB5ABrDvQDY2IAAWFhYWFhYQIDBAVhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhBgcICQoLDA0OD2FhYWFhEGFhYWFhYWFhYWFhEWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYRITFBUWFxgZGhthYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhHB0eHyAhIiMkJSYnKCkqKywtLi8wMTIzNDU2YTc4OTphYWFhYWFhYTthYWE8YWFhYT0+P2FhYWFhYWFhQGFhQWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYUJDREVGR0hJSktMTU5PUFFSU2FhYWFhYWFhVFVWV1hZWlthXF1hYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFeYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhYWFhX2BhC0HhJw8LQaQhDwtByywPC0H+MQ8LQcAkDwtBqyQPC0GNKA8LQeImDwtBgDAPC0G5Lw8LQdckDwtB7x8PC0HhHw8LQfofDwtB8iAPC0GoLw8LQa4yDwtBiDAPC0HsJw8LQYIiDwtBjh0PC0HQLg8LQcojDwtBxTIPC0HfHA8LQdIcDwtBxCAPC0HXIA8LQaIfDwtB7S4PC0GrMA8LQdQlDwtBzC4PC0H6Lg8LQfwrDwtB0jAPC0HxHQ8LQbsgDwtB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AAADAEGUCAsFBAAAAAUAQaQICwkGAAAABwAAAAgAQdwIC4otSW52YWxpZCBjaGFyIGluIHVybCBxdWVyeQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX2JvZHkAQ29udGVudC1MZW5ndGggb3ZlcmZsb3cAQ2h1bmsgc2l6ZSBvdmVyZmxvdwBSZXNwb25zZSBvdmVyZmxvdwBJbnZhbGlkIG1ldGhvZCBmb3IgSFRUUC94LnggcmVxdWVzdABJbnZhbGlkIG1ldGhvZCBmb3IgUlRTUC94LnggcmVxdWVzdABFeHBlY3RlZCBTT1VSQ0UgbWV0aG9kIGZvciBJQ0UveC54IHJlcXVlc3QASW52YWxpZCBjaGFyIGluIHVybCBmcmFnbWVudCBzdGFydABFeHBlY3RlZCBkb3QAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9zdGF0dXMASW52YWxpZCByZXNwb25zZSBzdGF0dXMASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucwBVc2VyIGNhbGxiYWNrIGVycm9yAGBvbl9yZXNldGAgY2FsbGJhY2sgZXJyb3IAYG9uX2NodW5rX2hlYWRlcmAgY2FsbGJhY2sgZXJyb3IAYG9uX21lc3NhZ2VfYmVnaW5gIGNhbGxiYWNrIGVycm9yAGBvbl9jaHVua19leHRlbnNpb25fdmFsdWVgIGNhbGxiYWNrIGVycm9yAGBvbl9zdGF0dXNfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl92ZXJzaW9uX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fdXJsX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGVgIGNhbGxiYWNrIGVycm9yAGBvbl9tZXNzYWdlX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fbWV0aG9kX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlYCBjYWxsYmFjayBlcnJvcgBgb25fY2h1bmtfZXh0ZW5zaW9uX25hbWVgIGNhbGxiYWNrIGVycm9yAFVuZXhwZWN0ZWQgY2hhciBpbiB1cmwgc2VydmVyAEludmFsaWQgaGVhZGVyIHZhbHVlIGNoYXIASW52YWxpZCBoZWFkZXIgZmllbGQgY2hhcgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3ZlcnNpb24ASW52YWxpZCBtaW5vciB2ZXJzaW9uAEludmFsaWQgbWFqb3IgdmVyc2lvbgBFeHBlY3RlZCBzcGFjZSBhZnRlciB2ZXJzaW9uAEV4cGVjdGVkIENSTEYgYWZ0ZXIgdmVyc2lvbgBJbnZhbGlkIEhUVFAgdmVyc2lvbgBJbnZhbGlkIGhlYWRlciB0b2tlbgBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX3VybABJbnZhbGlkIGNoYXJhY3RlcnMgaW4gdXJsAFVuZXhwZWN0ZWQgc3RhcnQgY2hhciBpbiB1cmwARG91YmxlIEAgaW4gdXJsAEVtcHR5IENvbnRlbnQtTGVuZ3RoAEludmFsaWQgY2hhcmFjdGVyIGluIENvbnRlbnQtTGVuZ3RoAER1cGxpY2F0ZSBDb250ZW50LUxlbmd0aABJbnZhbGlkIGNoYXIgaW4gdXJsIHBhdGgAQ29udGVudC1MZW5ndGggY2FuJ3QgYmUgcHJlc2VudCB3aXRoIFRyYW5zZmVyLUVuY29kaW5nAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIHNpemUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfdmFsdWUAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9jaHVua19leHRlbnNpb25fdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyB2YWx1ZQBNaXNzaW5nIGV4cGVjdGVkIExGIGFmdGVyIGhlYWRlciB2YWx1ZQBJbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AgaGVhZGVyIHZhbHVlAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgcXVvdGUgdmFsdWUASW52YWxpZCBjaGFyYWN0ZXIgaW4gY2h1bmsgZXh0ZW5zaW9ucyBxdW90ZWQgdmFsdWUAUGF1c2VkIGJ5IG9uX2hlYWRlcnNfY29tcGxldGUASW52YWxpZCBFT0Ygc3RhdGUAb25fcmVzZXQgcGF1c2UAb25fY2h1bmtfaGVhZGVyIHBhdXNlAG9uX21lc3NhZ2VfYmVnaW4gcGF1c2UAb25fY2h1bmtfZXh0ZW5zaW9uX3ZhbHVlIHBhdXNlAG9uX3N0YXR1c19jb21wbGV0ZSBwYXVzZQBvbl92ZXJzaW9uX2NvbXBsZXRlIHBhdXNlAG9uX3VybF9jb21wbGV0ZSBwYXVzZQBvbl9jaHVua19jb21wbGV0ZSBwYXVzZQBvbl9oZWFkZXJfdmFsdWVfY29tcGxldGUgcGF1c2UAb25fbWVzc2FnZV9jb21wbGV0ZSBwYXVzZQBvbl9tZXRob2RfY29tcGxldGUgcGF1c2UAb25faGVhZGVyX2ZpZWxkX2NvbXBsZXRlIHBhdXNlAG9uX2NodW5rX2V4dGVuc2lvbl9uYW1lIHBhdXNlAFVuZXhwZWN0ZWQgc3BhY2UgYWZ0ZXIgc3RhcnQgbGluZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX2NodW5rX2V4dGVuc2lvbl9uYW1lAEludmFsaWQgY2hhcmFjdGVyIGluIGNodW5rIGV4dGVuc2lvbnMgbmFtZQBQYXVzZSBvbiBDT05ORUNUL1VwZ3JhZGUAUGF1c2Ugb24gUFJJL1VwZ3JhZGUARXhwZWN0ZWQgSFRUUC8yIENvbm5lY3Rpb24gUHJlZmFjZQBTcGFuIGNhbGxiYWNrIGVycm9yIGluIG9uX21ldGhvZABFeHBlY3RlZCBzcGFjZSBhZnRlciBtZXRob2QAU3BhbiBjYWxsYmFjayBlcnJvciBpbiBvbl9oZWFkZXJfZmllbGQAUGF1c2VkAEludmFsaWQgd29yZCBlbmNvdW50ZXJlZABJbnZhbGlkIG1ldGhvZCBlbmNvdW50ZXJlZABVbmV4cGVjdGVkIGNoYXIgaW4gdXJsIHNjaGVtYQBSZXF1ZXN0IGhhcyBpbnZhbGlkIGBUcmFuc2Zlci1FbmNvZGluZ2AAU1dJVENIX1BST1hZAFVTRV9QUk9YWQBNS0FDVElWSVRZAFVOUFJPQ0VTU0FCTEVfRU5USVRZAENPUFkATU9WRURfUEVSTUFORU5UTFkAVE9PX0VBUkxZAE5PVElGWQBGQUlMRURfREVQRU5ERU5DWQBCQURfR0FURVdBWQBQTEFZAFBVVABDSEVDS09VVABHQVRFV0FZX1RJTUVPVVQAUkVRVUVTVF9USU1FT1VUAE5FVFdPUktfQ09OTkVDVF9USU1FT1VUAENPTk5FQ1RJT05fVElNRU9VVABMT0dJTl9USU1FT1VUAE5FVFdPUktfUkVBRF9USU1FT1VUAFBPU1QATUlTRElSRUNURURfUkVRVUVTVABDTElFTlRfQ0xPU0VEX1JFUVVFU1QAQ0xJRU5UX0NMT1NFRF9MT0FEX0JBTEFOQ0VEX1JFUVVFU1QAQkFEX1JFUVVFU1QASFRUUF9SRVFVRVNUX1NFTlRfVE9fSFRUUFNfUE9SVABSRVBPUlQASU1fQV9URUFQT1QAUkVTRVRfQ09OVEVOVABOT19DT05URU5UAFBBUlRJQUxfQ09OVEVOVABIUEVfSU5WQUxJRF9DT05TVEFOVABIUEVfQ0JfUkVTRVQAR0VUAEhQRV9TVFJJQ1QAQ09ORkxJQ1QAVEVNUE9SQVJZX1JFRElSRUNUAFBFUk1BTkVOVF9SRURJUkVDVABDT05ORUNUAE1VTFRJX1NUQVRVUwBIUEVfSU5WQUxJRF9TVEFUVVMAVE9PX01BTllfUkVRVUVTVFMARUFSTFlfSElOVFMAVU5BVkFJTEFCTEVfRk9SX0xFR0FMX1JFQVNPTlMAT1BUSU9OUwBTV0lUQ0hJTkdfUFJPVE9DT0xTAFZBUklBTlRfQUxTT19ORUdPVElBVEVTAE1VTFRJUExFX0NIT0lDRVMASU5URVJOQUxfU0VSVkVSX0VSUk9SAFdFQl9TRVJWRVJfVU5LTk9XTl9FUlJPUgBSQUlMR1VOX0VSUk9SAElERU5USVRZX1BST1ZJREVSX0FVVEhFTlRJQ0FUSU9OX0VSUk9SAFNTTF9DRVJUSUZJQ0FURV9FUlJPUgBJTlZBTElEX1hfRk9SV0FSREVEX0ZPUgBTRVRfUEFSQU1FVEVSAEdFVF9QQVJBTUVURVIASFBFX1VTRVIAU0VFX09USEVSAEhQRV9DQl9DSFVOS19IRUFERVIATUtDQUxFTkRBUgBTRVRVUABXRUJfU0VSVkVSX0lTX0RPV04AVEVBUkRPV04ASFBFX0NMT1NFRF9DT05ORUNUSU9OAEhFVVJJU1RJQ19FWFBJUkFUSU9OAERJU0NPTk5FQ1RFRF9PUEVSQVRJT04ATk9OX0FVVEhPUklUQVRJVkVfSU5GT1JNQVRJT04ASFBFX0lOVkFMSURfVkVSU0lPTgBIUEVfQ0JfTUVTU0FHRV9CRUdJTgBTSVRFX0lTX0ZST1pFTgBIUEVfSU5WQUxJRF9IRUFERVJfVE9LRU4ASU5WQUxJRF9UT0tFTgBGT1JCSURERU4ARU5IQU5DRV9ZT1VSX0NBTE0ASFBFX0lOVkFMSURfVVJMAEJMT0NLRURfQllfUEFSRU5UQUxfQ09OVFJPTABNS0NPTABBQ0wASFBFX0lOVEVSTkFMAFJFUVVFU1RfSEVBREVSX0ZJRUxEU19UT09fTEFSR0VfVU5PRkZJQ0lBTABIUEVfT0sAVU5MSU5LAFVOTE9DSwBQUkkAUkVUUllfV0lUSABIUEVfSU5WQUxJRF9DT05URU5UX0xFTkdUSABIUEVfVU5FWFBFQ1RFRF9DT05URU5UX0xFTkdUSABGTFVTSABQUk9QUEFUQ0gATS1TRUFSQ0gAVVJJX1RPT19MT05HAFBST0NFU1NJTkcATUlTQ0VMTEFORU9VU19QRVJTSVNURU5UX1dBUk5JTkcATUlTQ0VMTEFORU9VU19XQVJOSU5HAEhQRV9JTlZBTElEX1RSQU5TRkVSX0VOQ09ESU5HAEV4cGVjdGVkIENSTEYASFBFX0lOVkFMSURfQ0hVTktfU0laRQBNT1ZFAENPTlRJTlVFAEhQRV9DQl9TVEFUVVNfQ09NUExFVEUASFBFX0NCX0hFQURFUlNfQ09NUExFVEUASFBFX0NCX1ZFUlNJT05fQ09NUExFVEUASFBFX0NCX1VSTF9DT01QTEVURQBIUEVfQ0JfQ0hVTktfQ09NUExFVEUASFBFX0NCX0hFQURFUl9WQUxVRV9DT01QTEVURQBIUEVfQ0JfQ0hVTktfRVhURU5TSU9OX1ZBTFVFX0NPTVBMRVRFAEhQRV9DQl9DSFVOS19FWFRFTlNJT05fTkFNRV9DT01QTEVURQBIUEVfQ0JfTUVTU0FHRV9DT01QTEVURQBIUEVfQ0JfTUVUSE9EX0NPTVBMRVRFAEhQRV9DQl9IRUFERVJfRklFTERfQ09NUExFVEUAREVMRVRFAEhQRV9JTlZBTElEX0VPRl9TVEFURQBJTlZBTElEX1NTTF9DRVJUSUZJQ0FURQBQQVVTRQBOT19SRVNQT05TRQBVTlNVUFBPUlRFRF9NRURJQV9UWVBFAEdPTkUATk9UX0FDQ0VQVEFCTEUAU0VSVklDRV9VTkFWQUlMQUJMRQBSQU5HRV9OT1RfU0FUSVNGSUFCTEUAT1JJR0lOX0lTX1VOUkVBQ0hBQkxFAFJFU1BPTlNFX0lTX1NUQUxFAFBVUkdFAE1FUkdFAFJFUVVFU1RfSEVBREVSX0ZJRUxEU19UT09fTEFSR0UAUkVRVUVTVF9IRUFERVJfVE9PX0xBUkdFAFBBWUxPQURfVE9PX0xBUkdFAElOU1VGRklDSUVOVF9TVE9SQUdFAEhQRV9QQVVTRURfVVBHUkFERQBIUEVfUEFVU0VEX0gyX1VQR1JBREUAU09VUkNFAEFOTk9VTkNFAFRSQUNFAEhQRV9VTkVYUEVDVEVEX1NQQUNFAERFU0NSSUJFAFVOU1VCU0NSSUJFAFJFQ09SRABIUEVfSU5WQUxJRF9NRVRIT0QATk9UX0ZPVU5EAFBST1BGSU5EAFVOQklORABSRUJJTkQAVU5BVVRIT1JJWkVEAE1FVEhPRF9OT1RfQUxMT1dFRABIVFRQX1ZFUlNJT05fTk9UX1NVUFBPUlRFRABBTFJFQURZX1JFUE9SVEVEAEFDQ0VQVEVEAE5PVF9JTVBMRU1FTlRFRABMT09QX0RFVEVDVEVEAEhQRV9DUl9FWFBFQ1RFRABIUEVfTEZfRVhQRUNURUQAQ1JFQVRFRABJTV9VU0VEAEhQRV9QQVVTRUQAVElNRU9VVF9PQ0NVUkVEAFBBWU1FTlRfUkVRVUlSRUQAUFJFQ09ORElUSU9OX1JFUVVJUkVEAFBST1hZX0FVVEhFTlRJQ0FUSU9OX1JFUVVJUkVEAE5FVFdPUktfQVVUSEVOVElDQVRJT05fUkVRVUlSRUQATEVOR1RIX1JFUVVJUkVEAFNTTF9DRVJUSUZJQ0FURV9SRVFVSVJFRABVUEdSQURFX1JFUVVJUkVEAFBBR0VfRVhQSVJFRABQUkVDT05ESVRJT05fRkFJTEVEAEVYUEVDVEFUSU9OX0ZBSUxFRABSRVZBTElEQVRJT05fRkFJTEVEAFNTTF9IQU5EU0hBS0VfRkFJTEVEAExPQ0tFRABUUkFOU0ZPUk1BVElPTl9BUFBMSUVEAE5PVF9NT0RJRklFRABOT1RfRVhURU5ERUQAQkFORFdJRFRIX0xJTUlUX0VYQ0VFREVEAFNJVEVfSVNfT1ZFUkxPQURFRABIRUFEAEV4cGVjdGVkIEhUVFAvAABeEwAAJhMAADAQAADwFwAAnRMAABUSAAA5FwAA8BIAAAoQAAB1EgAArRIAAIITAABPFAAAfxAAAKAVAAAjFAAAiRIAAIsUAABNFQAA1BEAAM8UAAAQGAAAyRYAANwWAADBEQAA4BcAALsUAAB0FAAAfBUAAOUUAAAIFwAAHxAAAGUVAACjFAAAKBUAAAIVAACZFQAALBAAAIsZAABPDwAA1A4AAGoQAADOEAAAAhcAAIkOAABuEwAAHBMAAGYUAABWFwAAwRMAAM0TAABsEwAAaBcAAGYXAABfFwAAIhMAAM4PAABpDgAA2A4AAGMWAADLEwAAqg4AACgXAAAmFwAAxRMAAF0WAADoEQAAZxMAAGUTAADyFgAAcxMAAB0XAAD5FgAA8xEAAM8OAADOFQAADBIAALMRAAClEQAAYRAAADIXAAC7EwBB+TULAQEAQZA2C+ABAQECAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAQf03CwEBAEGROAteAgMCAgICAgAAAgIAAgIAAgICAgICAgICAgAEAAAAAAACAgICAgICAgICAgICAgICAgICAgICAgICAgAAAAICAgICAgICAgICAgICAgICAgICAgICAgICAgICAAIAAgBB/TkLAQEAQZE6C14CAAICAgICAAACAgACAgACAgICAgICAgICAAMABAAAAAICAgICAgICAgICAgICAgICAgICAgICAgICAAAAAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAAgACAEHwOwsNbG9zZWVlcC1hbGl2ZQBBiTwLAQEAQaA8C+ABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAQYk+CwEBAEGgPgvnAQEBAQEBAQEBAQEBAQIBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBY2h1bmtlZABBsMAAC18BAQABAQEBAQAAAQEAAQEAAQEBAQEBAQEBAQAAAAAAAAABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQBBkMIACyFlY3Rpb25lbnQtbGVuZ3Rob25yb3h5LWNvbm5lY3Rpb24AQcDCAAstcmFuc2Zlci1lbmNvZGluZ3BncmFkZQ0KDQoNClNNDQoNClRUUC9DRS9UU1AvAEH5wgALBQECAAEDAEGQwwAL4AEEAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBB+cQACwUBAgABAwBBkMUAC+ABBAEBBQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAQfnGAAsEAQAAAQBBkccAC98BAQEAAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQBB+sgACwQBAAACAEGQyQALXwMEAAAEBAQEBAQEBAQEBAUEBAQEBAQEBAQEBAQABAAGBwQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAAEAAQABAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQAAAAEAEH6ygALBAEAAAEAQZDLAAsBAQBBqssAC0ECAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAAAAAAAADAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwBB+swACwQBAAABAEGQzQALAQEAQZrNAAsGAgAAAAACAEGxzQALOgMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAAAAAAAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMAQfDOAAuWAU5PVU5DRUVDS09VVE5FQ1RFVEVDUklCRUxVU0hFVEVBRFNFQVJDSFJHRUNUSVZJVFlMRU5EQVJWRU9USUZZUFRJT05TQ0hTRUFZU1RBVENIR0VPUkRJUkVDVE9SVFJDSFBBUkFNRVRFUlVSQ0VCU0NSSUJFQVJET1dOQUNFSU5ETktDS1VCU0NSSUJFSFRUUC9BRFRQLw==", "base64"); + } +}); + +// viewer/node_modules/undici/lib/web/fetch/constants.js +var require_constants3 = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/constants.js"(exports, module) { + "use strict"; + var corsSafeListedMethods = ( + /** @type {const} */ + ["GET", "HEAD", "POST"] + ); + var corsSafeListedMethodsSet = new Set(corsSafeListedMethods); + var nullBodyStatus = ( + /** @type {const} */ + [101, 204, 205, 304] + ); + var redirectStatus = ( + /** @type {const} */ + [301, 302, 303, 307, 308] + ); + var redirectStatusSet = new Set(redirectStatus); + var badPorts = ( + /** @type {const} */ + [ + "1", + "7", + "9", + "11", + "13", + "15", + "17", + "19", + "20", + "21", + "22", + "23", + "25", + "37", + "42", + "43", + "53", + "69", + "77", + "79", + "87", + "95", + "101", + "102", + "103", + "104", + "109", + "110", + "111", + "113", + "115", + "117", + "119", + "123", + "135", + "137", + "139", + "143", + "161", + "179", + "389", + "427", + "465", + "512", + "513", + "514", + "515", + "526", + "530", + "531", + "532", + "540", + "548", + "554", + "556", + "563", + "587", + "601", + "636", + "989", + "990", + "993", + "995", + "1719", + "1720", + "1723", + "2049", + "3659", + "4045", + "4190", + "5060", + "5061", + "6000", + "6566", + "6665", + "6666", + "6667", + "6668", + "6669", + "6679", + "6697", + "10080" + ] + ); + var badPortsSet = new Set(badPorts); + var referrerPolicy = ( + /** @type {const} */ + [ + "", + "no-referrer", + "no-referrer-when-downgrade", + "same-origin", + "origin", + "strict-origin", + "origin-when-cross-origin", + "strict-origin-when-cross-origin", + "unsafe-url" + ] + ); + var referrerPolicySet = new Set(referrerPolicy); + var requestRedirect = ( + /** @type {const} */ + ["follow", "manual", "error"] + ); + var safeMethods = ( + /** @type {const} */ + ["GET", "HEAD", "OPTIONS", "TRACE"] + ); + var safeMethodsSet = new Set(safeMethods); + var requestMode = ( + /** @type {const} */ + ["navigate", "same-origin", "no-cors", "cors"] + ); + var requestCredentials = ( + /** @type {const} */ + ["omit", "same-origin", "include"] + ); + var requestCache = ( + /** @type {const} */ + [ + "default", + "no-store", + "reload", + "no-cache", + "force-cache", + "only-if-cached" + ] + ); + var requestBodyHeader = ( + /** @type {const} */ + [ + "content-encoding", + "content-language", + "content-location", + "content-type", + // See https://github.com/nodejs/undici/issues/2021 + // 'Content-Length' is a forbidden header name, which is typically + // removed in the Headers implementation. However, undici doesn't + // filter out headers, so we add it here. + "content-length" + ] + ); + var requestDuplex = ( + /** @type {const} */ + [ + "half" + ] + ); + var forbiddenMethods = ( + /** @type {const} */ + ["CONNECT", "TRACE", "TRACK"] + ); + var forbiddenMethodsSet = new Set(forbiddenMethods); + var subresource = ( + /** @type {const} */ + [ + "audio", + "audioworklet", + "font", + "image", + "manifest", + "paintworklet", + "script", + "style", + "track", + "video", + "xslt", + "" + ] + ); + var subresourceSet = new Set(subresource); + module.exports = { + subresource, + forbiddenMethods, + requestBodyHeader, + referrerPolicy, + requestRedirect, + requestMode, + requestCredentials, + requestCache, + redirectStatus, + corsSafeListedMethods, + nullBodyStatus, + safeMethods, + badPorts, + requestDuplex, + subresourceSet, + badPortsSet, + redirectStatusSet, + corsSafeListedMethodsSet, + safeMethodsSet, + forbiddenMethodsSet, + referrerPolicySet + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/global.js +var require_global = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/global.js"(exports, module) { + "use strict"; + var globalOrigin = /* @__PURE__ */ Symbol.for("undici.globalOrigin.1"); + function getGlobalOrigin() { + return globalThis[globalOrigin]; + } + function setGlobalOrigin(newOrigin) { + if (newOrigin === void 0) { + Object.defineProperty(globalThis, globalOrigin, { + value: void 0, + writable: true, + enumerable: false, + configurable: false + }); + return; + } + const parsedURL = new URL(newOrigin); + if (parsedURL.protocol !== "http:" && parsedURL.protocol !== "https:") { + throw new TypeError(`Only http & https urls are allowed, received ${parsedURL.protocol}`); + } + Object.defineProperty(globalThis, globalOrigin, { + value: parsedURL, + writable: true, + enumerable: false, + configurable: false + }); + } + module.exports = { + getGlobalOrigin, + setGlobalOrigin + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/data-url.js +var require_data_url = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/data-url.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var encoder = new TextEncoder(); + var HTTP_TOKEN_CODEPOINTS = /^[!#$%&'*+\-.^_|~A-Za-z0-9]+$/; + var HTTP_WHITESPACE_REGEX = /[\u000A\u000D\u0009\u0020]/; + var ASCII_WHITESPACE_REPLACE_REGEX = /[\u0009\u000A\u000C\u000D\u0020]/g; + var HTTP_QUOTED_STRING_TOKENS = /^[\u0009\u0020-\u007E\u0080-\u00FF]+$/; + function dataURLProcessor(dataURL) { + assert(dataURL.protocol === "data:"); + let input = URLSerializer(dataURL, true); + input = input.slice(5); + const position = { position: 0 }; + let mimeType = collectASequenceOfCodePointsFast( + ",", + input, + position + ); + const mimeTypeLength = mimeType.length; + mimeType = removeASCIIWhitespace(mimeType, true, true); + if (position.position >= input.length) { + return "failure"; + } + position.position++; + const encodedBody = input.slice(mimeTypeLength + 1); + let body = stringPercentDecode(encodedBody); + if (/;(\u0020){0,}base64$/i.test(mimeType)) { + const stringBody = isomorphicDecode(body); + body = forgivingBase64(stringBody); + if (body === "failure") { + return "failure"; + } + mimeType = mimeType.slice(0, -6); + mimeType = mimeType.replace(/(\u0020)+$/, ""); + mimeType = mimeType.slice(0, -1); + } + if (mimeType.startsWith(";")) { + mimeType = "text/plain" + mimeType; + } + let mimeTypeRecord = parseMIMEType(mimeType); + if (mimeTypeRecord === "failure") { + mimeTypeRecord = parseMIMEType("text/plain;charset=US-ASCII"); + } + return { mimeType: mimeTypeRecord, body }; + } + function URLSerializer(url, excludeFragment = false) { + if (!excludeFragment) { + return url.href; + } + const href = url.href; + const hashLength = url.hash.length; + const serialized = hashLength === 0 ? href : href.substring(0, href.length - hashLength); + if (!hashLength && href.endsWith("#")) { + return serialized.slice(0, -1); + } + return serialized; + } + function collectASequenceOfCodePoints(condition, input, position) { + let result = ""; + while (position.position < input.length && condition(input[position.position])) { + result += input[position.position]; + position.position++; + } + return result; + } + function collectASequenceOfCodePointsFast(char, input, position) { + const idx = input.indexOf(char, position.position); + const start = position.position; + if (idx === -1) { + position.position = input.length; + return input.slice(start); + } + position.position = idx; + return input.slice(start, position.position); + } + function stringPercentDecode(input) { + const bytes2 = encoder.encode(input); + return percentDecode(bytes2); + } + function isHexCharByte(byte) { + return byte >= 48 && byte <= 57 || byte >= 65 && byte <= 70 || byte >= 97 && byte <= 102; + } + function hexByteToNumber(byte) { + return ( + // 0-9 + byte >= 48 && byte <= 57 ? byte - 48 : (byte & 223) - 55 + ); + } + function percentDecode(input) { + const length = input.length; + const output = new Uint8Array(length); + let j = 0; + for (let i = 0; i < length; ++i) { + const byte = input[i]; + if (byte !== 37) { + output[j++] = byte; + } else if (byte === 37 && !(isHexCharByte(input[i + 1]) && isHexCharByte(input[i + 2]))) { + output[j++] = 37; + } else { + output[j++] = hexByteToNumber(input[i + 1]) << 4 | hexByteToNumber(input[i + 2]); + i += 2; + } + } + return length === j ? output : output.subarray(0, j); + } + function parseMIMEType(input) { + input = removeHTTPWhitespace(input, true, true); + const position = { position: 0 }; + const type = collectASequenceOfCodePointsFast( + "/", + input, + position + ); + if (type.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(type)) { + return "failure"; + } + if (position.position > input.length) { + return "failure"; + } + position.position++; + let subtype = collectASequenceOfCodePointsFast( + ";", + input, + position + ); + subtype = removeHTTPWhitespace(subtype, false, true); + if (subtype.length === 0 || !HTTP_TOKEN_CODEPOINTS.test(subtype)) { + return "failure"; + } + const typeLowercase = type.toLowerCase(); + const subtypeLowercase = subtype.toLowerCase(); + const mimeType = { + type: typeLowercase, + subtype: subtypeLowercase, + /** @type {Map} */ + parameters: /* @__PURE__ */ new Map(), + // https://mimesniff.spec.whatwg.org/#mime-type-essence + essence: `${typeLowercase}/${subtypeLowercase}` + }; + while (position.position < input.length) { + position.position++; + collectASequenceOfCodePoints( + // https://fetch.spec.whatwg.org/#http-whitespace + (char) => HTTP_WHITESPACE_REGEX.test(char), + input, + position + ); + let parameterName = collectASequenceOfCodePoints( + (char) => char !== ";" && char !== "=", + input, + position + ); + parameterName = parameterName.toLowerCase(); + if (position.position < input.length) { + if (input[position.position] === ";") { + continue; + } + position.position++; + } + if (position.position > input.length) { + break; + } + let parameterValue = null; + if (input[position.position] === '"') { + parameterValue = collectAnHTTPQuotedString(input, position, true); + collectASequenceOfCodePointsFast( + ";", + input, + position + ); + } else { + parameterValue = collectASequenceOfCodePointsFast( + ";", + input, + position + ); + parameterValue = removeHTTPWhitespace(parameterValue, false, true); + if (parameterValue.length === 0) { + continue; + } + } + if (parameterName.length !== 0 && HTTP_TOKEN_CODEPOINTS.test(parameterName) && (parameterValue.length === 0 || HTTP_QUOTED_STRING_TOKENS.test(parameterValue)) && !mimeType.parameters.has(parameterName)) { + mimeType.parameters.set(parameterName, parameterValue); + } + } + return mimeType; + } + function forgivingBase64(data) { + data = data.replace(ASCII_WHITESPACE_REPLACE_REGEX, ""); + let dataLength = data.length; + if (dataLength % 4 === 0) { + if (data.charCodeAt(dataLength - 1) === 61) { + --dataLength; + if (data.charCodeAt(dataLength - 1) === 61) { + --dataLength; + } + } + } + if (dataLength % 4 === 1) { + return "failure"; + } + if (/[^+/0-9A-Za-z]/.test(data.length === dataLength ? data : data.substring(0, dataLength))) { + return "failure"; + } + const buffer = Buffer.from(data, "base64"); + return new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength); + } + function collectAnHTTPQuotedString(input, position, extractValue) { + const positionStart = position.position; + let value = ""; + assert(input[position.position] === '"'); + position.position++; + while (true) { + value += collectASequenceOfCodePoints( + (char) => char !== '"' && char !== "\\", + input, + position + ); + if (position.position >= input.length) { + break; + } + const quoteOrBackslash = input[position.position]; + position.position++; + if (quoteOrBackslash === "\\") { + if (position.position >= input.length) { + value += "\\"; + break; + } + value += input[position.position]; + position.position++; + } else { + assert(quoteOrBackslash === '"'); + break; + } + } + if (extractValue) { + return value; + } + return input.slice(positionStart, position.position); + } + function serializeAMimeType(mimeType) { + assert(mimeType !== "failure"); + const { parameters, essence } = mimeType; + let serialization = essence; + for (let [name, value] of parameters.entries()) { + serialization += ";"; + serialization += name; + serialization += "="; + if (!HTTP_TOKEN_CODEPOINTS.test(value)) { + value = value.replace(/(\\|")/g, "\\$1"); + value = '"' + value; + value += '"'; + } + serialization += value; + } + return serialization; + } + function isHTTPWhiteSpace(char) { + return char === 13 || char === 10 || char === 9 || char === 32; + } + function removeHTTPWhitespace(str, leading = true, trailing = true) { + return removeChars(str, leading, trailing, isHTTPWhiteSpace); + } + function isASCIIWhitespace(char) { + return char === 13 || char === 10 || char === 9 || char === 12 || char === 32; + } + function removeASCIIWhitespace(str, leading = true, trailing = true) { + return removeChars(str, leading, trailing, isASCIIWhitespace); + } + function removeChars(str, leading, trailing, predicate) { + let lead = 0; + let trail = str.length - 1; + if (leading) { + while (lead < str.length && predicate(str.charCodeAt(lead))) lead++; + } + if (trailing) { + while (trail > 0 && predicate(str.charCodeAt(trail))) trail--; + } + return lead === 0 && trail === str.length - 1 ? str : str.slice(lead, trail + 1); + } + function isomorphicDecode(input) { + const length = input.length; + if ((2 << 15) - 1 > length) { + return String.fromCharCode.apply(null, input); + } + let result = ""; + let i = 0; + let addition = (2 << 15) - 1; + while (i < length) { + if (i + addition > length) { + addition = length - i; + } + result += String.fromCharCode.apply(null, input.subarray(i, i += addition)); + } + return result; + } + function minimizeSupportedMimeType(mimeType) { + switch (mimeType.essence) { + case "application/ecmascript": + case "application/javascript": + case "application/x-ecmascript": + case "application/x-javascript": + case "text/ecmascript": + case "text/javascript": + case "text/javascript1.0": + case "text/javascript1.1": + case "text/javascript1.2": + case "text/javascript1.3": + case "text/javascript1.4": + case "text/javascript1.5": + case "text/jscript": + case "text/livescript": + case "text/x-ecmascript": + case "text/x-javascript": + return "text/javascript"; + case "application/json": + case "text/json": + return "application/json"; + case "image/svg+xml": + return "image/svg+xml"; + case "text/xml": + case "application/xml": + return "application/xml"; + } + if (mimeType.subtype.endsWith("+json")) { + return "application/json"; + } + if (mimeType.subtype.endsWith("+xml")) { + return "application/xml"; + } + return ""; + } + module.exports = { + dataURLProcessor, + URLSerializer, + collectASequenceOfCodePoints, + collectASequenceOfCodePointsFast, + stringPercentDecode, + parseMIMEType, + collectAnHTTPQuotedString, + serializeAMimeType, + removeChars, + removeHTTPWhitespace, + minimizeSupportedMimeType, + HTTP_TOKEN_CODEPOINTS, + isomorphicDecode + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/webidl.js +var require_webidl = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/webidl.js"(exports, module) { + "use strict"; + var { types, inspect } = __require("node:util"); + var { markAsUncloneable } = __require("node:worker_threads"); + var { toUSVString } = require_util(); + var webidl = {}; + webidl.converters = {}; + webidl.util = {}; + webidl.errors = {}; + webidl.errors.exception = function(message) { + return new TypeError(`${message.header}: ${message.message}`); + }; + webidl.errors.conversionFailed = function(context) { + const plural = context.types.length === 1 ? "" : " one of"; + const message = `${context.argument} could not be converted to${plural}: ${context.types.join(", ")}.`; + return webidl.errors.exception({ + header: context.prefix, + message + }); + }; + webidl.errors.invalidArgument = function(context) { + return webidl.errors.exception({ + header: context.prefix, + message: `"${context.value}" is an invalid ${context.type}.` + }); + }; + webidl.brandCheck = function(V, I, opts) { + if (opts?.strict !== false) { + if (!(V instanceof I)) { + const err = new TypeError("Illegal invocation"); + err.code = "ERR_INVALID_THIS"; + throw err; + } + } else { + if (V?.[Symbol.toStringTag] !== I.prototype[Symbol.toStringTag]) { + const err = new TypeError("Illegal invocation"); + err.code = "ERR_INVALID_THIS"; + throw err; + } + } + }; + webidl.argumentLengthCheck = function({ length }, min, ctx) { + if (length < min) { + throw webidl.errors.exception({ + message: `${min} argument${min !== 1 ? "s" : ""} required, but${length ? " only" : ""} ${length} found.`, + header: ctx + }); + } + }; + webidl.illegalConstructor = function() { + throw webidl.errors.exception({ + header: "TypeError", + message: "Illegal constructor" + }); + }; + webidl.util.Type = function(V) { + switch (typeof V) { + case "undefined": + return "Undefined"; + case "boolean": + return "Boolean"; + case "string": + return "String"; + case "symbol": + return "Symbol"; + case "number": + return "Number"; + case "bigint": + return "BigInt"; + case "function": + case "object": { + if (V === null) { + return "Null"; + } + return "Object"; + } + } + }; + webidl.util.markAsUncloneable = markAsUncloneable || (() => { + }); + webidl.util.ConvertToInt = function(V, bitLength, signedness, opts) { + let upperBound; + let lowerBound; + if (bitLength === 64) { + upperBound = Math.pow(2, 53) - 1; + if (signedness === "unsigned") { + lowerBound = 0; + } else { + lowerBound = Math.pow(-2, 53) + 1; + } + } else if (signedness === "unsigned") { + lowerBound = 0; + upperBound = Math.pow(2, bitLength) - 1; + } else { + lowerBound = Math.pow(-2, bitLength) - 1; + upperBound = Math.pow(2, bitLength - 1) - 1; + } + let x = Number(V); + if (x === 0) { + x = 0; + } + if (opts?.enforceRange === true) { + if (Number.isNaN(x) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY) { + throw webidl.errors.exception({ + header: "Integer conversion", + message: `Could not convert ${webidl.util.Stringify(V)} to an integer.` + }); + } + x = webidl.util.IntegerPart(x); + if (x < lowerBound || x > upperBound) { + throw webidl.errors.exception({ + header: "Integer conversion", + message: `Value must be between ${lowerBound}-${upperBound}, got ${x}.` + }); + } + return x; + } + if (!Number.isNaN(x) && opts?.clamp === true) { + x = Math.min(Math.max(x, lowerBound), upperBound); + if (Math.floor(x) % 2 === 0) { + x = Math.floor(x); + } else { + x = Math.ceil(x); + } + return x; + } + if (Number.isNaN(x) || x === 0 && Object.is(0, x) || x === Number.POSITIVE_INFINITY || x === Number.NEGATIVE_INFINITY) { + return 0; + } + x = webidl.util.IntegerPart(x); + x = x % Math.pow(2, bitLength); + if (signedness === "signed" && x >= Math.pow(2, bitLength) - 1) { + return x - Math.pow(2, bitLength); + } + return x; + }; + webidl.util.IntegerPart = function(n) { + const r = Math.floor(Math.abs(n)); + if (n < 0) { + return -1 * r; + } + return r; + }; + webidl.util.Stringify = function(V) { + const type = webidl.util.Type(V); + switch (type) { + case "Symbol": + return `Symbol(${V.description})`; + case "Object": + return inspect(V); + case "String": + return `"${V}"`; + default: + return `${V}`; + } + }; + webidl.sequenceConverter = function(converter) { + return (V, prefix, argument, Iterable) => { + if (webidl.util.Type(V) !== "Object") { + throw webidl.errors.exception({ + header: prefix, + message: `${argument} (${webidl.util.Stringify(V)}) is not iterable.` + }); + } + const method = typeof Iterable === "function" ? Iterable() : V?.[Symbol.iterator]?.(); + const seq = []; + let index = 0; + if (method === void 0 || typeof method.next !== "function") { + throw webidl.errors.exception({ + header: prefix, + message: `${argument} is not iterable.` + }); + } + while (true) { + const { done, value } = method.next(); + if (done) { + break; + } + seq.push(converter(value, prefix, `${argument}[${index++}]`)); + } + return seq; + }; + }; + webidl.recordConverter = function(keyConverter, valueConverter) { + return (O, prefix, argument) => { + if (webidl.util.Type(O) !== "Object") { + throw webidl.errors.exception({ + header: prefix, + message: `${argument} ("${webidl.util.Type(O)}") is not an Object.` + }); + } + const result = {}; + if (!types.isProxy(O)) { + const keys2 = [...Object.getOwnPropertyNames(O), ...Object.getOwnPropertySymbols(O)]; + for (const key of keys2) { + const typedKey = keyConverter(key, prefix, argument); + const typedValue = valueConverter(O[key], prefix, argument); + result[typedKey] = typedValue; + } + return result; + } + const keys = Reflect.ownKeys(O); + for (const key of keys) { + const desc = Reflect.getOwnPropertyDescriptor(O, key); + if (desc?.enumerable) { + const typedKey = keyConverter(key, prefix, argument); + const typedValue = valueConverter(O[key], prefix, argument); + result[typedKey] = typedValue; + } + } + return result; + }; + }; + webidl.interfaceConverter = function(i) { + return (V, prefix, argument, opts) => { + if (opts?.strict !== false && !(V instanceof i)) { + throw webidl.errors.exception({ + header: prefix, + message: `Expected ${argument} ("${webidl.util.Stringify(V)}") to be an instance of ${i.name}.` + }); + } + return V; + }; + }; + webidl.dictionaryConverter = function(converters) { + return (dictionary, prefix, argument) => { + const type = webidl.util.Type(dictionary); + const dict = {}; + if (type === "Null" || type === "Undefined") { + return dict; + } else if (type !== "Object") { + throw webidl.errors.exception({ + header: prefix, + message: `Expected ${dictionary} to be one of: Null, Undefined, Object.` + }); + } + for (const options of converters) { + const { key, defaultValue, required, converter } = options; + if (required === true) { + if (!Object.hasOwn(dictionary, key)) { + throw webidl.errors.exception({ + header: prefix, + message: `Missing required key "${key}".` + }); + } + } + let value = dictionary[key]; + const hasDefault = Object.hasOwn(options, "defaultValue"); + if (hasDefault && value !== null) { + value ??= defaultValue(); + } + if (required || hasDefault || value !== void 0) { + value = converter(value, prefix, `${argument}.${key}`); + if (options.allowedValues && !options.allowedValues.includes(value)) { + throw webidl.errors.exception({ + header: prefix, + message: `${value} is not an accepted type. Expected one of ${options.allowedValues.join(", ")}.` + }); + } + dict[key] = value; + } + } + return dict; + }; + }; + webidl.nullableConverter = function(converter) { + return (V, prefix, argument) => { + if (V === null) { + return V; + } + return converter(V, prefix, argument); + }; + }; + webidl.converters.DOMString = function(V, prefix, argument, opts) { + if (V === null && opts?.legacyNullToEmptyString) { + return ""; + } + if (typeof V === "symbol") { + throw webidl.errors.exception({ + header: prefix, + message: `${argument} is a symbol, which cannot be converted to a DOMString.` + }); + } + return String(V); + }; + webidl.converters.ByteString = function(V, prefix, argument) { + const x = webidl.converters.DOMString(V, prefix, argument); + for (let index = 0; index < x.length; index++) { + if (x.charCodeAt(index) > 255) { + throw new TypeError( + `Cannot convert argument to a ByteString because the character at index ${index} has a value of ${x.charCodeAt(index)} which is greater than 255.` + ); + } + } + return x; + }; + webidl.converters.USVString = toUSVString; + webidl.converters.boolean = function(V) { + const x = Boolean(V); + return x; + }; + webidl.converters.any = function(V) { + return V; + }; + webidl.converters["long long"] = function(V, prefix, argument) { + const x = webidl.util.ConvertToInt(V, 64, "signed", void 0, prefix, argument); + return x; + }; + webidl.converters["unsigned long long"] = function(V, prefix, argument) { + const x = webidl.util.ConvertToInt(V, 64, "unsigned", void 0, prefix, argument); + return x; + }; + webidl.converters["unsigned long"] = function(V, prefix, argument) { + const x = webidl.util.ConvertToInt(V, 32, "unsigned", void 0, prefix, argument); + return x; + }; + webidl.converters["unsigned short"] = function(V, prefix, argument, opts) { + const x = webidl.util.ConvertToInt(V, 16, "unsigned", opts, prefix, argument); + return x; + }; + webidl.converters.ArrayBuffer = function(V, prefix, argument, opts) { + if (webidl.util.Type(V) !== "Object" || !types.isAnyArrayBuffer(V)) { + throw webidl.errors.conversionFailed({ + prefix, + argument: `${argument} ("${webidl.util.Stringify(V)}")`, + types: ["ArrayBuffer"] + }); + } + if (opts?.allowShared === false && types.isSharedArrayBuffer(V)) { + throw webidl.errors.exception({ + header: "ArrayBuffer", + message: "SharedArrayBuffer is not allowed." + }); + } + if (V.resizable || V.growable) { + throw webidl.errors.exception({ + header: "ArrayBuffer", + message: "Received a resizable ArrayBuffer." + }); + } + return V; + }; + webidl.converters.TypedArray = function(V, T, prefix, name, opts) { + if (webidl.util.Type(V) !== "Object" || !types.isTypedArray(V) || V.constructor.name !== T.name) { + throw webidl.errors.conversionFailed({ + prefix, + argument: `${name} ("${webidl.util.Stringify(V)}")`, + types: [T.name] + }); + } + if (opts?.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { + throw webidl.errors.exception({ + header: "ArrayBuffer", + message: "SharedArrayBuffer is not allowed." + }); + } + if (V.buffer.resizable || V.buffer.growable) { + throw webidl.errors.exception({ + header: "ArrayBuffer", + message: "Received a resizable ArrayBuffer." + }); + } + return V; + }; + webidl.converters.DataView = function(V, prefix, name, opts) { + if (webidl.util.Type(V) !== "Object" || !types.isDataView(V)) { + throw webidl.errors.exception({ + header: prefix, + message: `${name} is not a DataView.` + }); + } + if (opts?.allowShared === false && types.isSharedArrayBuffer(V.buffer)) { + throw webidl.errors.exception({ + header: "ArrayBuffer", + message: "SharedArrayBuffer is not allowed." + }); + } + if (V.buffer.resizable || V.buffer.growable) { + throw webidl.errors.exception({ + header: "ArrayBuffer", + message: "Received a resizable ArrayBuffer." + }); + } + return V; + }; + webidl.converters.BufferSource = function(V, prefix, name, opts) { + if (types.isAnyArrayBuffer(V)) { + return webidl.converters.ArrayBuffer(V, prefix, name, { ...opts, allowShared: false }); + } + if (types.isTypedArray(V)) { + return webidl.converters.TypedArray(V, V.constructor, prefix, name, { ...opts, allowShared: false }); + } + if (types.isDataView(V)) { + return webidl.converters.DataView(V, prefix, name, { ...opts, allowShared: false }); + } + throw webidl.errors.conversionFailed({ + prefix, + argument: `${name} ("${webidl.util.Stringify(V)}")`, + types: ["BufferSource"] + }); + }; + webidl.converters["sequence"] = webidl.sequenceConverter( + webidl.converters.ByteString + ); + webidl.converters["sequence>"] = webidl.sequenceConverter( + webidl.converters["sequence"] + ); + webidl.converters["record"] = webidl.recordConverter( + webidl.converters.ByteString, + webidl.converters.ByteString + ); + module.exports = { + webidl + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/util.js +var require_util2 = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/util.js"(exports, module) { + "use strict"; + var { Transform } = __require("node:stream"); + var zlib = __require("node:zlib"); + var { redirectStatusSet, referrerPolicySet: referrerPolicyTokens, badPortsSet } = require_constants3(); + var { getGlobalOrigin } = require_global(); + var { collectASequenceOfCodePoints, collectAnHTTPQuotedString, removeChars, parseMIMEType } = require_data_url(); + var { performance: performance2 } = __require("node:perf_hooks"); + var { isBlobLike, ReadableStreamFrom, isValidHTTPToken, normalizedMethodRecordsBase } = require_util(); + var assert = __require("node:assert"); + var { isUint8Array } = __require("node:util/types"); + var { webidl } = require_webidl(); + var supportedHashes = []; + var crypto3; + try { + crypto3 = __require("node:crypto"); + const possibleRelevantHashes = ["sha256", "sha384", "sha512"]; + supportedHashes = crypto3.getHashes().filter((hash) => possibleRelevantHashes.includes(hash)); + } catch { + } + function responseURL(response) { + const urlList = response.urlList; + const length = urlList.length; + return length === 0 ? null : urlList[length - 1].toString(); + } + function responseLocationURL(response, requestFragment) { + if (!redirectStatusSet.has(response.status)) { + return null; + } + let location = response.headersList.get("location", true); + if (location !== null && isValidHeaderValue(location)) { + if (!isValidEncodedURL(location)) { + location = normalizeBinaryStringToUtf8(location); + } + location = new URL(location, responseURL(response)); + } + if (location && !location.hash) { + location.hash = requestFragment; + } + return location; + } + function isValidEncodedURL(url) { + for (let i = 0; i < url.length; ++i) { + const code = url.charCodeAt(i); + if (code > 126 || // Non-US-ASCII + DEL + code < 32) { + return false; + } + } + return true; + } + function normalizeBinaryStringToUtf8(value) { + return Buffer.from(value, "binary").toString("utf8"); + } + function requestCurrentURL(request) { + return request.urlList[request.urlList.length - 1]; + } + function requestBadPort(request) { + const url = requestCurrentURL(request); + if (urlIsHttpHttpsScheme(url) && badPortsSet.has(url.port)) { + return "blocked"; + } + return "allowed"; + } + function isErrorLike(object) { + return object instanceof Error || (object?.constructor?.name === "Error" || object?.constructor?.name === "DOMException"); + } + function isValidReasonPhrase(statusText) { + for (let i = 0; i < statusText.length; ++i) { + const c = statusText.charCodeAt(i); + if (!(c === 9 || // HTAB + c >= 32 && c <= 126 || // SP / VCHAR + c >= 128 && c <= 255)) { + return false; + } + } + return true; + } + var isValidHeaderName = isValidHTTPToken; + function isValidHeaderValue(potentialValue) { + return (potentialValue[0] === " " || potentialValue[0] === " " || potentialValue[potentialValue.length - 1] === " " || potentialValue[potentialValue.length - 1] === " " || potentialValue.includes("\n") || potentialValue.includes("\r") || potentialValue.includes("\0")) === false; + } + function setRequestReferrerPolicyOnRedirect(request, actualResponse) { + const { headersList } = actualResponse; + const policyHeader = (headersList.get("referrer-policy", true) ?? "").split(","); + let policy = ""; + if (policyHeader.length > 0) { + for (let i = policyHeader.length; i !== 0; i--) { + const token = policyHeader[i - 1].trim(); + if (referrerPolicyTokens.has(token)) { + policy = token; + break; + } + } + } + if (policy !== "") { + request.referrerPolicy = policy; + } + } + function crossOriginResourcePolicyCheck() { + return "allowed"; + } + function corsCheck() { + return "success"; + } + function TAOCheck() { + return "success"; + } + function appendFetchMetadata(httpRequest) { + let header = null; + header = httpRequest.mode; + httpRequest.headersList.set("sec-fetch-mode", header, true); + } + function appendRequestOriginHeader(request) { + let serializedOrigin = request.origin; + if (serializedOrigin === "client" || serializedOrigin === void 0) { + return; + } + if (request.responseTainting === "cors" || request.mode === "websocket") { + request.headersList.append("origin", serializedOrigin, true); + } else if (request.method !== "GET" && request.method !== "HEAD") { + switch (request.referrerPolicy) { + case "no-referrer": + serializedOrigin = null; + break; + case "no-referrer-when-downgrade": + case "strict-origin": + case "strict-origin-when-cross-origin": + if (request.origin && urlHasHttpsScheme(request.origin) && !urlHasHttpsScheme(requestCurrentURL(request))) { + serializedOrigin = null; + } + break; + case "same-origin": + if (!sameOrigin(request, requestCurrentURL(request))) { + serializedOrigin = null; + } + break; + default: + } + request.headersList.append("origin", serializedOrigin, true); + } + } + function coarsenTime(timestamp, crossOriginIsolatedCapability) { + return timestamp; + } + function clampAndCoarsenConnectionTimingInfo(connectionTimingInfo, defaultStartTime, crossOriginIsolatedCapability) { + if (!connectionTimingInfo?.startTime || connectionTimingInfo.startTime < defaultStartTime) { + return { + domainLookupStartTime: defaultStartTime, + domainLookupEndTime: defaultStartTime, + connectionStartTime: defaultStartTime, + connectionEndTime: defaultStartTime, + secureConnectionStartTime: defaultStartTime, + ALPNNegotiatedProtocol: connectionTimingInfo?.ALPNNegotiatedProtocol + }; + } + return { + domainLookupStartTime: coarsenTime(connectionTimingInfo.domainLookupStartTime, crossOriginIsolatedCapability), + domainLookupEndTime: coarsenTime(connectionTimingInfo.domainLookupEndTime, crossOriginIsolatedCapability), + connectionStartTime: coarsenTime(connectionTimingInfo.connectionStartTime, crossOriginIsolatedCapability), + connectionEndTime: coarsenTime(connectionTimingInfo.connectionEndTime, crossOriginIsolatedCapability), + secureConnectionStartTime: coarsenTime(connectionTimingInfo.secureConnectionStartTime, crossOriginIsolatedCapability), + ALPNNegotiatedProtocol: connectionTimingInfo.ALPNNegotiatedProtocol + }; + } + function coarsenedSharedCurrentTime(crossOriginIsolatedCapability) { + return coarsenTime(performance2.now(), crossOriginIsolatedCapability); + } + function createOpaqueTimingInfo(timingInfo) { + return { + startTime: timingInfo.startTime ?? 0, + redirectStartTime: 0, + redirectEndTime: 0, + postRedirectStartTime: timingInfo.startTime ?? 0, + finalServiceWorkerStartTime: 0, + finalNetworkResponseStartTime: 0, + finalNetworkRequestStartTime: 0, + endTime: 0, + encodedBodySize: 0, + decodedBodySize: 0, + finalConnectionTimingInfo: null + }; + } + function makePolicyContainer() { + return { + referrerPolicy: "strict-origin-when-cross-origin" + }; + } + function clonePolicyContainer(policyContainer) { + return { + referrerPolicy: policyContainer.referrerPolicy + }; + } + function determineRequestsReferrer(request) { + const policy = request.referrerPolicy; + assert(policy); + let referrerSource = null; + if (request.referrer === "client") { + const globalOrigin = getGlobalOrigin(); + if (!globalOrigin || globalOrigin.origin === "null") { + return "no-referrer"; + } + referrerSource = new URL(globalOrigin); + } else if (request.referrer instanceof URL) { + referrerSource = request.referrer; + } + let referrerURL = stripURLForReferrer(referrerSource); + const referrerOrigin = stripURLForReferrer(referrerSource, true); + if (referrerURL.toString().length > 4096) { + referrerURL = referrerOrigin; + } + const areSameOrigin = sameOrigin(request, referrerURL); + const isNonPotentiallyTrustWorthy = isURLPotentiallyTrustworthy(referrerURL) && !isURLPotentiallyTrustworthy(request.url); + switch (policy) { + case "origin": + return referrerOrigin != null ? referrerOrigin : stripURLForReferrer(referrerSource, true); + case "unsafe-url": + return referrerURL; + case "same-origin": + return areSameOrigin ? referrerOrigin : "no-referrer"; + case "origin-when-cross-origin": + return areSameOrigin ? referrerURL : referrerOrigin; + case "strict-origin-when-cross-origin": { + const currentURL = requestCurrentURL(request); + if (sameOrigin(referrerURL, currentURL)) { + return referrerURL; + } + if (isURLPotentiallyTrustworthy(referrerURL) && !isURLPotentiallyTrustworthy(currentURL)) { + return "no-referrer"; + } + return referrerOrigin; + } + case "strict-origin": + // eslint-disable-line + /** + * 1. If referrerURL is a potentially trustworthy URL and + * request’s current URL is not a potentially trustworthy URL, + * then return no referrer. + * 2. Return referrerOrigin + */ + case "no-referrer-when-downgrade": + // eslint-disable-line + /** + * 1. If referrerURL is a potentially trustworthy URL and + * request’s current URL is not a potentially trustworthy URL, + * then return no referrer. + * 2. Return referrerOrigin + */ + default: + return isNonPotentiallyTrustWorthy ? "no-referrer" : referrerOrigin; + } + } + function stripURLForReferrer(url, originOnly) { + assert(url instanceof URL); + url = new URL(url); + if (url.protocol === "file:" || url.protocol === "about:" || url.protocol === "blank:") { + return "no-referrer"; + } + url.username = ""; + url.password = ""; + url.hash = ""; + if (originOnly) { + url.pathname = ""; + url.search = ""; + } + return url; + } + function isURLPotentiallyTrustworthy(url) { + if (!(url instanceof URL)) { + return false; + } + if (url.href === "about:blank" || url.href === "about:srcdoc") { + return true; + } + if (url.protocol === "data:") return true; + if (url.protocol === "file:") return true; + return isOriginPotentiallyTrustworthy(url.origin); + function isOriginPotentiallyTrustworthy(origin) { + if (origin == null || origin === "null") return false; + const originAsURL = new URL(origin); + if (originAsURL.protocol === "https:" || originAsURL.protocol === "wss:") { + return true; + } + if (/^127(?:\.[0-9]+){0,2}\.[0-9]+$|^\[(?:0*:)*?:?0*1\]$/.test(originAsURL.hostname) || (originAsURL.hostname === "localhost" || originAsURL.hostname.includes("localhost.")) || originAsURL.hostname.endsWith(".localhost")) { + return true; + } + return false; + } + } + function bytesMatch(bytes2, metadataList) { + if (crypto3 === void 0) { + return true; + } + const parsedMetadata = parseMetadata(metadataList); + if (parsedMetadata === "no metadata") { + return true; + } + if (parsedMetadata.length === 0) { + return true; + } + const strongest = getStrongestMetadata(parsedMetadata); + const metadata = filterMetadataListByAlgorithm(parsedMetadata, strongest); + for (const item of metadata) { + const algorithm = item.algo; + const expectedValue = item.hash; + let actualValue = crypto3.createHash(algorithm).update(bytes2).digest("base64"); + if (actualValue[actualValue.length - 1] === "=") { + if (actualValue[actualValue.length - 2] === "=") { + actualValue = actualValue.slice(0, -2); + } else { + actualValue = actualValue.slice(0, -1); + } + } + if (compareBase64Mixed(actualValue, expectedValue)) { + return true; + } + } + return false; + } + var parseHashWithOptions = /(?sha256|sha384|sha512)-((?[A-Za-z0-9+/]+|[A-Za-z0-9_-]+)={0,2}(?:\s|$)( +[!-~]*)?)?/i; + function parseMetadata(metadata) { + const result = []; + let empty = true; + for (const token of metadata.split(" ")) { + empty = false; + const parsedToken = parseHashWithOptions.exec(token); + if (parsedToken === null || parsedToken.groups === void 0 || parsedToken.groups.algo === void 0) { + continue; + } + const algorithm = parsedToken.groups.algo.toLowerCase(); + if (supportedHashes.includes(algorithm)) { + result.push(parsedToken.groups); + } + } + if (empty === true) { + return "no metadata"; + } + return result; + } + function getStrongestMetadata(metadataList) { + let algorithm = metadataList[0].algo; + if (algorithm[3] === "5") { + return algorithm; + } + for (let i = 1; i < metadataList.length; ++i) { + const metadata = metadataList[i]; + if (metadata.algo[3] === "5") { + algorithm = "sha512"; + break; + } else if (algorithm[3] === "3") { + continue; + } else if (metadata.algo[3] === "3") { + algorithm = "sha384"; + } + } + return algorithm; + } + function filterMetadataListByAlgorithm(metadataList, algorithm) { + if (metadataList.length === 1) { + return metadataList; + } + let pos = 0; + for (let i = 0; i < metadataList.length; ++i) { + if (metadataList[i].algo === algorithm) { + metadataList[pos++] = metadataList[i]; + } + } + metadataList.length = pos; + return metadataList; + } + function compareBase64Mixed(actualValue, expectedValue) { + if (actualValue.length !== expectedValue.length) { + return false; + } + for (let i = 0; i < actualValue.length; ++i) { + if (actualValue[i] !== expectedValue[i]) { + if (actualValue[i] === "+" && expectedValue[i] === "-" || actualValue[i] === "/" && expectedValue[i] === "_") { + continue; + } + return false; + } + } + return true; + } + function tryUpgradeRequestToAPotentiallyTrustworthyURL(request) { + } + function sameOrigin(A, B) { + if (A.origin === B.origin && A.origin === "null") { + return true; + } + if (A.protocol === B.protocol && A.hostname === B.hostname && A.port === B.port) { + return true; + } + return false; + } + function createDeferredPromise() { + let res; + let rej; + const promise = new Promise((resolve, reject) => { + res = resolve; + rej = reject; + }); + return { promise, resolve: res, reject: rej }; + } + function isAborted(fetchParams) { + return fetchParams.controller.state === "aborted"; + } + function isCancelled(fetchParams) { + return fetchParams.controller.state === "aborted" || fetchParams.controller.state === "terminated"; + } + function normalizeMethod(method) { + return normalizedMethodRecordsBase[method.toLowerCase()] ?? method; + } + function serializeJavascriptValueToJSONString(value) { + const result = JSON.stringify(value); + if (result === void 0) { + throw new TypeError("Value is not JSON serializable"); + } + assert(typeof result === "string"); + return result; + } + var esIteratorPrototype = Object.getPrototypeOf(Object.getPrototypeOf([][Symbol.iterator]())); + function createIterator(name, kInternalIterator, keyIndex = 0, valueIndex = 1) { + class FastIterableIterator { + /** @type {any} */ + #target; + /** @type {'key' | 'value' | 'key+value'} */ + #kind; + /** @type {number} */ + #index; + /** + * @see https://webidl.spec.whatwg.org/#dfn-default-iterator-object + * @param {unknown} target + * @param {'key' | 'value' | 'key+value'} kind + */ + constructor(target, kind) { + this.#target = target; + this.#kind = kind; + this.#index = 0; + } + next() { + if (typeof this !== "object" || this === null || !(#target in this)) { + throw new TypeError( + `'next' called on an object that does not implement interface ${name} Iterator.` + ); + } + const index = this.#index; + const values = this.#target[kInternalIterator]; + const len = values.length; + if (index >= len) { + return { + value: void 0, + done: true + }; + } + const { [keyIndex]: key, [valueIndex]: value } = values[index]; + this.#index = index + 1; + let result; + switch (this.#kind) { + case "key": + result = key; + break; + case "value": + result = value; + break; + case "key+value": + result = [key, value]; + break; + } + return { + value: result, + done: false + }; + } + } + delete FastIterableIterator.prototype.constructor; + Object.setPrototypeOf(FastIterableIterator.prototype, esIteratorPrototype); + Object.defineProperties(FastIterableIterator.prototype, { + [Symbol.toStringTag]: { + writable: false, + enumerable: false, + configurable: true, + value: `${name} Iterator` + }, + next: { writable: true, enumerable: true, configurable: true } + }); + return function(target, kind) { + return new FastIterableIterator(target, kind); + }; + } + function iteratorMixin(name, object, kInternalIterator, keyIndex = 0, valueIndex = 1) { + const makeIterator = createIterator(name, kInternalIterator, keyIndex, valueIndex); + const properties = { + keys: { + writable: true, + enumerable: true, + configurable: true, + value: function keys() { + webidl.brandCheck(this, object); + return makeIterator(this, "key"); + } + }, + values: { + writable: true, + enumerable: true, + configurable: true, + value: function values() { + webidl.brandCheck(this, object); + return makeIterator(this, "value"); + } + }, + entries: { + writable: true, + enumerable: true, + configurable: true, + value: function entries() { + webidl.brandCheck(this, object); + return makeIterator(this, "key+value"); + } + }, + forEach: { + writable: true, + enumerable: true, + configurable: true, + value: function forEach(callbackfn, thisArg = globalThis) { + webidl.brandCheck(this, object); + webidl.argumentLengthCheck(arguments, 1, `${name}.forEach`); + if (typeof callbackfn !== "function") { + throw new TypeError( + `Failed to execute 'forEach' on '${name}': parameter 1 is not of type 'Function'.` + ); + } + for (const { 0: key, 1: value } of makeIterator(this, "key+value")) { + callbackfn.call(thisArg, value, key, this); + } + } + } + }; + return Object.defineProperties(object.prototype, { + ...properties, + [Symbol.iterator]: { + writable: true, + enumerable: false, + configurable: true, + value: properties.entries.value + } + }); + } + async function fullyReadBody(body, processBody, processBodyError) { + const successSteps = processBody; + const errorSteps = processBodyError; + let reader; + try { + reader = body.stream.getReader(); + } catch (e) { + errorSteps(e); + return; + } + try { + successSteps(await readAllBytes(reader)); + } catch (e) { + errorSteps(e); + } + } + function isReadableStreamLike(stream) { + return stream instanceof ReadableStream || stream[Symbol.toStringTag] === "ReadableStream" && typeof stream.tee === "function"; + } + function readableStreamClose(controller) { + try { + controller.close(); + controller.byobRequest?.respond(0); + } catch (err) { + if (!err.message.includes("Controller is already closed") && !err.message.includes("ReadableStream is already closed")) { + throw err; + } + } + } + var invalidIsomorphicEncodeValueRegex = /[^\x00-\xFF]/; + function isomorphicEncode(input) { + assert(!invalidIsomorphicEncodeValueRegex.test(input)); + return input; + } + async function readAllBytes(reader) { + const bytes2 = []; + let byteLength = 0; + while (true) { + const { done, value: chunk } = await reader.read(); + if (done) { + return Buffer.concat(bytes2, byteLength); + } + if (!isUint8Array(chunk)) { + throw new TypeError("Received non-Uint8Array chunk"); + } + bytes2.push(chunk); + byteLength += chunk.length; + } + } + function urlIsLocal(url) { + assert("protocol" in url); + const protocol = url.protocol; + return protocol === "about:" || protocol === "blob:" || protocol === "data:"; + } + function urlHasHttpsScheme(url) { + return typeof url === "string" && url[5] === ":" && url[0] === "h" && url[1] === "t" && url[2] === "t" && url[3] === "p" && url[4] === "s" || url.protocol === "https:"; + } + function urlIsHttpHttpsScheme(url) { + assert("protocol" in url); + const protocol = url.protocol; + return protocol === "http:" || protocol === "https:"; + } + function simpleRangeHeaderValue(value, allowWhitespace) { + const data = value; + if (!data.startsWith("bytes")) { + return "failure"; + } + const position = { position: 5 }; + if (allowWhitespace) { + collectASequenceOfCodePoints( + (char) => char === " " || char === " ", + data, + position + ); + } + if (data.charCodeAt(position.position) !== 61) { + return "failure"; + } + position.position++; + if (allowWhitespace) { + collectASequenceOfCodePoints( + (char) => char === " " || char === " ", + data, + position + ); + } + const rangeStart = collectASequenceOfCodePoints( + (char) => { + const code = char.charCodeAt(0); + return code >= 48 && code <= 57; + }, + data, + position + ); + const rangeStartValue = rangeStart.length ? Number(rangeStart) : null; + if (allowWhitespace) { + collectASequenceOfCodePoints( + (char) => char === " " || char === " ", + data, + position + ); + } + if (data.charCodeAt(position.position) !== 45) { + return "failure"; + } + position.position++; + if (allowWhitespace) { + collectASequenceOfCodePoints( + (char) => char === " " || char === " ", + data, + position + ); + } + const rangeEnd = collectASequenceOfCodePoints( + (char) => { + const code = char.charCodeAt(0); + return code >= 48 && code <= 57; + }, + data, + position + ); + const rangeEndValue = rangeEnd.length ? Number(rangeEnd) : null; + if (position.position < data.length) { + return "failure"; + } + if (rangeEndValue === null && rangeStartValue === null) { + return "failure"; + } + if (rangeStartValue > rangeEndValue) { + return "failure"; + } + return { rangeStartValue, rangeEndValue }; + } + function buildContentRange(rangeStart, rangeEnd, fullLength) { + let contentRange = "bytes "; + contentRange += isomorphicEncode(`${rangeStart}`); + contentRange += "-"; + contentRange += isomorphicEncode(`${rangeEnd}`); + contentRange += "/"; + contentRange += isomorphicEncode(`${fullLength}`); + return contentRange; + } + var InflateStream = class extends Transform { + #zlibOptions; + /** @param {zlib.ZlibOptions} [zlibOptions] */ + constructor(zlibOptions) { + super(); + this.#zlibOptions = zlibOptions; + } + _transform(chunk, encoding, callback) { + if (!this._inflateStream) { + if (chunk.length === 0) { + callback(); + return; + } + this._inflateStream = (chunk[0] & 15) === 8 ? zlib.createInflate(this.#zlibOptions) : zlib.createInflateRaw(this.#zlibOptions); + this._inflateStream.on("data", this.push.bind(this)); + this._inflateStream.on("end", () => this.push(null)); + this._inflateStream.on("error", (err) => this.destroy(err)); + } + this._inflateStream.write(chunk, encoding, callback); + } + _final(callback) { + if (this._inflateStream) { + this._inflateStream.end(); + this._inflateStream = null; + } + callback(); + } + }; + function createInflate(zlibOptions) { + return new InflateStream(zlibOptions); + } + function extractMimeType(headers) { + let charset = null; + let essence = null; + let mimeType = null; + const values = getDecodeSplit("content-type", headers); + if (values === null) { + return "failure"; + } + for (const value of values) { + const temporaryMimeType = parseMIMEType(value); + if (temporaryMimeType === "failure" || temporaryMimeType.essence === "*/*") { + continue; + } + mimeType = temporaryMimeType; + if (mimeType.essence !== essence) { + charset = null; + if (mimeType.parameters.has("charset")) { + charset = mimeType.parameters.get("charset"); + } + essence = mimeType.essence; + } else if (!mimeType.parameters.has("charset") && charset !== null) { + mimeType.parameters.set("charset", charset); + } + } + if (mimeType == null) { + return "failure"; + } + return mimeType; + } + function gettingDecodingSplitting(value) { + const input = value; + const position = { position: 0 }; + const values = []; + let temporaryValue = ""; + while (position.position < input.length) { + temporaryValue += collectASequenceOfCodePoints( + (char) => char !== '"' && char !== ",", + input, + position + ); + if (position.position < input.length) { + if (input.charCodeAt(position.position) === 34) { + temporaryValue += collectAnHTTPQuotedString( + input, + position + ); + if (position.position < input.length) { + continue; + } + } else { + assert(input.charCodeAt(position.position) === 44); + position.position++; + } + } + temporaryValue = removeChars(temporaryValue, true, true, (char) => char === 9 || char === 32); + values.push(temporaryValue); + temporaryValue = ""; + } + return values; + } + function getDecodeSplit(name, list2) { + const value = list2.get(name, true); + if (value === null) { + return null; + } + return gettingDecodingSplitting(value); + } + var textDecoder = new TextDecoder(); + function utf8DecodeBytes(buffer) { + if (buffer.length === 0) { + return ""; + } + if (buffer[0] === 239 && buffer[1] === 187 && buffer[2] === 191) { + buffer = buffer.subarray(3); + } + const output = textDecoder.decode(buffer); + return output; + } + var EnvironmentSettingsObjectBase = class { + get baseUrl() { + return getGlobalOrigin(); + } + get origin() { + return this.baseUrl?.origin; + } + policyContainer = makePolicyContainer(); + }; + var EnvironmentSettingsObject = class { + settingsObject = new EnvironmentSettingsObjectBase(); + }; + var environmentSettingsObject = new EnvironmentSettingsObject(); + module.exports = { + isAborted, + isCancelled, + isValidEncodedURL, + createDeferredPromise, + ReadableStreamFrom, + tryUpgradeRequestToAPotentiallyTrustworthyURL, + clampAndCoarsenConnectionTimingInfo, + coarsenedSharedCurrentTime, + determineRequestsReferrer, + makePolicyContainer, + clonePolicyContainer, + appendFetchMetadata, + appendRequestOriginHeader, + TAOCheck, + corsCheck, + crossOriginResourcePolicyCheck, + createOpaqueTimingInfo, + setRequestReferrerPolicyOnRedirect, + isValidHTTPToken, + requestBadPort, + requestCurrentURL, + responseURL, + responseLocationURL, + isBlobLike, + isURLPotentiallyTrustworthy, + isValidReasonPhrase, + sameOrigin, + normalizeMethod, + serializeJavascriptValueToJSONString, + iteratorMixin, + createIterator, + isValidHeaderName, + isValidHeaderValue, + isErrorLike, + fullyReadBody, + bytesMatch, + isReadableStreamLike, + readableStreamClose, + isomorphicEncode, + urlIsLocal, + urlHasHttpsScheme, + urlIsHttpHttpsScheme, + readAllBytes, + simpleRangeHeaderValue, + buildContentRange, + parseMetadata, + createInflate, + extractMimeType, + getDecodeSplit, + utf8DecodeBytes, + environmentSettingsObject + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/symbols.js +var require_symbols2 = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/symbols.js"(exports, module) { + "use strict"; + module.exports = { + kUrl: /* @__PURE__ */ Symbol("url"), + kHeaders: /* @__PURE__ */ Symbol("headers"), + kSignal: /* @__PURE__ */ Symbol("signal"), + kState: /* @__PURE__ */ Symbol("state"), + kDispatcher: /* @__PURE__ */ Symbol("dispatcher") + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/file.js +var require_file = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/file.js"(exports, module) { + "use strict"; + var { Blob: Blob2, File } = __require("node:buffer"); + var { kState } = require_symbols2(); + var { webidl } = require_webidl(); + var FileLike = class _FileLike { + constructor(blobLike, fileName, options = {}) { + const n = fileName; + const t = options.type; + const d = options.lastModified ?? Date.now(); + this[kState] = { + blobLike, + name: n, + type: t, + lastModified: d + }; + } + stream(...args) { + webidl.brandCheck(this, _FileLike); + return this[kState].blobLike.stream(...args); + } + arrayBuffer(...args) { + webidl.brandCheck(this, _FileLike); + return this[kState].blobLike.arrayBuffer(...args); + } + slice(...args) { + webidl.brandCheck(this, _FileLike); + return this[kState].blobLike.slice(...args); + } + text(...args) { + webidl.brandCheck(this, _FileLike); + return this[kState].blobLike.text(...args); + } + get size() { + webidl.brandCheck(this, _FileLike); + return this[kState].blobLike.size; + } + get type() { + webidl.brandCheck(this, _FileLike); + return this[kState].blobLike.type; + } + get name() { + webidl.brandCheck(this, _FileLike); + return this[kState].name; + } + get lastModified() { + webidl.brandCheck(this, _FileLike); + return this[kState].lastModified; + } + get [Symbol.toStringTag]() { + return "File"; + } + }; + webidl.converters.Blob = webidl.interfaceConverter(Blob2); + function isFileLike(object) { + return object instanceof File || object && (typeof object.stream === "function" || typeof object.arrayBuffer === "function") && object[Symbol.toStringTag] === "File"; + } + module.exports = { FileLike, isFileLike }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/formdata.js +var require_formdata = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/formdata.js"(exports, module) { + "use strict"; + var { isBlobLike, iteratorMixin } = require_util2(); + var { kState } = require_symbols2(); + var { kEnumerableProperty } = require_util(); + var { FileLike, isFileLike } = require_file(); + var { webidl } = require_webidl(); + var { File: NativeFile } = __require("node:buffer"); + var nodeUtil = __require("node:util"); + var File = globalThis.File ?? NativeFile; + var FormData = class _FormData { + constructor(form) { + webidl.util.markAsUncloneable(this); + if (form !== void 0) { + throw webidl.errors.conversionFailed({ + prefix: "FormData constructor", + argument: "Argument 1", + types: ["undefined"] + }); + } + this[kState] = []; + } + append(name, value, filename = void 0) { + webidl.brandCheck(this, _FormData); + const prefix = "FormData.append"; + webidl.argumentLengthCheck(arguments, 2, prefix); + if (arguments.length === 3 && !isBlobLike(value)) { + throw new TypeError( + "Failed to execute 'append' on 'FormData': parameter 2 is not of type 'Blob'" + ); + } + name = webidl.converters.USVString(name, prefix, "name"); + value = isBlobLike(value) ? webidl.converters.Blob(value, prefix, "value", { strict: false }) : webidl.converters.USVString(value, prefix, "value"); + filename = arguments.length === 3 ? webidl.converters.USVString(filename, prefix, "filename") : void 0; + const entry = makeEntry(name, value, filename); + this[kState].push(entry); + } + delete(name) { + webidl.brandCheck(this, _FormData); + const prefix = "FormData.delete"; + webidl.argumentLengthCheck(arguments, 1, prefix); + name = webidl.converters.USVString(name, prefix, "name"); + this[kState] = this[kState].filter((entry) => entry.name !== name); + } + get(name) { + webidl.brandCheck(this, _FormData); + const prefix = "FormData.get"; + webidl.argumentLengthCheck(arguments, 1, prefix); + name = webidl.converters.USVString(name, prefix, "name"); + const idx = this[kState].findIndex((entry) => entry.name === name); + if (idx === -1) { + return null; + } + return this[kState][idx].value; + } + getAll(name) { + webidl.brandCheck(this, _FormData); + const prefix = "FormData.getAll"; + webidl.argumentLengthCheck(arguments, 1, prefix); + name = webidl.converters.USVString(name, prefix, "name"); + return this[kState].filter((entry) => entry.name === name).map((entry) => entry.value); + } + has(name) { + webidl.brandCheck(this, _FormData); + const prefix = "FormData.has"; + webidl.argumentLengthCheck(arguments, 1, prefix); + name = webidl.converters.USVString(name, prefix, "name"); + return this[kState].findIndex((entry) => entry.name === name) !== -1; + } + set(name, value, filename = void 0) { + webidl.brandCheck(this, _FormData); + const prefix = "FormData.set"; + webidl.argumentLengthCheck(arguments, 2, prefix); + if (arguments.length === 3 && !isBlobLike(value)) { + throw new TypeError( + "Failed to execute 'set' on 'FormData': parameter 2 is not of type 'Blob'" + ); + } + name = webidl.converters.USVString(name, prefix, "name"); + value = isBlobLike(value) ? webidl.converters.Blob(value, prefix, "name", { strict: false }) : webidl.converters.USVString(value, prefix, "name"); + filename = arguments.length === 3 ? webidl.converters.USVString(filename, prefix, "name") : void 0; + const entry = makeEntry(name, value, filename); + const idx = this[kState].findIndex((entry2) => entry2.name === name); + if (idx !== -1) { + this[kState] = [ + ...this[kState].slice(0, idx), + entry, + ...this[kState].slice(idx + 1).filter((entry2) => entry2.name !== name) + ]; + } else { + this[kState].push(entry); + } + } + [nodeUtil.inspect.custom](depth, options) { + const state = this[kState].reduce((a, b) => { + if (a[b.name]) { + if (Array.isArray(a[b.name])) { + a[b.name].push(b.value); + } else { + a[b.name] = [a[b.name], b.value]; + } + } else { + a[b.name] = b.value; + } + return a; + }, { __proto__: null }); + options.depth ??= depth; + options.colors ??= true; + const output = nodeUtil.formatWithOptions(options, state); + return `FormData ${output.slice(output.indexOf("]") + 2)}`; + } + }; + iteratorMixin("FormData", FormData, kState, "name", "value"); + Object.defineProperties(FormData.prototype, { + append: kEnumerableProperty, + delete: kEnumerableProperty, + get: kEnumerableProperty, + getAll: kEnumerableProperty, + has: kEnumerableProperty, + set: kEnumerableProperty, + [Symbol.toStringTag]: { + value: "FormData", + configurable: true + } + }); + function makeEntry(name, value, filename) { + if (typeof value === "string") { + } else { + if (!isFileLike(value)) { + value = value instanceof Blob ? new File([value], "blob", { type: value.type }) : new FileLike(value, "blob", { type: value.type }); + } + if (filename !== void 0) { + const options = { + type: value.type, + lastModified: value.lastModified + }; + value = value instanceof NativeFile ? new File([value], filename, options) : new FileLike(value, filename, options); + } + } + return { name, value }; + } + module.exports = { FormData, makeEntry }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/formdata-parser.js +var require_formdata_parser = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/formdata-parser.js"(exports, module) { + "use strict"; + var { isUSVString, bufferToLowerCasedHeaderName } = require_util(); + var { utf8DecodeBytes } = require_util2(); + var { HTTP_TOKEN_CODEPOINTS, isomorphicDecode } = require_data_url(); + var { isFileLike } = require_file(); + var { makeEntry } = require_formdata(); + var assert = __require("node:assert"); + var { File: NodeFile } = __require("node:buffer"); + var File = globalThis.File ?? NodeFile; + var formDataNameBuffer = Buffer.from('form-data; name="'); + var filenameBuffer = Buffer.from("; filename"); + var dd = Buffer.from("--"); + var ddcrlf = Buffer.from("--\r\n"); + function isAsciiString(chars) { + for (let i = 0; i < chars.length; ++i) { + if ((chars.charCodeAt(i) & ~127) !== 0) { + return false; + } + } + return true; + } + function validateBoundary(boundary) { + const length = boundary.length; + if (length < 27 || length > 70) { + return false; + } + for (let i = 0; i < length; ++i) { + const cp = boundary.charCodeAt(i); + if (!(cp >= 48 && cp <= 57 || cp >= 65 && cp <= 90 || cp >= 97 && cp <= 122 || cp === 39 || cp === 45 || cp === 95)) { + return false; + } + } + return true; + } + function multipartFormDataParser(input, mimeType) { + assert(mimeType !== "failure" && mimeType.essence === "multipart/form-data"); + const boundaryString = mimeType.parameters.get("boundary"); + if (boundaryString === void 0) { + return "failure"; + } + const boundary = Buffer.from(`--${boundaryString}`, "utf8"); + const entryList = []; + const position = { position: 0 }; + while (input[position.position] === 13 && input[position.position + 1] === 10) { + position.position += 2; + } + let trailing = input.length; + while (input[trailing - 1] === 10 && input[trailing - 2] === 13) { + trailing -= 2; + } + if (trailing !== input.length) { + input = input.subarray(0, trailing); + } + while (true) { + if (input.subarray(position.position, position.position + boundary.length).equals(boundary)) { + position.position += boundary.length; + } else { + return "failure"; + } + if (position.position === input.length - 2 && bufferStartsWith(input, dd, position) || position.position === input.length - 4 && bufferStartsWith(input, ddcrlf, position)) { + return entryList; + } + if (input[position.position] !== 13 || input[position.position + 1] !== 10) { + return "failure"; + } + position.position += 2; + const result = parseMultipartFormDataHeaders(input, position); + if (result === "failure") { + return "failure"; + } + let { name, filename, contentType, encoding } = result; + position.position += 2; + let body; + { + const boundaryIndex = input.indexOf(boundary.subarray(2), position.position); + if (boundaryIndex === -1) { + return "failure"; + } + body = input.subarray(position.position, boundaryIndex - 4); + position.position += body.length; + if (encoding === "base64") { + body = Buffer.from(body.toString(), "base64"); + } + } + if (input[position.position] !== 13 || input[position.position + 1] !== 10) { + return "failure"; + } else { + position.position += 2; + } + let value; + if (filename !== null) { + contentType ??= "text/plain"; + if (!isAsciiString(contentType)) { + contentType = ""; + } + value = new File([body], filename, { type: contentType }); + } else { + value = utf8DecodeBytes(Buffer.from(body)); + } + assert(isUSVString(name)); + assert(typeof value === "string" && isUSVString(value) || isFileLike(value)); + entryList.push(makeEntry(name, value, filename)); + } + } + function parseMultipartFormDataHeaders(input, position) { + let name = null; + let filename = null; + let contentType = null; + let encoding = null; + while (true) { + if (input[position.position] === 13 && input[position.position + 1] === 10) { + if (name === null) { + return "failure"; + } + return { name, filename, contentType, encoding }; + } + let headerName = collectASequenceOfBytes( + (char) => char !== 10 && char !== 13 && char !== 58, + input, + position + ); + headerName = removeChars(headerName, true, true, (char) => char === 9 || char === 32); + if (!HTTP_TOKEN_CODEPOINTS.test(headerName.toString())) { + return "failure"; + } + if (input[position.position] !== 58) { + return "failure"; + } + position.position++; + collectASequenceOfBytes( + (char) => char === 32 || char === 9, + input, + position + ); + switch (bufferToLowerCasedHeaderName(headerName)) { + case "content-disposition": { + name = filename = null; + if (!bufferStartsWith(input, formDataNameBuffer, position)) { + return "failure"; + } + position.position += 17; + name = parseMultipartFormDataName(input, position); + if (name === null) { + return "failure"; + } + if (bufferStartsWith(input, filenameBuffer, position)) { + let check = position.position + filenameBuffer.length; + if (input[check] === 42) { + position.position += 1; + check += 1; + } + if (input[check] !== 61 || input[check + 1] !== 34) { + return "failure"; + } + position.position += 12; + filename = parseMultipartFormDataName(input, position); + if (filename === null) { + return "failure"; + } + } + break; + } + case "content-type": { + let headerValue = collectASequenceOfBytes( + (char) => char !== 10 && char !== 13, + input, + position + ); + headerValue = removeChars(headerValue, false, true, (char) => char === 9 || char === 32); + contentType = isomorphicDecode(headerValue); + break; + } + case "content-transfer-encoding": { + let headerValue = collectASequenceOfBytes( + (char) => char !== 10 && char !== 13, + input, + position + ); + headerValue = removeChars(headerValue, false, true, (char) => char === 9 || char === 32); + encoding = isomorphicDecode(headerValue); + break; + } + default: { + collectASequenceOfBytes( + (char) => char !== 10 && char !== 13, + input, + position + ); + } + } + if (input[position.position] !== 13 && input[position.position + 1] !== 10) { + return "failure"; + } else { + position.position += 2; + } + } + } + function parseMultipartFormDataName(input, position) { + assert(input[position.position - 1] === 34); + let name = collectASequenceOfBytes( + (char) => char !== 10 && char !== 13 && char !== 34, + input, + position + ); + if (input[position.position] !== 34) { + return null; + } else { + position.position++; + } + name = new TextDecoder().decode(name).replace(/%0A/ig, "\n").replace(/%0D/ig, "\r").replace(/%22/g, '"'); + return name; + } + function collectASequenceOfBytes(condition, input, position) { + let start = position.position; + while (start < input.length && condition(input[start])) { + ++start; + } + return input.subarray(position.position, position.position = start); + } + function removeChars(buf, leading, trailing, predicate) { + let lead = 0; + let trail = buf.length - 1; + if (leading) { + while (lead < buf.length && predicate(buf[lead])) lead++; + } + if (trailing) { + while (trail > 0 && predicate(buf[trail])) trail--; + } + return lead === 0 && trail === buf.length - 1 ? buf : buf.subarray(lead, trail + 1); + } + function bufferStartsWith(buffer, start, position) { + if (buffer.length < start.length) { + return false; + } + for (let i = 0; i < start.length; i++) { + if (start[i] !== buffer[position.position + i]) { + return false; + } + } + return true; + } + module.exports = { + multipartFormDataParser, + validateBoundary + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/body.js +var require_body = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/body.js"(exports, module) { + "use strict"; + var util = require_util(); + var { + ReadableStreamFrom, + isBlobLike, + isReadableStreamLike, + readableStreamClose, + createDeferredPromise, + fullyReadBody, + extractMimeType, + utf8DecodeBytes + } = require_util2(); + var { FormData } = require_formdata(); + var { kState } = require_symbols2(); + var { webidl } = require_webidl(); + var { Blob: Blob2 } = __require("node:buffer"); + var assert = __require("node:assert"); + var { isErrored, isDisturbed } = __require("node:stream"); + var { isArrayBuffer } = __require("node:util/types"); + var { serializeAMimeType } = require_data_url(); + var { multipartFormDataParser } = require_formdata_parser(); + var random; + try { + const crypto3 = __require("node:crypto"); + random = (max) => crypto3.randomInt(0, max); + } catch { + random = (max) => Math.floor(Math.random(max)); + } + var textEncoder = new TextEncoder(); + function noop() { + } + var hasFinalizationRegistry = globalThis.FinalizationRegistry && process.version.indexOf("v18") !== 0; + var streamRegistry; + if (hasFinalizationRegistry) { + streamRegistry = new FinalizationRegistry((weakRef) => { + const stream = weakRef.deref(); + if (stream && !stream.locked && !isDisturbed(stream) && !isErrored(stream)) { + stream.cancel("Response object has been garbage collected").catch(noop); + } + }); + } + function extractBody(object, keepalive = false) { + let stream = null; + if (object instanceof ReadableStream) { + stream = object; + } else if (isBlobLike(object)) { + stream = object.stream(); + } else { + stream = new ReadableStream({ + async pull(controller) { + const buffer = typeof source === "string" ? textEncoder.encode(source) : source; + if (buffer.byteLength) { + controller.enqueue(buffer); + } + queueMicrotask(() => readableStreamClose(controller)); + }, + start() { + }, + type: "bytes" + }); + } + assert(isReadableStreamLike(stream)); + let action = null; + let source = null; + let length = null; + let type = null; + if (typeof object === "string") { + source = object; + type = "text/plain;charset=UTF-8"; + } else if (object instanceof URLSearchParams) { + source = object.toString(); + type = "application/x-www-form-urlencoded;charset=UTF-8"; + } else if (isArrayBuffer(object)) { + source = new Uint8Array(object.slice()); + } else if (ArrayBuffer.isView(object)) { + source = new Uint8Array(object.buffer.slice(object.byteOffset, object.byteOffset + object.byteLength)); + } else if (util.isFormDataLike(object)) { + const boundary = `----formdata-undici-0${`${random(1e11)}`.padStart(11, "0")}`; + const prefix = `--${boundary}\r +Content-Disposition: form-data`; + const escape = (str) => str.replace(/\n/g, "%0A").replace(/\r/g, "%0D").replace(/"/g, "%22"); + const normalizeLinefeeds = (value) => value.replace(/\r?\n|\r/g, "\r\n"); + const blobParts = []; + const rn = new Uint8Array([13, 10]); + length = 0; + let hasUnknownSizeValue = false; + for (const [name, value] of object) { + if (typeof value === "string") { + const chunk2 = textEncoder.encode(prefix + `; name="${escape(normalizeLinefeeds(name))}"\r +\r +${normalizeLinefeeds(value)}\r +`); + blobParts.push(chunk2); + length += chunk2.byteLength; + } else { + const chunk2 = textEncoder.encode(`${prefix}; name="${escape(normalizeLinefeeds(name))}"` + (value.name ? `; filename="${escape(value.name)}"` : "") + `\r +Content-Type: ${value.type || "application/octet-stream"}\r +\r +`); + blobParts.push(chunk2, value, rn); + if (typeof value.size === "number") { + length += chunk2.byteLength + value.size + rn.byteLength; + } else { + hasUnknownSizeValue = true; + } + } + } + const chunk = textEncoder.encode(`--${boundary}--\r +`); + blobParts.push(chunk); + length += chunk.byteLength; + if (hasUnknownSizeValue) { + length = null; + } + source = object; + action = async function* () { + for (const part of blobParts) { + if (part.stream) { + yield* part.stream(); + } else { + yield part; + } + } + }; + type = `multipart/form-data; boundary=${boundary}`; + } else if (isBlobLike(object)) { + source = object; + length = object.size; + if (object.type) { + type = object.type; + } + } else if (typeof object[Symbol.asyncIterator] === "function") { + if (keepalive) { + throw new TypeError("keepalive"); + } + if (util.isDisturbed(object) || object.locked) { + throw new TypeError( + "Response body object should not be disturbed or locked" + ); + } + stream = object instanceof ReadableStream ? object : ReadableStreamFrom(object); + } + if (typeof source === "string" || util.isBuffer(source)) { + length = Buffer.byteLength(source); + } + if (action != null) { + let iterator; + stream = new ReadableStream({ + async start() { + iterator = action(object)[Symbol.asyncIterator](); + }, + async pull(controller) { + const { value, done } = await iterator.next(); + if (done) { + queueMicrotask(() => { + controller.close(); + controller.byobRequest?.respond(0); + }); + } else { + if (!isErrored(stream)) { + const buffer = new Uint8Array(value); + if (buffer.byteLength) { + controller.enqueue(buffer); + } + } + } + return controller.desiredSize > 0; + }, + async cancel(reason) { + await iterator.return(); + }, + type: "bytes" + }); + } + const body = { stream, source, length }; + return [body, type]; + } + function safelyExtractBody(object, keepalive = false) { + if (object instanceof ReadableStream) { + assert(!util.isDisturbed(object), "The body has already been consumed."); + assert(!object.locked, "The stream is locked."); + } + return extractBody(object, keepalive); + } + function cloneBody(instance, body) { + const [out1, out2] = body.stream.tee(); + body.stream = out1; + return { + stream: out2, + length: body.length, + source: body.source + }; + } + function throwIfAborted(state) { + if (state.aborted) { + throw new DOMException("The operation was aborted.", "AbortError"); + } + } + function bodyMixinMethods(instance) { + const methods = { + blob() { + return consumeBody(this, (bytes2) => { + let mimeType = bodyMimeType(this); + if (mimeType === null) { + mimeType = ""; + } else if (mimeType) { + mimeType = serializeAMimeType(mimeType); + } + return new Blob2([bytes2], { type: mimeType }); + }, instance); + }, + arrayBuffer() { + return consumeBody(this, (bytes2) => { + return new Uint8Array(bytes2).buffer; + }, instance); + }, + text() { + return consumeBody(this, utf8DecodeBytes, instance); + }, + json() { + return consumeBody(this, parseJSONFromBytes, instance); + }, + formData() { + return consumeBody(this, (value) => { + const mimeType = bodyMimeType(this); + if (mimeType !== null) { + switch (mimeType.essence) { + case "multipart/form-data": { + const parsed = multipartFormDataParser(value, mimeType); + if (parsed === "failure") { + throw new TypeError("Failed to parse body as FormData."); + } + const fd = new FormData(); + fd[kState] = parsed; + return fd; + } + case "application/x-www-form-urlencoded": { + const entries = new URLSearchParams(value.toString()); + const fd = new FormData(); + for (const [name, value2] of entries) { + fd.append(name, value2); + } + return fd; + } + } + } + throw new TypeError( + 'Content-Type was not one of "multipart/form-data" or "application/x-www-form-urlencoded".' + ); + }, instance); + }, + bytes() { + return consumeBody(this, (bytes2) => { + return new Uint8Array(bytes2); + }, instance); + } + }; + return methods; + } + function mixinBody(prototype) { + Object.assign(prototype.prototype, bodyMixinMethods(prototype)); + } + async function consumeBody(object, convertBytesToJSValue, instance) { + webidl.brandCheck(object, instance); + if (bodyUnusable(object)) { + throw new TypeError("Body is unusable: Body has already been read"); + } + throwIfAborted(object[kState]); + const promise = createDeferredPromise(); + const errorSteps = (error) => promise.reject(error); + const successSteps = (data) => { + try { + promise.resolve(convertBytesToJSValue(data)); + } catch (e) { + errorSteps(e); + } + }; + if (object[kState].body == null) { + successSteps(Buffer.allocUnsafe(0)); + return promise.promise; + } + await fullyReadBody(object[kState].body, successSteps, errorSteps); + return promise.promise; + } + function bodyUnusable(object) { + const body = object[kState].body; + return body != null && (body.stream.locked || util.isDisturbed(body.stream)); + } + function parseJSONFromBytes(bytes2) { + return JSON.parse(utf8DecodeBytes(bytes2)); + } + function bodyMimeType(requestOrResponse) { + const headers = requestOrResponse[kState].headersList; + const mimeType = extractMimeType(headers); + if (mimeType === "failure") { + return null; + } + return mimeType; + } + module.exports = { + extractBody, + safelyExtractBody, + cloneBody, + mixinBody, + streamRegistry, + hasFinalizationRegistry, + bodyUnusable + }; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/client-h1.js +var require_client_h1 = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/client-h1.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var util = require_util(); + var { channels } = require_diagnostics(); + var timers = require_timers(); + var { + RequestContentLengthMismatchError, + ResponseContentLengthMismatchError, + RequestAbortedError, + HeadersTimeoutError, + HeadersOverflowError, + SocketError, + InformationalError, + BodyTimeoutError, + HTTPParserError, + ResponseExceededMaxSizeError + } = require_errors(); + var { + kUrl, + kReset, + kClient, + kParser, + kBlocking, + kRunning, + kPending, + kSize, + kWriting, + kQueue, + kNoRef, + kKeepAliveDefaultTimeout, + kHostHeader, + kPendingIdx, + kRunningIdx, + kError, + kPipelining, + kSocket, + kKeepAliveTimeoutValue, + kMaxHeadersSize, + kKeepAliveMaxTimeout, + kKeepAliveTimeoutThreshold, + kHeadersTimeout, + kBodyTimeout, + kStrictContentLength, + kMaxRequests, + kCounter, + kMaxResponseSize, + kOnError, + kResume, + kHTTPContext + } = require_symbols(); + var constants = require_constants2(); + var EMPTY_BUF = Buffer.alloc(0); + var FastBuffer = Buffer[Symbol.species]; + var addListener = util.addListener; + var removeAllListeners = util.removeAllListeners; + var extractBody; + async function lazyllhttp() { + const llhttpWasmData = process.env.JEST_WORKER_ID ? require_llhttp_wasm() : void 0; + let mod; + try { + mod = await WebAssembly.compile(require_llhttp_simd_wasm()); + } catch (e) { + mod = await WebAssembly.compile(llhttpWasmData || require_llhttp_wasm()); + } + return await WebAssembly.instantiate(mod, { + env: { + /* eslint-disable camelcase */ + wasm_on_url: (p, at, len) => { + return 0; + }, + wasm_on_status: (p, at, len) => { + assert(currentParser.ptr === p); + const start = at - currentBufferPtr + currentBufferRef.byteOffset; + return currentParser.onStatus(new FastBuffer(currentBufferRef.buffer, start, len)) || 0; + }, + wasm_on_message_begin: (p) => { + assert(currentParser.ptr === p); + return currentParser.onMessageBegin() || 0; + }, + wasm_on_header_field: (p, at, len) => { + assert(currentParser.ptr === p); + const start = at - currentBufferPtr + currentBufferRef.byteOffset; + return currentParser.onHeaderField(new FastBuffer(currentBufferRef.buffer, start, len)) || 0; + }, + wasm_on_header_value: (p, at, len) => { + assert(currentParser.ptr === p); + const start = at - currentBufferPtr + currentBufferRef.byteOffset; + return currentParser.onHeaderValue(new FastBuffer(currentBufferRef.buffer, start, len)) || 0; + }, + wasm_on_headers_complete: (p, statusCode, upgrade, shouldKeepAlive) => { + assert(currentParser.ptr === p); + return currentParser.onHeadersComplete(statusCode, Boolean(upgrade), Boolean(shouldKeepAlive)) || 0; + }, + wasm_on_body: (p, at, len) => { + assert(currentParser.ptr === p); + const start = at - currentBufferPtr + currentBufferRef.byteOffset; + return currentParser.onBody(new FastBuffer(currentBufferRef.buffer, start, len)) || 0; + }, + wasm_on_message_complete: (p) => { + assert(currentParser.ptr === p); + return currentParser.onMessageComplete() || 0; + } + /* eslint-enable camelcase */ + } + }); + } + var llhttpInstance = null; + var llhttpPromise = lazyllhttp(); + llhttpPromise.catch(); + var currentParser = null; + var currentBufferRef = null; + var currentBufferSize = 0; + var currentBufferPtr = null; + var USE_NATIVE_TIMER = 0; + var USE_FAST_TIMER = 1; + var TIMEOUT_HEADERS = 2 | USE_FAST_TIMER; + var TIMEOUT_BODY = 4 | USE_FAST_TIMER; + var TIMEOUT_KEEP_ALIVE = 8 | USE_NATIVE_TIMER; + var Parser = class { + constructor(client, socket, { exports: exports2 }) { + assert(Number.isFinite(client[kMaxHeadersSize]) && client[kMaxHeadersSize] > 0); + this.llhttp = exports2; + this.ptr = this.llhttp.llhttp_alloc(constants.TYPE.RESPONSE); + this.client = client; + this.socket = socket; + this.timeout = null; + this.timeoutValue = null; + this.timeoutType = null; + this.statusCode = null; + this.statusText = ""; + this.upgrade = false; + this.headers = []; + this.headersSize = 0; + this.headersMaxSize = client[kMaxHeadersSize]; + this.shouldKeepAlive = false; + this.paused = false; + this.resume = this.resume.bind(this); + this.bytesRead = 0; + this.keepAlive = ""; + this.contentLength = ""; + this.connection = ""; + this.maxResponseSize = client[kMaxResponseSize]; + } + setTimeout(delay, type) { + if (delay !== this.timeoutValue || type & USE_FAST_TIMER ^ this.timeoutType & USE_FAST_TIMER) { + if (this.timeout) { + timers.clearTimeout(this.timeout); + this.timeout = null; + } + if (delay) { + if (type & USE_FAST_TIMER) { + this.timeout = timers.setFastTimeout(onParserTimeout, delay, new WeakRef(this)); + } else { + this.timeout = setTimeout(onParserTimeout, delay, new WeakRef(this)); + this.timeout.unref(); + } + } + this.timeoutValue = delay; + } else if (this.timeout) { + if (this.timeout.refresh) { + this.timeout.refresh(); + } + } + this.timeoutType = type; + } + resume() { + if (this.socket.destroyed || !this.paused) { + return; + } + assert(this.ptr != null); + assert(currentParser == null); + this.llhttp.llhttp_resume(this.ptr); + assert(this.timeoutType === TIMEOUT_BODY); + if (this.timeout) { + if (this.timeout.refresh) { + this.timeout.refresh(); + } + } + this.paused = false; + this.execute(this.socket.read() || EMPTY_BUF); + this.readMore(); + } + readMore() { + while (!this.paused && this.ptr) { + const chunk = this.socket.read(); + if (chunk === null) { + break; + } + this.execute(chunk); + } + } + execute(data) { + assert(this.ptr != null); + assert(currentParser == null); + assert(!this.paused); + const { socket, llhttp } = this; + if (data.length > currentBufferSize) { + if (currentBufferPtr) { + llhttp.free(currentBufferPtr); + } + currentBufferSize = Math.ceil(data.length / 4096) * 4096; + currentBufferPtr = llhttp.malloc(currentBufferSize); + } + new Uint8Array(llhttp.memory.buffer, currentBufferPtr, currentBufferSize).set(data); + try { + let ret; + try { + currentBufferRef = data; + currentParser = this; + ret = llhttp.llhttp_execute(this.ptr, currentBufferPtr, data.length); + } catch (err) { + throw err; + } finally { + currentParser = null; + currentBufferRef = null; + } + const offset = llhttp.llhttp_get_error_pos(this.ptr) - currentBufferPtr; + if (ret !== constants.ERROR.OK) { + const body = data.subarray(offset); + if (ret === constants.ERROR.PAUSED_UPGRADE) { + this.onUpgrade(body); + } else if (ret === constants.ERROR.PAUSED) { + this.paused = true; + socket.unshift(body); + } else { + throw this.createError(ret, body); + } + } + } catch (err) { + util.destroy(socket, err); + } + } + finish() { + assert(currentParser === null); + assert(this.ptr != null); + assert(!this.paused); + const { llhttp } = this; + let ret; + try { + currentParser = this; + ret = llhttp.llhttp_finish(this.ptr); + } finally { + currentParser = null; + } + if (ret === constants.ERROR.OK) { + return null; + } + if (ret === constants.ERROR.PAUSED || ret === constants.ERROR.PAUSED_UPGRADE) { + this.paused = true; + return null; + } + return this.createError(ret, EMPTY_BUF); + } + createError(ret, data) { + const { llhttp, contentLength, bytesRead } = this; + if (contentLength && bytesRead !== parseInt(contentLength, 10)) { + return new ResponseContentLengthMismatchError(); + } + const ptr = llhttp.llhttp_get_error_reason(this.ptr); + let message = ""; + if (ptr) { + const len = new Uint8Array(llhttp.memory.buffer, ptr).indexOf(0); + message = "Response does not match the HTTP/1.1 protocol (" + Buffer.from(llhttp.memory.buffer, ptr, len).toString() + ")"; + } + return new HTTPParserError(message, constants.ERROR[ret], data); + } + destroy() { + assert(this.ptr != null); + assert(currentParser == null); + this.llhttp.llhttp_free(this.ptr); + this.ptr = null; + this.timeout && timers.clearTimeout(this.timeout); + this.timeout = null; + this.timeoutValue = null; + this.timeoutType = null; + this.paused = false; + } + onStatus(buf) { + this.statusText = buf.toString(); + } + onMessageBegin() { + const { socket, client } = this; + if (socket.destroyed) { + return -1; + } + const request = client[kQueue][client[kRunningIdx]]; + if (!request) { + return -1; + } + request.onResponseStarted(); + } + onHeaderField(buf) { + const len = this.headers.length; + if ((len & 1) === 0) { + this.headers.push(buf); + } else { + this.headers[len - 1] = Buffer.concat([this.headers[len - 1], buf]); + } + this.trackHeader(buf.length); + } + onHeaderValue(buf) { + let len = this.headers.length; + if ((len & 1) === 1) { + this.headers.push(buf); + len += 1; + } else { + this.headers[len - 1] = Buffer.concat([this.headers[len - 1], buf]); + } + const key = this.headers[len - 2]; + if (key.length === 10) { + const headerName = util.bufferToLowerCasedHeaderName(key); + if (headerName === "keep-alive") { + this.keepAlive += buf.toString(); + } else if (headerName === "connection") { + this.connection += buf.toString(); + } + } else if (key.length === 14 && util.bufferToLowerCasedHeaderName(key) === "content-length") { + this.contentLength += buf.toString(); + } + this.trackHeader(buf.length); + } + trackHeader(len) { + this.headersSize += len; + if (this.headersSize >= this.headersMaxSize) { + util.destroy(this.socket, new HeadersOverflowError()); + } + } + onUpgrade(head2) { + const { upgrade, client, socket, headers, statusCode } = this; + assert(upgrade); + assert(client[kSocket] === socket); + assert(!socket.destroyed); + assert(!this.paused); + assert((headers.length & 1) === 0); + const request = client[kQueue][client[kRunningIdx]]; + assert(request); + assert(request.upgrade || request.method === "CONNECT"); + this.statusCode = null; + this.statusText = ""; + this.shouldKeepAlive = null; + this.headers = []; + this.headersSize = 0; + socket.unshift(head2); + socket[kParser].destroy(); + socket[kParser] = null; + socket[kClient] = null; + socket[kError] = null; + removeAllListeners(socket); + client[kSocket] = null; + client[kHTTPContext] = null; + client[kQueue][client[kRunningIdx]++] = null; + client.emit("disconnect", client[kUrl], [client], new InformationalError("upgrade")); + try { + request.onUpgrade(statusCode, headers, socket); + } catch (err) { + util.destroy(socket, err); + } + client[kResume](); + } + onHeadersComplete(statusCode, upgrade, shouldKeepAlive) { + const { client, socket, headers, statusText } = this; + if (socket.destroyed) { + return -1; + } + const request = client[kQueue][client[kRunningIdx]]; + if (!request) { + return -1; + } + assert(!this.upgrade); + assert(this.statusCode < 200); + if (statusCode === 100) { + util.destroy(socket, new SocketError("bad response", util.getSocketInfo(socket))); + return -1; + } + if (upgrade && !request.upgrade) { + util.destroy(socket, new SocketError("bad upgrade", util.getSocketInfo(socket))); + return -1; + } + assert(this.timeoutType === TIMEOUT_HEADERS); + this.statusCode = statusCode; + this.shouldKeepAlive = shouldKeepAlive || // Override llhttp value which does not allow keepAlive for HEAD. + request.method === "HEAD" && !socket[kReset] && this.connection.toLowerCase() === "keep-alive"; + if (this.statusCode >= 200) { + const bodyTimeout = request.bodyTimeout != null ? request.bodyTimeout : client[kBodyTimeout]; + this.setTimeout(bodyTimeout, TIMEOUT_BODY); + } else if (this.timeout) { + if (this.timeout.refresh) { + this.timeout.refresh(); + } + } + if (request.method === "CONNECT") { + assert(client[kRunning] === 1); + this.upgrade = true; + return 2; + } + if (upgrade) { + assert(client[kRunning] === 1); + this.upgrade = true; + return 2; + } + assert((this.headers.length & 1) === 0); + this.headers = []; + this.headersSize = 0; + if (this.shouldKeepAlive && client[kPipelining]) { + const keepAliveTimeout = this.keepAlive ? util.parseKeepAliveTimeout(this.keepAlive) : null; + if (keepAliveTimeout != null) { + const timeout = Math.min( + keepAliveTimeout - client[kKeepAliveTimeoutThreshold], + client[kKeepAliveMaxTimeout] + ); + if (timeout <= 0) { + socket[kReset] = true; + } else { + client[kKeepAliveTimeoutValue] = timeout; + } + } else { + client[kKeepAliveTimeoutValue] = client[kKeepAliveDefaultTimeout]; + } + } else { + socket[kReset] = true; + } + const pause = request.onHeaders(statusCode, headers, this.resume, statusText) === false; + if (request.aborted) { + return -1; + } + if (request.method === "HEAD") { + return 1; + } + if (statusCode < 200) { + return 1; + } + if (socket[kBlocking]) { + socket[kBlocking] = false; + client[kResume](); + } + return pause ? constants.ERROR.PAUSED : 0; + } + onBody(buf) { + const { client, socket, statusCode, maxResponseSize } = this; + if (socket.destroyed) { + return -1; + } + const request = client[kQueue][client[kRunningIdx]]; + assert(request); + assert(this.timeoutType === TIMEOUT_BODY); + if (this.timeout) { + if (this.timeout.refresh) { + this.timeout.refresh(); + } + } + assert(statusCode >= 200); + if (maxResponseSize > -1 && this.bytesRead + buf.length > maxResponseSize) { + util.destroy(socket, new ResponseExceededMaxSizeError()); + return -1; + } + this.bytesRead += buf.length; + if (request.onData(buf) === false) { + return constants.ERROR.PAUSED; + } + } + onMessageComplete() { + const { client, socket, statusCode, upgrade, headers, contentLength, bytesRead, shouldKeepAlive } = this; + if (socket.destroyed && (!statusCode || shouldKeepAlive)) { + return -1; + } + if (upgrade) { + return; + } + assert(statusCode >= 100); + assert((this.headers.length & 1) === 0); + const request = client[kQueue][client[kRunningIdx]]; + assert(request); + this.statusCode = null; + this.statusText = ""; + this.bytesRead = 0; + this.contentLength = ""; + this.keepAlive = ""; + this.connection = ""; + this.headers = []; + this.headersSize = 0; + if (statusCode < 200) { + return; + } + if (request.method !== "HEAD" && contentLength && bytesRead !== parseInt(contentLength, 10)) { + util.destroy(socket, new ResponseContentLengthMismatchError()); + return -1; + } + request.onComplete(headers); + client[kQueue][client[kRunningIdx]++] = null; + if (socket[kWriting]) { + assert(client[kRunning] === 0); + util.destroy(socket, new InformationalError("reset")); + return constants.ERROR.PAUSED; + } else if (!shouldKeepAlive) { + util.destroy(socket, new InformationalError("reset")); + return constants.ERROR.PAUSED; + } else if (socket[kReset] && client[kRunning] === 0) { + util.destroy(socket, new InformationalError("reset")); + return constants.ERROR.PAUSED; + } else if (client[kPipelining] == null || client[kPipelining] === 1) { + setImmediate(() => client[kResume]()); + } else { + client[kResume](); + } + } + }; + function onParserTimeout(parser) { + const { socket, timeoutType, client, paused } = parser.deref(); + if (timeoutType === TIMEOUT_HEADERS) { + if (!socket[kWriting] || socket.writableNeedDrain || client[kRunning] > 1) { + assert(!paused, "cannot be paused while waiting for headers"); + util.destroy(socket, new HeadersTimeoutError()); + } + } else if (timeoutType === TIMEOUT_BODY) { + if (!paused) { + util.destroy(socket, new BodyTimeoutError()); + } + } else if (timeoutType === TIMEOUT_KEEP_ALIVE) { + assert(client[kRunning] === 0 && client[kKeepAliveTimeoutValue]); + util.destroy(socket, new InformationalError("socket idle timeout")); + } + } + async function connectH1(client, socket) { + client[kSocket] = socket; + if (!llhttpInstance) { + llhttpInstance = await llhttpPromise; + llhttpPromise = null; + } + socket[kNoRef] = false; + socket[kWriting] = false; + socket[kReset] = false; + socket[kBlocking] = false; + socket[kParser] = new Parser(client, socket, llhttpInstance); + addListener(socket, "error", function(err) { + assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); + const parser = this[kParser]; + if (err.code === "ECONNRESET" && parser.statusCode && !parser.shouldKeepAlive) { + const parserErr = parser.finish(); + if (parserErr) { + this[kError] = parserErr; + this[kClient][kOnError](parserErr); + } + return; + } + this[kError] = err; + this[kClient][kOnError](err); + }); + addListener(socket, "readable", function() { + const parser = this[kParser]; + if (parser) { + parser.readMore(); + } + }); + addListener(socket, "end", function() { + const parser = this[kParser]; + if (parser.statusCode && !parser.shouldKeepAlive) { + const parserErr = parser.finish(); + if (parserErr) { + util.destroy(this, parserErr); + } + return; + } + util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); + }); + addListener(socket, "close", function() { + const client2 = this[kClient]; + const parser = this[kParser]; + if (parser) { + if (!this[kError] && parser.statusCode && !parser.shouldKeepAlive) { + this[kError] = parser.finish() || this[kError]; + } + this[kParser].destroy(); + this[kParser] = null; + } + const err = this[kError] || new SocketError("closed", util.getSocketInfo(this)); + client2[kSocket] = null; + client2[kHTTPContext] = null; + if (client2.destroyed) { + assert(client2[kPending] === 0); + const requests = client2[kQueue].splice(client2[kRunningIdx]); + for (let i = 0; i < requests.length; i++) { + const request = requests[i]; + util.errorRequest(client2, request, err); + } + } else if (client2[kRunning] > 0 && err.code !== "UND_ERR_INFO") { + const request = client2[kQueue][client2[kRunningIdx]]; + client2[kQueue][client2[kRunningIdx]++] = null; + util.errorRequest(client2, request, err); + } + client2[kPendingIdx] = client2[kRunningIdx]; + assert(client2[kRunning] === 0); + client2.emit("disconnect", client2[kUrl], [client2], err); + client2[kResume](); + }); + let closed = false; + socket.on("close", () => { + closed = true; + }); + return { + version: "h1", + defaultPipelining: 1, + write(...args) { + return writeH1(client, ...args); + }, + resume() { + resumeH1(client); + }, + destroy(err, callback) { + if (closed) { + queueMicrotask(callback); + } else { + socket.destroy(err).on("close", callback); + } + }, + get destroyed() { + return socket.destroyed; + }, + busy(request) { + if (socket[kWriting] || socket[kReset] || socket[kBlocking]) { + return true; + } + if (request) { + if (client[kRunning] > 0 && !request.idempotent) { + return true; + } + if (client[kRunning] > 0 && (request.upgrade || request.method === "CONNECT")) { + return true; + } + if (client[kRunning] > 0 && util.bodyLength(request.body) !== 0 && (util.isStream(request.body) || util.isAsyncIterable(request.body) || util.isFormDataLike(request.body))) { + return true; + } + } + return false; + } + }; + } + function resumeH1(client) { + const socket = client[kSocket]; + if (socket && !socket.destroyed) { + if (client[kSize] === 0) { + if (!socket[kNoRef] && socket.unref) { + socket.unref(); + socket[kNoRef] = true; + } + } else if (socket[kNoRef] && socket.ref) { + socket.ref(); + socket[kNoRef] = false; + } + if (client[kSize] === 0) { + if (socket[kParser].timeoutType !== TIMEOUT_KEEP_ALIVE) { + socket[kParser].setTimeout(client[kKeepAliveTimeoutValue], TIMEOUT_KEEP_ALIVE); + } + } else if (client[kRunning] > 0 && socket[kParser].statusCode < 200) { + if (socket[kParser].timeoutType !== TIMEOUT_HEADERS) { + const request = client[kQueue][client[kRunningIdx]]; + const headersTimeout = request.headersTimeout != null ? request.headersTimeout : client[kHeadersTimeout]; + socket[kParser].setTimeout(headersTimeout, TIMEOUT_HEADERS); + } + } + } + } + function shouldSendContentLength(method) { + return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT"; + } + function writeH1(client, request) { + const { method, path: path12, host: host2, upgrade, blocking, reset } = request; + let { body, headers, contentLength } = request; + const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH" || method === "QUERY" || method === "PROPFIND" || method === "PROPPATCH"; + if (util.isFormDataLike(body)) { + if (!extractBody) { + extractBody = require_body().extractBody; + } + const [bodyStream, contentType] = extractBody(body); + if (request.contentType == null) { + headers.push("content-type", contentType); + } + body = bodyStream.stream; + contentLength = bodyStream.length; + } else if (util.isBlobLike(body) && request.contentType == null && body.type) { + headers.push("content-type", body.type); + } + if (body && typeof body.read === "function") { + body.read(0); + } + const bodyLength = util.bodyLength(body); + contentLength = bodyLength ?? contentLength; + if (contentLength === null) { + contentLength = request.contentLength; + } + if (contentLength === 0 && !expectsPayload) { + contentLength = null; + } + if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength !== null && request.contentLength !== contentLength) { + if (client[kStrictContentLength]) { + util.errorRequest(client, request, new RequestContentLengthMismatchError()); + return false; + } + process.emitWarning(new RequestContentLengthMismatchError()); + } + const socket = client[kSocket]; + const abort = (err) => { + if (request.aborted || request.completed) { + return; + } + util.errorRequest(client, request, err || new RequestAbortedError()); + util.destroy(body); + util.destroy(socket, new InformationalError("aborted")); + }; + try { + request.onConnect(abort); + } catch (err) { + util.errorRequest(client, request, err); + } + if (request.aborted) { + return false; + } + if (method === "HEAD") { + socket[kReset] = true; + } + if (upgrade || method === "CONNECT") { + socket[kReset] = true; + } + if (reset != null) { + socket[kReset] = reset; + } + if (client[kMaxRequests] && socket[kCounter]++ >= client[kMaxRequests]) { + socket[kReset] = true; + } + if (blocking) { + socket[kBlocking] = true; + } + let header = `${method} ${path12} HTTP/1.1\r +`; + if (typeof host2 === "string") { + header += `host: ${host2}\r +`; + } else { + header += client[kHostHeader]; + } + if (upgrade) { + header += `connection: upgrade\r +upgrade: ${upgrade}\r +`; + } else if (client[kPipelining] && !socket[kReset]) { + header += "connection: keep-alive\r\n"; + } else { + header += "connection: close\r\n"; + } + if (Array.isArray(headers)) { + for (let n = 0; n < headers.length; n += 2) { + const key = headers[n + 0]; + const val = headers[n + 1]; + if (Array.isArray(val)) { + for (let i = 0; i < val.length; i++) { + header += `${key}: ${val[i]}\r +`; + } + } else { + header += `${key}: ${val}\r +`; + } + } + } + if (channels.sendHeaders.hasSubscribers) { + channels.sendHeaders.publish({ request, headers: header, socket }); + } + if (!body || bodyLength === 0) { + writeBuffer(abort, null, client, request, socket, contentLength, header, expectsPayload); + } else if (util.isBuffer(body)) { + writeBuffer(abort, body, client, request, socket, contentLength, header, expectsPayload); + } else if (util.isBlobLike(body)) { + if (typeof body.stream === "function") { + writeIterable(abort, body.stream(), client, request, socket, contentLength, header, expectsPayload); + } else { + writeBlob(abort, body, client, request, socket, contentLength, header, expectsPayload); + } + } else if (util.isStream(body)) { + writeStream(abort, body, client, request, socket, contentLength, header, expectsPayload); + } else if (util.isIterable(body)) { + writeIterable(abort, body, client, request, socket, contentLength, header, expectsPayload); + } else { + assert(false); + } + return true; + } + function writeStream(abort, body, client, request, socket, contentLength, header, expectsPayload) { + assert(contentLength !== 0 || client[kRunning] === 0, "stream body cannot be pipelined"); + let finished = false; + const writer = new AsyncWriter({ abort, socket, request, contentLength, client, expectsPayload, header }); + const onData = function(chunk) { + if (finished) { + return; + } + try { + if (!writer.write(chunk) && this.pause) { + this.pause(); + } + } catch (err) { + util.destroy(this, err); + } + }; + const onDrain = function() { + if (finished) { + return; + } + if (body.resume) { + body.resume(); + } + }; + const onClose = function() { + queueMicrotask(() => { + body.removeListener("error", onFinished); + }); + if (!finished) { + const err = new RequestAbortedError(); + queueMicrotask(() => onFinished(err)); + } + }; + const onFinished = function(err) { + if (finished) { + return; + } + finished = true; + assert(socket.destroyed || socket[kWriting] && client[kRunning] <= 1); + socket.off("drain", onDrain).off("error", onFinished); + body.removeListener("data", onData).removeListener("end", onFinished).removeListener("close", onClose); + if (!err) { + try { + writer.end(); + } catch (er) { + err = er; + } + } + writer.destroy(err); + if (err && (err.code !== "UND_ERR_INFO" || err.message !== "reset")) { + util.destroy(body, err); + } else { + util.destroy(body); + } + }; + body.on("data", onData).on("end", onFinished).on("error", onFinished).on("close", onClose); + if (body.resume) { + body.resume(); + } + socket.on("drain", onDrain).on("error", onFinished); + if (body.errorEmitted ?? body.errored) { + setImmediate(() => onFinished(body.errored)); + } else if (body.endEmitted ?? body.readableEnded) { + setImmediate(() => onFinished(null)); + } + if (body.closeEmitted ?? body.closed) { + setImmediate(onClose); + } + } + function writeBuffer(abort, body, client, request, socket, contentLength, header, expectsPayload) { + try { + if (!body) { + if (contentLength === 0) { + socket.write(`${header}content-length: 0\r +\r +`, "latin1"); + } else { + assert(contentLength === null, "no body must not have content length"); + socket.write(`${header}\r +`, "latin1"); + } + } else if (util.isBuffer(body)) { + assert(contentLength === body.byteLength, "buffer body must have content length"); + socket.cork(); + socket.write(`${header}content-length: ${contentLength}\r +\r +`, "latin1"); + socket.write(body); + socket.uncork(); + request.onBodySent(body); + if (!expectsPayload && request.reset !== false) { + socket[kReset] = true; + } + } + request.onRequestSent(); + client[kResume](); + } catch (err) { + abort(err); + } + } + async function writeBlob(abort, body, client, request, socket, contentLength, header, expectsPayload) { + assert(contentLength === body.size, "blob body must have content length"); + try { + if (contentLength != null && contentLength !== body.size) { + throw new RequestContentLengthMismatchError(); + } + const buffer = Buffer.from(await body.arrayBuffer()); + socket.cork(); + socket.write(`${header}content-length: ${contentLength}\r +\r +`, "latin1"); + socket.write(buffer); + socket.uncork(); + request.onBodySent(buffer); + request.onRequestSent(); + if (!expectsPayload && request.reset !== false) { + socket[kReset] = true; + } + client[kResume](); + } catch (err) { + abort(err); + } + } + async function writeIterable(abort, body, client, request, socket, contentLength, header, expectsPayload) { + assert(contentLength !== 0 || client[kRunning] === 0, "iterator body cannot be pipelined"); + let callback = null; + function onDrain() { + if (callback) { + const cb = callback; + callback = null; + cb(); + } + } + const waitForDrain = () => new Promise((resolve, reject) => { + assert(callback === null); + if (socket[kError]) { + reject(socket[kError]); + } else { + callback = resolve; + } + }); + socket.on("close", onDrain).on("drain", onDrain); + const writer = new AsyncWriter({ abort, socket, request, contentLength, client, expectsPayload, header }); + try { + for await (const chunk of body) { + if (socket[kError]) { + throw socket[kError]; + } + if (!writer.write(chunk)) { + await waitForDrain(); + } + } + writer.end(); + } catch (err) { + writer.destroy(err); + } finally { + socket.off("close", onDrain).off("drain", onDrain); + } + } + var AsyncWriter = class { + constructor({ abort, socket, request, contentLength, client, expectsPayload, header }) { + this.socket = socket; + this.request = request; + this.contentLength = contentLength; + this.client = client; + this.bytesWritten = 0; + this.expectsPayload = expectsPayload; + this.header = header; + this.abort = abort; + socket[kWriting] = true; + } + write(chunk) { + const { socket, request, contentLength, client, bytesWritten, expectsPayload, header } = this; + if (socket[kError]) { + throw socket[kError]; + } + if (socket.destroyed) { + return false; + } + const len = Buffer.byteLength(chunk); + if (!len) { + return true; + } + if (contentLength !== null && bytesWritten + len > contentLength) { + if (client[kStrictContentLength]) { + throw new RequestContentLengthMismatchError(); + } + process.emitWarning(new RequestContentLengthMismatchError()); + } + socket.cork(); + if (bytesWritten === 0) { + if (!expectsPayload && request.reset !== false) { + socket[kReset] = true; + } + if (contentLength === null) { + socket.write(`${header}transfer-encoding: chunked\r +`, "latin1"); + } else { + socket.write(`${header}content-length: ${contentLength}\r +\r +`, "latin1"); + } + } + if (contentLength === null) { + socket.write(`\r +${len.toString(16)}\r +`, "latin1"); + } + this.bytesWritten += len; + const ret = socket.write(chunk); + socket.uncork(); + request.onBodySent(chunk); + if (!ret) { + if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) { + if (socket[kParser].timeout.refresh) { + socket[kParser].timeout.refresh(); + } + } + } + return ret; + } + end() { + const { socket, contentLength, client, bytesWritten, expectsPayload, header, request } = this; + request.onRequestSent(); + socket[kWriting] = false; + if (socket[kError]) { + throw socket[kError]; + } + if (socket.destroyed) { + return; + } + if (bytesWritten === 0) { + if (expectsPayload) { + socket.write(`${header}content-length: 0\r +\r +`, "latin1"); + } else { + socket.write(`${header}\r +`, "latin1"); + } + } else if (contentLength === null) { + socket.write("\r\n0\r\n\r\n", "latin1"); + } + if (contentLength !== null && bytesWritten !== contentLength) { + if (client[kStrictContentLength]) { + throw new RequestContentLengthMismatchError(); + } else { + process.emitWarning(new RequestContentLengthMismatchError()); + } + } + if (socket[kParser].timeout && socket[kParser].timeoutType === TIMEOUT_HEADERS) { + if (socket[kParser].timeout.refresh) { + socket[kParser].timeout.refresh(); + } + } + client[kResume](); + } + destroy(err) { + const { socket, client, abort } = this; + socket[kWriting] = false; + if (err) { + assert(client[kRunning] <= 1, "pipeline should only contain this request"); + abort(err); + } + } + }; + module.exports = connectH1; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/client-h2.js +var require_client_h2 = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/client-h2.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var { pipeline } = __require("node:stream"); + var util = require_util(); + var { + RequestContentLengthMismatchError, + RequestAbortedError, + SocketError, + InformationalError + } = require_errors(); + var { + kUrl, + kReset, + kClient, + kRunning, + kPending, + kQueue, + kPendingIdx, + kRunningIdx, + kError, + kSocket, + kStrictContentLength, + kOnError, + kMaxConcurrentStreams, + kHTTP2Session, + kResume, + kSize, + kHTTPContext + } = require_symbols(); + var kOpenStreams = /* @__PURE__ */ Symbol("open streams"); + var extractBody; + var h2ExperimentalWarned = false; + var http2; + try { + http2 = __require("node:http2"); + } catch { + http2 = { constants: {} }; + } + var { + constants: { + HTTP2_HEADER_AUTHORITY, + HTTP2_HEADER_METHOD, + HTTP2_HEADER_PATH, + HTTP2_HEADER_SCHEME, + HTTP2_HEADER_CONTENT_LENGTH, + HTTP2_HEADER_EXPECT, + HTTP2_HEADER_STATUS + } + } = http2; + function parseH2Headers(headers) { + const result = []; + for (const [name, value] of Object.entries(headers)) { + if (Array.isArray(value)) { + for (const subvalue of value) { + result.push(Buffer.from(name), Buffer.from(subvalue)); + } + } else { + result.push(Buffer.from(name), Buffer.from(value)); + } + } + return result; + } + async function connectH2(client, socket) { + client[kSocket] = socket; + if (!h2ExperimentalWarned) { + h2ExperimentalWarned = true; + process.emitWarning("H2 support is experimental, expect them to change at any time.", { + code: "UNDICI-H2" + }); + } + const session = http2.connect(client[kUrl], { + createConnection: () => socket, + peerMaxConcurrentStreams: client[kMaxConcurrentStreams] + }); + session[kOpenStreams] = 0; + session[kClient] = client; + session[kSocket] = socket; + util.addListener(session, "error", onHttp2SessionError); + util.addListener(session, "frameError", onHttp2FrameError); + util.addListener(session, "end", onHttp2SessionEnd); + util.addListener(session, "goaway", onHTTP2GoAway); + util.addListener(session, "close", function() { + const { [kClient]: client2 } = this; + const { [kSocket]: socket2 } = client2; + const err = this[kSocket][kError] || this[kError] || new SocketError("closed", util.getSocketInfo(socket2)); + client2[kHTTP2Session] = null; + if (client2.destroyed) { + assert(client2[kPending] === 0); + const requests = client2[kQueue].splice(client2[kRunningIdx]); + for (let i = 0; i < requests.length; i++) { + const request = requests[i]; + util.errorRequest(client2, request, err); + } + } + }); + session.unref(); + client[kHTTP2Session] = session; + socket[kHTTP2Session] = session; + util.addListener(socket, "error", function(err) { + assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); + this[kError] = err; + this[kClient][kOnError](err); + }); + util.addListener(socket, "end", function() { + util.destroy(this, new SocketError("other side closed", util.getSocketInfo(this))); + }); + util.addListener(socket, "close", function() { + const err = this[kError] || new SocketError("closed", util.getSocketInfo(this)); + client[kSocket] = null; + if (this[kHTTP2Session] != null) { + this[kHTTP2Session].destroy(err); + } + client[kPendingIdx] = client[kRunningIdx]; + assert(client[kRunning] === 0); + client.emit("disconnect", client[kUrl], [client], err); + client[kResume](); + }); + let closed = false; + socket.on("close", () => { + closed = true; + }); + return { + version: "h2", + defaultPipelining: Infinity, + write(...args) { + return writeH2(client, ...args); + }, + resume() { + resumeH2(client); + }, + destroy(err, callback) { + if (closed) { + queueMicrotask(callback); + } else { + socket.destroy(err).on("close", callback); + } + }, + get destroyed() { + return socket.destroyed; + }, + busy() { + return false; + } + }; + } + function resumeH2(client) { + const socket = client[kSocket]; + if (socket?.destroyed === false) { + if (client[kSize] === 0 && client[kMaxConcurrentStreams] === 0) { + socket.unref(); + client[kHTTP2Session].unref(); + } else { + socket.ref(); + client[kHTTP2Session].ref(); + } + } + } + function onHttp2SessionError(err) { + assert(err.code !== "ERR_TLS_CERT_ALTNAME_INVALID"); + this[kSocket][kError] = err; + this[kClient][kOnError](err); + } + function onHttp2FrameError(type, code, id) { + if (id === 0) { + const err = new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`); + this[kSocket][kError] = err; + this[kClient][kOnError](err); + } + } + function onHttp2SessionEnd() { + const err = new SocketError("other side closed", util.getSocketInfo(this[kSocket])); + this.destroy(err); + util.destroy(this[kSocket], err); + } + function onHTTP2GoAway(code) { + const err = this[kError] || new SocketError(`HTTP/2: "GOAWAY" frame received with code ${code}`, util.getSocketInfo(this)); + const client = this[kClient]; + client[kSocket] = null; + client[kHTTPContext] = null; + if (this[kHTTP2Session] != null) { + this[kHTTP2Session].destroy(err); + this[kHTTP2Session] = null; + } + util.destroy(this[kSocket], err); + if (client[kRunningIdx] < client[kQueue].length) { + const request = client[kQueue][client[kRunningIdx]]; + client[kQueue][client[kRunningIdx]++] = null; + util.errorRequest(client, request, err); + client[kPendingIdx] = client[kRunningIdx]; + } + assert(client[kRunning] === 0); + client.emit("disconnect", client[kUrl], [client], err); + client[kResume](); + } + function shouldSendContentLength(method) { + return method !== "GET" && method !== "HEAD" && method !== "OPTIONS" && method !== "TRACE" && method !== "CONNECT"; + } + function writeH2(client, request) { + const session = client[kHTTP2Session]; + const { method, path: path12, host: host2, upgrade, expectContinue, signal, headers: reqHeaders } = request; + let { body } = request; + if (upgrade) { + util.errorRequest(client, request, new Error("Upgrade not supported for H2")); + return false; + } + const headers = {}; + for (let n = 0; n < reqHeaders.length; n += 2) { + const key = reqHeaders[n + 0]; + const val = reqHeaders[n + 1]; + if (Array.isArray(val)) { + for (let i = 0; i < val.length; i++) { + if (headers[key]) { + headers[key] += `,${val[i]}`; + } else { + headers[key] = val[i]; + } + } + } else { + headers[key] = val; + } + } + let stream; + const { hostname, port: port2 } = client[kUrl]; + headers[HTTP2_HEADER_AUTHORITY] = host2 || `${hostname}${port2 ? `:${port2}` : ""}`; + headers[HTTP2_HEADER_METHOD] = method; + const abort = (err) => { + if (request.aborted || request.completed) { + return; + } + err = err || new RequestAbortedError(); + util.errorRequest(client, request, err); + if (stream != null) { + util.destroy(stream, err); + } + util.destroy(body, err); + client[kQueue][client[kRunningIdx]++] = null; + client[kResume](); + }; + try { + request.onConnect(abort); + } catch (err) { + util.errorRequest(client, request, err); + } + if (request.aborted) { + return false; + } + if (method === "CONNECT") { + session.ref(); + stream = session.request(headers, { endStream: false, signal }); + if (stream.id && !stream.pending) { + request.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + } else { + stream.once("ready", () => { + request.onUpgrade(null, null, stream); + ++session[kOpenStreams]; + client[kQueue][client[kRunningIdx]++] = null; + }); + } + stream.once("close", () => { + session[kOpenStreams] -= 1; + if (session[kOpenStreams] === 0) session.unref(); + }); + return true; + } + headers[HTTP2_HEADER_PATH] = path12; + headers[HTTP2_HEADER_SCHEME] = "https"; + const expectsPayload = method === "PUT" || method === "POST" || method === "PATCH"; + if (body && typeof body.read === "function") { + body.read(0); + } + let contentLength = util.bodyLength(body); + if (util.isFormDataLike(body)) { + extractBody ??= require_body().extractBody; + const [bodyStream, contentType] = extractBody(body); + headers["content-type"] = contentType; + body = bodyStream.stream; + contentLength = bodyStream.length; + } + if (contentLength == null) { + contentLength = request.contentLength; + } + if (contentLength === 0 || !expectsPayload) { + contentLength = null; + } + if (shouldSendContentLength(method) && contentLength > 0 && request.contentLength != null && request.contentLength !== contentLength) { + if (client[kStrictContentLength]) { + util.errorRequest(client, request, new RequestContentLengthMismatchError()); + return false; + } + process.emitWarning(new RequestContentLengthMismatchError()); + } + if (contentLength != null) { + assert(body, "no body must not have content length"); + headers[HTTP2_HEADER_CONTENT_LENGTH] = `${contentLength}`; + } + session.ref(); + const shouldEndStream = method === "GET" || method === "HEAD" || body === null; + if (expectContinue) { + headers[HTTP2_HEADER_EXPECT] = "100-continue"; + stream = session.request(headers, { endStream: shouldEndStream, signal }); + stream.once("continue", writeBodyH2); + } else { + stream = session.request(headers, { + endStream: shouldEndStream, + signal + }); + writeBodyH2(); + } + ++session[kOpenStreams]; + stream.once("response", (headers2) => { + const { [HTTP2_HEADER_STATUS]: statusCode, ...realHeaders } = headers2; + request.onResponseStarted(); + if (request.aborted) { + const err = new RequestAbortedError(); + util.errorRequest(client, request, err); + util.destroy(stream, err); + return; + } + if (request.onHeaders(Number(statusCode), parseH2Headers(realHeaders), stream.resume.bind(stream), "") === false) { + stream.pause(); + } + stream.on("data", (chunk) => { + if (request.onData(chunk) === false) { + stream.pause(); + } + }); + }); + stream.once("end", () => { + if (stream.state?.state == null || stream.state.state < 6) { + request.onComplete([]); + } + if (session[kOpenStreams] === 0) { + session.unref(); + } + abort(new InformationalError("HTTP/2: stream half-closed (remote)")); + client[kQueue][client[kRunningIdx]++] = null; + client[kPendingIdx] = client[kRunningIdx]; + client[kResume](); + }); + stream.once("close", () => { + session[kOpenStreams] -= 1; + if (session[kOpenStreams] === 0) { + session.unref(); + } + }); + stream.once("error", function(err) { + abort(err); + }); + stream.once("frameError", (type, code) => { + abort(new InformationalError(`HTTP/2: "frameError" received - type ${type}, code ${code}`)); + }); + return true; + function writeBodyH2() { + if (!body || contentLength === 0) { + writeBuffer( + abort, + stream, + null, + client, + request, + client[kSocket], + contentLength, + expectsPayload + ); + } else if (util.isBuffer(body)) { + writeBuffer( + abort, + stream, + body, + client, + request, + client[kSocket], + contentLength, + expectsPayload + ); + } else if (util.isBlobLike(body)) { + if (typeof body.stream === "function") { + writeIterable( + abort, + stream, + body.stream(), + client, + request, + client[kSocket], + contentLength, + expectsPayload + ); + } else { + writeBlob( + abort, + stream, + body, + client, + request, + client[kSocket], + contentLength, + expectsPayload + ); + } + } else if (util.isStream(body)) { + writeStream( + abort, + client[kSocket], + expectsPayload, + stream, + body, + client, + request, + contentLength + ); + } else if (util.isIterable(body)) { + writeIterable( + abort, + stream, + body, + client, + request, + client[kSocket], + contentLength, + expectsPayload + ); + } else { + assert(false); + } + } + } + function writeBuffer(abort, h2stream, body, client, request, socket, contentLength, expectsPayload) { + try { + if (body != null && util.isBuffer(body)) { + assert(contentLength === body.byteLength, "buffer body must have content length"); + h2stream.cork(); + h2stream.write(body); + h2stream.uncork(); + h2stream.end(); + request.onBodySent(body); + } + if (!expectsPayload) { + socket[kReset] = true; + } + request.onRequestSent(); + client[kResume](); + } catch (error) { + abort(error); + } + } + function writeStream(abort, socket, expectsPayload, h2stream, body, client, request, contentLength) { + assert(contentLength !== 0 || client[kRunning] === 0, "stream body cannot be pipelined"); + const pipe = pipeline( + body, + h2stream, + (err) => { + if (err) { + util.destroy(pipe, err); + abort(err); + } else { + util.removeAllListeners(pipe); + request.onRequestSent(); + if (!expectsPayload) { + socket[kReset] = true; + } + client[kResume](); + } + } + ); + util.addListener(pipe, "data", onPipeData); + function onPipeData(chunk) { + request.onBodySent(chunk); + } + } + async function writeBlob(abort, h2stream, body, client, request, socket, contentLength, expectsPayload) { + assert(contentLength === body.size, "blob body must have content length"); + try { + if (contentLength != null && contentLength !== body.size) { + throw new RequestContentLengthMismatchError(); + } + const buffer = Buffer.from(await body.arrayBuffer()); + h2stream.cork(); + h2stream.write(buffer); + h2stream.uncork(); + h2stream.end(); + request.onBodySent(buffer); + request.onRequestSent(); + if (!expectsPayload) { + socket[kReset] = true; + } + client[kResume](); + } catch (err) { + abort(err); + } + } + async function writeIterable(abort, h2stream, body, client, request, socket, contentLength, expectsPayload) { + assert(contentLength !== 0 || client[kRunning] === 0, "iterator body cannot be pipelined"); + let callback = null; + function onDrain() { + if (callback) { + const cb = callback; + callback = null; + cb(); + } + } + const waitForDrain = () => new Promise((resolve, reject) => { + assert(callback === null); + if (socket[kError]) { + reject(socket[kError]); + } else { + callback = resolve; + } + }); + h2stream.on("close", onDrain).on("drain", onDrain); + try { + for await (const chunk of body) { + if (socket[kError]) { + throw socket[kError]; + } + const res = h2stream.write(chunk); + request.onBodySent(chunk); + if (!res) { + await waitForDrain(); + } + } + h2stream.end(); + request.onRequestSent(); + if (!expectsPayload) { + socket[kReset] = true; + } + client[kResume](); + } catch (err) { + abort(err); + } finally { + h2stream.off("close", onDrain).off("drain", onDrain); + } + } + module.exports = connectH2; + } +}); + +// viewer/node_modules/undici/lib/handler/redirect-handler.js +var require_redirect_handler = __commonJS({ + "viewer/node_modules/undici/lib/handler/redirect-handler.js"(exports, module) { + "use strict"; + var util = require_util(); + var { kBodyUsed } = require_symbols(); + var assert = __require("node:assert"); + var { InvalidArgumentError } = require_errors(); + var EE = __require("node:events"); + var redirectableStatusCodes = [300, 301, 302, 303, 307, 308]; + var kBody = /* @__PURE__ */ Symbol("body"); + var BodyAsyncIterable = class { + constructor(body) { + this[kBody] = body; + this[kBodyUsed] = false; + } + async *[Symbol.asyncIterator]() { + assert(!this[kBodyUsed], "disturbed"); + this[kBodyUsed] = true; + yield* this[kBody]; + } + }; + var RedirectHandler = class { + constructor(dispatch, maxRedirections, opts, handler) { + if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { + throw new InvalidArgumentError("maxRedirections must be a positive number"); + } + util.validateHandler(handler, opts.method, opts.upgrade); + this.dispatch = dispatch; + this.location = null; + this.abort = null; + this.opts = { ...opts, maxRedirections: 0 }; + this.maxRedirections = maxRedirections; + this.handler = handler; + this.history = []; + this.redirectionLimitReached = false; + if (util.isStream(this.opts.body)) { + if (util.bodyLength(this.opts.body) === 0) { + this.opts.body.on("data", function() { + assert(false); + }); + } + if (typeof this.opts.body.readableDidRead !== "boolean") { + this.opts.body[kBodyUsed] = false; + EE.prototype.on.call(this.opts.body, "data", function() { + this[kBodyUsed] = true; + }); + } + } else if (this.opts.body && typeof this.opts.body.pipeTo === "function") { + this.opts.body = new BodyAsyncIterable(this.opts.body); + } else if (this.opts.body && typeof this.opts.body !== "string" && !ArrayBuffer.isView(this.opts.body) && util.isIterable(this.opts.body)) { + this.opts.body = new BodyAsyncIterable(this.opts.body); + } + } + onConnect(abort) { + this.abort = abort; + this.handler.onConnect(abort, { history: this.history }); + } + onUpgrade(statusCode, headers, socket) { + this.handler.onUpgrade(statusCode, headers, socket); + } + onError(error) { + this.handler.onError(error); + } + onHeaders(statusCode, headers, resume, statusText) { + this.location = this.history.length >= this.maxRedirections || util.isDisturbed(this.opts.body) ? null : parseLocation(statusCode, headers); + if (this.opts.throwOnMaxRedirect && this.history.length >= this.maxRedirections) { + if (this.request) { + this.request.abort(new Error("max redirects")); + } + this.redirectionLimitReached = true; + this.abort(new Error("max redirects")); + return; + } + if (this.opts.origin) { + this.history.push(new URL(this.opts.path, this.opts.origin)); + } + if (!this.location) { + return this.handler.onHeaders(statusCode, headers, resume, statusText); + } + const { origin, pathname, search } = util.parseURL(new URL(this.location, this.opts.origin && new URL(this.opts.path, this.opts.origin))); + const path12 = search ? `${pathname}${search}` : pathname; + this.opts.headers = cleanRequestHeaders(this.opts.headers, statusCode === 303, this.opts.origin !== origin); + this.opts.path = path12; + this.opts.origin = origin; + this.opts.maxRedirections = 0; + this.opts.query = null; + if (statusCode === 303 && this.opts.method !== "HEAD") { + this.opts.method = "GET"; + this.opts.body = null; + } + } + onData(chunk) { + if (this.location) { + } else { + return this.handler.onData(chunk); + } + } + onComplete(trailers) { + if (this.location) { + this.location = null; + this.abort = null; + this.dispatch(this.opts, this); + } else { + this.handler.onComplete(trailers); + } + } + onBodySent(chunk) { + if (this.handler.onBodySent) { + this.handler.onBodySent(chunk); + } + } + }; + function parseLocation(statusCode, headers) { + if (redirectableStatusCodes.indexOf(statusCode) === -1) { + return null; + } + for (let i = 0; i < headers.length; i += 2) { + if (headers[i].length === 8 && util.headerNameToString(headers[i]) === "location") { + return headers[i + 1]; + } + } + } + function shouldRemoveHeader(header, removeContent, unknownOrigin) { + if (header.length === 4) { + return util.headerNameToString(header) === "host"; + } + if (removeContent && util.headerNameToString(header).startsWith("content-")) { + return true; + } + if (unknownOrigin && (header.length === 13 || header.length === 6 || header.length === 19)) { + const name = util.headerNameToString(header); + return name === "authorization" || name === "cookie" || name === "proxy-authorization"; + } + return false; + } + function cleanRequestHeaders(headers, removeContent, unknownOrigin) { + const ret = []; + if (Array.isArray(headers)) { + for (let i = 0; i < headers.length; i += 2) { + if (!shouldRemoveHeader(headers[i], removeContent, unknownOrigin)) { + ret.push(headers[i], headers[i + 1]); + } + } + } else if (headers && typeof headers === "object") { + for (const key of Object.keys(headers)) { + if (!shouldRemoveHeader(key, removeContent, unknownOrigin)) { + ret.push(key, headers[key]); + } + } + } else { + assert(headers == null, "headers must be an object or an array"); + } + return ret; + } + module.exports = RedirectHandler; + } +}); + +// viewer/node_modules/undici/lib/interceptor/redirect-interceptor.js +var require_redirect_interceptor = __commonJS({ + "viewer/node_modules/undici/lib/interceptor/redirect-interceptor.js"(exports, module) { + "use strict"; + var RedirectHandler = require_redirect_handler(); + function createRedirectInterceptor({ maxRedirections: defaultMaxRedirections }) { + return (dispatch) => { + return function Intercept(opts, handler) { + const { maxRedirections = defaultMaxRedirections } = opts; + if (!maxRedirections) { + return dispatch(opts, handler); + } + const redirectHandler = new RedirectHandler(dispatch, maxRedirections, opts, handler); + opts = { ...opts, maxRedirections: 0 }; + return dispatch(opts, redirectHandler); + }; + }; + } + module.exports = createRedirectInterceptor; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/client.js +var require_client = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/client.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var net = __require("node:net"); + var http2 = __require("node:http"); + var util = require_util(); + var { channels } = require_diagnostics(); + var Request2 = require_request(); + var DispatcherBase = require_dispatcher_base(); + var { + InvalidArgumentError, + InformationalError, + ClientDestroyedError + } = require_errors(); + var buildConnector = require_connect(); + var { + kUrl, + kServerName, + kClient, + kBusy, + kConnect, + kResuming, + kRunning, + kPending, + kSize, + kQueue, + kConnected, + kConnecting, + kNeedDrain, + kKeepAliveDefaultTimeout, + kHostHeader, + kPendingIdx, + kRunningIdx, + kError, + kPipelining, + kKeepAliveTimeoutValue, + kMaxHeadersSize, + kKeepAliveMaxTimeout, + kKeepAliveTimeoutThreshold, + kHeadersTimeout, + kBodyTimeout, + kStrictContentLength, + kConnector, + kMaxRedirections, + kMaxRequests, + kCounter, + kClose, + kDestroy, + kDispatch, + kInterceptors, + kLocalAddress, + kMaxResponseSize, + kOnError, + kHTTPContext, + kMaxConcurrentStreams, + kResume + } = require_symbols(); + var connectH1 = require_client_h1(); + var connectH2 = require_client_h2(); + var deprecatedInterceptorWarned = false; + var kClosedResolve = /* @__PURE__ */ Symbol("kClosedResolve"); + var noop = () => { + }; + function getPipelining(client) { + return client[kPipelining] ?? client[kHTTPContext]?.defaultPipelining ?? 1; + } + var Client = class extends DispatcherBase { + /** + * + * @param {string|URL} url + * @param {import('../../types/client.js').Client.Options} options + */ + constructor(url, { + interceptors, + maxHeaderSize, + headersTimeout, + socketTimeout, + requestTimeout, + connectTimeout, + bodyTimeout, + idleTimeout, + keepAlive, + keepAliveTimeout, + maxKeepAliveTimeout, + keepAliveMaxTimeout, + keepAliveTimeoutThreshold, + socketPath, + pipelining, + tls, + strictContentLength, + maxCachedSessions, + maxRedirections, + connect: connect2, + maxRequestsPerClient, + localAddress, + maxResponseSize, + autoSelectFamily, + autoSelectFamilyAttemptTimeout, + // h2 + maxConcurrentStreams, + allowH2, + webSocket + } = {}) { + super({ webSocket }); + if (keepAlive !== void 0) { + throw new InvalidArgumentError("unsupported keepAlive, use pipelining=0 instead"); + } + if (socketTimeout !== void 0) { + throw new InvalidArgumentError("unsupported socketTimeout, use headersTimeout & bodyTimeout instead"); + } + if (requestTimeout !== void 0) { + throw new InvalidArgumentError("unsupported requestTimeout, use headersTimeout & bodyTimeout instead"); + } + if (idleTimeout !== void 0) { + throw new InvalidArgumentError("unsupported idleTimeout, use keepAliveTimeout instead"); + } + if (maxKeepAliveTimeout !== void 0) { + throw new InvalidArgumentError("unsupported maxKeepAliveTimeout, use keepAliveMaxTimeout instead"); + } + if (maxHeaderSize != null && !Number.isFinite(maxHeaderSize)) { + throw new InvalidArgumentError("invalid maxHeaderSize"); + } + if (socketPath != null && typeof socketPath !== "string") { + throw new InvalidArgumentError("invalid socketPath"); + } + if (connectTimeout != null && (!Number.isFinite(connectTimeout) || connectTimeout < 0)) { + throw new InvalidArgumentError("invalid connectTimeout"); + } + if (keepAliveTimeout != null && (!Number.isFinite(keepAliveTimeout) || keepAliveTimeout <= 0)) { + throw new InvalidArgumentError("invalid keepAliveTimeout"); + } + if (keepAliveMaxTimeout != null && (!Number.isFinite(keepAliveMaxTimeout) || keepAliveMaxTimeout <= 0)) { + throw new InvalidArgumentError("invalid keepAliveMaxTimeout"); + } + if (keepAliveTimeoutThreshold != null && !Number.isFinite(keepAliveTimeoutThreshold)) { + throw new InvalidArgumentError("invalid keepAliveTimeoutThreshold"); + } + if (headersTimeout != null && (!Number.isInteger(headersTimeout) || headersTimeout < 0)) { + throw new InvalidArgumentError("headersTimeout must be a positive integer or zero"); + } + if (bodyTimeout != null && (!Number.isInteger(bodyTimeout) || bodyTimeout < 0)) { + throw new InvalidArgumentError("bodyTimeout must be a positive integer or zero"); + } + if (connect2 != null && typeof connect2 !== "function" && typeof connect2 !== "object") { + throw new InvalidArgumentError("connect must be a function or an object"); + } + if (maxRedirections != null && (!Number.isInteger(maxRedirections) || maxRedirections < 0)) { + throw new InvalidArgumentError("maxRedirections must be a positive number"); + } + if (maxRequestsPerClient != null && (!Number.isInteger(maxRequestsPerClient) || maxRequestsPerClient < 0)) { + throw new InvalidArgumentError("maxRequestsPerClient must be a positive number"); + } + if (localAddress != null && (typeof localAddress !== "string" || net.isIP(localAddress) === 0)) { + throw new InvalidArgumentError("localAddress must be valid string IP address"); + } + if (maxResponseSize != null && (!Number.isInteger(maxResponseSize) || maxResponseSize < -1)) { + throw new InvalidArgumentError("maxResponseSize must be a positive number"); + } + if (autoSelectFamilyAttemptTimeout != null && (!Number.isInteger(autoSelectFamilyAttemptTimeout) || autoSelectFamilyAttemptTimeout < -1)) { + throw new InvalidArgumentError("autoSelectFamilyAttemptTimeout must be a positive number"); + } + if (allowH2 != null && typeof allowH2 !== "boolean") { + throw new InvalidArgumentError("allowH2 must be a valid boolean value"); + } + if (maxConcurrentStreams != null && (typeof maxConcurrentStreams !== "number" || maxConcurrentStreams < 1)) { + throw new InvalidArgumentError("maxConcurrentStreams must be a positive integer, greater than 0"); + } + if (typeof connect2 !== "function") { + connect2 = buildConnector({ + ...tls, + maxCachedSessions, + allowH2, + socketPath, + timeout: connectTimeout, + ...autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : void 0, + ...connect2 + }); + } + if (interceptors?.Client && Array.isArray(interceptors.Client)) { + this[kInterceptors] = interceptors.Client; + if (!deprecatedInterceptorWarned) { + deprecatedInterceptorWarned = true; + process.emitWarning("Client.Options#interceptor is deprecated. Use Dispatcher#compose instead.", { + code: "UNDICI-CLIENT-INTERCEPTOR-DEPRECATED" + }); + } + } else { + this[kInterceptors] = [createRedirectInterceptor({ maxRedirections })]; + } + this[kUrl] = util.parseOrigin(url); + this[kConnector] = connect2; + this[kPipelining] = pipelining != null ? pipelining : 1; + this[kMaxHeadersSize] = maxHeaderSize || http2.maxHeaderSize; + this[kKeepAliveDefaultTimeout] = keepAliveTimeout == null ? 4e3 : keepAliveTimeout; + this[kKeepAliveMaxTimeout] = keepAliveMaxTimeout == null ? 6e5 : keepAliveMaxTimeout; + this[kKeepAliveTimeoutThreshold] = keepAliveTimeoutThreshold == null ? 2e3 : keepAliveTimeoutThreshold; + this[kKeepAliveTimeoutValue] = this[kKeepAliveDefaultTimeout]; + this[kServerName] = null; + this[kLocalAddress] = localAddress != null ? localAddress : null; + this[kResuming] = 0; + this[kNeedDrain] = 0; + this[kHostHeader] = `host: ${this[kUrl].hostname}${this[kUrl].port ? `:${this[kUrl].port}` : ""}\r +`; + this[kBodyTimeout] = bodyTimeout != null ? bodyTimeout : 3e5; + this[kHeadersTimeout] = headersTimeout != null ? headersTimeout : 3e5; + this[kStrictContentLength] = strictContentLength == null ? true : strictContentLength; + this[kMaxRedirections] = maxRedirections; + this[kMaxRequests] = maxRequestsPerClient; + this[kClosedResolve] = null; + this[kMaxResponseSize] = maxResponseSize > -1 ? maxResponseSize : -1; + this[kMaxConcurrentStreams] = maxConcurrentStreams != null ? maxConcurrentStreams : 100; + this[kHTTPContext] = null; + this[kQueue] = []; + this[kRunningIdx] = 0; + this[kPendingIdx] = 0; + this[kResume] = (sync) => resume(this, sync); + this[kOnError] = (err) => onError(this, err); + } + get pipelining() { + return this[kPipelining]; + } + set pipelining(value) { + this[kPipelining] = value; + this[kResume](true); + } + get [kPending]() { + return this[kQueue].length - this[kPendingIdx]; + } + get [kRunning]() { + return this[kPendingIdx] - this[kRunningIdx]; + } + get [kSize]() { + return this[kQueue].length - this[kRunningIdx]; + } + get [kConnected]() { + return !!this[kHTTPContext] && !this[kConnecting] && !this[kHTTPContext].destroyed; + } + get [kBusy]() { + return Boolean( + this[kHTTPContext]?.busy(null) || this[kSize] >= (getPipelining(this) || 1) || this[kPending] > 0 + ); + } + /* istanbul ignore: only used for test */ + [kConnect](cb) { + connect(this); + this.once("connect", cb); + } + [kDispatch](opts, handler) { + const origin = opts.origin || this[kUrl].origin; + const request = new Request2(origin, opts, handler); + this[kQueue].push(request); + if (this[kResuming]) { + } else if (util.bodyLength(request.body) == null && util.isIterable(request.body)) { + this[kResuming] = 1; + queueMicrotask(() => resume(this)); + } else { + this[kResume](true); + } + if (this[kResuming] && this[kNeedDrain] !== 2 && this[kBusy]) { + this[kNeedDrain] = 2; + } + return this[kNeedDrain] < 2; + } + async [kClose]() { + return new Promise((resolve) => { + if (this[kSize]) { + this[kClosedResolve] = resolve; + } else { + resolve(null); + } + }); + } + async [kDestroy](err) { + return new Promise((resolve) => { + const requests = this[kQueue].splice(this[kPendingIdx]); + for (let i = 0; i < requests.length; i++) { + const request = requests[i]; + util.errorRequest(this, request, err); + } + const callback = () => { + if (this[kClosedResolve]) { + this[kClosedResolve](); + this[kClosedResolve] = null; + } + resolve(null); + }; + if (this[kHTTPContext]) { + this[kHTTPContext].destroy(err, callback); + this[kHTTPContext] = null; + } else { + queueMicrotask(callback); + } + this[kResume](); + }); + } + }; + var createRedirectInterceptor = require_redirect_interceptor(); + function onError(client, err) { + if (client[kRunning] === 0 && err.code !== "UND_ERR_INFO" && err.code !== "UND_ERR_SOCKET") { + assert(client[kPendingIdx] === client[kRunningIdx]); + const requests = client[kQueue].splice(client[kRunningIdx]); + for (let i = 0; i < requests.length; i++) { + const request = requests[i]; + util.errorRequest(client, request, err); + } + assert(client[kSize] === 0); + } + } + async function connect(client) { + assert(!client[kConnecting]); + assert(!client[kHTTPContext]); + let { host: host2, hostname, protocol, port: port2 } = client[kUrl]; + if (hostname[0] === "[") { + const idx = hostname.indexOf("]"); + assert(idx !== -1); + const ip = hostname.substring(1, idx); + assert(net.isIP(ip)); + hostname = ip; + } + client[kConnecting] = true; + if (channels.beforeConnect.hasSubscribers) { + channels.beforeConnect.publish({ + connectParams: { + host: host2, + hostname, + protocol, + port: port2, + version: client[kHTTPContext]?.version, + servername: client[kServerName], + localAddress: client[kLocalAddress] + }, + connector: client[kConnector] + }); + } + try { + const socket = await new Promise((resolve, reject) => { + client[kConnector]({ + host: host2, + hostname, + protocol, + port: port2, + servername: client[kServerName], + localAddress: client[kLocalAddress] + }, (err, socket2) => { + if (err) { + reject(err); + } else { + resolve(socket2); + } + }); + }); + if (client.destroyed) { + util.destroy(socket.on("error", noop), new ClientDestroyedError()); + return; + } + assert(socket); + try { + client[kHTTPContext] = socket.alpnProtocol === "h2" ? await connectH2(client, socket) : await connectH1(client, socket); + } catch (err) { + socket.destroy().on("error", noop); + throw err; + } + client[kConnecting] = false; + socket[kCounter] = 0; + socket[kMaxRequests] = client[kMaxRequests]; + socket[kClient] = client; + socket[kError] = null; + if (channels.connected.hasSubscribers) { + channels.connected.publish({ + connectParams: { + host: host2, + hostname, + protocol, + port: port2, + version: client[kHTTPContext]?.version, + servername: client[kServerName], + localAddress: client[kLocalAddress] + }, + connector: client[kConnector], + socket + }); + } + client.emit("connect", client[kUrl], [client]); + } catch (err) { + if (client.destroyed) { + return; + } + client[kConnecting] = false; + if (channels.connectError.hasSubscribers) { + channels.connectError.publish({ + connectParams: { + host: host2, + hostname, + protocol, + port: port2, + version: client[kHTTPContext]?.version, + servername: client[kServerName], + localAddress: client[kLocalAddress] + }, + connector: client[kConnector], + error: err + }); + } + if (err.code === "ERR_TLS_CERT_ALTNAME_INVALID") { + assert(client[kRunning] === 0); + while (client[kPending] > 0 && client[kQueue][client[kPendingIdx]].servername === client[kServerName]) { + const request = client[kQueue][client[kPendingIdx]++]; + util.errorRequest(client, request, err); + } + } else { + onError(client, err); + } + client.emit("connectionError", client[kUrl], [client], err); + } + client[kResume](); + } + function emitDrain(client) { + client[kNeedDrain] = 0; + client.emit("drain", client[kUrl], [client]); + } + function resume(client, sync) { + if (client[kResuming] === 2) { + return; + } + client[kResuming] = 2; + _resume(client, sync); + client[kResuming] = 0; + if (client[kRunningIdx] > 256) { + client[kQueue].splice(0, client[kRunningIdx]); + client[kPendingIdx] -= client[kRunningIdx]; + client[kRunningIdx] = 0; + } + } + function _resume(client, sync) { + while (true) { + if (client.destroyed) { + assert(client[kPending] === 0); + return; + } + if (client[kClosedResolve] && !client[kSize]) { + client[kClosedResolve](); + client[kClosedResolve] = null; + return; + } + if (client[kHTTPContext]) { + client[kHTTPContext].resume(); + } + if (client[kBusy]) { + client[kNeedDrain] = 2; + } else if (client[kNeedDrain] === 2) { + if (sync) { + client[kNeedDrain] = 1; + queueMicrotask(() => emitDrain(client)); + } else { + emitDrain(client); + } + continue; + } + if (client[kPending] === 0) { + return; + } + if (client[kRunning] >= (getPipelining(client) || 1)) { + return; + } + const request = client[kQueue][client[kPendingIdx]]; + if (client[kUrl].protocol === "https:" && client[kServerName] !== request.servername) { + if (client[kRunning] > 0) { + return; + } + client[kServerName] = request.servername; + client[kHTTPContext]?.destroy(new InformationalError("servername changed"), () => { + client[kHTTPContext] = null; + resume(client); + }); + } + if (client[kConnecting]) { + return; + } + if (!client[kHTTPContext]) { + connect(client); + return; + } + if (client[kHTTPContext].destroyed) { + return; + } + if (client[kHTTPContext].busy(request)) { + return; + } + if (!request.aborted && client[kHTTPContext].write(request)) { + client[kPendingIdx]++; + } else { + client[kQueue].splice(client[kPendingIdx], 1); + } + } + } + module.exports = Client; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/fixed-queue.js +var require_fixed_queue = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/fixed-queue.js"(exports, module) { + "use strict"; + var kSize = 2048; + var kMask = kSize - 1; + var FixedCircularBuffer = class { + constructor() { + this.bottom = 0; + this.top = 0; + this.list = new Array(kSize); + this.next = null; + } + isEmpty() { + return this.top === this.bottom; + } + isFull() { + return (this.top + 1 & kMask) === this.bottom; + } + push(data) { + this.list[this.top] = data; + this.top = this.top + 1 & kMask; + } + shift() { + const nextItem = this.list[this.bottom]; + if (nextItem === void 0) + return null; + this.list[this.bottom] = void 0; + this.bottom = this.bottom + 1 & kMask; + return nextItem; + } + }; + module.exports = class FixedQueue { + constructor() { + this.head = this.tail = new FixedCircularBuffer(); + } + isEmpty() { + return this.head.isEmpty(); + } + push(data) { + if (this.head.isFull()) { + this.head = this.head.next = new FixedCircularBuffer(); + } + this.head.push(data); + } + shift() { + const tail = this.tail; + const next = tail.shift(); + if (tail.isEmpty() && tail.next !== null) { + this.tail = tail.next; + } + return next; + } + }; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/pool-stats.js +var require_pool_stats = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/pool-stats.js"(exports, module) { + var { kFree, kConnected, kPending, kQueued, kRunning, kSize } = require_symbols(); + var kPool = /* @__PURE__ */ Symbol("pool"); + var PoolStats = class { + constructor(pool) { + this[kPool] = pool; + } + get connected() { + return this[kPool][kConnected]; + } + get free() { + return this[kPool][kFree]; + } + get pending() { + return this[kPool][kPending]; + } + get queued() { + return this[kPool][kQueued]; + } + get running() { + return this[kPool][kRunning]; + } + get size() { + return this[kPool][kSize]; + } + }; + module.exports = PoolStats; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/pool-base.js +var require_pool_base = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/pool-base.js"(exports, module) { + "use strict"; + var DispatcherBase = require_dispatcher_base(); + var FixedQueue = require_fixed_queue(); + var { kConnected, kSize, kRunning, kPending, kQueued, kBusy, kFree, kUrl, kClose, kDestroy, kDispatch } = require_symbols(); + var PoolStats = require_pool_stats(); + var kClients = /* @__PURE__ */ Symbol("clients"); + var kNeedDrain = /* @__PURE__ */ Symbol("needDrain"); + var kQueue = /* @__PURE__ */ Symbol("queue"); + var kClosedResolve = /* @__PURE__ */ Symbol("closed resolve"); + var kOnDrain = /* @__PURE__ */ Symbol("onDrain"); + var kOnConnect = /* @__PURE__ */ Symbol("onConnect"); + var kOnDisconnect = /* @__PURE__ */ Symbol("onDisconnect"); + var kOnConnectionError = /* @__PURE__ */ Symbol("onConnectionError"); + var kGetDispatcher = /* @__PURE__ */ Symbol("get dispatcher"); + var kAddClient = /* @__PURE__ */ Symbol("add client"); + var kRemoveClient = /* @__PURE__ */ Symbol("remove client"); + var kStats = /* @__PURE__ */ Symbol("stats"); + var PoolBase = class extends DispatcherBase { + constructor(opts) { + super(opts); + this[kQueue] = new FixedQueue(); + this[kClients] = []; + this[kQueued] = 0; + const pool = this; + this[kOnDrain] = function onDrain(origin, targets) { + const queue = pool[kQueue]; + let needDrain = false; + while (!needDrain) { + const item = queue.shift(); + if (!item) { + break; + } + pool[kQueued]--; + needDrain = !this.dispatch(item.opts, item.handler); + } + this[kNeedDrain] = needDrain; + if (!this[kNeedDrain] && pool[kNeedDrain]) { + pool[kNeedDrain] = false; + pool.emit("drain", origin, [pool, ...targets]); + } + if (pool[kClosedResolve] && queue.isEmpty()) { + Promise.all(pool[kClients].map((c) => c.close())).then(pool[kClosedResolve]); + } + }; + this[kOnConnect] = (origin, targets) => { + pool.emit("connect", origin, [pool, ...targets]); + }; + this[kOnDisconnect] = (origin, targets, err) => { + pool.emit("disconnect", origin, [pool, ...targets], err); + }; + this[kOnConnectionError] = (origin, targets, err) => { + pool.emit("connectionError", origin, [pool, ...targets], err); + }; + this[kStats] = new PoolStats(this); + } + get [kBusy]() { + return this[kNeedDrain]; + } + get [kConnected]() { + return this[kClients].filter((client) => client[kConnected]).length; + } + get [kFree]() { + return this[kClients].filter((client) => client[kConnected] && !client[kNeedDrain]).length; + } + get [kPending]() { + let ret = this[kQueued]; + for (const { [kPending]: pending } of this[kClients]) { + ret += pending; + } + return ret; + } + get [kRunning]() { + let ret = 0; + for (const { [kRunning]: running } of this[kClients]) { + ret += running; + } + return ret; + } + get [kSize]() { + let ret = this[kQueued]; + for (const { [kSize]: size } of this[kClients]) { + ret += size; + } + return ret; + } + get stats() { + return this[kStats]; + } + async [kClose]() { + if (this[kQueue].isEmpty()) { + await Promise.all(this[kClients].map((c) => c.close())); + } else { + await new Promise((resolve) => { + this[kClosedResolve] = resolve; + }); + } + } + async [kDestroy](err) { + while (true) { + const item = this[kQueue].shift(); + if (!item) { + break; + } + item.handler.onError(err); + } + await Promise.all(this[kClients].map((c) => c.destroy(err))); + } + [kDispatch](opts, handler) { + const dispatcher = this[kGetDispatcher](); + if (!dispatcher) { + this[kNeedDrain] = true; + this[kQueue].push({ opts, handler }); + this[kQueued]++; + } else if (!dispatcher.dispatch(opts, handler)) { + dispatcher[kNeedDrain] = true; + this[kNeedDrain] = !this[kGetDispatcher](); + } + return !this[kNeedDrain]; + } + [kAddClient](client) { + client.on("drain", this[kOnDrain]).on("connect", this[kOnConnect]).on("disconnect", this[kOnDisconnect]).on("connectionError", this[kOnConnectionError]); + this[kClients].push(client); + if (this[kNeedDrain]) { + queueMicrotask(() => { + if (this[kNeedDrain]) { + this[kOnDrain](client[kUrl], [this, client]); + } + }); + } + return this; + } + [kRemoveClient](client) { + client.close(() => { + const idx = this[kClients].indexOf(client); + if (idx !== -1) { + this[kClients].splice(idx, 1); + } + }); + this[kNeedDrain] = this[kClients].some((dispatcher) => !dispatcher[kNeedDrain] && dispatcher.closed !== true && dispatcher.destroyed !== true); + } + }; + module.exports = { + PoolBase, + kClients, + kNeedDrain, + kAddClient, + kRemoveClient, + kGetDispatcher + }; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/pool.js +var require_pool = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/pool.js"(exports, module) { + "use strict"; + var { + PoolBase, + kClients, + kNeedDrain, + kAddClient, + kGetDispatcher + } = require_pool_base(); + var Client = require_client(); + var { + InvalidArgumentError + } = require_errors(); + var util = require_util(); + var { kUrl, kInterceptors } = require_symbols(); + var buildConnector = require_connect(); + var kOptions = /* @__PURE__ */ Symbol("options"); + var kConnections = /* @__PURE__ */ Symbol("connections"); + var kFactory = /* @__PURE__ */ Symbol("factory"); + function defaultFactory(origin, opts) { + return new Client(origin, opts); + } + var Pool = class extends PoolBase { + constructor(origin, { + connections, + factory = defaultFactory, + connect, + connectTimeout, + tls, + maxCachedSessions, + socketPath, + autoSelectFamily, + autoSelectFamilyAttemptTimeout, + allowH2, + ...options + } = {}) { + if (connections != null && (!Number.isFinite(connections) || connections < 0)) { + throw new InvalidArgumentError("invalid connections"); + } + if (typeof factory !== "function") { + throw new InvalidArgumentError("factory must be a function."); + } + if (connect != null && typeof connect !== "function" && typeof connect !== "object") { + throw new InvalidArgumentError("connect must be a function or an object"); + } + if (typeof connect !== "function") { + connect = buildConnector({ + ...tls, + maxCachedSessions, + allowH2, + socketPath, + timeout: connectTimeout, + ...autoSelectFamily ? { autoSelectFamily, autoSelectFamilyAttemptTimeout } : void 0, + ...connect + }); + } + super(options); + this[kInterceptors] = options.interceptors?.Pool && Array.isArray(options.interceptors.Pool) ? options.interceptors.Pool : []; + this[kConnections] = connections || null; + this[kUrl] = util.parseOrigin(origin); + this[kOptions] = { ...util.deepClone(options), connect, allowH2 }; + this[kOptions].interceptors = options.interceptors ? { ...options.interceptors } : void 0; + this[kFactory] = factory; + this.on("connectionError", (origin2, targets, error) => { + for (const target of targets) { + const idx = this[kClients].indexOf(target); + if (idx !== -1) { + this[kClients].splice(idx, 1); + } + } + }); + } + [kGetDispatcher]() { + for (const client of this[kClients]) { + if (!client[kNeedDrain]) { + return client; + } + } + if (!this[kConnections] || this[kClients].length < this[kConnections]) { + const dispatcher = this[kFactory](this[kUrl], this[kOptions]); + this[kAddClient](dispatcher); + return dispatcher; + } + } + }; + module.exports = Pool; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/balanced-pool.js +var require_balanced_pool = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/balanced-pool.js"(exports, module) { + "use strict"; + var { + BalancedPoolMissingUpstreamError, + InvalidArgumentError + } = require_errors(); + var { + PoolBase, + kClients, + kNeedDrain, + kAddClient, + kRemoveClient, + kGetDispatcher + } = require_pool_base(); + var Pool = require_pool(); + var { kUrl, kInterceptors } = require_symbols(); + var { parseOrigin } = require_util(); + var kFactory = /* @__PURE__ */ Symbol("factory"); + var kOptions = /* @__PURE__ */ Symbol("options"); + var kGreatestCommonDivisor = /* @__PURE__ */ Symbol("kGreatestCommonDivisor"); + var kCurrentWeight = /* @__PURE__ */ Symbol("kCurrentWeight"); + var kIndex = /* @__PURE__ */ Symbol("kIndex"); + var kWeight = /* @__PURE__ */ Symbol("kWeight"); + var kMaxWeightPerServer = /* @__PURE__ */ Symbol("kMaxWeightPerServer"); + var kErrorPenalty = /* @__PURE__ */ Symbol("kErrorPenalty"); + function getGreatestCommonDivisor(a, b) { + if (a === 0) return b; + while (b !== 0) { + const t = b; + b = a % b; + a = t; + } + return a; + } + function defaultFactory(origin, opts) { + return new Pool(origin, opts); + } + var BalancedPool = class extends PoolBase { + constructor(upstreams = [], { factory = defaultFactory, ...opts } = {}) { + super(); + this[kOptions] = opts; + this[kIndex] = -1; + this[kCurrentWeight] = 0; + this[kMaxWeightPerServer] = this[kOptions].maxWeightPerServer || 100; + this[kErrorPenalty] = this[kOptions].errorPenalty || 15; + if (!Array.isArray(upstreams)) { + upstreams = [upstreams]; + } + if (typeof factory !== "function") { + throw new InvalidArgumentError("factory must be a function."); + } + this[kInterceptors] = opts.interceptors?.BalancedPool && Array.isArray(opts.interceptors.BalancedPool) ? opts.interceptors.BalancedPool : []; + this[kFactory] = factory; + for (const upstream of upstreams) { + this.addUpstream(upstream); + } + this._updateBalancedPoolStats(); + } + addUpstream(upstream) { + const upstreamOrigin = parseOrigin(upstream).origin; + if (this[kClients].find((pool2) => pool2[kUrl].origin === upstreamOrigin && pool2.closed !== true && pool2.destroyed !== true)) { + return this; + } + const pool = this[kFactory](upstreamOrigin, Object.assign({}, this[kOptions])); + this[kAddClient](pool); + pool.on("connect", () => { + pool[kWeight] = Math.min(this[kMaxWeightPerServer], pool[kWeight] + this[kErrorPenalty]); + }); + pool.on("connectionError", () => { + pool[kWeight] = Math.max(1, pool[kWeight] - this[kErrorPenalty]); + this._updateBalancedPoolStats(); + }); + pool.on("disconnect", (...args) => { + const err = args[2]; + if (err && err.code === "UND_ERR_SOCKET") { + pool[kWeight] = Math.max(1, pool[kWeight] - this[kErrorPenalty]); + this._updateBalancedPoolStats(); + } + }); + for (const client of this[kClients]) { + client[kWeight] = this[kMaxWeightPerServer]; + } + this._updateBalancedPoolStats(); + return this; + } + _updateBalancedPoolStats() { + let result = 0; + for (let i = 0; i < this[kClients].length; i++) { + result = getGreatestCommonDivisor(this[kClients][i][kWeight], result); + } + this[kGreatestCommonDivisor] = result; + } + removeUpstream(upstream) { + const upstreamOrigin = parseOrigin(upstream).origin; + const pool = this[kClients].find((pool2) => pool2[kUrl].origin === upstreamOrigin && pool2.closed !== true && pool2.destroyed !== true); + if (pool) { + this[kRemoveClient](pool); + } + return this; + } + get upstreams() { + return this[kClients].filter((dispatcher) => dispatcher.closed !== true && dispatcher.destroyed !== true).map((p) => p[kUrl].origin); + } + [kGetDispatcher]() { + if (this[kClients].length === 0) { + throw new BalancedPoolMissingUpstreamError(); + } + const dispatcher = this[kClients].find((dispatcher2) => !dispatcher2[kNeedDrain] && dispatcher2.closed !== true && dispatcher2.destroyed !== true); + if (!dispatcher) { + return; + } + const allClientsBusy = this[kClients].map((pool) => pool[kNeedDrain]).reduce((a, b) => a && b, true); + if (allClientsBusy) { + return; + } + let counter = 0; + let maxWeightIndex = this[kClients].findIndex((pool) => !pool[kNeedDrain]); + while (counter++ < this[kClients].length) { + this[kIndex] = (this[kIndex] + 1) % this[kClients].length; + const pool = this[kClients][this[kIndex]]; + if (pool[kWeight] > this[kClients][maxWeightIndex][kWeight] && !pool[kNeedDrain]) { + maxWeightIndex = this[kIndex]; + } + if (this[kIndex] === 0) { + this[kCurrentWeight] = this[kCurrentWeight] - this[kGreatestCommonDivisor]; + if (this[kCurrentWeight] <= 0) { + this[kCurrentWeight] = this[kMaxWeightPerServer]; + } + } + if (pool[kWeight] >= this[kCurrentWeight] && !pool[kNeedDrain]) { + return pool; + } + } + this[kCurrentWeight] = this[kClients][maxWeightIndex][kWeight]; + this[kIndex] = maxWeightIndex; + return this[kClients][maxWeightIndex]; + } + }; + module.exports = BalancedPool; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/agent.js +var require_agent = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/agent.js"(exports, module) { + "use strict"; + var { InvalidArgumentError } = require_errors(); + var { kClients, kRunning, kClose, kDestroy, kDispatch, kInterceptors } = require_symbols(); + var DispatcherBase = require_dispatcher_base(); + var Pool = require_pool(); + var Client = require_client(); + var util = require_util(); + var createRedirectInterceptor = require_redirect_interceptor(); + var kOnConnect = /* @__PURE__ */ Symbol("onConnect"); + var kOnDisconnect = /* @__PURE__ */ Symbol("onDisconnect"); + var kOnConnectionError = /* @__PURE__ */ Symbol("onConnectionError"); + var kMaxRedirections = /* @__PURE__ */ Symbol("maxRedirections"); + var kOnDrain = /* @__PURE__ */ Symbol("onDrain"); + var kFactory = /* @__PURE__ */ Symbol("factory"); + var kOptions = /* @__PURE__ */ Symbol("options"); + function defaultFactory(origin, opts) { + return opts && opts.connections === 1 ? new Client(origin, opts) : new Pool(origin, opts); + } + var Agent = class extends DispatcherBase { + constructor({ factory = defaultFactory, maxRedirections = 0, connect, ...options } = {}) { + if (typeof factory !== "function") { + throw new InvalidArgumentError("factory must be a function."); + } + if (connect != null && typeof connect !== "function" && typeof connect !== "object") { + throw new InvalidArgumentError("connect must be a function or an object"); + } + if (!Number.isInteger(maxRedirections) || maxRedirections < 0) { + throw new InvalidArgumentError("maxRedirections must be a positive number"); + } + super(options); + if (connect && typeof connect !== "function") { + connect = { ...connect }; + } + this[kInterceptors] = options.interceptors?.Agent && Array.isArray(options.interceptors.Agent) ? options.interceptors.Agent : [createRedirectInterceptor({ maxRedirections })]; + this[kOptions] = { ...util.deepClone(options), connect }; + this[kOptions].interceptors = options.interceptors ? { ...options.interceptors } : void 0; + this[kMaxRedirections] = maxRedirections; + this[kFactory] = factory; + this[kClients] = /* @__PURE__ */ new Map(); + this[kOnDrain] = (origin, targets) => { + this.emit("drain", origin, [this, ...targets]); + }; + this[kOnConnect] = (origin, targets) => { + this.emit("connect", origin, [this, ...targets]); + }; + this[kOnDisconnect] = (origin, targets, err) => { + this.emit("disconnect", origin, [this, ...targets], err); + }; + this[kOnConnectionError] = (origin, targets, err) => { + this.emit("connectionError", origin, [this, ...targets], err); + }; + } + get [kRunning]() { + let ret = 0; + for (const client of this[kClients].values()) { + ret += client[kRunning]; + } + return ret; + } + [kDispatch](opts, handler) { + let key; + if (opts.origin && (typeof opts.origin === "string" || opts.origin instanceof URL)) { + key = String(opts.origin); + } else { + throw new InvalidArgumentError("opts.origin must be a non-empty string or URL."); + } + let dispatcher = this[kClients].get(key); + if (!dispatcher) { + dispatcher = this[kFactory](opts.origin, this[kOptions]).on("drain", this[kOnDrain]).on("connect", this[kOnConnect]).on("disconnect", this[kOnDisconnect]).on("connectionError", this[kOnConnectionError]); + this[kClients].set(key, dispatcher); + } + return dispatcher.dispatch(opts, handler); + } + async [kClose]() { + const closePromises = []; + for (const client of this[kClients].values()) { + closePromises.push(client.close()); + } + this[kClients].clear(); + await Promise.all(closePromises); + } + async [kDestroy](err) { + const destroyPromises = []; + for (const client of this[kClients].values()) { + destroyPromises.push(client.destroy(err)); + } + this[kClients].clear(); + await Promise.all(destroyPromises); + } + }; + module.exports = Agent; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/proxy-agent.js +var require_proxy_agent = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/proxy-agent.js"(exports, module) { + "use strict"; + var { kProxy, kClose, kDestroy, kDispatch, kInterceptors } = require_symbols(); + var { URL: URL2 } = __require("node:url"); + var Agent = require_agent(); + var Pool = require_pool(); + var DispatcherBase = require_dispatcher_base(); + var { InvalidArgumentError, RequestAbortedError, SecureProxyConnectionError } = require_errors(); + var buildConnector = require_connect(); + var Client = require_client(); + var kAgent = /* @__PURE__ */ Symbol("proxy agent"); + var kClient = /* @__PURE__ */ Symbol("proxy client"); + var kProxyHeaders = /* @__PURE__ */ Symbol("proxy headers"); + var kRequestTls = /* @__PURE__ */ Symbol("request tls settings"); + var kProxyTls = /* @__PURE__ */ Symbol("proxy tls settings"); + var kConnectEndpoint = /* @__PURE__ */ Symbol("connect endpoint function"); + var kTunnelProxy = /* @__PURE__ */ Symbol("tunnel proxy"); + function defaultProtocolPort(protocol) { + return protocol === "https:" ? 443 : 80; + } + function defaultFactory(origin, opts) { + return new Pool(origin, opts); + } + var noop = () => { + }; + function defaultAgentFactory(origin, opts) { + if (opts.connections === 1) { + return new Client(origin, opts); + } + return new Pool(origin, opts); + } + var Http1ProxyWrapper = class extends DispatcherBase { + #client; + constructor(proxyUrl, { headers = {}, connect, factory }) { + super(); + if (!proxyUrl) { + throw new InvalidArgumentError("Proxy URL is mandatory"); + } + this[kProxyHeaders] = headers; + if (factory) { + this.#client = factory(proxyUrl, { connect }); + } else { + this.#client = new Client(proxyUrl, { connect }); + } + } + [kDispatch](opts, handler) { + const onHeaders = handler.onHeaders; + handler.onHeaders = function(statusCode, data, resume) { + if (statusCode === 407) { + if (typeof handler.onError === "function") { + handler.onError(new InvalidArgumentError("Proxy Authentication Required (407)")); + } + return; + } + if (onHeaders) onHeaders.call(this, statusCode, data, resume); + }; + const { + origin, + path: path12 = "/", + headers = {} + } = opts; + opts.path = origin + path12; + if (!("host" in headers) && !("Host" in headers)) { + const { host: host2 } = new URL2(origin); + headers.host = host2; + } + opts.headers = { ...this[kProxyHeaders], ...headers }; + return this.#client[kDispatch](opts, handler); + } + async [kClose]() { + return this.#client.close(); + } + async [kDestroy](err) { + return this.#client.destroy(err); + } + }; + var ProxyAgent = class extends DispatcherBase { + constructor(opts) { + super(); + if (!opts || typeof opts === "object" && !(opts instanceof URL2) && !opts.uri) { + throw new InvalidArgumentError("Proxy uri is mandatory"); + } + const { clientFactory = defaultFactory } = opts; + if (typeof clientFactory !== "function") { + throw new InvalidArgumentError("Proxy opts.clientFactory must be a function."); + } + const { proxyTunnel = true } = opts; + const url = this.#getUrl(opts); + const { href, origin, port: port2, protocol, username, password, hostname: proxyHostname } = url; + this[kProxy] = { uri: href, protocol }; + this[kInterceptors] = opts.interceptors?.ProxyAgent && Array.isArray(opts.interceptors.ProxyAgent) ? opts.interceptors.ProxyAgent : []; + this[kRequestTls] = opts.requestTls; + this[kProxyTls] = opts.proxyTls; + this[kProxyHeaders] = opts.headers || {}; + this[kTunnelProxy] = proxyTunnel; + if (opts.auth && opts.token) { + throw new InvalidArgumentError("opts.auth cannot be used in combination with opts.token"); + } else if (opts.auth) { + this[kProxyHeaders]["proxy-authorization"] = `Basic ${opts.auth}`; + } else if (opts.token) { + this[kProxyHeaders]["proxy-authorization"] = opts.token; + } else if (username && password) { + this[kProxyHeaders]["proxy-authorization"] = `Basic ${Buffer.from(`${decodeURIComponent(username)}:${decodeURIComponent(password)}`).toString("base64")}`; + } + const connect = buildConnector({ ...opts.proxyTls }); + this[kConnectEndpoint] = buildConnector({ ...opts.requestTls }); + const agentFactory = opts.factory || defaultAgentFactory; + const factory = (origin2, options) => { + const { protocol: protocol2 } = new URL2(origin2); + if (!this[kTunnelProxy] && protocol2 === "http:" && this[kProxy].protocol === "http:") { + return new Http1ProxyWrapper(this[kProxy].uri, { + headers: this[kProxyHeaders], + connect, + factory: agentFactory + }); + } + return agentFactory(origin2, options); + }; + this[kClient] = clientFactory(url, { connect }); + this[kAgent] = new Agent({ + ...opts, + factory, + connect: async (opts2, callback) => { + let requestedPath = opts2.host; + if (!opts2.port) { + requestedPath += `:${defaultProtocolPort(opts2.protocol)}`; + } + try { + const { socket, statusCode } = await this[kClient].connect({ + origin, + port: port2, + path: requestedPath, + signal: opts2.signal, + headers: { + ...this[kProxyHeaders], + host: opts2.host + }, + servername: this[kProxyTls]?.servername || proxyHostname + }); + if (statusCode !== 200) { + socket.on("error", noop).destroy(); + callback(new RequestAbortedError(`Proxy response (${statusCode}) !== 200 when HTTP Tunneling`)); + } + if (opts2.protocol !== "https:") { + callback(null, socket); + return; + } + let servername; + if (this[kRequestTls]) { + servername = this[kRequestTls].servername; + } else { + servername = opts2.servername; + } + this[kConnectEndpoint]({ ...opts2, servername, httpSocket: socket }, callback); + } catch (err) { + if (err.code === "ERR_TLS_CERT_ALTNAME_INVALID") { + callback(new SecureProxyConnectionError(err)); + } else { + callback(err); + } + } + } + }); + } + dispatch(opts, handler) { + const headers = buildHeaders(opts.headers); + throwIfProxyAuthIsSent(headers); + if (headers && !("host" in headers) && !("Host" in headers)) { + const { host: host2 } = new URL2(opts.origin); + headers.host = host2; + } + return this[kAgent].dispatch( + { + ...opts, + headers + }, + handler + ); + } + /** + * @param {import('../types/proxy-agent').ProxyAgent.Options | string | URL} opts + * @returns {URL} + */ + #getUrl(opts) { + if (typeof opts === "string") { + return new URL2(opts); + } else if (opts instanceof URL2) { + return opts; + } else { + return new URL2(opts.uri); + } + } + async [kClose]() { + await this[kAgent].close(); + await this[kClient].close(); + } + async [kDestroy]() { + await this[kAgent].destroy(); + await this[kClient].destroy(); + } + }; + function buildHeaders(headers) { + if (Array.isArray(headers)) { + const headersPair = {}; + for (let i = 0; i < headers.length; i += 2) { + headersPair[headers[i]] = headers[i + 1]; + } + return headersPair; + } + return headers; + } + function throwIfProxyAuthIsSent(headers) { + const existProxyAuth = headers && Object.keys(headers).find((key) => key.toLowerCase() === "proxy-authorization"); + if (existProxyAuth) { + throw new InvalidArgumentError("Proxy-Authorization should be sent in ProxyAgent constructor"); + } + } + module.exports = ProxyAgent; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js +var require_env_http_proxy_agent = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/env-http-proxy-agent.js"(exports, module) { + "use strict"; + var DispatcherBase = require_dispatcher_base(); + var { kClose, kDestroy, kClosed, kDestroyed, kDispatch, kNoProxyAgent, kHttpProxyAgent, kHttpsProxyAgent } = require_symbols(); + var ProxyAgent = require_proxy_agent(); + var Agent = require_agent(); + var DEFAULT_PORTS = { + "http:": 80, + "https:": 443 + }; + var experimentalWarned = false; + var EnvHttpProxyAgent = class extends DispatcherBase { + #noProxyValue = null; + #noProxyEntries = null; + #opts = null; + constructor(opts = {}) { + super(); + this.#opts = opts; + if (!experimentalWarned) { + experimentalWarned = true; + process.emitWarning("EnvHttpProxyAgent is experimental, expect them to change at any time.", { + code: "UNDICI-EHPA" + }); + } + const { httpProxy, httpsProxy, noProxy, ...agentOpts } = opts; + this[kNoProxyAgent] = new Agent(agentOpts); + const HTTP_PROXY = httpProxy ?? process.env.http_proxy ?? process.env.HTTP_PROXY; + if (HTTP_PROXY) { + this[kHttpProxyAgent] = new ProxyAgent({ ...agentOpts, uri: HTTP_PROXY }); + } else { + this[kHttpProxyAgent] = this[kNoProxyAgent]; + } + const HTTPS_PROXY = httpsProxy ?? process.env.https_proxy ?? process.env.HTTPS_PROXY; + if (HTTPS_PROXY) { + this[kHttpsProxyAgent] = new ProxyAgent({ ...agentOpts, uri: HTTPS_PROXY }); + } else { + this[kHttpsProxyAgent] = this[kHttpProxyAgent]; + } + this.#parseNoProxy(); + } + [kDispatch](opts, handler) { + const url = new URL(opts.origin); + const agent = this.#getProxyAgentForUrl(url); + return agent.dispatch(opts, handler); + } + async [kClose]() { + await this[kNoProxyAgent].close(); + if (!this[kHttpProxyAgent][kClosed]) { + await this[kHttpProxyAgent].close(); + } + if (!this[kHttpsProxyAgent][kClosed]) { + await this[kHttpsProxyAgent].close(); + } + } + async [kDestroy](err) { + await this[kNoProxyAgent].destroy(err); + if (!this[kHttpProxyAgent][kDestroyed]) { + await this[kHttpProxyAgent].destroy(err); + } + if (!this[kHttpsProxyAgent][kDestroyed]) { + await this[kHttpsProxyAgent].destroy(err); + } + } + #getProxyAgentForUrl(url) { + let { protocol, host: hostname, port: port2 } = url; + hostname = hostname.replace(/:\d*$/, "").toLowerCase(); + port2 = Number.parseInt(port2, 10) || DEFAULT_PORTS[protocol] || 0; + if (!this.#shouldProxy(hostname, port2)) { + return this[kNoProxyAgent]; + } + if (protocol === "https:") { + return this[kHttpsProxyAgent]; + } + return this[kHttpProxyAgent]; + } + #shouldProxy(hostname, port2) { + if (this.#noProxyChanged) { + this.#parseNoProxy(); + } + if (this.#noProxyEntries.length === 0) { + return true; + } + if (this.#noProxyValue === "*") { + return false; + } + for (let i = 0; i < this.#noProxyEntries.length; i++) { + const entry = this.#noProxyEntries[i]; + if (entry.port && entry.port !== port2) { + continue; + } + if (!/^[.*]/.test(entry.hostname)) { + if (hostname === entry.hostname) { + return false; + } + } else { + if (hostname.endsWith(entry.hostname.replace(/^\*/, ""))) { + return false; + } + } + } + return true; + } + #parseNoProxy() { + const noProxyValue = this.#opts.noProxy ?? this.#noProxyEnv; + const noProxySplit = noProxyValue.split(/[,\s]/); + const noProxyEntries = []; + for (let i = 0; i < noProxySplit.length; i++) { + const entry = noProxySplit[i]; + if (!entry) { + continue; + } + const parsed = entry.match(/^(.+):(\d+)$/); + noProxyEntries.push({ + hostname: (parsed ? parsed[1] : entry).toLowerCase(), + port: parsed ? Number.parseInt(parsed[2], 10) : 0 + }); + } + this.#noProxyValue = noProxyValue; + this.#noProxyEntries = noProxyEntries; + } + get #noProxyChanged() { + if (this.#opts.noProxy !== void 0) { + return false; + } + return this.#noProxyValue !== this.#noProxyEnv; + } + get #noProxyEnv() { + return process.env.no_proxy ?? process.env.NO_PROXY ?? ""; + } + }; + module.exports = EnvHttpProxyAgent; + } +}); + +// viewer/node_modules/undici/lib/handler/retry-handler.js +var require_retry_handler = __commonJS({ + "viewer/node_modules/undici/lib/handler/retry-handler.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var { kRetryHandlerDefaultRetry } = require_symbols(); + var { RequestRetryError } = require_errors(); + var { + isDisturbed, + parseHeaders, + parseRangeHeader, + wrapRequestBody + } = require_util(); + function calculateRetryAfterHeader(retryAfter) { + const current = Date.now(); + return new Date(retryAfter).getTime() - current; + } + var RetryHandler = class _RetryHandler { + constructor(opts, handlers) { + const { retryOptions, ...dispatchOpts } = opts; + const { + // Retry scoped + retry: retryFn, + maxRetries, + maxTimeout, + minTimeout, + timeoutFactor, + // Response scoped + methods, + errorCodes, + retryAfter, + statusCodes + } = retryOptions ?? {}; + this.dispatch = handlers.dispatch; + this.handler = handlers.handler; + this.opts = { ...dispatchOpts, body: wrapRequestBody(opts.body) }; + this.abort = null; + this.aborted = false; + this.retryOpts = { + retry: retryFn ?? _RetryHandler[kRetryHandlerDefaultRetry], + retryAfter: retryAfter ?? true, + maxTimeout: maxTimeout ?? 30 * 1e3, + // 30s, + minTimeout: minTimeout ?? 500, + // .5s + timeoutFactor: timeoutFactor ?? 2, + maxRetries: maxRetries ?? 5, + // What errors we should retry + methods: methods ?? ["GET", "HEAD", "OPTIONS", "PUT", "DELETE", "TRACE"], + // Indicates which errors to retry + statusCodes: statusCodes ?? [500, 502, 503, 504, 429], + // List of errors to retry + errorCodes: errorCodes ?? [ + "ECONNRESET", + "ECONNREFUSED", + "ENOTFOUND", + "ENETDOWN", + "ENETUNREACH", + "EHOSTDOWN", + "EHOSTUNREACH", + "EPIPE", + "UND_ERR_SOCKET" + ] + }; + this.retryCount = 0; + this.retryCountCheckpoint = 0; + this.start = 0; + this.end = null; + this.etag = null; + this.resume = null; + this.handler.onConnect((reason) => { + this.aborted = true; + if (this.abort) { + this.abort(reason); + } else { + this.reason = reason; + } + }); + } + onRequestSent() { + if (this.handler.onRequestSent) { + this.handler.onRequestSent(); + } + } + onUpgrade(statusCode, headers, socket) { + if (this.handler.onUpgrade) { + this.handler.onUpgrade(statusCode, headers, socket); + } + } + onConnect(abort) { + if (this.aborted) { + abort(this.reason); + } else { + this.abort = abort; + } + } + onBodySent(chunk) { + if (this.handler.onBodySent) return this.handler.onBodySent(chunk); + } + static [kRetryHandlerDefaultRetry](err, { state, opts }, cb) { + const { statusCode, code, headers } = err; + const { method, retryOptions } = opts; + const { + maxRetries, + minTimeout, + maxTimeout, + timeoutFactor, + statusCodes, + errorCodes, + methods + } = retryOptions; + const { counter } = state; + if (code && code !== "UND_ERR_REQ_RETRY" && !errorCodes.includes(code)) { + cb(err); + return; + } + if (Array.isArray(methods) && !methods.includes(method)) { + cb(err); + return; + } + if (statusCode != null && Array.isArray(statusCodes) && !statusCodes.includes(statusCode)) { + cb(err); + return; + } + if (counter > maxRetries) { + cb(err); + return; + } + let retryAfterHeader = headers?.["retry-after"]; + if (retryAfterHeader) { + retryAfterHeader = Number(retryAfterHeader); + retryAfterHeader = Number.isNaN(retryAfterHeader) ? calculateRetryAfterHeader(retryAfterHeader) : retryAfterHeader * 1e3; + } + const retryTimeout = retryAfterHeader > 0 ? Math.min(retryAfterHeader, maxTimeout) : Math.min(minTimeout * timeoutFactor ** (counter - 1), maxTimeout); + setTimeout(() => cb(null), retryTimeout); + } + onHeaders(statusCode, rawHeaders, resume, statusMessage) { + const headers = parseHeaders(rawHeaders); + this.retryCount += 1; + if (statusCode >= 300) { + if (this.retryOpts.statusCodes.includes(statusCode) === false) { + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ); + } else { + this.abort( + new RequestRetryError("Request failed", statusCode, { + headers, + data: { + count: this.retryCount + } + }) + ); + return false; + } + } + if (this.resume != null) { + this.resume = null; + if (statusCode !== 206 && (this.start > 0 || statusCode !== 200)) { + this.abort( + new RequestRetryError("server does not support the range header and the payload was partially consumed", statusCode, { + headers, + data: { count: this.retryCount } + }) + ); + return false; + } + const contentRange = parseRangeHeader(headers["content-range"]); + if (!contentRange) { + this.abort( + new RequestRetryError("Content-Range mismatch", statusCode, { + headers, + data: { count: this.retryCount } + }) + ); + return false; + } + if (this.etag != null && this.etag !== headers.etag) { + this.abort( + new RequestRetryError("ETag mismatch", statusCode, { + headers, + data: { count: this.retryCount } + }) + ); + return false; + } + const { start, size, end = size - 1 } = contentRange; + assert(this.start === start, "content-range mismatch"); + assert(this.end == null || this.end === end, "content-range mismatch"); + this.resume = resume; + return true; + } + if (this.end == null) { + if (statusCode === 206) { + const range = parseRangeHeader(headers["content-range"]); + if (range == null) { + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ); + } + const { start, size, end = size - 1 } = range; + assert( + start != null && Number.isFinite(start), + "content-range mismatch" + ); + assert(end != null && Number.isFinite(end), "invalid content-length"); + this.start = start; + this.end = end; + } + if (this.end == null) { + const contentLength = headers["content-length"]; + this.end = contentLength != null ? Number(contentLength) - 1 : null; + } + assert(Number.isFinite(this.start)); + assert( + this.end == null || Number.isFinite(this.end), + "invalid content-length" + ); + this.resume = resume; + this.etag = headers.etag != null ? headers.etag : null; + if (this.etag != null && this.etag.startsWith("W/")) { + this.etag = null; + } + return this.handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ); + } + const err = new RequestRetryError("Request failed", statusCode, { + headers, + data: { count: this.retryCount } + }); + this.abort(err); + return false; + } + onData(chunk) { + this.start += chunk.length; + return this.handler.onData(chunk); + } + onComplete(rawTrailers) { + this.retryCount = 0; + return this.handler.onComplete(rawTrailers); + } + onError(err) { + if (this.aborted || isDisturbed(this.opts.body)) { + return this.handler.onError(err); + } + if (this.retryCount - this.retryCountCheckpoint > 0) { + this.retryCount = this.retryCountCheckpoint + (this.retryCount - this.retryCountCheckpoint); + } else { + this.retryCount += 1; + } + this.retryOpts.retry( + err, + { + state: { counter: this.retryCount }, + opts: { retryOptions: this.retryOpts, ...this.opts } + }, + onRetry.bind(this) + ); + function onRetry(err2) { + if (err2 != null || this.aborted || isDisturbed(this.opts.body)) { + return this.handler.onError(err2); + } + if (this.start !== 0) { + const headers = { range: `bytes=${this.start}-${this.end ?? ""}` }; + if (this.etag != null) { + headers["if-match"] = this.etag; + } + this.opts = { + ...this.opts, + headers: { + ...this.opts.headers, + ...headers + } + }; + } + try { + this.retryCountCheckpoint = this.retryCount; + this.dispatch(this.opts, this); + } catch (err3) { + this.handler.onError(err3); + } + } + } + }; + module.exports = RetryHandler; + } +}); + +// viewer/node_modules/undici/lib/dispatcher/retry-agent.js +var require_retry_agent = __commonJS({ + "viewer/node_modules/undici/lib/dispatcher/retry-agent.js"(exports, module) { + "use strict"; + var Dispatcher = require_dispatcher(); + var RetryHandler = require_retry_handler(); + var RetryAgent = class extends Dispatcher { + #agent = null; + #options = null; + constructor(agent, options = {}) { + super(options); + this.#agent = agent; + this.#options = options; + } + dispatch(opts, handler) { + const retry2 = new RetryHandler({ + ...opts, + retryOptions: this.#options + }, { + dispatch: this.#agent.dispatch.bind(this.#agent), + handler + }); + return this.#agent.dispatch(opts, retry2); + } + close() { + return this.#agent.close(); + } + destroy() { + return this.#agent.destroy(); + } + }; + module.exports = RetryAgent; + } +}); + +// viewer/node_modules/undici/lib/api/readable.js +var require_readable = __commonJS({ + "viewer/node_modules/undici/lib/api/readable.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var { Readable: Readable2 } = __require("node:stream"); + var { RequestAbortedError, NotSupportedError, InvalidArgumentError, AbortError } = require_errors(); + var util = require_util(); + var { ReadableStreamFrom } = require_util(); + var kConsume = /* @__PURE__ */ Symbol("kConsume"); + var kReading = /* @__PURE__ */ Symbol("kReading"); + var kBody = /* @__PURE__ */ Symbol("kBody"); + var kAbort = /* @__PURE__ */ Symbol("kAbort"); + var kContentType = /* @__PURE__ */ Symbol("kContentType"); + var kContentLength = /* @__PURE__ */ Symbol("kContentLength"); + var noop = () => { + }; + var BodyReadable = class extends Readable2 { + constructor({ + resume, + abort, + contentType = "", + contentLength, + highWaterMark = 64 * 1024 + // Same as nodejs fs streams. + }) { + super({ + autoDestroy: true, + read: resume, + highWaterMark + }); + this._readableState.dataEmitted = false; + this[kAbort] = abort; + this[kConsume] = null; + this[kBody] = null; + this[kContentType] = contentType; + this[kContentLength] = contentLength; + this[kReading] = false; + } + destroy(err) { + if (!err && !this._readableState.endEmitted) { + err = new RequestAbortedError(); + } + if (err) { + this[kAbort](); + } + return super.destroy(err); + } + _destroy(err, callback) { + if (!this[kReading]) { + setImmediate(() => { + callback(err); + }); + } else { + callback(err); + } + } + on(ev, ...args) { + if (ev === "data" || ev === "readable") { + this[kReading] = true; + } + return super.on(ev, ...args); + } + addListener(ev, ...args) { + return this.on(ev, ...args); + } + off(ev, ...args) { + const ret = super.off(ev, ...args); + if (ev === "data" || ev === "readable") { + this[kReading] = this.listenerCount("data") > 0 || this.listenerCount("readable") > 0; + } + return ret; + } + removeListener(ev, ...args) { + return this.off(ev, ...args); + } + push(chunk) { + if (this[kConsume] && chunk !== null) { + consumePush(this[kConsume], chunk); + return this[kReading] ? super.push(chunk) : true; + } + return super.push(chunk); + } + // https://fetch.spec.whatwg.org/#dom-body-text + async text() { + return consume(this, "text"); + } + // https://fetch.spec.whatwg.org/#dom-body-json + async json() { + return consume(this, "json"); + } + // https://fetch.spec.whatwg.org/#dom-body-blob + async blob() { + return consume(this, "blob"); + } + // https://fetch.spec.whatwg.org/#dom-body-bytes + async bytes() { + return consume(this, "bytes"); + } + // https://fetch.spec.whatwg.org/#dom-body-arraybuffer + async arrayBuffer() { + return consume(this, "arrayBuffer"); + } + // https://fetch.spec.whatwg.org/#dom-body-formdata + async formData() { + throw new NotSupportedError(); + } + // https://fetch.spec.whatwg.org/#dom-body-bodyused + get bodyUsed() { + return util.isDisturbed(this); + } + // https://fetch.spec.whatwg.org/#dom-body-body + get body() { + if (!this[kBody]) { + this[kBody] = ReadableStreamFrom(this); + if (this[kConsume]) { + this[kBody].getReader(); + assert(this[kBody].locked); + } + } + return this[kBody]; + } + async dump(opts) { + let limit = Number.isFinite(opts?.limit) ? opts.limit : 128 * 1024; + const signal = opts?.signal; + if (signal != null && (typeof signal !== "object" || !("aborted" in signal))) { + throw new InvalidArgumentError("signal must be an AbortSignal"); + } + signal?.throwIfAborted(); + if (this._readableState.closeEmitted) { + return null; + } + return await new Promise((resolve, reject) => { + if (this[kContentLength] > limit) { + this.destroy(new AbortError()); + } + const onAbort = () => { + this.destroy(signal.reason ?? new AbortError()); + }; + signal?.addEventListener("abort", onAbort); + this.on("close", function() { + signal?.removeEventListener("abort", onAbort); + if (signal?.aborted) { + reject(signal.reason ?? new AbortError()); + } else { + resolve(null); + } + }).on("error", noop).on("data", function(chunk) { + limit -= chunk.length; + if (limit <= 0) { + this.destroy(); + } + }).resume(); + }); + } + }; + function isLocked(self) { + return self[kBody] && self[kBody].locked === true || self[kConsume]; + } + function isUnusable(self) { + return util.isDisturbed(self) || isLocked(self); + } + async function consume(stream, type) { + assert(!stream[kConsume]); + return new Promise((resolve, reject) => { + if (isUnusable(stream)) { + const rState = stream._readableState; + if (rState.destroyed && rState.closeEmitted === false) { + stream.on("error", (err) => { + reject(err); + }).on("close", () => { + reject(new TypeError("unusable")); + }); + } else { + reject(rState.errored ?? new TypeError("unusable")); + } + } else { + queueMicrotask(() => { + stream[kConsume] = { + type, + stream, + resolve, + reject, + length: 0, + body: [] + }; + stream.on("error", function(err) { + consumeFinish(this[kConsume], err); + }).on("close", function() { + if (this[kConsume].body !== null) { + consumeFinish(this[kConsume], new RequestAbortedError()); + } + }); + consumeStart(stream[kConsume]); + }); + } + }); + } + function consumeStart(consume2) { + if (consume2.body === null) { + return; + } + const { _readableState: state } = consume2.stream; + if (state.bufferIndex) { + const start = state.bufferIndex; + const end = state.buffer.length; + for (let n = start; n < end; n++) { + consumePush(consume2, state.buffer[n]); + } + } else { + for (const chunk of state.buffer) { + consumePush(consume2, chunk); + } + } + if (state.endEmitted) { + consumeEnd(this[kConsume]); + } else { + consume2.stream.on("end", function() { + consumeEnd(this[kConsume]); + }); + } + consume2.stream.resume(); + while (consume2.stream.read() != null) { + } + } + function chunksDecode(chunks, length) { + if (chunks.length === 0 || length === 0) { + return ""; + } + const buffer = chunks.length === 1 ? chunks[0] : Buffer.concat(chunks, length); + const bufferLength = buffer.length; + const start = bufferLength > 2 && buffer[0] === 239 && buffer[1] === 187 && buffer[2] === 191 ? 3 : 0; + return buffer.utf8Slice(start, bufferLength); + } + function chunksConcat(chunks, length) { + if (chunks.length === 0 || length === 0) { + return new Uint8Array(0); + } + if (chunks.length === 1) { + return new Uint8Array(chunks[0]); + } + const buffer = new Uint8Array(Buffer.allocUnsafeSlow(length).buffer); + let offset = 0; + for (let i = 0; i < chunks.length; ++i) { + const chunk = chunks[i]; + buffer.set(chunk, offset); + offset += chunk.length; + } + return buffer; + } + function consumeEnd(consume2) { + const { type, body, resolve, stream, length } = consume2; + try { + if (type === "text") { + resolve(chunksDecode(body, length)); + } else if (type === "json") { + resolve(JSON.parse(chunksDecode(body, length))); + } else if (type === "arrayBuffer") { + resolve(chunksConcat(body, length).buffer); + } else if (type === "blob") { + resolve(new Blob(body, { type: stream[kContentType] })); + } else if (type === "bytes") { + resolve(chunksConcat(body, length)); + } + consumeFinish(consume2); + } catch (err) { + stream.destroy(err); + } + } + function consumePush(consume2, chunk) { + consume2.length += chunk.length; + consume2.body.push(chunk); + } + function consumeFinish(consume2, err) { + if (consume2.body === null) { + return; + } + if (err) { + consume2.reject(err); + } else { + consume2.resolve(); + } + consume2.type = null; + consume2.stream = null; + consume2.resolve = null; + consume2.reject = null; + consume2.length = 0; + consume2.body = null; + } + module.exports = { Readable: BodyReadable, chunksDecode }; + } +}); + +// viewer/node_modules/undici/lib/api/util.js +var require_util3 = __commonJS({ + "viewer/node_modules/undici/lib/api/util.js"(exports, module) { + var assert = __require("node:assert"); + var { + ResponseStatusCodeError + } = require_errors(); + var { chunksDecode } = require_readable(); + var CHUNK_LIMIT = 128 * 1024; + async function getResolveErrorBodyCallback({ callback, body, contentType, statusCode, statusMessage, headers }) { + assert(body); + let chunks = []; + let length = 0; + try { + for await (const chunk of body) { + chunks.push(chunk); + length += chunk.length; + if (length > CHUNK_LIMIT) { + chunks = []; + length = 0; + break; + } + } + } catch { + chunks = []; + length = 0; + } + const message = `Response status code ${statusCode}${statusMessage ? `: ${statusMessage}` : ""}`; + if (statusCode === 204 || !contentType || !length) { + queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers))); + return; + } + const stackTraceLimit = Error.stackTraceLimit; + Error.stackTraceLimit = 0; + let payload; + try { + if (isContentTypeApplicationJson(contentType)) { + payload = JSON.parse(chunksDecode(chunks, length)); + } else if (isContentTypeText(contentType)) { + payload = chunksDecode(chunks, length); + } + } catch { + } finally { + Error.stackTraceLimit = stackTraceLimit; + } + queueMicrotask(() => callback(new ResponseStatusCodeError(message, statusCode, headers, payload))); + } + var isContentTypeApplicationJson = (contentType) => { + return contentType.length > 15 && contentType[11] === "/" && contentType[0] === "a" && contentType[1] === "p" && contentType[2] === "p" && contentType[3] === "l" && contentType[4] === "i" && contentType[5] === "c" && contentType[6] === "a" && contentType[7] === "t" && contentType[8] === "i" && contentType[9] === "o" && contentType[10] === "n" && contentType[12] === "j" && contentType[13] === "s" && contentType[14] === "o" && contentType[15] === "n"; + }; + var isContentTypeText = (contentType) => { + return contentType.length > 4 && contentType[4] === "/" && contentType[0] === "t" && contentType[1] === "e" && contentType[2] === "x" && contentType[3] === "t"; + }; + module.exports = { + getResolveErrorBodyCallback, + isContentTypeApplicationJson, + isContentTypeText + }; + } +}); + +// viewer/node_modules/undici/lib/api/api-request.js +var require_api_request = __commonJS({ + "viewer/node_modules/undici/lib/api/api-request.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var { Readable: Readable2 } = require_readable(); + var { InvalidArgumentError, RequestAbortedError } = require_errors(); + var util = require_util(); + var { getResolveErrorBodyCallback } = require_util3(); + var { AsyncResource } = __require("node:async_hooks"); + var RequestHandler = class extends AsyncResource { + constructor(opts, callback) { + if (!opts || typeof opts !== "object") { + throw new InvalidArgumentError("invalid opts"); + } + const { signal, method, opaque, body, onInfo, responseHeaders, throwOnError, highWaterMark } = opts; + try { + if (typeof callback !== "function") { + throw new InvalidArgumentError("invalid callback"); + } + if (highWaterMark && (typeof highWaterMark !== "number" || highWaterMark < 0)) { + throw new InvalidArgumentError("invalid highWaterMark"); + } + if (signal && typeof signal.on !== "function" && typeof signal.addEventListener !== "function") { + throw new InvalidArgumentError("signal must be an EventEmitter or EventTarget"); + } + if (method === "CONNECT") { + throw new InvalidArgumentError("invalid method"); + } + if (onInfo && typeof onInfo !== "function") { + throw new InvalidArgumentError("invalid onInfo callback"); + } + super("UNDICI_REQUEST"); + } catch (err) { + if (util.isStream(body)) { + util.destroy(body.on("error", util.nop), err); + } + throw err; + } + this.method = method; + this.responseHeaders = responseHeaders || null; + this.opaque = opaque || null; + this.callback = callback; + this.res = null; + this.abort = null; + this.body = body; + this.trailers = {}; + this.context = null; + this.onInfo = onInfo || null; + this.throwOnError = throwOnError; + this.highWaterMark = highWaterMark; + this.signal = signal; + this.reason = null; + this.removeAbortListener = null; + if (util.isStream(body)) { + body.on("error", (err) => { + this.onError(err); + }); + } + if (this.signal) { + if (this.signal.aborted) { + this.reason = this.signal.reason ?? new RequestAbortedError(); + } else { + this.removeAbortListener = util.addAbortListener(this.signal, () => { + this.reason = this.signal.reason ?? new RequestAbortedError(); + if (this.res) { + util.destroy(this.res.on("error", util.nop), this.reason); + } else if (this.abort) { + this.abort(this.reason); + } + if (this.removeAbortListener) { + this.res?.off("close", this.removeAbortListener); + this.removeAbortListener(); + this.removeAbortListener = null; + } + }); + } + } + } + onConnect(abort, context) { + if (this.reason) { + abort(this.reason); + return; + } + assert(this.callback); + this.abort = abort; + this.context = context; + } + onHeaders(statusCode, rawHeaders, resume, statusMessage) { + const { callback, opaque, abort, context, responseHeaders, highWaterMark } = this; + const headers = responseHeaders === "raw" ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders); + if (statusCode < 200) { + if (this.onInfo) { + this.onInfo({ statusCode, headers }); + } + return; + } + const parsedHeaders = responseHeaders === "raw" ? util.parseHeaders(rawHeaders) : headers; + const contentType = parsedHeaders["content-type"]; + const contentLength = parsedHeaders["content-length"]; + const res = new Readable2({ + resume, + abort, + contentType, + contentLength: this.method !== "HEAD" && contentLength ? Number(contentLength) : null, + highWaterMark + }); + if (this.removeAbortListener) { + res.on("close", this.removeAbortListener); + } + this.callback = null; + this.res = res; + if (callback !== null) { + if (this.throwOnError && statusCode >= 400) { + this.runInAsyncScope( + getResolveErrorBodyCallback, + null, + { callback, body: res, contentType, statusCode, statusMessage, headers } + ); + } else { + this.runInAsyncScope(callback, null, null, { + statusCode, + headers, + trailers: this.trailers, + opaque, + body: res, + context + }); + } + } + } + onData(chunk) { + return this.res.push(chunk); + } + onComplete(trailers) { + util.parseHeaders(trailers, this.trailers); + this.res.push(null); + } + onError(err) { + const { res, callback, body, opaque } = this; + if (callback) { + this.callback = null; + queueMicrotask(() => { + this.runInAsyncScope(callback, null, err, { opaque }); + }); + } + if (res) { + this.res = null; + queueMicrotask(() => { + util.destroy(res, err); + }); + } + if (body) { + this.body = null; + util.destroy(body, err); + } + if (this.removeAbortListener) { + res?.off("close", this.removeAbortListener); + this.removeAbortListener(); + this.removeAbortListener = null; + } + } + }; + function request(opts, callback) { + if (callback === void 0) { + return new Promise((resolve, reject) => { + request.call(this, opts, (err, data) => { + return err ? reject(err) : resolve(data); + }); + }); + } + try { + this.dispatch(opts, new RequestHandler(opts, callback)); + } catch (err) { + if (typeof callback !== "function") { + throw err; + } + const opaque = opts?.opaque; + queueMicrotask(() => callback(err, { opaque })); + } + } + module.exports = request; + module.exports.RequestHandler = RequestHandler; + } +}); + +// viewer/node_modules/undici/lib/api/abort-signal.js +var require_abort_signal = __commonJS({ + "viewer/node_modules/undici/lib/api/abort-signal.js"(exports, module) { + var { addAbortListener } = require_util(); + var { RequestAbortedError } = require_errors(); + var kListener = /* @__PURE__ */ Symbol("kListener"); + var kSignal = /* @__PURE__ */ Symbol("kSignal"); + function abort(self) { + if (self.abort) { + self.abort(self[kSignal]?.reason); + } else { + self.reason = self[kSignal]?.reason ?? new RequestAbortedError(); + } + removeSignal(self); + } + function addSignal(self, signal) { + self.reason = null; + self[kSignal] = null; + self[kListener] = null; + if (!signal) { + return; + } + if (signal.aborted) { + abort(self); + return; + } + self[kSignal] = signal; + self[kListener] = () => { + abort(self); + }; + addAbortListener(self[kSignal], self[kListener]); + } + function removeSignal(self) { + if (!self[kSignal]) { + return; + } + if ("removeEventListener" in self[kSignal]) { + self[kSignal].removeEventListener("abort", self[kListener]); + } else { + self[kSignal].removeListener("abort", self[kListener]); + } + self[kSignal] = null; + self[kListener] = null; + } + module.exports = { + addSignal, + removeSignal + }; + } +}); + +// viewer/node_modules/undici/lib/api/api-stream.js +var require_api_stream = __commonJS({ + "viewer/node_modules/undici/lib/api/api-stream.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var { finished, PassThrough } = __require("node:stream"); + var { InvalidArgumentError, InvalidReturnValueError } = require_errors(); + var util = require_util(); + var { getResolveErrorBodyCallback } = require_util3(); + var { AsyncResource } = __require("node:async_hooks"); + var { addSignal, removeSignal } = require_abort_signal(); + var StreamHandler = class extends AsyncResource { + constructor(opts, factory, callback) { + if (!opts || typeof opts !== "object") { + throw new InvalidArgumentError("invalid opts"); + } + const { signal, method, opaque, body, onInfo, responseHeaders, throwOnError } = opts; + try { + if (typeof callback !== "function") { + throw new InvalidArgumentError("invalid callback"); + } + if (typeof factory !== "function") { + throw new InvalidArgumentError("invalid factory"); + } + if (signal && typeof signal.on !== "function" && typeof signal.addEventListener !== "function") { + throw new InvalidArgumentError("signal must be an EventEmitter or EventTarget"); + } + if (method === "CONNECT") { + throw new InvalidArgumentError("invalid method"); + } + if (onInfo && typeof onInfo !== "function") { + throw new InvalidArgumentError("invalid onInfo callback"); + } + super("UNDICI_STREAM"); + } catch (err) { + if (util.isStream(body)) { + util.destroy(body.on("error", util.nop), err); + } + throw err; + } + this.responseHeaders = responseHeaders || null; + this.opaque = opaque || null; + this.factory = factory; + this.callback = callback; + this.res = null; + this.abort = null; + this.context = null; + this.trailers = null; + this.body = body; + this.onInfo = onInfo || null; + this.throwOnError = throwOnError || false; + if (util.isStream(body)) { + body.on("error", (err) => { + this.onError(err); + }); + } + addSignal(this, signal); + } + onConnect(abort, context) { + if (this.reason) { + abort(this.reason); + return; + } + assert(this.callback); + this.abort = abort; + this.context = context; + } + onHeaders(statusCode, rawHeaders, resume, statusMessage) { + const { factory, opaque, context, callback, responseHeaders } = this; + const headers = responseHeaders === "raw" ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders); + if (statusCode < 200) { + if (this.onInfo) { + this.onInfo({ statusCode, headers }); + } + return; + } + this.factory = null; + let res; + if (this.throwOnError && statusCode >= 400) { + const parsedHeaders = responseHeaders === "raw" ? util.parseHeaders(rawHeaders) : headers; + const contentType = parsedHeaders["content-type"]; + res = new PassThrough(); + this.callback = null; + this.runInAsyncScope( + getResolveErrorBodyCallback, + null, + { callback, body: res, contentType, statusCode, statusMessage, headers } + ); + } else { + if (factory === null) { + return; + } + res = this.runInAsyncScope(factory, null, { + statusCode, + headers, + opaque, + context + }); + if (!res || typeof res.write !== "function" || typeof res.end !== "function" || typeof res.on !== "function") { + throw new InvalidReturnValueError("expected Writable"); + } + finished(res, { readable: false }, (err) => { + const { callback: callback2, res: res2, opaque: opaque2, trailers, abort } = this; + this.res = null; + if (err || !res2.readable) { + util.destroy(res2, err); + } + this.callback = null; + this.runInAsyncScope(callback2, null, err || null, { opaque: opaque2, trailers }); + if (err) { + abort(); + } + }); + } + res.on("drain", resume); + this.res = res; + const needDrain = res.writableNeedDrain !== void 0 ? res.writableNeedDrain : res._writableState?.needDrain; + return needDrain !== true; + } + onData(chunk) { + const { res } = this; + return res ? res.write(chunk) : true; + } + onComplete(trailers) { + const { res } = this; + removeSignal(this); + if (!res) { + return; + } + this.trailers = util.parseHeaders(trailers); + res.end(); + } + onError(err) { + const { res, callback, opaque, body } = this; + removeSignal(this); + this.factory = null; + if (res) { + this.res = null; + util.destroy(res, err); + } else if (callback) { + this.callback = null; + queueMicrotask(() => { + this.runInAsyncScope(callback, null, err, { opaque }); + }); + } + if (body) { + this.body = null; + util.destroy(body, err); + } + } + }; + function stream(opts, factory, callback) { + if (callback === void 0) { + return new Promise((resolve, reject) => { + stream.call(this, opts, factory, (err, data) => { + return err ? reject(err) : resolve(data); + }); + }); + } + try { + this.dispatch(opts, new StreamHandler(opts, factory, callback)); + } catch (err) { + if (typeof callback !== "function") { + throw err; + } + const opaque = opts?.opaque; + queueMicrotask(() => callback(err, { opaque })); + } + } + module.exports = stream; + } +}); + +// viewer/node_modules/undici/lib/api/api-pipeline.js +var require_api_pipeline = __commonJS({ + "viewer/node_modules/undici/lib/api/api-pipeline.js"(exports, module) { + "use strict"; + var { + Readable: Readable2, + Duplex, + PassThrough + } = __require("node:stream"); + var { + InvalidArgumentError, + InvalidReturnValueError, + RequestAbortedError + } = require_errors(); + var util = require_util(); + var { AsyncResource } = __require("node:async_hooks"); + var { addSignal, removeSignal } = require_abort_signal(); + var assert = __require("node:assert"); + var kResume = /* @__PURE__ */ Symbol("resume"); + var PipelineRequest = class extends Readable2 { + constructor() { + super({ autoDestroy: true }); + this[kResume] = null; + } + _read() { + const { [kResume]: resume } = this; + if (resume) { + this[kResume] = null; + resume(); + } + } + _destroy(err, callback) { + this._read(); + callback(err); + } + }; + var PipelineResponse = class extends Readable2 { + constructor(resume) { + super({ autoDestroy: true }); + this[kResume] = resume; + } + _read() { + this[kResume](); + } + _destroy(err, callback) { + if (!err && !this._readableState.endEmitted) { + err = new RequestAbortedError(); + } + callback(err); + } + }; + var PipelineHandler = class extends AsyncResource { + constructor(opts, handler) { + if (!opts || typeof opts !== "object") { + throw new InvalidArgumentError("invalid opts"); + } + if (typeof handler !== "function") { + throw new InvalidArgumentError("invalid handler"); + } + const { signal, method, opaque, onInfo, responseHeaders } = opts; + if (signal && typeof signal.on !== "function" && typeof signal.addEventListener !== "function") { + throw new InvalidArgumentError("signal must be an EventEmitter or EventTarget"); + } + if (method === "CONNECT") { + throw new InvalidArgumentError("invalid method"); + } + if (onInfo && typeof onInfo !== "function") { + throw new InvalidArgumentError("invalid onInfo callback"); + } + super("UNDICI_PIPELINE"); + this.opaque = opaque || null; + this.responseHeaders = responseHeaders || null; + this.handler = handler; + this.abort = null; + this.context = null; + this.onInfo = onInfo || null; + this.req = new PipelineRequest().on("error", util.nop); + this.ret = new Duplex({ + readableObjectMode: opts.objectMode, + autoDestroy: true, + read: () => { + const { body } = this; + if (body?.resume) { + body.resume(); + } + }, + write: (chunk, encoding, callback) => { + const { req } = this; + if (req.push(chunk, encoding) || req._readableState.destroyed) { + callback(); + } else { + req[kResume] = callback; + } + }, + destroy: (err, callback) => { + const { body, req, res, ret, abort } = this; + if (!err && !ret._readableState.endEmitted) { + err = new RequestAbortedError(); + } + if (abort && err) { + abort(); + } + util.destroy(body, err); + util.destroy(req, err); + util.destroy(res, err); + removeSignal(this); + callback(err); + } + }).on("prefinish", () => { + const { req } = this; + req.push(null); + }); + this.res = null; + addSignal(this, signal); + } + onConnect(abort, context) { + const { ret, res } = this; + if (this.reason) { + abort(this.reason); + return; + } + assert(!res, "pipeline cannot be retried"); + assert(!ret.destroyed); + this.abort = abort; + this.context = context; + } + onHeaders(statusCode, rawHeaders, resume) { + const { opaque, handler, context } = this; + if (statusCode < 200) { + if (this.onInfo) { + const headers = this.responseHeaders === "raw" ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders); + this.onInfo({ statusCode, headers }); + } + return; + } + this.res = new PipelineResponse(resume); + let body; + try { + this.handler = null; + const headers = this.responseHeaders === "raw" ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders); + body = this.runInAsyncScope(handler, null, { + statusCode, + headers, + opaque, + body: this.res, + context + }); + } catch (err) { + this.res.on("error", util.nop); + throw err; + } + if (!body || typeof body.on !== "function") { + throw new InvalidReturnValueError("expected Readable"); + } + body.on("data", (chunk) => { + const { ret, body: body2 } = this; + if (!ret.push(chunk) && body2.pause) { + body2.pause(); + } + }).on("error", (err) => { + const { ret } = this; + util.destroy(ret, err); + }).on("end", () => { + const { ret } = this; + ret.push(null); + }).on("close", () => { + const { ret } = this; + if (!ret._readableState.ended) { + util.destroy(ret, new RequestAbortedError()); + } + }); + this.body = body; + } + onData(chunk) { + const { res } = this; + return res.push(chunk); + } + onComplete(trailers) { + const { res } = this; + res.push(null); + } + onError(err) { + const { ret } = this; + this.handler = null; + util.destroy(ret, err); + } + }; + function pipeline(opts, handler) { + try { + const pipelineHandler = new PipelineHandler(opts, handler); + this.dispatch({ ...opts, body: pipelineHandler.req }, pipelineHandler); + return pipelineHandler.ret; + } catch (err) { + return new PassThrough().destroy(err); + } + } + module.exports = pipeline; + } +}); + +// viewer/node_modules/undici/lib/api/api-upgrade.js +var require_api_upgrade = __commonJS({ + "viewer/node_modules/undici/lib/api/api-upgrade.js"(exports, module) { + "use strict"; + var { InvalidArgumentError, SocketError } = require_errors(); + var { AsyncResource } = __require("node:async_hooks"); + var util = require_util(); + var { addSignal, removeSignal } = require_abort_signal(); + var assert = __require("node:assert"); + var UpgradeHandler = class extends AsyncResource { + constructor(opts, callback) { + if (!opts || typeof opts !== "object") { + throw new InvalidArgumentError("invalid opts"); + } + if (typeof callback !== "function") { + throw new InvalidArgumentError("invalid callback"); + } + const { signal, opaque, responseHeaders } = opts; + if (signal && typeof signal.on !== "function" && typeof signal.addEventListener !== "function") { + throw new InvalidArgumentError("signal must be an EventEmitter or EventTarget"); + } + super("UNDICI_UPGRADE"); + this.responseHeaders = responseHeaders || null; + this.opaque = opaque || null; + this.callback = callback; + this.abort = null; + this.context = null; + addSignal(this, signal); + } + onConnect(abort, context) { + if (this.reason) { + abort(this.reason); + return; + } + assert(this.callback); + this.abort = abort; + this.context = null; + } + onHeaders() { + throw new SocketError("bad upgrade", null); + } + onUpgrade(statusCode, rawHeaders, socket) { + assert(statusCode === 101); + const { callback, opaque, context } = this; + removeSignal(this); + this.callback = null; + const headers = this.responseHeaders === "raw" ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders); + this.runInAsyncScope(callback, null, null, { + headers, + socket, + opaque, + context + }); + } + onError(err) { + const { callback, opaque } = this; + removeSignal(this); + if (callback) { + this.callback = null; + queueMicrotask(() => { + this.runInAsyncScope(callback, null, err, { opaque }); + }); + } + } + }; + function upgrade(opts, callback) { + if (callback === void 0) { + return new Promise((resolve, reject) => { + upgrade.call(this, opts, (err, data) => { + return err ? reject(err) : resolve(data); + }); + }); + } + try { + const upgradeHandler = new UpgradeHandler(opts, callback); + this.dispatch({ + ...opts, + method: opts.method || "GET", + upgrade: opts.protocol || "Websocket" + }, upgradeHandler); + } catch (err) { + if (typeof callback !== "function") { + throw err; + } + const opaque = opts?.opaque; + queueMicrotask(() => callback(err, { opaque })); + } + } + module.exports = upgrade; + } +}); + +// viewer/node_modules/undici/lib/api/api-connect.js +var require_api_connect = __commonJS({ + "viewer/node_modules/undici/lib/api/api-connect.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var { AsyncResource } = __require("node:async_hooks"); + var { InvalidArgumentError, SocketError } = require_errors(); + var util = require_util(); + var { addSignal, removeSignal } = require_abort_signal(); + var ConnectHandler = class extends AsyncResource { + constructor(opts, callback) { + if (!opts || typeof opts !== "object") { + throw new InvalidArgumentError("invalid opts"); + } + if (typeof callback !== "function") { + throw new InvalidArgumentError("invalid callback"); + } + const { signal, opaque, responseHeaders } = opts; + if (signal && typeof signal.on !== "function" && typeof signal.addEventListener !== "function") { + throw new InvalidArgumentError("signal must be an EventEmitter or EventTarget"); + } + super("UNDICI_CONNECT"); + this.opaque = opaque || null; + this.responseHeaders = responseHeaders || null; + this.callback = callback; + this.abort = null; + addSignal(this, signal); + } + onConnect(abort, context) { + if (this.reason) { + abort(this.reason); + return; + } + assert(this.callback); + this.abort = abort; + this.context = context; + } + onHeaders() { + throw new SocketError("bad connect", null); + } + onUpgrade(statusCode, rawHeaders, socket) { + const { callback, opaque, context } = this; + removeSignal(this); + this.callback = null; + let headers = rawHeaders; + if (headers != null) { + headers = this.responseHeaders === "raw" ? util.parseRawHeaders(rawHeaders) : util.parseHeaders(rawHeaders); + } + this.runInAsyncScope(callback, null, null, { + statusCode, + headers, + socket, + opaque, + context + }); + } + onError(err) { + const { callback, opaque } = this; + removeSignal(this); + if (callback) { + this.callback = null; + queueMicrotask(() => { + this.runInAsyncScope(callback, null, err, { opaque }); + }); + } + } + }; + function connect(opts, callback) { + if (callback === void 0) { + return new Promise((resolve, reject) => { + connect.call(this, opts, (err, data) => { + return err ? reject(err) : resolve(data); + }); + }); + } + try { + const connectHandler = new ConnectHandler(opts, callback); + this.dispatch({ ...opts, method: "CONNECT" }, connectHandler); + } catch (err) { + if (typeof callback !== "function") { + throw err; + } + const opaque = opts?.opaque; + queueMicrotask(() => callback(err, { opaque })); + } + } + module.exports = connect; + } +}); + +// viewer/node_modules/undici/lib/api/index.js +var require_api = __commonJS({ + "viewer/node_modules/undici/lib/api/index.js"(exports, module) { + "use strict"; + module.exports.request = require_api_request(); + module.exports.stream = require_api_stream(); + module.exports.pipeline = require_api_pipeline(); + module.exports.upgrade = require_api_upgrade(); + module.exports.connect = require_api_connect(); + } +}); + +// viewer/node_modules/undici/lib/mock/mock-errors.js +var require_mock_errors = __commonJS({ + "viewer/node_modules/undici/lib/mock/mock-errors.js"(exports, module) { + "use strict"; + var { UndiciError } = require_errors(); + var kMockNotMatchedError = /* @__PURE__ */ Symbol.for("undici.error.UND_MOCK_ERR_MOCK_NOT_MATCHED"); + var MockNotMatchedError = class _MockNotMatchedError extends UndiciError { + constructor(message) { + super(message); + Error.captureStackTrace(this, _MockNotMatchedError); + this.name = "MockNotMatchedError"; + this.message = message || "The request does not match any registered mock dispatches"; + this.code = "UND_MOCK_ERR_MOCK_NOT_MATCHED"; + } + static [Symbol.hasInstance](instance) { + return instance && instance[kMockNotMatchedError] === true; + } + [kMockNotMatchedError] = true; + }; + module.exports = { + MockNotMatchedError + }; + } +}); + +// viewer/node_modules/undici/lib/mock/mock-symbols.js +var require_mock_symbols = __commonJS({ + "viewer/node_modules/undici/lib/mock/mock-symbols.js"(exports, module) { + "use strict"; + module.exports = { + kAgent: /* @__PURE__ */ Symbol("agent"), + kOptions: /* @__PURE__ */ Symbol("options"), + kFactory: /* @__PURE__ */ Symbol("factory"), + kDispatches: /* @__PURE__ */ Symbol("dispatches"), + kDispatchKey: /* @__PURE__ */ Symbol("dispatch key"), + kDefaultHeaders: /* @__PURE__ */ Symbol("default headers"), + kDefaultTrailers: /* @__PURE__ */ Symbol("default trailers"), + kContentLength: /* @__PURE__ */ Symbol("content length"), + kMockAgent: /* @__PURE__ */ Symbol("mock agent"), + kMockAgentSet: /* @__PURE__ */ Symbol("mock agent set"), + kMockAgentGet: /* @__PURE__ */ Symbol("mock agent get"), + kMockDispatch: /* @__PURE__ */ Symbol("mock dispatch"), + kClose: /* @__PURE__ */ Symbol("close"), + kOriginalClose: /* @__PURE__ */ Symbol("original agent close"), + kOrigin: /* @__PURE__ */ Symbol("origin"), + kIsMockActive: /* @__PURE__ */ Symbol("is mock active"), + kNetConnect: /* @__PURE__ */ Symbol("net connect"), + kGetNetConnect: /* @__PURE__ */ Symbol("get net connect"), + kConnected: /* @__PURE__ */ Symbol("connected") + }; + } +}); + +// viewer/node_modules/undici/lib/mock/mock-utils.js +var require_mock_utils = __commonJS({ + "viewer/node_modules/undici/lib/mock/mock-utils.js"(exports, module) { + "use strict"; + var { MockNotMatchedError } = require_mock_errors(); + var { + kDispatches, + kMockAgent, + kOriginalDispatch, + kOrigin, + kGetNetConnect + } = require_mock_symbols(); + var { buildURL } = require_util(); + var { STATUS_CODES } = __require("node:http"); + var { + types: { + isPromise + } + } = __require("node:util"); + function matchValue(match, value) { + if (typeof match === "string") { + return match === value; + } + if (match instanceof RegExp) { + return match.test(value); + } + if (typeof match === "function") { + return match(value) === true; + } + return false; + } + function lowerCaseEntries(headers) { + return Object.fromEntries( + Object.entries(headers).map(([headerName, headerValue]) => { + return [headerName.toLocaleLowerCase(), headerValue]; + }) + ); + } + function getHeaderByName(headers, key) { + if (Array.isArray(headers)) { + for (let i = 0; i < headers.length; i += 2) { + if (headers[i].toLocaleLowerCase() === key.toLocaleLowerCase()) { + return headers[i + 1]; + } + } + return void 0; + } else if (typeof headers.get === "function") { + return headers.get(key); + } else { + return lowerCaseEntries(headers)[key.toLocaleLowerCase()]; + } + } + function buildHeadersFromArray(headers) { + const clone = headers.slice(); + const entries = []; + for (let index = 0; index < clone.length; index += 2) { + entries.push([clone[index], clone[index + 1]]); + } + return Object.fromEntries(entries); + } + function matchHeaders(mockDispatch2, headers) { + if (typeof mockDispatch2.headers === "function") { + if (Array.isArray(headers)) { + headers = buildHeadersFromArray(headers); + } + return mockDispatch2.headers(headers ? lowerCaseEntries(headers) : {}); + } + if (typeof mockDispatch2.headers === "undefined") { + return true; + } + if (typeof headers !== "object" || typeof mockDispatch2.headers !== "object") { + return false; + } + for (const [matchHeaderName, matchHeaderValue] of Object.entries(mockDispatch2.headers)) { + const headerValue = getHeaderByName(headers, matchHeaderName); + if (!matchValue(matchHeaderValue, headerValue)) { + return false; + } + } + return true; + } + function safeUrl(path12) { + if (typeof path12 !== "string") { + return path12; + } + const pathSegments = path12.split("?"); + if (pathSegments.length !== 2) { + return path12; + } + const qp = new URLSearchParams(pathSegments.pop()); + qp.sort(); + return [...pathSegments, qp.toString()].join("?"); + } + function matchKey(mockDispatch2, { path: path12, method, body, headers }) { + const pathMatch = matchValue(mockDispatch2.path, path12); + const methodMatch = matchValue(mockDispatch2.method, method); + const bodyMatch = typeof mockDispatch2.body !== "undefined" ? matchValue(mockDispatch2.body, body) : true; + const headersMatch = matchHeaders(mockDispatch2, headers); + return pathMatch && methodMatch && bodyMatch && headersMatch; + } + function getResponseData(data) { + if (Buffer.isBuffer(data)) { + return data; + } else if (data instanceof Uint8Array) { + return data; + } else if (data instanceof ArrayBuffer) { + return data; + } else if (typeof data === "object") { + return JSON.stringify(data); + } else { + return data.toString(); + } + } + function getMockDispatch(mockDispatches, key) { + const basePath = key.query ? buildURL(key.path, key.query) : key.path; + const resolvedPath = typeof basePath === "string" ? safeUrl(basePath) : basePath; + let matchedMockDispatches = mockDispatches.filter(({ consumed }) => !consumed).filter(({ path: path12 }) => matchValue(safeUrl(path12), resolvedPath)); + if (matchedMockDispatches.length === 0) { + throw new MockNotMatchedError(`Mock dispatch not matched for path '${resolvedPath}'`); + } + matchedMockDispatches = matchedMockDispatches.filter(({ method }) => matchValue(method, key.method)); + if (matchedMockDispatches.length === 0) { + throw new MockNotMatchedError(`Mock dispatch not matched for method '${key.method}' on path '${resolvedPath}'`); + } + matchedMockDispatches = matchedMockDispatches.filter(({ body }) => typeof body !== "undefined" ? matchValue(body, key.body) : true); + if (matchedMockDispatches.length === 0) { + throw new MockNotMatchedError(`Mock dispatch not matched for body '${key.body}' on path '${resolvedPath}'`); + } + matchedMockDispatches = matchedMockDispatches.filter((mockDispatch2) => matchHeaders(mockDispatch2, key.headers)); + if (matchedMockDispatches.length === 0) { + const headers = typeof key.headers === "object" ? JSON.stringify(key.headers) : key.headers; + throw new MockNotMatchedError(`Mock dispatch not matched for headers '${headers}' on path '${resolvedPath}'`); + } + return matchedMockDispatches[0]; + } + function addMockDispatch(mockDispatches, key, data) { + const baseData = { timesInvoked: 0, times: 1, persist: false, consumed: false }; + const replyData = typeof data === "function" ? { callback: data } : { ...data }; + const newMockDispatch = { ...baseData, ...key, pending: true, data: { error: null, ...replyData } }; + mockDispatches.push(newMockDispatch); + return newMockDispatch; + } + function deleteMockDispatch(mockDispatches, key) { + const index = mockDispatches.findIndex((dispatch) => { + if (!dispatch.consumed) { + return false; + } + return matchKey(dispatch, key); + }); + if (index !== -1) { + mockDispatches.splice(index, 1); + } + } + function buildKey(opts) { + const { path: path12, method, body, headers, query } = opts; + return { + path: path12, + method, + body, + headers, + query + }; + } + function generateKeyValues(data) { + const keys = Object.keys(data); + const result = []; + for (let i = 0; i < keys.length; ++i) { + const key = keys[i]; + const value = data[key]; + const name = Buffer.from(`${key}`); + if (Array.isArray(value)) { + for (let j = 0; j < value.length; ++j) { + result.push(name, Buffer.from(`${value[j]}`)); + } + } else { + result.push(name, Buffer.from(`${value}`)); + } + } + return result; + } + function getStatusText(statusCode) { + return STATUS_CODES[statusCode] || "unknown"; + } + async function getResponse(body) { + const buffers = []; + for await (const data of body) { + buffers.push(data); + } + return Buffer.concat(buffers).toString("utf8"); + } + function mockDispatch(opts, handler) { + const key = buildKey(opts); + const mockDispatch2 = getMockDispatch(this[kDispatches], key); + mockDispatch2.timesInvoked++; + if (mockDispatch2.data.callback) { + mockDispatch2.data = { ...mockDispatch2.data, ...mockDispatch2.data.callback(opts) }; + } + const { data: { statusCode, data, headers, trailers, error }, delay, persist } = mockDispatch2; + const { timesInvoked, times } = mockDispatch2; + mockDispatch2.consumed = !persist && timesInvoked >= times; + mockDispatch2.pending = timesInvoked < times; + if (error !== null) { + deleteMockDispatch(this[kDispatches], key); + handler.onError(error); + return true; + } + if (typeof delay === "number" && delay > 0) { + setTimeout(() => { + handleReply(this[kDispatches]); + }, delay); + } else { + handleReply(this[kDispatches]); + } + function handleReply(mockDispatches, _data = data) { + const optsHeaders = Array.isArray(opts.headers) ? buildHeadersFromArray(opts.headers) : opts.headers; + const body = typeof _data === "function" ? _data({ ...opts, headers: optsHeaders }) : _data; + if (isPromise(body)) { + body.then((newData) => handleReply(mockDispatches, newData)); + return; + } + const responseData = getResponseData(body); + const responseHeaders = generateKeyValues(headers); + const responseTrailers = generateKeyValues(trailers); + handler.onConnect?.((err) => handler.onError(err), null); + handler.onHeaders?.(statusCode, responseHeaders, resume, getStatusText(statusCode)); + handler.onData?.(Buffer.from(responseData)); + handler.onComplete?.(responseTrailers); + deleteMockDispatch(mockDispatches, key); + } + function resume() { + } + return true; + } + function buildMockDispatch() { + const agent = this[kMockAgent]; + const origin = this[kOrigin]; + const originalDispatch = this[kOriginalDispatch]; + return function dispatch(opts, handler) { + if (agent.isMockActive) { + try { + mockDispatch.call(this, opts, handler); + } catch (error) { + if (error instanceof MockNotMatchedError) { + const netConnect = agent[kGetNetConnect](); + if (netConnect === false) { + throw new MockNotMatchedError(`${error.message}: subsequent request to origin ${origin} was not allowed (net.connect disabled)`); + } + if (checkNetConnect(netConnect, origin)) { + originalDispatch.call(this, opts, handler); + } else { + throw new MockNotMatchedError(`${error.message}: subsequent request to origin ${origin} was not allowed (net.connect is not enabled for this origin)`); + } + } else { + throw error; + } + } + } else { + originalDispatch.call(this, opts, handler); + } + }; + } + function checkNetConnect(netConnect, origin) { + const url = new URL(origin); + if (netConnect === true) { + return true; + } else if (Array.isArray(netConnect) && netConnect.some((matcher) => matchValue(matcher, url.host))) { + return true; + } + return false; + } + function buildMockOptions(opts) { + if (opts) { + const { agent, ...mockOptions } = opts; + return mockOptions; + } + } + module.exports = { + getResponseData, + getMockDispatch, + addMockDispatch, + deleteMockDispatch, + buildKey, + generateKeyValues, + matchValue, + getResponse, + getStatusText, + mockDispatch, + buildMockDispatch, + checkNetConnect, + buildMockOptions, + getHeaderByName, + buildHeadersFromArray + }; + } +}); + +// viewer/node_modules/undici/lib/mock/mock-interceptor.js +var require_mock_interceptor = __commonJS({ + "viewer/node_modules/undici/lib/mock/mock-interceptor.js"(exports, module) { + "use strict"; + var { getResponseData, buildKey, addMockDispatch } = require_mock_utils(); + var { + kDispatches, + kDispatchKey, + kDefaultHeaders, + kDefaultTrailers, + kContentLength, + kMockDispatch + } = require_mock_symbols(); + var { InvalidArgumentError } = require_errors(); + var { buildURL } = require_util(); + var MockScope = class { + constructor(mockDispatch) { + this[kMockDispatch] = mockDispatch; + } + /** + * Delay a reply by a set amount in ms. + */ + delay(waitInMs) { + if (typeof waitInMs !== "number" || !Number.isInteger(waitInMs) || waitInMs <= 0) { + throw new InvalidArgumentError("waitInMs must be a valid integer > 0"); + } + this[kMockDispatch].delay = waitInMs; + return this; + } + /** + * For a defined reply, never mark as consumed. + */ + persist() { + this[kMockDispatch].persist = true; + return this; + } + /** + * Allow one to define a reply for a set amount of matching requests. + */ + times(repeatTimes) { + if (typeof repeatTimes !== "number" || !Number.isInteger(repeatTimes) || repeatTimes <= 0) { + throw new InvalidArgumentError("repeatTimes must be a valid integer > 0"); + } + this[kMockDispatch].times = repeatTimes; + return this; + } + }; + var MockInterceptor = class { + constructor(opts, mockDispatches) { + if (typeof opts !== "object") { + throw new InvalidArgumentError("opts must be an object"); + } + if (typeof opts.path === "undefined") { + throw new InvalidArgumentError("opts.path must be defined"); + } + if (typeof opts.method === "undefined") { + opts.method = "GET"; + } + if (typeof opts.path === "string") { + if (opts.query) { + opts.path = buildURL(opts.path, opts.query); + } else { + const parsedURL = new URL(opts.path, "data://"); + opts.path = parsedURL.pathname + parsedURL.search; + } + } + if (typeof opts.method === "string") { + opts.method = opts.method.toUpperCase(); + } + this[kDispatchKey] = buildKey(opts); + this[kDispatches] = mockDispatches; + this[kDefaultHeaders] = {}; + this[kDefaultTrailers] = {}; + this[kContentLength] = false; + } + createMockScopeDispatchData({ statusCode, data, responseOptions }) { + const responseData = getResponseData(data); + const contentLength = this[kContentLength] ? { "content-length": responseData.length } : {}; + const headers = { ...this[kDefaultHeaders], ...contentLength, ...responseOptions.headers }; + const trailers = { ...this[kDefaultTrailers], ...responseOptions.trailers }; + return { statusCode, data, headers, trailers }; + } + validateReplyParameters(replyParameters) { + if (typeof replyParameters.statusCode === "undefined") { + throw new InvalidArgumentError("statusCode must be defined"); + } + if (typeof replyParameters.responseOptions !== "object" || replyParameters.responseOptions === null) { + throw new InvalidArgumentError("responseOptions must be an object"); + } + } + /** + * Mock an undici request with a defined reply. + */ + reply(replyOptionsCallbackOrStatusCode) { + if (typeof replyOptionsCallbackOrStatusCode === "function") { + const wrappedDefaultsCallback = (opts) => { + const resolvedData = replyOptionsCallbackOrStatusCode(opts); + if (typeof resolvedData !== "object" || resolvedData === null) { + throw new InvalidArgumentError("reply options callback must return an object"); + } + const replyParameters2 = { data: "", responseOptions: {}, ...resolvedData }; + this.validateReplyParameters(replyParameters2); + return { + ...this.createMockScopeDispatchData(replyParameters2) + }; + }; + const newMockDispatch2 = addMockDispatch(this[kDispatches], this[kDispatchKey], wrappedDefaultsCallback); + return new MockScope(newMockDispatch2); + } + const replyParameters = { + statusCode: replyOptionsCallbackOrStatusCode, + data: arguments[1] === void 0 ? "" : arguments[1], + responseOptions: arguments[2] === void 0 ? {} : arguments[2] + }; + this.validateReplyParameters(replyParameters); + const dispatchData = this.createMockScopeDispatchData(replyParameters); + const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], dispatchData); + return new MockScope(newMockDispatch); + } + /** + * Mock an undici request with a defined error. + */ + replyWithError(error) { + if (typeof error === "undefined") { + throw new InvalidArgumentError("error must be defined"); + } + const newMockDispatch = addMockDispatch(this[kDispatches], this[kDispatchKey], { error }); + return new MockScope(newMockDispatch); + } + /** + * Set default reply headers on the interceptor for subsequent replies + */ + defaultReplyHeaders(headers) { + if (typeof headers === "undefined") { + throw new InvalidArgumentError("headers must be defined"); + } + this[kDefaultHeaders] = headers; + return this; + } + /** + * Set default reply trailers on the interceptor for subsequent replies + */ + defaultReplyTrailers(trailers) { + if (typeof trailers === "undefined") { + throw new InvalidArgumentError("trailers must be defined"); + } + this[kDefaultTrailers] = trailers; + return this; + } + /** + * Set reply content length header for replies on the interceptor + */ + replyContentLength() { + this[kContentLength] = true; + return this; + } + }; + module.exports.MockInterceptor = MockInterceptor; + module.exports.MockScope = MockScope; + } +}); + +// viewer/node_modules/undici/lib/mock/mock-client.js +var require_mock_client = __commonJS({ + "viewer/node_modules/undici/lib/mock/mock-client.js"(exports, module) { + "use strict"; + var { promisify } = __require("node:util"); + var Client = require_client(); + var { buildMockDispatch } = require_mock_utils(); + var { + kDispatches, + kMockAgent, + kClose, + kOriginalClose, + kOrigin, + kOriginalDispatch, + kConnected + } = require_mock_symbols(); + var { MockInterceptor } = require_mock_interceptor(); + var Symbols = require_symbols(); + var { InvalidArgumentError } = require_errors(); + var MockClient = class extends Client { + constructor(origin, opts) { + super(origin, opts); + if (!opts || !opts.agent || typeof opts.agent.dispatch !== "function") { + throw new InvalidArgumentError("Argument opts.agent must implement Agent"); + } + this[kMockAgent] = opts.agent; + this[kOrigin] = origin; + this[kDispatches] = []; + this[kConnected] = 1; + this[kOriginalDispatch] = this.dispatch; + this[kOriginalClose] = this.close.bind(this); + this.dispatch = buildMockDispatch.call(this); + this.close = this[kClose]; + } + get [Symbols.kConnected]() { + return this[kConnected]; + } + /** + * Sets up the base interceptor for mocking replies from undici. + */ + intercept(opts) { + return new MockInterceptor(opts, this[kDispatches]); + } + async [kClose]() { + await promisify(this[kOriginalClose])(); + this[kConnected] = 0; + this[kMockAgent][Symbols.kClients].delete(this[kOrigin]); + } + }; + module.exports = MockClient; + } +}); + +// viewer/node_modules/undici/lib/mock/mock-pool.js +var require_mock_pool = __commonJS({ + "viewer/node_modules/undici/lib/mock/mock-pool.js"(exports, module) { + "use strict"; + var { promisify } = __require("node:util"); + var Pool = require_pool(); + var { buildMockDispatch } = require_mock_utils(); + var { + kDispatches, + kMockAgent, + kClose, + kOriginalClose, + kOrigin, + kOriginalDispatch, + kConnected + } = require_mock_symbols(); + var { MockInterceptor } = require_mock_interceptor(); + var Symbols = require_symbols(); + var { InvalidArgumentError } = require_errors(); + var MockPool = class extends Pool { + constructor(origin, opts) { + super(origin, opts); + if (!opts || !opts.agent || typeof opts.agent.dispatch !== "function") { + throw new InvalidArgumentError("Argument opts.agent must implement Agent"); + } + this[kMockAgent] = opts.agent; + this[kOrigin] = origin; + this[kDispatches] = []; + this[kConnected] = 1; + this[kOriginalDispatch] = this.dispatch; + this[kOriginalClose] = this.close.bind(this); + this.dispatch = buildMockDispatch.call(this); + this.close = this[kClose]; + } + get [Symbols.kConnected]() { + return this[kConnected]; + } + /** + * Sets up the base interceptor for mocking replies from undici. + */ + intercept(opts) { + return new MockInterceptor(opts, this[kDispatches]); + } + async [kClose]() { + await promisify(this[kOriginalClose])(); + this[kConnected] = 0; + this[kMockAgent][Symbols.kClients].delete(this[kOrigin]); + } + }; + module.exports = MockPool; + } +}); + +// viewer/node_modules/undici/lib/mock/pluralizer.js +var require_pluralizer = __commonJS({ + "viewer/node_modules/undici/lib/mock/pluralizer.js"(exports, module) { + "use strict"; + var singulars = { + pronoun: "it", + is: "is", + was: "was", + this: "this" + }; + var plurals = { + pronoun: "they", + is: "are", + was: "were", + this: "these" + }; + module.exports = class Pluralizer { + constructor(singular, plural) { + this.singular = singular; + this.plural = plural; + } + pluralize(count) { + const one = count === 1; + const keys = one ? singulars : plurals; + const noun = one ? this.singular : this.plural; + return { ...keys, count, noun }; + } + }; + } +}); + +// viewer/node_modules/undici/lib/mock/pending-interceptors-formatter.js +var require_pending_interceptors_formatter = __commonJS({ + "viewer/node_modules/undici/lib/mock/pending-interceptors-formatter.js"(exports, module) { + "use strict"; + var { Transform } = __require("node:stream"); + var { Console } = __require("node:console"); + var PERSISTENT = process.versions.icu ? "\u2705" : "Y "; + var NOT_PERSISTENT = process.versions.icu ? "\u274C" : "N "; + module.exports = class PendingInterceptorsFormatter { + constructor({ disableColors } = {}) { + this.transform = new Transform({ + transform(chunk, _enc, cb) { + cb(null, chunk); + } + }); + this.logger = new Console({ + stdout: this.transform, + inspectOptions: { + colors: !disableColors && !process.env.CI + } + }); + } + format(pendingInterceptors) { + const withPrettyHeaders = pendingInterceptors.map( + ({ method, path: path12, data: { statusCode }, persist, times, timesInvoked, origin }) => ({ + Method: method, + Origin: origin, + Path: path12, + "Status code": statusCode, + Persistent: persist ? PERSISTENT : NOT_PERSISTENT, + Invocations: timesInvoked, + Remaining: persist ? Infinity : times - timesInvoked + }) + ); + this.logger.table(withPrettyHeaders); + return this.transform.read().toString(); + } + }; + } +}); + +// viewer/node_modules/undici/lib/mock/mock-agent.js +var require_mock_agent = __commonJS({ + "viewer/node_modules/undici/lib/mock/mock-agent.js"(exports, module) { + "use strict"; + var { kClients } = require_symbols(); + var Agent = require_agent(); + var { + kAgent, + kMockAgentSet, + kMockAgentGet, + kDispatches, + kIsMockActive, + kNetConnect, + kGetNetConnect, + kOptions, + kFactory + } = require_mock_symbols(); + var MockClient = require_mock_client(); + var MockPool = require_mock_pool(); + var { matchValue, buildMockOptions } = require_mock_utils(); + var { InvalidArgumentError, UndiciError } = require_errors(); + var Dispatcher = require_dispatcher(); + var Pluralizer = require_pluralizer(); + var PendingInterceptorsFormatter = require_pending_interceptors_formatter(); + var MockAgent = class extends Dispatcher { + constructor(opts) { + super(opts); + this[kNetConnect] = true; + this[kIsMockActive] = true; + if (opts?.agent && typeof opts.agent.dispatch !== "function") { + throw new InvalidArgumentError("Argument opts.agent must implement Agent"); + } + const agent = opts?.agent ? opts.agent : new Agent(opts); + this[kAgent] = agent; + this[kClients] = agent[kClients]; + this[kOptions] = buildMockOptions(opts); + } + get(origin) { + let dispatcher = this[kMockAgentGet](origin); + if (!dispatcher) { + dispatcher = this[kFactory](origin); + this[kMockAgentSet](origin, dispatcher); + } + return dispatcher; + } + dispatch(opts, handler) { + this.get(opts.origin); + return this[kAgent].dispatch(opts, handler); + } + async close() { + await this[kAgent].close(); + this[kClients].clear(); + } + deactivate() { + this[kIsMockActive] = false; + } + activate() { + this[kIsMockActive] = true; + } + enableNetConnect(matcher) { + if (typeof matcher === "string" || typeof matcher === "function" || matcher instanceof RegExp) { + if (Array.isArray(this[kNetConnect])) { + this[kNetConnect].push(matcher); + } else { + this[kNetConnect] = [matcher]; + } + } else if (typeof matcher === "undefined") { + this[kNetConnect] = true; + } else { + throw new InvalidArgumentError("Unsupported matcher. Must be one of String|Function|RegExp."); + } + } + disableNetConnect() { + this[kNetConnect] = false; + } + // This is required to bypass issues caused by using global symbols - see: + // https://github.com/nodejs/undici/issues/1447 + get isMockActive() { + return this[kIsMockActive]; + } + [kMockAgentSet](origin, dispatcher) { + this[kClients].set(origin, dispatcher); + } + [kFactory](origin) { + const mockOptions = Object.assign({ agent: this }, this[kOptions]); + return this[kOptions] && this[kOptions].connections === 1 ? new MockClient(origin, mockOptions) : new MockPool(origin, mockOptions); + } + [kMockAgentGet](origin) { + const client = this[kClients].get(origin); + if (client) { + return client; + } + if (typeof origin !== "string") { + const dispatcher = this[kFactory]("http://localhost:9999"); + this[kMockAgentSet](origin, dispatcher); + return dispatcher; + } + for (const [keyMatcher, nonExplicitDispatcher] of Array.from(this[kClients])) { + if (nonExplicitDispatcher && typeof keyMatcher !== "string" && matchValue(keyMatcher, origin)) { + const dispatcher = this[kFactory](origin); + this[kMockAgentSet](origin, dispatcher); + dispatcher[kDispatches] = nonExplicitDispatcher[kDispatches]; + return dispatcher; + } + } + } + [kGetNetConnect]() { + return this[kNetConnect]; + } + pendingInterceptors() { + const mockAgentClients = this[kClients]; + return Array.from(mockAgentClients.entries()).flatMap(([origin, scope]) => scope[kDispatches].map((dispatch) => ({ ...dispatch, origin }))).filter(({ pending }) => pending); + } + assertNoPendingInterceptors({ pendingInterceptorsFormatter = new PendingInterceptorsFormatter() } = {}) { + const pending = this.pendingInterceptors(); + if (pending.length === 0) { + return; + } + const pluralizer = new Pluralizer("interceptor", "interceptors").pluralize(pending.length); + throw new UndiciError(` +${pluralizer.count} ${pluralizer.noun} ${pluralizer.is} pending: + +${pendingInterceptorsFormatter.format(pending)} +`.trim()); + } + }; + module.exports = MockAgent; + } +}); + +// viewer/node_modules/undici/lib/global.js +var require_global2 = __commonJS({ + "viewer/node_modules/undici/lib/global.js"(exports, module) { + "use strict"; + var globalDispatcher = /* @__PURE__ */ Symbol.for("undici.globalDispatcher.1"); + var { InvalidArgumentError } = require_errors(); + var Agent = require_agent(); + if (getGlobalDispatcher() === void 0) { + setGlobalDispatcher(new Agent()); + } + function setGlobalDispatcher(agent) { + if (!agent || typeof agent.dispatch !== "function") { + throw new InvalidArgumentError("Argument agent must implement Agent"); + } + Object.defineProperty(globalThis, globalDispatcher, { + value: agent, + writable: true, + enumerable: false, + configurable: false + }); + } + function getGlobalDispatcher() { + return globalThis[globalDispatcher]; + } + module.exports = { + setGlobalDispatcher, + getGlobalDispatcher + }; + } +}); + +// viewer/node_modules/undici/lib/handler/decorator-handler.js +var require_decorator_handler = __commonJS({ + "viewer/node_modules/undici/lib/handler/decorator-handler.js"(exports, module) { + "use strict"; + module.exports = class DecoratorHandler { + #handler; + constructor(handler) { + if (typeof handler !== "object" || handler === null) { + throw new TypeError("handler must be an object"); + } + this.#handler = handler; + } + onConnect(...args) { + return this.#handler.onConnect?.(...args); + } + onError(...args) { + return this.#handler.onError?.(...args); + } + onUpgrade(...args) { + return this.#handler.onUpgrade?.(...args); + } + onResponseStarted(...args) { + return this.#handler.onResponseStarted?.(...args); + } + onHeaders(...args) { + return this.#handler.onHeaders?.(...args); + } + onData(...args) { + return this.#handler.onData?.(...args); + } + onComplete(...args) { + return this.#handler.onComplete?.(...args); + } + onBodySent(...args) { + return this.#handler.onBodySent?.(...args); + } + }; + } +}); + +// viewer/node_modules/undici/lib/interceptor/redirect.js +var require_redirect = __commonJS({ + "viewer/node_modules/undici/lib/interceptor/redirect.js"(exports, module) { + "use strict"; + var RedirectHandler = require_redirect_handler(); + module.exports = (opts) => { + const globalMaxRedirections = opts?.maxRedirections; + return (dispatch) => { + return function redirectInterceptor(opts2, handler) { + const { maxRedirections = globalMaxRedirections, ...baseOpts } = opts2; + if (!maxRedirections) { + return dispatch(opts2, handler); + } + const redirectHandler = new RedirectHandler( + dispatch, + maxRedirections, + opts2, + handler + ); + return dispatch(baseOpts, redirectHandler); + }; + }; + }; + } +}); + +// viewer/node_modules/undici/lib/interceptor/retry.js +var require_retry3 = __commonJS({ + "viewer/node_modules/undici/lib/interceptor/retry.js"(exports, module) { + "use strict"; + var RetryHandler = require_retry_handler(); + module.exports = (globalOpts) => { + return (dispatch) => { + return function retryInterceptor(opts, handler) { + return dispatch( + opts, + new RetryHandler( + { ...opts, retryOptions: { ...globalOpts, ...opts.retryOptions } }, + { + handler, + dispatch + } + ) + ); + }; + }; + }; + } +}); + +// viewer/node_modules/undici/lib/interceptor/dump.js +var require_dump = __commonJS({ + "viewer/node_modules/undici/lib/interceptor/dump.js"(exports, module) { + "use strict"; + var util = require_util(); + var { InvalidArgumentError, RequestAbortedError } = require_errors(); + var DecoratorHandler = require_decorator_handler(); + var DumpHandler = class extends DecoratorHandler { + #maxSize = 1024 * 1024; + #abort = null; + #dumped = false; + #aborted = false; + #size = 0; + #reason = null; + #handler = null; + constructor({ maxSize }, handler) { + super(handler); + if (maxSize != null && (!Number.isFinite(maxSize) || maxSize < 1)) { + throw new InvalidArgumentError("maxSize must be a number greater than 0"); + } + this.#maxSize = maxSize ?? this.#maxSize; + this.#handler = handler; + } + onConnect(abort) { + this.#abort = abort; + this.#handler.onConnect(this.#customAbort.bind(this)); + } + #customAbort(reason) { + this.#aborted = true; + this.#reason = reason; + } + // TODO: will require adjustment after new hooks are out + onHeaders(statusCode, rawHeaders, resume, statusMessage) { + const headers = util.parseHeaders(rawHeaders); + const contentLength = headers["content-length"]; + if (contentLength != null && contentLength > this.#maxSize) { + throw new RequestAbortedError( + `Response size (${contentLength}) larger than maxSize (${this.#maxSize})` + ); + } + if (this.#aborted) { + return true; + } + return this.#handler.onHeaders( + statusCode, + rawHeaders, + resume, + statusMessage + ); + } + onError(err) { + if (this.#dumped) { + return; + } + err = this.#reason ?? err; + this.#handler.onError(err); + } + onData(chunk) { + this.#size = this.#size + chunk.length; + if (this.#size >= this.#maxSize) { + this.#dumped = true; + if (this.#aborted) { + this.#handler.onError(this.#reason); + } else { + this.#handler.onComplete([]); + } + } + return true; + } + onComplete(trailers) { + if (this.#dumped) { + return; + } + if (this.#aborted) { + this.#handler.onError(this.reason); + return; + } + this.#handler.onComplete(trailers); + } + }; + function createDumpInterceptor({ maxSize: defaultMaxSize } = { + maxSize: 1024 * 1024 + }) { + return (dispatch) => { + return function Intercept(opts, handler) { + const { dumpMaxSize = defaultMaxSize } = opts; + const dumpHandler = new DumpHandler( + { maxSize: dumpMaxSize }, + handler + ); + return dispatch(opts, dumpHandler); + }; + }; + } + module.exports = createDumpInterceptor; + } +}); + +// viewer/node_modules/undici/lib/interceptor/dns.js +var require_dns = __commonJS({ + "viewer/node_modules/undici/lib/interceptor/dns.js"(exports, module) { + "use strict"; + var { isIP } = __require("node:net"); + var { lookup } = __require("node:dns"); + var DecoratorHandler = require_decorator_handler(); + var { InvalidArgumentError, InformationalError } = require_errors(); + var maxInt = Math.pow(2, 31) - 1; + var DNSInstance = class { + #maxTTL = 0; + #maxItems = 0; + #records = /* @__PURE__ */ new Map(); + dualStack = true; + affinity = null; + lookup = null; + pick = null; + constructor(opts) { + this.#maxTTL = opts.maxTTL; + this.#maxItems = opts.maxItems; + this.dualStack = opts.dualStack; + this.affinity = opts.affinity; + this.lookup = opts.lookup ?? this.#defaultLookup; + this.pick = opts.pick ?? this.#defaultPick; + } + get full() { + return this.#records.size === this.#maxItems; + } + runLookup(origin, opts, cb) { + const ips = this.#records.get(origin.hostname); + if (ips == null && this.full) { + cb(null, origin.origin); + return; + } + const newOpts = { + affinity: this.affinity, + dualStack: this.dualStack, + lookup: this.lookup, + pick: this.pick, + ...opts.dns, + maxTTL: this.#maxTTL, + maxItems: this.#maxItems + }; + if (ips == null) { + this.lookup(origin, newOpts, (err, addresses) => { + if (err || addresses == null || addresses.length === 0) { + cb(err ?? new InformationalError("No DNS entries found")); + return; + } + this.setRecords(origin, addresses); + const records = this.#records.get(origin.hostname); + const ip = this.pick( + origin, + records, + newOpts.affinity + ); + let port2; + if (typeof ip.port === "number") { + port2 = `:${ip.port}`; + } else if (origin.port !== "") { + port2 = `:${origin.port}`; + } else { + port2 = ""; + } + cb( + null, + `${origin.protocol}//${ip.family === 6 ? `[${ip.address}]` : ip.address}${port2}` + ); + }); + } else { + const ip = this.pick( + origin, + ips, + newOpts.affinity + ); + if (ip == null) { + this.#records.delete(origin.hostname); + this.runLookup(origin, opts, cb); + return; + } + let port2; + if (typeof ip.port === "number") { + port2 = `:${ip.port}`; + } else if (origin.port !== "") { + port2 = `:${origin.port}`; + } else { + port2 = ""; + } + cb( + null, + `${origin.protocol}//${ip.family === 6 ? `[${ip.address}]` : ip.address}${port2}` + ); + } + } + #defaultLookup(origin, opts, cb) { + lookup( + origin.hostname, + { + all: true, + family: this.dualStack === false ? this.affinity : 0, + order: "ipv4first" + }, + (err, addresses) => { + if (err) { + return cb(err); + } + const results = /* @__PURE__ */ new Map(); + for (const addr of addresses) { + results.set(`${addr.address}:${addr.family}`, addr); + } + cb(null, results.values()); + } + ); + } + #defaultPick(origin, hostnameRecords, affinity) { + let ip = null; + const { records, offset } = hostnameRecords; + let family; + if (this.dualStack) { + if (affinity == null) { + if (offset == null || offset === maxInt) { + hostnameRecords.offset = 0; + affinity = 4; + } else { + hostnameRecords.offset++; + affinity = (hostnameRecords.offset & 1) === 1 ? 6 : 4; + } + } + if (records[affinity] != null && records[affinity].ips.length > 0) { + family = records[affinity]; + } else { + family = records[affinity === 4 ? 6 : 4]; + } + } else { + family = records[affinity]; + } + if (family == null || family.ips.length === 0) { + return ip; + } + if (family.offset == null || family.offset === maxInt) { + family.offset = 0; + } else { + family.offset++; + } + const position = family.offset % family.ips.length; + ip = family.ips[position] ?? null; + if (ip == null) { + return ip; + } + if (Date.now() - ip.timestamp > ip.ttl) { + family.ips.splice(position, 1); + return this.pick(origin, hostnameRecords, affinity); + } + return ip; + } + setRecords(origin, addresses) { + const timestamp = Date.now(); + const records = { records: { 4: null, 6: null } }; + for (const record of addresses) { + record.timestamp = timestamp; + if (typeof record.ttl === "number") { + record.ttl = Math.min(record.ttl, this.#maxTTL); + } else { + record.ttl = this.#maxTTL; + } + const familyRecords = records.records[record.family] ?? { ips: [] }; + familyRecords.ips.push(record); + records.records[record.family] = familyRecords; + } + this.#records.set(origin.hostname, records); + } + getHandler(meta, opts) { + return new DNSDispatchHandler(this, meta, opts); + } + }; + var DNSDispatchHandler = class extends DecoratorHandler { + #state = null; + #opts = null; + #dispatch = null; + #handler = null; + #origin = null; + constructor(state, { origin, handler, dispatch }, opts) { + super(handler); + this.#origin = origin; + this.#handler = handler; + this.#opts = { ...opts }; + this.#state = state; + this.#dispatch = dispatch; + } + onError(err) { + switch (err.code) { + case "ETIMEDOUT": + case "ECONNREFUSED": { + if (this.#state.dualStack) { + this.#state.runLookup(this.#origin, this.#opts, (err2, newOrigin) => { + if (err2) { + return this.#handler.onError(err2); + } + const dispatchOpts = { + ...this.#opts, + origin: newOrigin + }; + this.#dispatch(dispatchOpts, this); + }); + return; + } + this.#handler.onError(err); + return; + } + case "ENOTFOUND": + this.#state.deleteRecord(this.#origin); + // eslint-disable-next-line no-fallthrough + default: + this.#handler.onError(err); + break; + } + } + }; + module.exports = (interceptorOpts) => { + if (interceptorOpts?.maxTTL != null && (typeof interceptorOpts?.maxTTL !== "number" || interceptorOpts?.maxTTL < 0)) { + throw new InvalidArgumentError("Invalid maxTTL. Must be a positive number"); + } + if (interceptorOpts?.maxItems != null && (typeof interceptorOpts?.maxItems !== "number" || interceptorOpts?.maxItems < 1)) { + throw new InvalidArgumentError( + "Invalid maxItems. Must be a positive number and greater than zero" + ); + } + if (interceptorOpts?.affinity != null && interceptorOpts?.affinity !== 4 && interceptorOpts?.affinity !== 6) { + throw new InvalidArgumentError("Invalid affinity. Must be either 4 or 6"); + } + if (interceptorOpts?.dualStack != null && typeof interceptorOpts?.dualStack !== "boolean") { + throw new InvalidArgumentError("Invalid dualStack. Must be a boolean"); + } + if (interceptorOpts?.lookup != null && typeof interceptorOpts?.lookup !== "function") { + throw new InvalidArgumentError("Invalid lookup. Must be a function"); + } + if (interceptorOpts?.pick != null && typeof interceptorOpts?.pick !== "function") { + throw new InvalidArgumentError("Invalid pick. Must be a function"); + } + const dualStack = interceptorOpts?.dualStack ?? true; + let affinity; + if (dualStack) { + affinity = interceptorOpts?.affinity ?? null; + } else { + affinity = interceptorOpts?.affinity ?? 4; + } + const opts = { + maxTTL: interceptorOpts?.maxTTL ?? 1e4, + // Expressed in ms + lookup: interceptorOpts?.lookup ?? null, + pick: interceptorOpts?.pick ?? null, + dualStack, + affinity, + maxItems: interceptorOpts?.maxItems ?? Infinity + }; + const instance = new DNSInstance(opts); + return (dispatch) => { + return function dnsInterceptor(origDispatchOpts, handler) { + const origin = origDispatchOpts.origin.constructor === URL ? origDispatchOpts.origin : new URL(origDispatchOpts.origin); + if (isIP(origin.hostname) !== 0) { + return dispatch(origDispatchOpts, handler); + } + instance.runLookup(origin, origDispatchOpts, (err, newOrigin) => { + if (err) { + return handler.onError(err); + } + let dispatchOpts = null; + dispatchOpts = { + ...origDispatchOpts, + servername: origin.hostname, + // For SNI on TLS + origin: newOrigin, + headers: { + host: origin.hostname, + ...origDispatchOpts.headers + } + }; + dispatch( + dispatchOpts, + instance.getHandler({ origin, dispatch, handler }, origDispatchOpts) + ); + }); + return true; + }; + }; + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/headers.js +var require_headers = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/headers.js"(exports, module) { + "use strict"; + var { kConstruct } = require_symbols(); + var { kEnumerableProperty } = require_util(); + var { + iteratorMixin, + isValidHeaderName, + isValidHeaderValue + } = require_util2(); + var { webidl } = require_webidl(); + var assert = __require("node:assert"); + var util = __require("node:util"); + var kHeadersMap = /* @__PURE__ */ Symbol("headers map"); + var kHeadersSortedMap = /* @__PURE__ */ Symbol("headers map sorted"); + function isHTTPWhiteSpaceCharCode(code) { + return code === 10 || code === 13 || code === 9 || code === 32; + } + function headerValueNormalize(potentialValue) { + let i = 0; + let j = potentialValue.length; + while (j > i && isHTTPWhiteSpaceCharCode(potentialValue.charCodeAt(j - 1))) --j; + while (j > i && isHTTPWhiteSpaceCharCode(potentialValue.charCodeAt(i))) ++i; + return i === 0 && j === potentialValue.length ? potentialValue : potentialValue.substring(i, j); + } + function fill(headers, object) { + if (Array.isArray(object)) { + for (let i = 0; i < object.length; ++i) { + const header = object[i]; + if (header.length !== 2) { + throw webidl.errors.exception({ + header: "Headers constructor", + message: `expected name/value pair to be length 2, found ${header.length}.` + }); + } + appendHeader(headers, header[0], header[1]); + } + } else if (typeof object === "object" && object !== null) { + const keys = Object.keys(object); + for (let i = 0; i < keys.length; ++i) { + appendHeader(headers, keys[i], object[keys[i]]); + } + } else { + throw webidl.errors.conversionFailed({ + prefix: "Headers constructor", + argument: "Argument 1", + types: ["sequence>", "record"] + }); + } + } + function appendHeader(headers, name, value) { + value = headerValueNormalize(value); + if (!isValidHeaderName(name)) { + throw webidl.errors.invalidArgument({ + prefix: "Headers.append", + value: name, + type: "header name" + }); + } else if (!isValidHeaderValue(value)) { + throw webidl.errors.invalidArgument({ + prefix: "Headers.append", + value, + type: "header value" + }); + } + if (getHeadersGuard(headers) === "immutable") { + throw new TypeError("immutable"); + } + return getHeadersList(headers).append(name, value, false); + } + function compareHeaderName(a, b) { + return a[0] < b[0] ? -1 : 1; + } + var HeadersList = class _HeadersList { + /** @type {[string, string][]|null} */ + cookies = null; + constructor(init) { + if (init instanceof _HeadersList) { + this[kHeadersMap] = new Map(init[kHeadersMap]); + this[kHeadersSortedMap] = init[kHeadersSortedMap]; + this.cookies = init.cookies === null ? null : [...init.cookies]; + } else { + this[kHeadersMap] = new Map(init); + this[kHeadersSortedMap] = null; + } + } + /** + * @see https://fetch.spec.whatwg.org/#header-list-contains + * @param {string} name + * @param {boolean} isLowerCase + */ + contains(name, isLowerCase) { + return this[kHeadersMap].has(isLowerCase ? name : name.toLowerCase()); + } + clear() { + this[kHeadersMap].clear(); + this[kHeadersSortedMap] = null; + this.cookies = null; + } + /** + * @see https://fetch.spec.whatwg.org/#concept-header-list-append + * @param {string} name + * @param {string} value + * @param {boolean} isLowerCase + */ + append(name, value, isLowerCase) { + this[kHeadersSortedMap] = null; + const lowercaseName = isLowerCase ? name : name.toLowerCase(); + const exists = this[kHeadersMap].get(lowercaseName); + if (exists) { + const delimiter = lowercaseName === "cookie" ? "; " : ", "; + this[kHeadersMap].set(lowercaseName, { + name: exists.name, + value: `${exists.value}${delimiter}${value}` + }); + } else { + this[kHeadersMap].set(lowercaseName, { name, value }); + } + if (lowercaseName === "set-cookie") { + (this.cookies ??= []).push(value); + } + } + /** + * @see https://fetch.spec.whatwg.org/#concept-header-list-set + * @param {string} name + * @param {string} value + * @param {boolean} isLowerCase + */ + set(name, value, isLowerCase) { + this[kHeadersSortedMap] = null; + const lowercaseName = isLowerCase ? name : name.toLowerCase(); + if (lowercaseName === "set-cookie") { + this.cookies = [value]; + } + this[kHeadersMap].set(lowercaseName, { name, value }); + } + /** + * @see https://fetch.spec.whatwg.org/#concept-header-list-delete + * @param {string} name + * @param {boolean} isLowerCase + */ + delete(name, isLowerCase) { + this[kHeadersSortedMap] = null; + if (!isLowerCase) name = name.toLowerCase(); + if (name === "set-cookie") { + this.cookies = null; + } + this[kHeadersMap].delete(name); + } + /** + * @see https://fetch.spec.whatwg.org/#concept-header-list-get + * @param {string} name + * @param {boolean} isLowerCase + * @returns {string | null} + */ + get(name, isLowerCase) { + return this[kHeadersMap].get(isLowerCase ? name : name.toLowerCase())?.value ?? null; + } + *[Symbol.iterator]() { + for (const { 0: name, 1: { value } } of this[kHeadersMap]) { + yield [name, value]; + } + } + get entries() { + const headers = {}; + if (this[kHeadersMap].size !== 0) { + for (const { name, value } of this[kHeadersMap].values()) { + headers[name] = value; + } + } + return headers; + } + rawValues() { + return this[kHeadersMap].values(); + } + get entriesList() { + const headers = []; + if (this[kHeadersMap].size !== 0) { + for (const { 0: lowerName, 1: { name, value } } of this[kHeadersMap]) { + if (lowerName === "set-cookie") { + for (const cookie of this.cookies) { + headers.push([name, cookie]); + } + } else { + headers.push([name, value]); + } + } + } + return headers; + } + // https://fetch.spec.whatwg.org/#convert-header-names-to-a-sorted-lowercase-set + toSortedArray() { + const size = this[kHeadersMap].size; + const array = new Array(size); + if (size <= 32) { + if (size === 0) { + return array; + } + const iterator = this[kHeadersMap][Symbol.iterator](); + const firstValue = iterator.next().value; + array[0] = [firstValue[0], firstValue[1].value]; + assert(firstValue[1].value !== null); + for (let i = 1, j = 0, right = 0, left = 0, pivot = 0, x, value; i < size; ++i) { + value = iterator.next().value; + x = array[i] = [value[0], value[1].value]; + assert(x[1] !== null); + left = 0; + right = i; + while (left < right) { + pivot = left + (right - left >> 1); + if (array[pivot][0] <= x[0]) { + left = pivot + 1; + } else { + right = pivot; + } + } + if (i !== pivot) { + j = i; + while (j > left) { + array[j] = array[--j]; + } + array[left] = x; + } + } + if (!iterator.next().done) { + throw new TypeError("Unreachable"); + } + return array; + } else { + let i = 0; + for (const { 0: name, 1: { value } } of this[kHeadersMap]) { + array[i++] = [name, value]; + assert(value !== null); + } + return array.sort(compareHeaderName); + } + } + }; + var Headers2 = class _Headers { + #guard; + #headersList; + constructor(init = void 0) { + webidl.util.markAsUncloneable(this); + if (init === kConstruct) { + return; + } + this.#headersList = new HeadersList(); + this.#guard = "none"; + if (init !== void 0) { + init = webidl.converters.HeadersInit(init, "Headers contructor", "init"); + fill(this, init); + } + } + // https://fetch.spec.whatwg.org/#dom-headers-append + append(name, value) { + webidl.brandCheck(this, _Headers); + webidl.argumentLengthCheck(arguments, 2, "Headers.append"); + const prefix = "Headers.append"; + name = webidl.converters.ByteString(name, prefix, "name"); + value = webidl.converters.ByteString(value, prefix, "value"); + return appendHeader(this, name, value); + } + // https://fetch.spec.whatwg.org/#dom-headers-delete + delete(name) { + webidl.brandCheck(this, _Headers); + webidl.argumentLengthCheck(arguments, 1, "Headers.delete"); + const prefix = "Headers.delete"; + name = webidl.converters.ByteString(name, prefix, "name"); + if (!isValidHeaderName(name)) { + throw webidl.errors.invalidArgument({ + prefix: "Headers.delete", + value: name, + type: "header name" + }); + } + if (this.#guard === "immutable") { + throw new TypeError("immutable"); + } + if (!this.#headersList.contains(name, false)) { + return; + } + this.#headersList.delete(name, false); + } + // https://fetch.spec.whatwg.org/#dom-headers-get + get(name) { + webidl.brandCheck(this, _Headers); + webidl.argumentLengthCheck(arguments, 1, "Headers.get"); + const prefix = "Headers.get"; + name = webidl.converters.ByteString(name, prefix, "name"); + if (!isValidHeaderName(name)) { + throw webidl.errors.invalidArgument({ + prefix, + value: name, + type: "header name" + }); + } + return this.#headersList.get(name, false); + } + // https://fetch.spec.whatwg.org/#dom-headers-has + has(name) { + webidl.brandCheck(this, _Headers); + webidl.argumentLengthCheck(arguments, 1, "Headers.has"); + const prefix = "Headers.has"; + name = webidl.converters.ByteString(name, prefix, "name"); + if (!isValidHeaderName(name)) { + throw webidl.errors.invalidArgument({ + prefix, + value: name, + type: "header name" + }); + } + return this.#headersList.contains(name, false); + } + // https://fetch.spec.whatwg.org/#dom-headers-set + set(name, value) { + webidl.brandCheck(this, _Headers); + webidl.argumentLengthCheck(arguments, 2, "Headers.set"); + const prefix = "Headers.set"; + name = webidl.converters.ByteString(name, prefix, "name"); + value = webidl.converters.ByteString(value, prefix, "value"); + value = headerValueNormalize(value); + if (!isValidHeaderName(name)) { + throw webidl.errors.invalidArgument({ + prefix, + value: name, + type: "header name" + }); + } else if (!isValidHeaderValue(value)) { + throw webidl.errors.invalidArgument({ + prefix, + value, + type: "header value" + }); + } + if (this.#guard === "immutable") { + throw new TypeError("immutable"); + } + this.#headersList.set(name, value, false); + } + // https://fetch.spec.whatwg.org/#dom-headers-getsetcookie + getSetCookie() { + webidl.brandCheck(this, _Headers); + const list2 = this.#headersList.cookies; + if (list2) { + return [...list2]; + } + return []; + } + // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine + get [kHeadersSortedMap]() { + if (this.#headersList[kHeadersSortedMap]) { + return this.#headersList[kHeadersSortedMap]; + } + const headers = []; + const names = this.#headersList.toSortedArray(); + const cookies = this.#headersList.cookies; + if (cookies === null || cookies.length === 1) { + return this.#headersList[kHeadersSortedMap] = names; + } + for (let i = 0; i < names.length; ++i) { + const { 0: name, 1: value } = names[i]; + if (name === "set-cookie") { + for (let j = 0; j < cookies.length; ++j) { + headers.push([name, cookies[j]]); + } + } else { + headers.push([name, value]); + } + } + return this.#headersList[kHeadersSortedMap] = headers; + } + [util.inspect.custom](depth, options) { + options.depth ??= depth; + return `Headers ${util.formatWithOptions(options, this.#headersList.entries)}`; + } + static getHeadersGuard(o) { + return o.#guard; + } + static setHeadersGuard(o, guard) { + o.#guard = guard; + } + static getHeadersList(o) { + return o.#headersList; + } + static setHeadersList(o, list2) { + o.#headersList = list2; + } + }; + var { getHeadersGuard, setHeadersGuard, getHeadersList, setHeadersList } = Headers2; + Reflect.deleteProperty(Headers2, "getHeadersGuard"); + Reflect.deleteProperty(Headers2, "setHeadersGuard"); + Reflect.deleteProperty(Headers2, "getHeadersList"); + Reflect.deleteProperty(Headers2, "setHeadersList"); + iteratorMixin("Headers", Headers2, kHeadersSortedMap, 0, 1); + Object.defineProperties(Headers2.prototype, { + append: kEnumerableProperty, + delete: kEnumerableProperty, + get: kEnumerableProperty, + has: kEnumerableProperty, + set: kEnumerableProperty, + getSetCookie: kEnumerableProperty, + [Symbol.toStringTag]: { + value: "Headers", + configurable: true + }, + [util.inspect.custom]: { + enumerable: false + } + }); + webidl.converters.HeadersInit = function(V, prefix, argument) { + if (webidl.util.Type(V) === "Object") { + const iterator = Reflect.get(V, Symbol.iterator); + if (!util.types.isProxy(V) && iterator === Headers2.prototype.entries) { + try { + return getHeadersList(V).entriesList; + } catch { + } + } + if (typeof iterator === "function") { + return webidl.converters["sequence>"](V, prefix, argument, iterator.bind(V)); + } + return webidl.converters["record"](V, prefix, argument); + } + throw webidl.errors.conversionFailed({ + prefix: "Headers constructor", + argument: "Argument 1", + types: ["sequence>", "record"] + }); + }; + module.exports = { + fill, + // for test. + compareHeaderName, + Headers: Headers2, + HeadersList, + getHeadersGuard, + setHeadersGuard, + setHeadersList, + getHeadersList + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/response.js +var require_response = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/response.js"(exports, module) { + "use strict"; + var { Headers: Headers2, HeadersList, fill, getHeadersGuard, setHeadersGuard, setHeadersList } = require_headers(); + var { extractBody, cloneBody, mixinBody, hasFinalizationRegistry, streamRegistry, bodyUnusable } = require_body(); + var util = require_util(); + var nodeUtil = __require("node:util"); + var { kEnumerableProperty } = util; + var { + isValidReasonPhrase, + isCancelled, + isAborted, + isBlobLike, + serializeJavascriptValueToJSONString, + isErrorLike, + isomorphicEncode, + environmentSettingsObject: relevantRealm + } = require_util2(); + var { + redirectStatusSet, + nullBodyStatus + } = require_constants3(); + var { kState, kHeaders } = require_symbols2(); + var { webidl } = require_webidl(); + var { FormData } = require_formdata(); + var { URLSerializer } = require_data_url(); + var { kConstruct } = require_symbols(); + var assert = __require("node:assert"); + var { types } = __require("node:util"); + var textEncoder = new TextEncoder("utf-8"); + var Response2 = class _Response { + // Creates network error Response. + static error() { + const responseObject = fromInnerResponse(makeNetworkError(), "immutable"); + return responseObject; + } + // https://fetch.spec.whatwg.org/#dom-response-json + static json(data, init = {}) { + webidl.argumentLengthCheck(arguments, 1, "Response.json"); + if (init !== null) { + init = webidl.converters.ResponseInit(init); + } + const bytes2 = textEncoder.encode( + serializeJavascriptValueToJSONString(data) + ); + const body = extractBody(bytes2); + const responseObject = fromInnerResponse(makeResponse({}), "response"); + initializeResponse(responseObject, init, { body: body[0], type: "application/json" }); + return responseObject; + } + // Creates a redirect Response that redirects to url with status status. + static redirect(url, status = 302) { + webidl.argumentLengthCheck(arguments, 1, "Response.redirect"); + url = webidl.converters.USVString(url); + status = webidl.converters["unsigned short"](status); + let parsedURL; + try { + parsedURL = new URL(url, relevantRealm.settingsObject.baseUrl); + } catch (err) { + throw new TypeError(`Failed to parse URL from ${url}`, { cause: err }); + } + if (!redirectStatusSet.has(status)) { + throw new RangeError(`Invalid status code ${status}`); + } + const responseObject = fromInnerResponse(makeResponse({}), "immutable"); + responseObject[kState].status = status; + const value = isomorphicEncode(URLSerializer(parsedURL)); + responseObject[kState].headersList.append("location", value, true); + return responseObject; + } + // https://fetch.spec.whatwg.org/#dom-response + constructor(body = null, init = {}) { + webidl.util.markAsUncloneable(this); + if (body === kConstruct) { + return; + } + if (body !== null) { + body = webidl.converters.BodyInit(body); + } + init = webidl.converters.ResponseInit(init); + this[kState] = makeResponse({}); + this[kHeaders] = new Headers2(kConstruct); + setHeadersGuard(this[kHeaders], "response"); + setHeadersList(this[kHeaders], this[kState].headersList); + let bodyWithType = null; + if (body != null) { + const [extractedBody, type] = extractBody(body); + bodyWithType = { body: extractedBody, type }; + } + initializeResponse(this, init, bodyWithType); + } + // Returns response’s type, e.g., "cors". + get type() { + webidl.brandCheck(this, _Response); + return this[kState].type; + } + // Returns response’s URL, if it has one; otherwise the empty string. + get url() { + webidl.brandCheck(this, _Response); + const urlList = this[kState].urlList; + const url = urlList[urlList.length - 1] ?? null; + if (url === null) { + return ""; + } + return URLSerializer(url, true); + } + // Returns whether response was obtained through a redirect. + get redirected() { + webidl.brandCheck(this, _Response); + return this[kState].urlList.length > 1; + } + // Returns response’s status. + get status() { + webidl.brandCheck(this, _Response); + return this[kState].status; + } + // Returns whether response’s status is an ok status. + get ok() { + webidl.brandCheck(this, _Response); + return this[kState].status >= 200 && this[kState].status <= 299; + } + // Returns response’s status message. + get statusText() { + webidl.brandCheck(this, _Response); + return this[kState].statusText; + } + // Returns response’s headers as Headers. + get headers() { + webidl.brandCheck(this, _Response); + return this[kHeaders]; + } + get body() { + webidl.brandCheck(this, _Response); + return this[kState].body ? this[kState].body.stream : null; + } + get bodyUsed() { + webidl.brandCheck(this, _Response); + return !!this[kState].body && util.isDisturbed(this[kState].body.stream); + } + // Returns a clone of response. + clone() { + webidl.brandCheck(this, _Response); + if (bodyUnusable(this)) { + throw webidl.errors.exception({ + header: "Response.clone", + message: "Body has already been consumed." + }); + } + const clonedResponse = cloneResponse(this[kState]); + if (hasFinalizationRegistry && this[kState].body?.stream) { + streamRegistry.register(this, new WeakRef(this[kState].body.stream)); + } + return fromInnerResponse(clonedResponse, getHeadersGuard(this[kHeaders])); + } + [nodeUtil.inspect.custom](depth, options) { + if (options.depth === null) { + options.depth = 2; + } + options.colors ??= true; + const properties = { + status: this.status, + statusText: this.statusText, + headers: this.headers, + body: this.body, + bodyUsed: this.bodyUsed, + ok: this.ok, + redirected: this.redirected, + type: this.type, + url: this.url + }; + return `Response ${nodeUtil.formatWithOptions(options, properties)}`; + } + }; + mixinBody(Response2); + Object.defineProperties(Response2.prototype, { + type: kEnumerableProperty, + url: kEnumerableProperty, + status: kEnumerableProperty, + ok: kEnumerableProperty, + redirected: kEnumerableProperty, + statusText: kEnumerableProperty, + headers: kEnumerableProperty, + clone: kEnumerableProperty, + body: kEnumerableProperty, + bodyUsed: kEnumerableProperty, + [Symbol.toStringTag]: { + value: "Response", + configurable: true + } + }); + Object.defineProperties(Response2, { + json: kEnumerableProperty, + redirect: kEnumerableProperty, + error: kEnumerableProperty + }); + function cloneResponse(response) { + if (response.internalResponse) { + return filterResponse( + cloneResponse(response.internalResponse), + response.type + ); + } + const newResponse = makeResponse({ ...response, body: null }); + if (response.body != null) { + newResponse.body = cloneBody(newResponse, response.body); + } + return newResponse; + } + function makeResponse(init) { + return { + aborted: false, + rangeRequested: false, + timingAllowPassed: false, + requestIncludesCredentials: false, + type: "default", + status: 200, + timingInfo: null, + cacheState: "", + statusText: "", + ...init, + headersList: init?.headersList ? new HeadersList(init?.headersList) : new HeadersList(), + urlList: init?.urlList ? [...init.urlList] : [] + }; + } + function makeNetworkError(reason) { + const isError2 = isErrorLike(reason); + return makeResponse({ + type: "error", + status: 0, + error: isError2 ? reason : new Error(reason ? String(reason) : reason), + aborted: reason && reason.name === "AbortError" + }); + } + function isNetworkError2(response) { + return ( + // A network error is a response whose type is "error", + response.type === "error" && // status is 0 + response.status === 0 + ); + } + function makeFilteredResponse(response, state) { + state = { + internalResponse: response, + ...state + }; + return new Proxy(response, { + get(target, p) { + return p in state ? state[p] : target[p]; + }, + set(target, p, value) { + assert(!(p in state)); + target[p] = value; + return true; + } + }); + } + function filterResponse(response, type) { + if (type === "basic") { + return makeFilteredResponse(response, { + type: "basic", + headersList: response.headersList + }); + } else if (type === "cors") { + return makeFilteredResponse(response, { + type: "cors", + headersList: response.headersList + }); + } else if (type === "opaque") { + return makeFilteredResponse(response, { + type: "opaque", + urlList: Object.freeze([]), + status: 0, + statusText: "", + body: null + }); + } else if (type === "opaqueredirect") { + return makeFilteredResponse(response, { + type: "opaqueredirect", + status: 0, + statusText: "", + headersList: [], + body: null + }); + } else { + assert(false); + } + } + function makeAppropriateNetworkError(fetchParams, err = null) { + assert(isCancelled(fetchParams)); + return isAborted(fetchParams) ? makeNetworkError(Object.assign(new DOMException("The operation was aborted.", "AbortError"), { cause: err })) : makeNetworkError(Object.assign(new DOMException("Request was cancelled."), { cause: err })); + } + function initializeResponse(response, init, body) { + if (init.status !== null && (init.status < 200 || init.status > 599)) { + throw new RangeError('init["status"] must be in the range of 200 to 599, inclusive.'); + } + if ("statusText" in init && init.statusText != null) { + if (!isValidReasonPhrase(String(init.statusText))) { + throw new TypeError("Invalid statusText"); + } + } + if ("status" in init && init.status != null) { + response[kState].status = init.status; + } + if ("statusText" in init && init.statusText != null) { + response[kState].statusText = init.statusText; + } + if ("headers" in init && init.headers != null) { + fill(response[kHeaders], init.headers); + } + if (body) { + if (nullBodyStatus.includes(response.status)) { + throw webidl.errors.exception({ + header: "Response constructor", + message: `Invalid response status code ${response.status}` + }); + } + response[kState].body = body.body; + if (body.type != null && !response[kState].headersList.contains("content-type", true)) { + response[kState].headersList.append("content-type", body.type, true); + } + } + } + function fromInnerResponse(innerResponse, guard) { + const response = new Response2(kConstruct); + response[kState] = innerResponse; + response[kHeaders] = new Headers2(kConstruct); + setHeadersList(response[kHeaders], innerResponse.headersList); + setHeadersGuard(response[kHeaders], guard); + if (hasFinalizationRegistry && innerResponse.body?.stream) { + streamRegistry.register(response, new WeakRef(innerResponse.body.stream)); + } + return response; + } + webidl.converters.ReadableStream = webidl.interfaceConverter( + ReadableStream + ); + webidl.converters.FormData = webidl.interfaceConverter( + FormData + ); + webidl.converters.URLSearchParams = webidl.interfaceConverter( + URLSearchParams + ); + webidl.converters.XMLHttpRequestBodyInit = function(V, prefix, name) { + if (typeof V === "string") { + return webidl.converters.USVString(V, prefix, name); + } + if (isBlobLike(V)) { + return webidl.converters.Blob(V, prefix, name, { strict: false }); + } + if (ArrayBuffer.isView(V) || types.isArrayBuffer(V)) { + return webidl.converters.BufferSource(V, prefix, name); + } + if (util.isFormDataLike(V)) { + return webidl.converters.FormData(V, prefix, name, { strict: false }); + } + if (V instanceof URLSearchParams) { + return webidl.converters.URLSearchParams(V, prefix, name); + } + return webidl.converters.DOMString(V, prefix, name); + }; + webidl.converters.BodyInit = function(V, prefix, argument) { + if (V instanceof ReadableStream) { + return webidl.converters.ReadableStream(V, prefix, argument); + } + if (V?.[Symbol.asyncIterator]) { + return V; + } + return webidl.converters.XMLHttpRequestBodyInit(V, prefix, argument); + }; + webidl.converters.ResponseInit = webidl.dictionaryConverter([ + { + key: "status", + converter: webidl.converters["unsigned short"], + defaultValue: () => 200 + }, + { + key: "statusText", + converter: webidl.converters.ByteString, + defaultValue: () => "" + }, + { + key: "headers", + converter: webidl.converters.HeadersInit + } + ]); + module.exports = { + isNetworkError: isNetworkError2, + makeNetworkError, + makeResponse, + makeAppropriateNetworkError, + filterResponse, + Response: Response2, + cloneResponse, + fromInnerResponse + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/dispatcher-weakref.js +var require_dispatcher_weakref = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/dispatcher-weakref.js"(exports, module) { + "use strict"; + var { kConnected, kSize } = require_symbols(); + var CompatWeakRef = class { + constructor(value) { + this.value = value; + } + deref() { + return this.value[kConnected] === 0 && this.value[kSize] === 0 ? void 0 : this.value; + } + }; + var CompatFinalizer = class { + constructor(finalizer) { + this.finalizer = finalizer; + } + register(dispatcher, key) { + if (dispatcher.on) { + dispatcher.on("disconnect", () => { + if (dispatcher[kConnected] === 0 && dispatcher[kSize] === 0) { + this.finalizer(key); + } + }); + } + } + unregister(key) { + } + }; + module.exports = function() { + if (process.env.NODE_V8_COVERAGE && process.version.startsWith("v18")) { + process._rawDebug("Using compatibility WeakRef and FinalizationRegistry"); + return { + WeakRef: CompatWeakRef, + FinalizationRegistry: CompatFinalizer + }; + } + return { WeakRef, FinalizationRegistry }; + }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/request.js +var require_request2 = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/request.js"(exports, module) { + "use strict"; + var { extractBody, mixinBody, cloneBody, bodyUnusable } = require_body(); + var { Headers: Headers2, fill: fillHeaders, HeadersList, setHeadersGuard, getHeadersGuard, setHeadersList, getHeadersList } = require_headers(); + var { FinalizationRegistry: FinalizationRegistry2 } = require_dispatcher_weakref()(); + var util = require_util(); + var nodeUtil = __require("node:util"); + var { + isValidHTTPToken, + sameOrigin, + environmentSettingsObject + } = require_util2(); + var { + forbiddenMethodsSet, + corsSafeListedMethodsSet, + referrerPolicy, + requestRedirect, + requestMode, + requestCredentials, + requestCache, + requestDuplex + } = require_constants3(); + var { kEnumerableProperty, normalizedMethodRecordsBase, normalizedMethodRecords } = util; + var { kHeaders, kSignal, kState, kDispatcher } = require_symbols2(); + var { webidl } = require_webidl(); + var { URLSerializer } = require_data_url(); + var { kConstruct } = require_symbols(); + var assert = __require("node:assert"); + var { getMaxListeners, setMaxListeners, getEventListeners, defaultMaxListeners } = __require("node:events"); + var kAbortController = /* @__PURE__ */ Symbol("abortController"); + var requestFinalizer = new FinalizationRegistry2(({ signal, abort }) => { + signal.removeEventListener("abort", abort); + }); + var dependentControllerMap = /* @__PURE__ */ new WeakMap(); + function buildAbort(acRef) { + return abort; + function abort() { + const ac = acRef.deref(); + if (ac !== void 0) { + requestFinalizer.unregister(abort); + this.removeEventListener("abort", abort); + ac.abort(this.reason); + const controllerList = dependentControllerMap.get(ac.signal); + if (controllerList !== void 0) { + if (controllerList.size !== 0) { + for (const ref of controllerList) { + const ctrl = ref.deref(); + if (ctrl !== void 0) { + ctrl.abort(this.reason); + } + } + controllerList.clear(); + } + dependentControllerMap.delete(ac.signal); + } + } + } + } + var patchMethodWarning = false; + var Request2 = class _Request { + // https://fetch.spec.whatwg.org/#dom-request + constructor(input, init = {}) { + webidl.util.markAsUncloneable(this); + if (input === kConstruct) { + return; + } + const prefix = "Request constructor"; + webidl.argumentLengthCheck(arguments, 1, prefix); + input = webidl.converters.RequestInfo(input, prefix, "input"); + init = webidl.converters.RequestInit(init, prefix, "init"); + let request = null; + let fallbackMode = null; + const baseUrl = environmentSettingsObject.settingsObject.baseUrl; + let signal = null; + if (typeof input === "string") { + this[kDispatcher] = init.dispatcher; + let parsedURL; + try { + parsedURL = new URL(input, baseUrl); + } catch (err) { + throw new TypeError("Failed to parse URL from " + input, { cause: err }); + } + if (parsedURL.username || parsedURL.password) { + throw new TypeError( + "Request cannot be constructed from a URL that includes credentials: " + input + ); + } + request = makeRequest({ urlList: [parsedURL] }); + fallbackMode = "cors"; + } else { + this[kDispatcher] = init.dispatcher || input[kDispatcher]; + assert(input instanceof _Request); + request = input[kState]; + signal = input[kSignal]; + } + const origin = environmentSettingsObject.settingsObject.origin; + let window2 = "client"; + if (request.window?.constructor?.name === "EnvironmentSettingsObject" && sameOrigin(request.window, origin)) { + window2 = request.window; + } + if (init.window != null) { + throw new TypeError(`'window' option '${window2}' must be null`); + } + if ("window" in init) { + window2 = "no-window"; + } + request = makeRequest({ + // URL request’s URL. + // undici implementation note: this is set as the first item in request's urlList in makeRequest + // method request’s method. + method: request.method, + // header list A copy of request’s header list. + // undici implementation note: headersList is cloned in makeRequest + headersList: request.headersList, + // unsafe-request flag Set. + unsafeRequest: request.unsafeRequest, + // client This’s relevant settings object. + client: environmentSettingsObject.settingsObject, + // window window. + window: window2, + // priority request’s priority. + priority: request.priority, + // origin request’s origin. The propagation of the origin is only significant for navigation requests + // being handled by a service worker. In this scenario a request can have an origin that is different + // from the current client. + origin: request.origin, + // referrer request’s referrer. + referrer: request.referrer, + // referrer policy request’s referrer policy. + referrerPolicy: request.referrerPolicy, + // mode request’s mode. + mode: request.mode, + // credentials mode request’s credentials mode. + credentials: request.credentials, + // cache mode request’s cache mode. + cache: request.cache, + // redirect mode request’s redirect mode. + redirect: request.redirect, + // integrity metadata request’s integrity metadata. + integrity: request.integrity, + // keepalive request’s keepalive. + keepalive: request.keepalive, + // reload-navigation flag request’s reload-navigation flag. + reloadNavigation: request.reloadNavigation, + // history-navigation flag request’s history-navigation flag. + historyNavigation: request.historyNavigation, + // URL list A clone of request’s URL list. + urlList: [...request.urlList] + }); + const initHasKey = Object.keys(init).length !== 0; + if (initHasKey) { + if (request.mode === "navigate") { + request.mode = "same-origin"; + } + request.reloadNavigation = false; + request.historyNavigation = false; + request.origin = "client"; + request.referrer = "client"; + request.referrerPolicy = ""; + request.url = request.urlList[request.urlList.length - 1]; + request.urlList = [request.url]; + } + if (init.referrer !== void 0) { + const referrer = init.referrer; + if (referrer === "") { + request.referrer = "no-referrer"; + } else { + let parsedReferrer; + try { + parsedReferrer = new URL(referrer, baseUrl); + } catch (err) { + throw new TypeError(`Referrer "${referrer}" is not a valid URL.`, { cause: err }); + } + if (parsedReferrer.protocol === "about:" && parsedReferrer.hostname === "client" || origin && !sameOrigin(parsedReferrer, environmentSettingsObject.settingsObject.baseUrl)) { + request.referrer = "client"; + } else { + request.referrer = parsedReferrer; + } + } + } + if (init.referrerPolicy !== void 0) { + request.referrerPolicy = init.referrerPolicy; + } + let mode; + if (init.mode !== void 0) { + mode = init.mode; + } else { + mode = fallbackMode; + } + if (mode === "navigate") { + throw webidl.errors.exception({ + header: "Request constructor", + message: "invalid request mode navigate." + }); + } + if (mode != null) { + request.mode = mode; + } + if (init.credentials !== void 0) { + request.credentials = init.credentials; + } + if (init.cache !== void 0) { + request.cache = init.cache; + } + if (request.cache === "only-if-cached" && request.mode !== "same-origin") { + throw new TypeError( + "'only-if-cached' can be set only with 'same-origin' mode" + ); + } + if (init.redirect !== void 0) { + request.redirect = init.redirect; + } + if (init.integrity != null) { + request.integrity = String(init.integrity); + } + if (init.keepalive !== void 0) { + request.keepalive = Boolean(init.keepalive); + } + if (init.method !== void 0) { + let method = init.method; + const mayBeNormalized = normalizedMethodRecords[method]; + if (mayBeNormalized !== void 0) { + request.method = mayBeNormalized; + } else { + if (!isValidHTTPToken(method)) { + throw new TypeError(`'${method}' is not a valid HTTP method.`); + } + const upperCase = method.toUpperCase(); + if (forbiddenMethodsSet.has(upperCase)) { + throw new TypeError(`'${method}' HTTP method is unsupported.`); + } + method = normalizedMethodRecordsBase[upperCase] ?? method; + request.method = method; + } + if (!patchMethodWarning && request.method === "patch") { + process.emitWarning("Using `patch` is highly likely to result in a `405 Method Not Allowed`. `PATCH` is much more likely to succeed.", { + code: "UNDICI-FETCH-patch" + }); + patchMethodWarning = true; + } + } + if (init.signal !== void 0) { + signal = init.signal; + } + this[kState] = request; + const ac = new AbortController(); + this[kSignal] = ac.signal; + if (signal != null) { + if (!signal || typeof signal.aborted !== "boolean" || typeof signal.addEventListener !== "function") { + throw new TypeError( + "Failed to construct 'Request': member signal is not of type AbortSignal." + ); + } + if (signal.aborted) { + ac.abort(signal.reason); + } else { + this[kAbortController] = ac; + const acRef = new WeakRef(ac); + const abort = buildAbort(acRef); + try { + if (typeof getMaxListeners === "function" && getMaxListeners(signal) === defaultMaxListeners) { + setMaxListeners(1500, signal); + } else if (getEventListeners(signal, "abort").length >= defaultMaxListeners) { + setMaxListeners(1500, signal); + } + } catch { + } + util.addAbortListener(signal, abort); + requestFinalizer.register(ac, { signal, abort }, abort); + } + } + this[kHeaders] = new Headers2(kConstruct); + setHeadersList(this[kHeaders], request.headersList); + setHeadersGuard(this[kHeaders], "request"); + if (mode === "no-cors") { + if (!corsSafeListedMethodsSet.has(request.method)) { + throw new TypeError( + `'${request.method} is unsupported in no-cors mode.` + ); + } + setHeadersGuard(this[kHeaders], "request-no-cors"); + } + if (initHasKey) { + const headersList = getHeadersList(this[kHeaders]); + const headers = init.headers !== void 0 ? init.headers : new HeadersList(headersList); + headersList.clear(); + if (headers instanceof HeadersList) { + for (const { name, value } of headers.rawValues()) { + headersList.append(name, value, false); + } + headersList.cookies = headers.cookies; + } else { + fillHeaders(this[kHeaders], headers); + } + } + const inputBody = input instanceof _Request ? input[kState].body : null; + if ((init.body != null || inputBody != null) && (request.method === "GET" || request.method === "HEAD")) { + throw new TypeError("Request with GET/HEAD method cannot have body."); + } + let initBody = null; + if (init.body != null) { + const [extractedBody, contentType] = extractBody( + init.body, + request.keepalive + ); + initBody = extractedBody; + if (contentType && !getHeadersList(this[kHeaders]).contains("content-type", true)) { + this[kHeaders].append("content-type", contentType); + } + } + const inputOrInitBody = initBody ?? inputBody; + if (inputOrInitBody != null && inputOrInitBody.source == null) { + if (initBody != null && init.duplex == null) { + throw new TypeError("RequestInit: duplex option is required when sending a body."); + } + if (request.mode !== "same-origin" && request.mode !== "cors") { + throw new TypeError( + 'If request is made from ReadableStream, mode should be "same-origin" or "cors"' + ); + } + request.useCORSPreflightFlag = true; + } + let finalBody = inputOrInitBody; + if (initBody == null && inputBody != null) { + if (bodyUnusable(input)) { + throw new TypeError( + "Cannot construct a Request with a Request object that has already been used." + ); + } + const identityTransform = new TransformStream(); + inputBody.stream.pipeThrough(identityTransform); + finalBody = { + source: inputBody.source, + length: inputBody.length, + stream: identityTransform.readable + }; + } + this[kState].body = finalBody; + } + // Returns request’s HTTP method, which is "GET" by default. + get method() { + webidl.brandCheck(this, _Request); + return this[kState].method; + } + // Returns the URL of request as a string. + get url() { + webidl.brandCheck(this, _Request); + return URLSerializer(this[kState].url); + } + // Returns a Headers object consisting of the headers associated with request. + // Note that headers added in the network layer by the user agent will not + // be accounted for in this object, e.g., the "Host" header. + get headers() { + webidl.brandCheck(this, _Request); + return this[kHeaders]; + } + // Returns the kind of resource requested by request, e.g., "document" + // or "script". + get destination() { + webidl.brandCheck(this, _Request); + return this[kState].destination; + } + // Returns the referrer of request. Its value can be a same-origin URL if + // explicitly set in init, the empty string to indicate no referrer, and + // "about:client" when defaulting to the global’s default. This is used + // during fetching to determine the value of the `Referer` header of the + // request being made. + get referrer() { + webidl.brandCheck(this, _Request); + if (this[kState].referrer === "no-referrer") { + return ""; + } + if (this[kState].referrer === "client") { + return "about:client"; + } + return this[kState].referrer.toString(); + } + // Returns the referrer policy associated with request. + // This is used during fetching to compute the value of the request’s + // referrer. + get referrerPolicy() { + webidl.brandCheck(this, _Request); + return this[kState].referrerPolicy; + } + // Returns the mode associated with request, which is a string indicating + // whether the request will use CORS, or will be restricted to same-origin + // URLs. + get mode() { + webidl.brandCheck(this, _Request); + return this[kState].mode; + } + // Returns the credentials mode associated with request, + // which is a string indicating whether credentials will be sent with the + // request always, never, or only when sent to a same-origin URL. + get credentials() { + return this[kState].credentials; + } + // Returns the cache mode associated with request, + // which is a string indicating how the request will + // interact with the browser’s cache when fetching. + get cache() { + webidl.brandCheck(this, _Request); + return this[kState].cache; + } + // Returns the redirect mode associated with request, + // which is a string indicating how redirects for the + // request will be handled during fetching. A request + // will follow redirects by default. + get redirect() { + webidl.brandCheck(this, _Request); + return this[kState].redirect; + } + // Returns request’s subresource integrity metadata, which is a + // cryptographic hash of the resource being fetched. Its value + // consists of multiple hashes separated by whitespace. [SRI] + get integrity() { + webidl.brandCheck(this, _Request); + return this[kState].integrity; + } + // Returns a boolean indicating whether or not request can outlive the + // global in which it was created. + get keepalive() { + webidl.brandCheck(this, _Request); + return this[kState].keepalive; + } + // Returns a boolean indicating whether or not request is for a reload + // navigation. + get isReloadNavigation() { + webidl.brandCheck(this, _Request); + return this[kState].reloadNavigation; + } + // Returns a boolean indicating whether or not request is for a history + // navigation (a.k.a. back-forward navigation). + get isHistoryNavigation() { + webidl.brandCheck(this, _Request); + return this[kState].historyNavigation; + } + // Returns the signal associated with request, which is an AbortSignal + // object indicating whether or not request has been aborted, and its + // abort event handler. + get signal() { + webidl.brandCheck(this, _Request); + return this[kSignal]; + } + get body() { + webidl.brandCheck(this, _Request); + return this[kState].body ? this[kState].body.stream : null; + } + get bodyUsed() { + webidl.brandCheck(this, _Request); + return !!this[kState].body && util.isDisturbed(this[kState].body.stream); + } + get duplex() { + webidl.brandCheck(this, _Request); + return "half"; + } + // Returns a clone of request. + clone() { + webidl.brandCheck(this, _Request); + if (bodyUnusable(this)) { + throw new TypeError("unusable"); + } + const clonedRequest = cloneRequest(this[kState]); + const ac = new AbortController(); + if (this.signal.aborted) { + ac.abort(this.signal.reason); + } else { + let list2 = dependentControllerMap.get(this.signal); + if (list2 === void 0) { + list2 = /* @__PURE__ */ new Set(); + dependentControllerMap.set(this.signal, list2); + } + const acRef = new WeakRef(ac); + list2.add(acRef); + util.addAbortListener( + ac.signal, + buildAbort(acRef) + ); + } + return fromInnerRequest(clonedRequest, ac.signal, getHeadersGuard(this[kHeaders])); + } + [nodeUtil.inspect.custom](depth, options) { + if (options.depth === null) { + options.depth = 2; + } + options.colors ??= true; + const properties = { + method: this.method, + url: this.url, + headers: this.headers, + destination: this.destination, + referrer: this.referrer, + referrerPolicy: this.referrerPolicy, + mode: this.mode, + credentials: this.credentials, + cache: this.cache, + redirect: this.redirect, + integrity: this.integrity, + keepalive: this.keepalive, + isReloadNavigation: this.isReloadNavigation, + isHistoryNavigation: this.isHistoryNavigation, + signal: this.signal + }; + return `Request ${nodeUtil.formatWithOptions(options, properties)}`; + } + }; + mixinBody(Request2); + function makeRequest(init) { + return { + method: init.method ?? "GET", + localURLsOnly: init.localURLsOnly ?? false, + unsafeRequest: init.unsafeRequest ?? false, + body: init.body ?? null, + client: init.client ?? null, + reservedClient: init.reservedClient ?? null, + replacesClientId: init.replacesClientId ?? "", + window: init.window ?? "client", + keepalive: init.keepalive ?? false, + serviceWorkers: init.serviceWorkers ?? "all", + initiator: init.initiator ?? "", + destination: init.destination ?? "", + priority: init.priority ?? null, + origin: init.origin ?? "client", + policyContainer: init.policyContainer ?? "client", + referrer: init.referrer ?? "client", + referrerPolicy: init.referrerPolicy ?? "", + mode: init.mode ?? "no-cors", + useCORSPreflightFlag: init.useCORSPreflightFlag ?? false, + credentials: init.credentials ?? "same-origin", + useCredentials: init.useCredentials ?? false, + cache: init.cache ?? "default", + redirect: init.redirect ?? "follow", + integrity: init.integrity ?? "", + cryptoGraphicsNonceMetadata: init.cryptoGraphicsNonceMetadata ?? "", + parserMetadata: init.parserMetadata ?? "", + reloadNavigation: init.reloadNavigation ?? false, + historyNavigation: init.historyNavigation ?? false, + userActivation: init.userActivation ?? false, + taintedOrigin: init.taintedOrigin ?? false, + redirectCount: init.redirectCount ?? 0, + responseTainting: init.responseTainting ?? "basic", + preventNoCacheCacheControlHeaderModification: init.preventNoCacheCacheControlHeaderModification ?? false, + done: init.done ?? false, + timingAllowFailed: init.timingAllowFailed ?? false, + urlList: init.urlList, + url: init.urlList[0], + headersList: init.headersList ? new HeadersList(init.headersList) : new HeadersList() + }; + } + function cloneRequest(request) { + const newRequest = makeRequest({ ...request, body: null }); + if (request.body != null) { + newRequest.body = cloneBody(newRequest, request.body); + } + return newRequest; + } + function fromInnerRequest(innerRequest, signal, guard) { + const request = new Request2(kConstruct); + request[kState] = innerRequest; + request[kSignal] = signal; + request[kHeaders] = new Headers2(kConstruct); + setHeadersList(request[kHeaders], innerRequest.headersList); + setHeadersGuard(request[kHeaders], guard); + return request; + } + Object.defineProperties(Request2.prototype, { + method: kEnumerableProperty, + url: kEnumerableProperty, + headers: kEnumerableProperty, + redirect: kEnumerableProperty, + clone: kEnumerableProperty, + signal: kEnumerableProperty, + duplex: kEnumerableProperty, + destination: kEnumerableProperty, + body: kEnumerableProperty, + bodyUsed: kEnumerableProperty, + isHistoryNavigation: kEnumerableProperty, + isReloadNavigation: kEnumerableProperty, + keepalive: kEnumerableProperty, + integrity: kEnumerableProperty, + cache: kEnumerableProperty, + credentials: kEnumerableProperty, + attribute: kEnumerableProperty, + referrerPolicy: kEnumerableProperty, + referrer: kEnumerableProperty, + mode: kEnumerableProperty, + [Symbol.toStringTag]: { + value: "Request", + configurable: true + } + }); + webidl.converters.Request = webidl.interfaceConverter( + Request2 + ); + webidl.converters.RequestInfo = function(V, prefix, argument) { + if (typeof V === "string") { + return webidl.converters.USVString(V, prefix, argument); + } + if (V instanceof Request2) { + return webidl.converters.Request(V, prefix, argument); + } + return webidl.converters.USVString(V, prefix, argument); + }; + webidl.converters.AbortSignal = webidl.interfaceConverter( + AbortSignal + ); + webidl.converters.RequestInit = webidl.dictionaryConverter([ + { + key: "method", + converter: webidl.converters.ByteString + }, + { + key: "headers", + converter: webidl.converters.HeadersInit + }, + { + key: "body", + converter: webidl.nullableConverter( + webidl.converters.BodyInit + ) + }, + { + key: "referrer", + converter: webidl.converters.USVString + }, + { + key: "referrerPolicy", + converter: webidl.converters.DOMString, + // https://w3c.github.io/webappsec-referrer-policy/#referrer-policy + allowedValues: referrerPolicy + }, + { + key: "mode", + converter: webidl.converters.DOMString, + // https://fetch.spec.whatwg.org/#concept-request-mode + allowedValues: requestMode + }, + { + key: "credentials", + converter: webidl.converters.DOMString, + // https://fetch.spec.whatwg.org/#requestcredentials + allowedValues: requestCredentials + }, + { + key: "cache", + converter: webidl.converters.DOMString, + // https://fetch.spec.whatwg.org/#requestcache + allowedValues: requestCache + }, + { + key: "redirect", + converter: webidl.converters.DOMString, + // https://fetch.spec.whatwg.org/#requestredirect + allowedValues: requestRedirect + }, + { + key: "integrity", + converter: webidl.converters.DOMString + }, + { + key: "keepalive", + converter: webidl.converters.boolean + }, + { + key: "signal", + converter: webidl.nullableConverter( + (signal) => webidl.converters.AbortSignal( + signal, + "RequestInit", + "signal", + { strict: false } + ) + ) + }, + { + key: "window", + converter: webidl.converters.any + }, + { + key: "duplex", + converter: webidl.converters.DOMString, + allowedValues: requestDuplex + }, + { + key: "dispatcher", + // undici specific option + converter: webidl.converters.any + } + ]); + module.exports = { Request: Request2, makeRequest, fromInnerRequest, cloneRequest }; + } +}); + +// viewer/node_modules/undici/lib/web/fetch/index.js +var require_fetch = __commonJS({ + "viewer/node_modules/undici/lib/web/fetch/index.js"(exports, module) { + "use strict"; + var { + makeNetworkError, + makeAppropriateNetworkError, + filterResponse, + makeResponse, + fromInnerResponse + } = require_response(); + var { HeadersList } = require_headers(); + var { Request: Request2, cloneRequest } = require_request2(); + var zlib = __require("node:zlib"); + var { + bytesMatch, + makePolicyContainer, + clonePolicyContainer, + requestBadPort, + TAOCheck, + appendRequestOriginHeader, + responseLocationURL, + requestCurrentURL, + setRequestReferrerPolicyOnRedirect, + tryUpgradeRequestToAPotentiallyTrustworthyURL, + createOpaqueTimingInfo, + appendFetchMetadata, + corsCheck, + crossOriginResourcePolicyCheck, + determineRequestsReferrer, + coarsenedSharedCurrentTime, + createDeferredPromise, + isBlobLike, + sameOrigin, + isCancelled, + isAborted, + isErrorLike, + fullyReadBody, + readableStreamClose, + isomorphicEncode, + urlIsLocal, + urlIsHttpHttpsScheme, + urlHasHttpsScheme, + clampAndCoarsenConnectionTimingInfo, + simpleRangeHeaderValue, + buildContentRange, + createInflate, + extractMimeType + } = require_util2(); + var { kState, kDispatcher } = require_symbols2(); + var assert = __require("node:assert"); + var { safelyExtractBody, extractBody } = require_body(); + var { + redirectStatusSet, + nullBodyStatus, + safeMethodsSet, + requestBodyHeader, + subresourceSet + } = require_constants3(); + var EE = __require("node:events"); + var { Readable: Readable2, pipeline, finished } = __require("node:stream"); + var { addAbortListener, isErrored, isReadable, bufferToLowerCasedHeaderName } = require_util(); + var { dataURLProcessor, serializeAMimeType, minimizeSupportedMimeType } = require_data_url(); + var { getGlobalDispatcher } = require_global2(); + var { webidl } = require_webidl(); + var { STATUS_CODES } = __require("node:http"); + var GET_OR_HEAD = ["GET", "HEAD"]; + var defaultUserAgent = typeof __UNDICI_IS_NODE__ !== "undefined" || typeof esbuildDetection !== "undefined" ? "node" : "undici"; + var resolveObjectURL; + var Fetch = class extends EE { + constructor(dispatcher) { + super(); + this.dispatcher = dispatcher; + this.connection = null; + this.dump = false; + this.state = "ongoing"; + } + terminate(reason) { + if (this.state !== "ongoing") { + return; + } + this.state = "terminated"; + this.connection?.destroy(reason); + this.emit("terminated", reason); + } + // https://fetch.spec.whatwg.org/#fetch-controller-abort + abort(error) { + if (this.state !== "ongoing") { + return; + } + this.state = "aborted"; + if (!error) { + error = new DOMException("The operation was aborted.", "AbortError"); + } + this.serializedAbortReason = error; + this.connection?.destroy(error); + this.emit("terminated", error); + } + }; + function handleFetchDone(response) { + finalizeAndReportTiming(response, "fetch"); + } + function fetch3(input, init = void 0) { + webidl.argumentLengthCheck(arguments, 1, "globalThis.fetch"); + let p = createDeferredPromise(); + let requestObject; + try { + requestObject = new Request2(input, init); + } catch (e) { + p.reject(e); + return p.promise; + } + const request = requestObject[kState]; + if (requestObject.signal.aborted) { + abortFetch(p, request, null, requestObject.signal.reason); + return p.promise; + } + const globalObject = request.client.globalObject; + if (globalObject?.constructor?.name === "ServiceWorkerGlobalScope") { + request.serviceWorkers = "none"; + } + let responseObject = null; + let locallyAborted = false; + let controller = null; + addAbortListener( + requestObject.signal, + () => { + locallyAborted = true; + assert(controller != null); + controller.abort(requestObject.signal.reason); + const realResponse = responseObject?.deref(); + abortFetch(p, request, realResponse, requestObject.signal.reason); + } + ); + const processResponse = (response) => { + if (locallyAborted) { + return; + } + if (response.aborted) { + abortFetch(p, request, responseObject, controller.serializedAbortReason); + return; + } + if (response.type === "error") { + p.reject(new TypeError("fetch failed", { cause: response.error })); + return; + } + responseObject = new WeakRef(fromInnerResponse(response, "immutable")); + p.resolve(responseObject.deref()); + p = null; + }; + controller = fetching({ + request, + processResponseEndOfBody: handleFetchDone, + processResponse, + dispatcher: requestObject[kDispatcher] + // undici + }); + return p.promise; + } + function finalizeAndReportTiming(response, initiatorType = "other") { + if (response.type === "error" && response.aborted) { + return; + } + if (!response.urlList?.length) { + return; + } + const originalURL = response.urlList[0]; + let timingInfo = response.timingInfo; + let cacheState = response.cacheState; + if (!urlIsHttpHttpsScheme(originalURL)) { + return; + } + if (timingInfo === null) { + return; + } + if (!response.timingAllowPassed) { + timingInfo = createOpaqueTimingInfo({ + startTime: timingInfo.startTime + }); + cacheState = ""; + } + timingInfo.endTime = coarsenedSharedCurrentTime(); + response.timingInfo = timingInfo; + markResourceTiming( + timingInfo, + originalURL.href, + initiatorType, + globalThis, + cacheState + ); + } + var markResourceTiming = performance.markResourceTiming; + function abortFetch(p, request, responseObject, error) { + if (p) { + p.reject(error); + } + if (request.body != null && isReadable(request.body?.stream)) { + request.body.stream.cancel(error).catch((err) => { + if (err.code === "ERR_INVALID_STATE") { + return; + } + throw err; + }); + } + if (responseObject == null) { + return; + } + const response = responseObject[kState]; + if (response.body != null && isReadable(response.body?.stream)) { + response.body.stream.cancel(error).catch((err) => { + if (err.code === "ERR_INVALID_STATE") { + return; + } + throw err; + }); + } + } + function fetching({ + request, + processRequestBodyChunkLength, + processRequestEndOfBody, + processResponse, + processResponseEndOfBody, + processResponseConsumeBody, + useParallelQueue = false, + dispatcher = getGlobalDispatcher() + // undici + }) { + assert(dispatcher); + let taskDestination = null; + let crossOriginIsolatedCapability = false; + if (request.client != null) { + taskDestination = request.client.globalObject; + crossOriginIsolatedCapability = request.client.crossOriginIsolatedCapability; + } + const currentTime = coarsenedSharedCurrentTime(crossOriginIsolatedCapability); + const timingInfo = createOpaqueTimingInfo({ + startTime: currentTime + }); + const fetchParams = { + controller: new Fetch(dispatcher), + request, + timingInfo, + processRequestBodyChunkLength, + processRequestEndOfBody, + processResponse, + processResponseConsumeBody, + processResponseEndOfBody, + taskDestination, + crossOriginIsolatedCapability + }; + assert(!request.body || request.body.stream); + if (request.window === "client") { + request.window = request.client?.globalObject?.constructor?.name === "Window" ? request.client : "no-window"; + } + if (request.origin === "client") { + request.origin = request.client.origin; + } + if (request.policyContainer === "client") { + if (request.client != null) { + request.policyContainer = clonePolicyContainer( + request.client.policyContainer + ); + } else { + request.policyContainer = makePolicyContainer(); + } + } + if (!request.headersList.contains("accept", true)) { + const value = "*/*"; + request.headersList.append("accept", value, true); + } + if (!request.headersList.contains("accept-language", true)) { + request.headersList.append("accept-language", "*", true); + } + if (request.priority === null) { + } + if (subresourceSet.has(request.destination)) { + } + mainFetch(fetchParams).catch((err) => { + fetchParams.controller.terminate(err); + }); + return fetchParams.controller; + } + async function mainFetch(fetchParams, recursive = false) { + const request = fetchParams.request; + let response = null; + if (request.localURLsOnly && !urlIsLocal(requestCurrentURL(request))) { + response = makeNetworkError("local URLs only"); + } + tryUpgradeRequestToAPotentiallyTrustworthyURL(request); + if (requestBadPort(request) === "blocked") { + response = makeNetworkError("bad port"); + } + if (request.referrerPolicy === "") { + request.referrerPolicy = request.policyContainer.referrerPolicy; + } + if (request.referrer !== "no-referrer") { + request.referrer = determineRequestsReferrer(request); + } + if (response === null) { + response = await (async () => { + const currentURL = requestCurrentURL(request); + if ( + // - request’s current URL’s origin is same origin with request’s origin, + // and request’s response tainting is "basic" + sameOrigin(currentURL, request.url) && request.responseTainting === "basic" || // request’s current URL’s scheme is "data" + currentURL.protocol === "data:" || // - request’s mode is "navigate" or "websocket" + (request.mode === "navigate" || request.mode === "websocket") + ) { + request.responseTainting = "basic"; + return await schemeFetch(fetchParams); + } + if (request.mode === "same-origin") { + return makeNetworkError('request mode cannot be "same-origin"'); + } + if (request.mode === "no-cors") { + if (request.redirect !== "follow") { + return makeNetworkError( + 'redirect mode cannot be "follow" for "no-cors" request' + ); + } + request.responseTainting = "opaque"; + return await schemeFetch(fetchParams); + } + if (!urlIsHttpHttpsScheme(requestCurrentURL(request))) { + return makeNetworkError("URL scheme must be a HTTP(S) scheme"); + } + request.responseTainting = "cors"; + return await httpFetch(fetchParams); + })(); + } + if (recursive) { + return response; + } + if (response.status !== 0 && !response.internalResponse) { + if (request.responseTainting === "cors") { + } + if (request.responseTainting === "basic") { + response = filterResponse(response, "basic"); + } else if (request.responseTainting === "cors") { + response = filterResponse(response, "cors"); + } else if (request.responseTainting === "opaque") { + response = filterResponse(response, "opaque"); + } else { + assert(false); + } + } + let internalResponse = response.status === 0 ? response : response.internalResponse; + if (internalResponse.urlList.length === 0) { + internalResponse.urlList.push(...request.urlList); + } + if (!request.timingAllowFailed) { + response.timingAllowPassed = true; + } + if (response.type === "opaque" && internalResponse.status === 206 && internalResponse.rangeRequested && !request.headers.contains("range", true)) { + response = internalResponse = makeNetworkError(); + } + if (response.status !== 0 && (request.method === "HEAD" || request.method === "CONNECT" || nullBodyStatus.includes(internalResponse.status))) { + internalResponse.body = null; + fetchParams.controller.dump = true; + } + if (request.integrity) { + const processBodyError = (reason) => fetchFinale(fetchParams, makeNetworkError(reason)); + if (request.responseTainting === "opaque" || response.body == null) { + processBodyError(response.error); + return; + } + const processBody = (bytes2) => { + if (!bytesMatch(bytes2, request.integrity)) { + processBodyError("integrity mismatch"); + return; + } + response.body = safelyExtractBody(bytes2)[0]; + fetchFinale(fetchParams, response); + }; + await fullyReadBody(response.body, processBody, processBodyError); + } else { + fetchFinale(fetchParams, response); + } + } + function schemeFetch(fetchParams) { + if (isCancelled(fetchParams) && fetchParams.request.redirectCount === 0) { + return Promise.resolve(makeAppropriateNetworkError(fetchParams)); + } + const { request } = fetchParams; + const { protocol: scheme } = requestCurrentURL(request); + switch (scheme) { + case "about:": { + return Promise.resolve(makeNetworkError("about scheme is not supported")); + } + case "blob:": { + if (!resolveObjectURL) { + resolveObjectURL = __require("node:buffer").resolveObjectURL; + } + const blobURLEntry = requestCurrentURL(request); + if (blobURLEntry.search.length !== 0) { + return Promise.resolve(makeNetworkError("NetworkError when attempting to fetch resource.")); + } + const blob = resolveObjectURL(blobURLEntry.toString()); + if (request.method !== "GET" || !isBlobLike(blob)) { + return Promise.resolve(makeNetworkError("invalid method")); + } + const response = makeResponse(); + const fullLength = blob.size; + const serializedFullLength = isomorphicEncode(`${fullLength}`); + const type = blob.type; + if (!request.headersList.contains("range", true)) { + const bodyWithType = extractBody(blob); + response.statusText = "OK"; + response.body = bodyWithType[0]; + response.headersList.set("content-length", serializedFullLength, true); + response.headersList.set("content-type", type, true); + } else { + response.rangeRequested = true; + const rangeHeader = request.headersList.get("range", true); + const rangeValue = simpleRangeHeaderValue(rangeHeader, true); + if (rangeValue === "failure") { + return Promise.resolve(makeNetworkError("failed to fetch the data URL")); + } + let { rangeStartValue: rangeStart, rangeEndValue: rangeEnd } = rangeValue; + if (rangeStart === null) { + rangeStart = fullLength - rangeEnd; + rangeEnd = rangeStart + rangeEnd - 1; + } else { + if (rangeStart >= fullLength) { + return Promise.resolve(makeNetworkError("Range start is greater than the blob's size.")); + } + if (rangeEnd === null || rangeEnd >= fullLength) { + rangeEnd = fullLength - 1; + } + } + const slicedBlob = blob.slice(rangeStart, rangeEnd, type); + const slicedBodyWithType = extractBody(slicedBlob); + response.body = slicedBodyWithType[0]; + const serializedSlicedLength = isomorphicEncode(`${slicedBlob.size}`); + const contentRange = buildContentRange(rangeStart, rangeEnd, fullLength); + response.status = 206; + response.statusText = "Partial Content"; + response.headersList.set("content-length", serializedSlicedLength, true); + response.headersList.set("content-type", type, true); + response.headersList.set("content-range", contentRange, true); + } + return Promise.resolve(response); + } + case "data:": { + const currentURL = requestCurrentURL(request); + const dataURLStruct = dataURLProcessor(currentURL); + if (dataURLStruct === "failure") { + return Promise.resolve(makeNetworkError("failed to fetch the data URL")); + } + const mimeType = serializeAMimeType(dataURLStruct.mimeType); + return Promise.resolve(makeResponse({ + statusText: "OK", + headersList: [ + ["content-type", { name: "Content-Type", value: mimeType }] + ], + body: safelyExtractBody(dataURLStruct.body)[0] + })); + } + case "file:": { + return Promise.resolve(makeNetworkError("not implemented... yet...")); + } + case "http:": + case "https:": { + return httpFetch(fetchParams).catch((err) => makeNetworkError(err)); + } + default: { + return Promise.resolve(makeNetworkError("unknown scheme")); + } + } + } + function finalizeResponse(fetchParams, response) { + fetchParams.request.done = true; + if (fetchParams.processResponseDone != null) { + queueMicrotask(() => fetchParams.processResponseDone(response)); + } + } + function fetchFinale(fetchParams, response) { + let timingInfo = fetchParams.timingInfo; + const processResponseEndOfBody = () => { + const unsafeEndTime = Date.now(); + if (fetchParams.request.destination === "document") { + fetchParams.controller.fullTimingInfo = timingInfo; + } + fetchParams.controller.reportTimingSteps = () => { + if (fetchParams.request.url.protocol !== "https:") { + return; + } + timingInfo.endTime = unsafeEndTime; + let cacheState = response.cacheState; + const bodyInfo = response.bodyInfo; + if (!response.timingAllowPassed) { + timingInfo = createOpaqueTimingInfo(timingInfo); + cacheState = ""; + } + let responseStatus = 0; + if (fetchParams.request.mode !== "navigator" || !response.hasCrossOriginRedirects) { + responseStatus = response.status; + const mimeType = extractMimeType(response.headersList); + if (mimeType !== "failure") { + bodyInfo.contentType = minimizeSupportedMimeType(mimeType); + } + } + if (fetchParams.request.initiatorType != null) { + markResourceTiming(timingInfo, fetchParams.request.url.href, fetchParams.request.initiatorType, globalThis, cacheState, bodyInfo, responseStatus); + } + }; + const processResponseEndOfBodyTask = () => { + fetchParams.request.done = true; + if (fetchParams.processResponseEndOfBody != null) { + queueMicrotask(() => fetchParams.processResponseEndOfBody(response)); + } + if (fetchParams.request.initiatorType != null) { + fetchParams.controller.reportTimingSteps(); + } + }; + queueMicrotask(() => processResponseEndOfBodyTask()); + }; + if (fetchParams.processResponse != null) { + queueMicrotask(() => { + fetchParams.processResponse(response); + fetchParams.processResponse = null; + }); + } + const internalResponse = response.type === "error" ? response : response.internalResponse ?? response; + if (internalResponse.body == null) { + processResponseEndOfBody(); + } else { + finished(internalResponse.body.stream, () => { + processResponseEndOfBody(); + }); + } + } + async function httpFetch(fetchParams) { + const request = fetchParams.request; + let response = null; + let actualResponse = null; + const timingInfo = fetchParams.timingInfo; + if (request.serviceWorkers === "all") { + } + if (response === null) { + if (request.redirect === "follow") { + request.serviceWorkers = "none"; + } + actualResponse = response = await httpNetworkOrCacheFetch(fetchParams); + if (request.responseTainting === "cors" && corsCheck(request, response) === "failure") { + return makeNetworkError("cors failure"); + } + if (TAOCheck(request, response) === "failure") { + request.timingAllowFailed = true; + } + } + if ((request.responseTainting === "opaque" || response.type === "opaque") && crossOriginResourcePolicyCheck( + request.origin, + request.client, + request.destination, + actualResponse + ) === "blocked") { + return makeNetworkError("blocked"); + } + if (redirectStatusSet.has(actualResponse.status)) { + if (request.redirect !== "manual") { + fetchParams.controller.connection.destroy(void 0, false); + } + if (request.redirect === "error") { + response = makeNetworkError("unexpected redirect"); + } else if (request.redirect === "manual") { + response = actualResponse; + } else if (request.redirect === "follow") { + response = await httpRedirectFetch(fetchParams, response); + } else { + assert(false); + } + } + response.timingInfo = timingInfo; + return response; + } + function httpRedirectFetch(fetchParams, response) { + const request = fetchParams.request; + const actualResponse = response.internalResponse ? response.internalResponse : response; + let locationURL; + try { + locationURL = responseLocationURL( + actualResponse, + requestCurrentURL(request).hash + ); + if (locationURL == null) { + return response; + } + } catch (err) { + return Promise.resolve(makeNetworkError(err)); + } + if (!urlIsHttpHttpsScheme(locationURL)) { + return Promise.resolve(makeNetworkError("URL scheme must be a HTTP(S) scheme")); + } + if (request.redirectCount === 20) { + return Promise.resolve(makeNetworkError("redirect count exceeded")); + } + request.redirectCount += 1; + if (request.mode === "cors" && (locationURL.username || locationURL.password) && !sameOrigin(request, locationURL)) { + return Promise.resolve(makeNetworkError('cross origin not allowed for request mode "cors"')); + } + if (request.responseTainting === "cors" && (locationURL.username || locationURL.password)) { + return Promise.resolve(makeNetworkError( + 'URL cannot contain credentials for request mode "cors"' + )); + } + if (actualResponse.status !== 303 && request.body != null && request.body.source == null) { + return Promise.resolve(makeNetworkError()); + } + if ([301, 302].includes(actualResponse.status) && request.method === "POST" || actualResponse.status === 303 && !GET_OR_HEAD.includes(request.method)) { + request.method = "GET"; + request.body = null; + for (const headerName of requestBodyHeader) { + request.headersList.delete(headerName); + } + } + if (!sameOrigin(requestCurrentURL(request), locationURL)) { + request.headersList.delete("authorization", true); + request.headersList.delete("proxy-authorization", true); + request.headersList.delete("cookie", true); + request.headersList.delete("host", true); + } + if (request.body != null) { + assert(request.body.source != null); + request.body = safelyExtractBody(request.body.source)[0]; + } + const timingInfo = fetchParams.timingInfo; + timingInfo.redirectEndTime = timingInfo.postRedirectStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability); + if (timingInfo.redirectStartTime === 0) { + timingInfo.redirectStartTime = timingInfo.startTime; + } + request.urlList.push(locationURL); + setRequestReferrerPolicyOnRedirect(request, actualResponse); + return mainFetch(fetchParams, true); + } + async function httpNetworkOrCacheFetch(fetchParams, isAuthenticationFetch = false, isNewConnectionFetch = false) { + const request = fetchParams.request; + let httpFetchParams = null; + let httpRequest = null; + let response = null; + const httpCache = null; + const revalidatingFlag = false; + if (request.window === "no-window" && request.redirect === "error") { + httpFetchParams = fetchParams; + httpRequest = request; + } else { + httpRequest = cloneRequest(request); + httpFetchParams = { ...fetchParams }; + httpFetchParams.request = httpRequest; + } + const includeCredentials = request.credentials === "include" || request.credentials === "same-origin" && request.responseTainting === "basic"; + const contentLength = httpRequest.body ? httpRequest.body.length : null; + let contentLengthHeaderValue = null; + if (httpRequest.body == null && ["POST", "PUT"].includes(httpRequest.method)) { + contentLengthHeaderValue = "0"; + } + if (contentLength != null) { + contentLengthHeaderValue = isomorphicEncode(`${contentLength}`); + } + if (contentLengthHeaderValue != null) { + httpRequest.headersList.append("content-length", contentLengthHeaderValue, true); + } + if (contentLength != null && httpRequest.keepalive) { + } + if (httpRequest.referrer instanceof URL) { + httpRequest.headersList.append("referer", isomorphicEncode(httpRequest.referrer.href), true); + } + appendRequestOriginHeader(httpRequest); + appendFetchMetadata(httpRequest); + if (!httpRequest.headersList.contains("user-agent", true)) { + httpRequest.headersList.append("user-agent", defaultUserAgent); + } + if (httpRequest.cache === "default" && (httpRequest.headersList.contains("if-modified-since", true) || httpRequest.headersList.contains("if-none-match", true) || httpRequest.headersList.contains("if-unmodified-since", true) || httpRequest.headersList.contains("if-match", true) || httpRequest.headersList.contains("if-range", true))) { + httpRequest.cache = "no-store"; + } + if (httpRequest.cache === "no-cache" && !httpRequest.preventNoCacheCacheControlHeaderModification && !httpRequest.headersList.contains("cache-control", true)) { + httpRequest.headersList.append("cache-control", "max-age=0", true); + } + if (httpRequest.cache === "no-store" || httpRequest.cache === "reload") { + if (!httpRequest.headersList.contains("pragma", true)) { + httpRequest.headersList.append("pragma", "no-cache", true); + } + if (!httpRequest.headersList.contains("cache-control", true)) { + httpRequest.headersList.append("cache-control", "no-cache", true); + } + } + if (httpRequest.headersList.contains("range", true)) { + httpRequest.headersList.append("accept-encoding", "identity", true); + } + if (!httpRequest.headersList.contains("accept-encoding", true)) { + if (urlHasHttpsScheme(requestCurrentURL(httpRequest))) { + httpRequest.headersList.append("accept-encoding", "br, gzip, deflate", true); + } else { + httpRequest.headersList.append("accept-encoding", "gzip, deflate", true); + } + } + httpRequest.headersList.delete("host", true); + if (includeCredentials) { + } + if (httpCache == null) { + httpRequest.cache = "no-store"; + } + if (httpRequest.cache !== "no-store" && httpRequest.cache !== "reload") { + } + if (response == null) { + if (httpRequest.cache === "only-if-cached") { + return makeNetworkError("only if cached"); + } + const forwardResponse = await httpNetworkFetch( + httpFetchParams, + includeCredentials, + isNewConnectionFetch + ); + if (!safeMethodsSet.has(httpRequest.method) && forwardResponse.status >= 200 && forwardResponse.status <= 399) { + } + if (revalidatingFlag && forwardResponse.status === 304) { + } + if (response == null) { + response = forwardResponse; + } + } + response.urlList = [...httpRequest.urlList]; + if (httpRequest.headersList.contains("range", true)) { + response.rangeRequested = true; + } + response.requestIncludesCredentials = includeCredentials; + if (response.status === 407) { + if (request.window === "no-window") { + return makeNetworkError(); + } + if (isCancelled(fetchParams)) { + return makeAppropriateNetworkError(fetchParams); + } + return makeNetworkError("proxy authentication required"); + } + if ( + // response’s status is 421 + response.status === 421 && // isNewConnectionFetch is false + !isNewConnectionFetch && // request’s body is null, or request’s body is non-null and request’s body’s source is non-null + (request.body == null || request.body.source != null) + ) { + if (isCancelled(fetchParams)) { + return makeAppropriateNetworkError(fetchParams); + } + fetchParams.controller.connection.destroy(); + response = await httpNetworkOrCacheFetch( + fetchParams, + isAuthenticationFetch, + true + ); + } + if (isAuthenticationFetch) { + } + return response; + } + async function httpNetworkFetch(fetchParams, includeCredentials = false, forceNewConnection = false) { + assert(!fetchParams.controller.connection || fetchParams.controller.connection.destroyed); + fetchParams.controller.connection = { + abort: null, + destroyed: false, + destroy(err, abort = true) { + if (!this.destroyed) { + this.destroyed = true; + if (abort) { + this.abort?.(err ?? new DOMException("The operation was aborted.", "AbortError")); + } + } + } + }; + const request = fetchParams.request; + let response = null; + const timingInfo = fetchParams.timingInfo; + const httpCache = null; + if (httpCache == null) { + request.cache = "no-store"; + } + const newConnection = forceNewConnection ? "yes" : "no"; + if (request.mode === "websocket") { + } else { + } + let requestBody = null; + if (request.body == null && fetchParams.processRequestEndOfBody) { + queueMicrotask(() => fetchParams.processRequestEndOfBody()); + } else if (request.body != null) { + const processBodyChunk = async function* (bytes2) { + if (isCancelled(fetchParams)) { + return; + } + yield bytes2; + fetchParams.processRequestBodyChunkLength?.(bytes2.byteLength); + }; + const processEndOfBody = () => { + if (isCancelled(fetchParams)) { + return; + } + if (fetchParams.processRequestEndOfBody) { + fetchParams.processRequestEndOfBody(); + } + }; + const processBodyError = (e) => { + if (isCancelled(fetchParams)) { + return; + } + if (e.name === "AbortError") { + fetchParams.controller.abort(); + } else { + fetchParams.controller.terminate(e); + } + }; + requestBody = (async function* () { + try { + for await (const bytes2 of request.body.stream) { + yield* processBodyChunk(bytes2); + } + processEndOfBody(); + } catch (err) { + processBodyError(err); + } + })(); + } + try { + const { body, status, statusText, headersList, socket } = await dispatch({ body: requestBody }); + if (socket) { + response = makeResponse({ status, statusText, headersList, socket }); + } else { + const iterator = body[Symbol.asyncIterator](); + fetchParams.controller.next = () => iterator.next(); + response = makeResponse({ status, statusText, headersList }); + } + } catch (err) { + if (err.name === "AbortError") { + fetchParams.controller.connection.destroy(); + return makeAppropriateNetworkError(fetchParams, err); + } + return makeNetworkError(err); + } + const pullAlgorithm = async () => { + await fetchParams.controller.resume(); + }; + const cancelAlgorithm = (reason) => { + if (!isCancelled(fetchParams)) { + fetchParams.controller.abort(reason); + } + }; + const stream = new ReadableStream( + { + async start(controller) { + fetchParams.controller.controller = controller; + }, + async pull(controller) { + await pullAlgorithm(controller); + }, + async cancel(reason) { + await cancelAlgorithm(reason); + }, + type: "bytes" + } + ); + response.body = { stream, source: null, length: null }; + fetchParams.controller.onAborted = onAborted; + fetchParams.controller.on("terminated", onAborted); + fetchParams.controller.resume = async () => { + while (true) { + let bytes2; + let isFailure; + try { + const { done, value } = await fetchParams.controller.next(); + if (isAborted(fetchParams)) { + break; + } + bytes2 = done ? void 0 : value; + } catch (err) { + if (fetchParams.controller.ended && !timingInfo.encodedBodySize) { + bytes2 = void 0; + } else { + bytes2 = err; + isFailure = true; + } + } + if (bytes2 === void 0) { + readableStreamClose(fetchParams.controller.controller); + finalizeResponse(fetchParams, response); + return; + } + timingInfo.decodedBodySize += bytes2?.byteLength ?? 0; + if (isFailure) { + fetchParams.controller.terminate(bytes2); + return; + } + const buffer = new Uint8Array(bytes2); + if (buffer.byteLength) { + fetchParams.controller.controller.enqueue(buffer); + } + if (isErrored(stream)) { + fetchParams.controller.terminate(); + return; + } + if (fetchParams.controller.controller.desiredSize <= 0) { + return; + } + } + }; + function onAborted(reason) { + if (isAborted(fetchParams)) { + response.aborted = true; + if (isReadable(stream)) { + fetchParams.controller.controller.error( + fetchParams.controller.serializedAbortReason + ); + } + } else { + if (isReadable(stream)) { + fetchParams.controller.controller.error(new TypeError("terminated", { + cause: isErrorLike(reason) ? reason : void 0 + })); + } + } + fetchParams.controller.connection.destroy(); + } + return response; + function dispatch({ body }) { + const url = requestCurrentURL(request); + const agent = fetchParams.controller.dispatcher; + return new Promise((resolve, reject) => agent.dispatch( + { + path: url.pathname + url.search, + origin: url.origin, + method: request.method, + body: agent.isMockActive ? request.body && (request.body.source || request.body.stream) : body, + headers: request.headersList.entries, + maxRedirections: 0, + upgrade: request.mode === "websocket" ? "websocket" : void 0 + }, + { + body: null, + abort: null, + onConnect(abort) { + const { connection } = fetchParams.controller; + timingInfo.finalConnectionTimingInfo = clampAndCoarsenConnectionTimingInfo(void 0, timingInfo.postRedirectStartTime, fetchParams.crossOriginIsolatedCapability); + if (connection.destroyed) { + abort(new DOMException("The operation was aborted.", "AbortError")); + } else { + fetchParams.controller.on("terminated", abort); + this.abort = connection.abort = abort; + } + timingInfo.finalNetworkRequestStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability); + }, + onResponseStarted() { + timingInfo.finalNetworkResponseStartTime = coarsenedSharedCurrentTime(fetchParams.crossOriginIsolatedCapability); + }, + onHeaders(status, rawHeaders, resume, statusText) { + if (status < 200) { + return; + } + let location = ""; + const headersList = new HeadersList(); + for (let i = 0; i < rawHeaders.length; i += 2) { + headersList.append(bufferToLowerCasedHeaderName(rawHeaders[i]), rawHeaders[i + 1].toString("latin1"), true); + } + location = headersList.get("location", true); + this.body = new Readable2({ read: resume }); + const decoders = []; + const willFollow = location && request.redirect === "follow" && redirectStatusSet.has(status); + if (request.method !== "HEAD" && request.method !== "CONNECT" && !nullBodyStatus.includes(status) && !willFollow) { + const contentEncoding = headersList.get("content-encoding", true); + const codings = contentEncoding ? contentEncoding.toLowerCase().split(",") : []; + const maxContentEncodings = 5; + if (codings.length > maxContentEncodings) { + reject(new Error(`too many content-encodings in response: ${codings.length}, maximum allowed is ${maxContentEncodings}`)); + return true; + } + for (let i = codings.length - 1; i >= 0; --i) { + const coding = codings[i].trim(); + if (coding === "x-gzip" || coding === "gzip") { + decoders.push(zlib.createGunzip({ + // Be less strict when decoding compressed responses, since sometimes + // servers send slightly invalid responses that are still accepted + // by common browsers. + // Always using Z_SYNC_FLUSH is what cURL does. + flush: zlib.constants.Z_SYNC_FLUSH, + finishFlush: zlib.constants.Z_SYNC_FLUSH + })); + } else if (coding === "deflate") { + decoders.push(createInflate({ + flush: zlib.constants.Z_SYNC_FLUSH, + finishFlush: zlib.constants.Z_SYNC_FLUSH + })); + } else if (coding === "br") { + decoders.push(zlib.createBrotliDecompress({ + flush: zlib.constants.BROTLI_OPERATION_FLUSH, + finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH + })); + } else { + decoders.length = 0; + break; + } + } + } + const onError = this.onError.bind(this); + resolve({ + status, + statusText, + headersList, + body: decoders.length ? pipeline(this.body, ...decoders, (err) => { + if (err) { + this.onError(err); + } + }).on("error", onError) : this.body.on("error", onError) + }); + return true; + }, + onData(chunk) { + if (fetchParams.controller.dump) { + return; + } + const bytes2 = chunk; + timingInfo.encodedBodySize += bytes2.byteLength; + return this.body.push(bytes2); + }, + onComplete() { + if (this.abort) { + fetchParams.controller.off("terminated", this.abort); + } + if (fetchParams.controller.onAborted) { + fetchParams.controller.off("terminated", fetchParams.controller.onAborted); + } + fetchParams.controller.ended = true; + this.body.push(null); + }, + onError(error) { + if (this.abort) { + fetchParams.controller.off("terminated", this.abort); + } + this.body?.destroy(error); + fetchParams.controller.terminate(error); + reject(error); + }, + onUpgrade(status, rawHeaders, socket) { + if (status !== 101) { + return; + } + const headersList = new HeadersList(); + for (let i = 0; i < rawHeaders.length; i += 2) { + headersList.append(bufferToLowerCasedHeaderName(rawHeaders[i]), rawHeaders[i + 1].toString("latin1"), true); + } + resolve({ + status, + statusText: STATUS_CODES[status], + headersList, + socket + }); + return true; + } + } + )); + } + } + module.exports = { + fetch: fetch3, + Fetch, + fetching, + finalizeAndReportTiming + }; + } +}); + +// viewer/node_modules/undici/lib/web/fileapi/symbols.js +var require_symbols3 = __commonJS({ + "viewer/node_modules/undici/lib/web/fileapi/symbols.js"(exports, module) { + "use strict"; + module.exports = { + kState: /* @__PURE__ */ Symbol("FileReader state"), + kResult: /* @__PURE__ */ Symbol("FileReader result"), + kError: /* @__PURE__ */ Symbol("FileReader error"), + kLastProgressEventFired: /* @__PURE__ */ Symbol("FileReader last progress event fired timestamp"), + kEvents: /* @__PURE__ */ Symbol("FileReader events"), + kAborted: /* @__PURE__ */ Symbol("FileReader aborted") + }; + } +}); + +// viewer/node_modules/undici/lib/web/fileapi/progressevent.js +var require_progressevent = __commonJS({ + "viewer/node_modules/undici/lib/web/fileapi/progressevent.js"(exports, module) { + "use strict"; + var { webidl } = require_webidl(); + var kState = /* @__PURE__ */ Symbol("ProgressEvent state"); + var ProgressEvent = class _ProgressEvent extends Event { + constructor(type, eventInitDict = {}) { + type = webidl.converters.DOMString(type, "ProgressEvent constructor", "type"); + eventInitDict = webidl.converters.ProgressEventInit(eventInitDict ?? {}); + super(type, eventInitDict); + this[kState] = { + lengthComputable: eventInitDict.lengthComputable, + loaded: eventInitDict.loaded, + total: eventInitDict.total + }; + } + get lengthComputable() { + webidl.brandCheck(this, _ProgressEvent); + return this[kState].lengthComputable; + } + get loaded() { + webidl.brandCheck(this, _ProgressEvent); + return this[kState].loaded; + } + get total() { + webidl.brandCheck(this, _ProgressEvent); + return this[kState].total; + } + }; + webidl.converters.ProgressEventInit = webidl.dictionaryConverter([ + { + key: "lengthComputable", + converter: webidl.converters.boolean, + defaultValue: () => false + }, + { + key: "loaded", + converter: webidl.converters["unsigned long long"], + defaultValue: () => 0 + }, + { + key: "total", + converter: webidl.converters["unsigned long long"], + defaultValue: () => 0 + }, + { + key: "bubbles", + converter: webidl.converters.boolean, + defaultValue: () => false + }, + { + key: "cancelable", + converter: webidl.converters.boolean, + defaultValue: () => false + }, + { + key: "composed", + converter: webidl.converters.boolean, + defaultValue: () => false + } + ]); + module.exports = { + ProgressEvent + }; + } +}); + +// viewer/node_modules/undici/lib/web/fileapi/encoding.js +var require_encoding = __commonJS({ + "viewer/node_modules/undici/lib/web/fileapi/encoding.js"(exports, module) { + "use strict"; + function getEncoding(label) { + if (!label) { + return "failure"; + } + switch (label.trim().toLowerCase()) { + case "unicode-1-1-utf-8": + case "unicode11utf8": + case "unicode20utf8": + case "utf-8": + case "utf8": + case "x-unicode20utf8": + return "UTF-8"; + case "866": + case "cp866": + case "csibm866": + case "ibm866": + return "IBM866"; + case "csisolatin2": + case "iso-8859-2": + case "iso-ir-101": + case "iso8859-2": + case "iso88592": + case "iso_8859-2": + case "iso_8859-2:1987": + case "l2": + case "latin2": + return "ISO-8859-2"; + case "csisolatin3": + case "iso-8859-3": + case "iso-ir-109": + case "iso8859-3": + case "iso88593": + case "iso_8859-3": + case "iso_8859-3:1988": + case "l3": + case "latin3": + return "ISO-8859-3"; + case "csisolatin4": + case "iso-8859-4": + case "iso-ir-110": + case "iso8859-4": + case "iso88594": + case "iso_8859-4": + case "iso_8859-4:1988": + case "l4": + case "latin4": + return "ISO-8859-4"; + case "csisolatincyrillic": + case "cyrillic": + case "iso-8859-5": + case "iso-ir-144": + case "iso8859-5": + case "iso88595": + case "iso_8859-5": + case "iso_8859-5:1988": + return "ISO-8859-5"; + case "arabic": + case "asmo-708": + case "csiso88596e": + case "csiso88596i": + case "csisolatinarabic": + case "ecma-114": + case "iso-8859-6": + case "iso-8859-6-e": + case "iso-8859-6-i": + case "iso-ir-127": + case "iso8859-6": + case "iso88596": + case "iso_8859-6": + case "iso_8859-6:1987": + return "ISO-8859-6"; + case "csisolatingreek": + case "ecma-118": + case "elot_928": + case "greek": + case "greek8": + case "iso-8859-7": + case "iso-ir-126": + case "iso8859-7": + case "iso88597": + case "iso_8859-7": + case "iso_8859-7:1987": + case "sun_eu_greek": + return "ISO-8859-7"; + case "csiso88598e": + case "csisolatinhebrew": + case "hebrew": + case "iso-8859-8": + case "iso-8859-8-e": + case "iso-ir-138": + case "iso8859-8": + case "iso88598": + case "iso_8859-8": + case "iso_8859-8:1988": + case "visual": + return "ISO-8859-8"; + case "csiso88598i": + case "iso-8859-8-i": + case "logical": + return "ISO-8859-8-I"; + case "csisolatin6": + case "iso-8859-10": + case "iso-ir-157": + case "iso8859-10": + case "iso885910": + case "l6": + case "latin6": + return "ISO-8859-10"; + case "iso-8859-13": + case "iso8859-13": + case "iso885913": + return "ISO-8859-13"; + case "iso-8859-14": + case "iso8859-14": + case "iso885914": + return "ISO-8859-14"; + case "csisolatin9": + case "iso-8859-15": + case "iso8859-15": + case "iso885915": + case "iso_8859-15": + case "l9": + return "ISO-8859-15"; + case "iso-8859-16": + return "ISO-8859-16"; + case "cskoi8r": + case "koi": + case "koi8": + case "koi8-r": + case "koi8_r": + return "KOI8-R"; + case "koi8-ru": + case "koi8-u": + return "KOI8-U"; + case "csmacintosh": + case "mac": + case "macintosh": + case "x-mac-roman": + return "macintosh"; + case "iso-8859-11": + case "iso8859-11": + case "iso885911": + case "tis-620": + case "windows-874": + return "windows-874"; + case "cp1250": + case "windows-1250": + case "x-cp1250": + return "windows-1250"; + case "cp1251": + case "windows-1251": + case "x-cp1251": + return "windows-1251"; + case "ansi_x3.4-1968": + case "ascii": + case "cp1252": + case "cp819": + case "csisolatin1": + case "ibm819": + case "iso-8859-1": + case "iso-ir-100": + case "iso8859-1": + case "iso88591": + case "iso_8859-1": + case "iso_8859-1:1987": + case "l1": + case "latin1": + case "us-ascii": + case "windows-1252": + case "x-cp1252": + return "windows-1252"; + case "cp1253": + case "windows-1253": + case "x-cp1253": + return "windows-1253"; + case "cp1254": + case "csisolatin5": + case "iso-8859-9": + case "iso-ir-148": + case "iso8859-9": + case "iso88599": + case "iso_8859-9": + case "iso_8859-9:1989": + case "l5": + case "latin5": + case "windows-1254": + case "x-cp1254": + return "windows-1254"; + case "cp1255": + case "windows-1255": + case "x-cp1255": + return "windows-1255"; + case "cp1256": + case "windows-1256": + case "x-cp1256": + return "windows-1256"; + case "cp1257": + case "windows-1257": + case "x-cp1257": + return "windows-1257"; + case "cp1258": + case "windows-1258": + case "x-cp1258": + return "windows-1258"; + case "x-mac-cyrillic": + case "x-mac-ukrainian": + return "x-mac-cyrillic"; + case "chinese": + case "csgb2312": + case "csiso58gb231280": + case "gb2312": + case "gb_2312": + case "gb_2312-80": + case "gbk": + case "iso-ir-58": + case "x-gbk": + return "GBK"; + case "gb18030": + return "gb18030"; + case "big5": + case "big5-hkscs": + case "cn-big5": + case "csbig5": + case "x-x-big5": + return "Big5"; + case "cseucpkdfmtjapanese": + case "euc-jp": + case "x-euc-jp": + return "EUC-JP"; + case "csiso2022jp": + case "iso-2022-jp": + return "ISO-2022-JP"; + case "csshiftjis": + case "ms932": + case "ms_kanji": + case "shift-jis": + case "shift_jis": + case "sjis": + case "windows-31j": + case "x-sjis": + return "Shift_JIS"; + case "cseuckr": + case "csksc56011987": + case "euc-kr": + case "iso-ir-149": + case "korean": + case "ks_c_5601-1987": + case "ks_c_5601-1989": + case "ksc5601": + case "ksc_5601": + case "windows-949": + return "EUC-KR"; + case "csiso2022kr": + case "hz-gb-2312": + case "iso-2022-cn": + case "iso-2022-cn-ext": + case "iso-2022-kr": + case "replacement": + return "replacement"; + case "unicodefffe": + case "utf-16be": + return "UTF-16BE"; + case "csunicode": + case "iso-10646-ucs-2": + case "ucs-2": + case "unicode": + case "unicodefeff": + case "utf-16": + case "utf-16le": + return "UTF-16LE"; + case "x-user-defined": + return "x-user-defined"; + default: + return "failure"; + } + } + module.exports = { + getEncoding + }; + } +}); + +// viewer/node_modules/undici/lib/web/fileapi/util.js +var require_util4 = __commonJS({ + "viewer/node_modules/undici/lib/web/fileapi/util.js"(exports, module) { + "use strict"; + var { + kState, + kError, + kResult, + kAborted, + kLastProgressEventFired + } = require_symbols3(); + var { ProgressEvent } = require_progressevent(); + var { getEncoding } = require_encoding(); + var { serializeAMimeType, parseMIMEType } = require_data_url(); + var { types } = __require("node:util"); + var { StringDecoder } = __require("string_decoder"); + var { btoa: btoa2 } = __require("node:buffer"); + var staticPropertyDescriptors = { + enumerable: true, + writable: false, + configurable: false + }; + function readOperation(fr, blob, type, encodingName) { + if (fr[kState] === "loading") { + throw new DOMException("Invalid state", "InvalidStateError"); + } + fr[kState] = "loading"; + fr[kResult] = null; + fr[kError] = null; + const stream = blob.stream(); + const reader = stream.getReader(); + const bytes2 = []; + let chunkPromise = reader.read(); + let isFirstChunk = true; + (async () => { + while (!fr[kAborted]) { + try { + const { done, value } = await chunkPromise; + if (isFirstChunk && !fr[kAborted]) { + queueMicrotask(() => { + fireAProgressEvent("loadstart", fr); + }); + } + isFirstChunk = false; + if (!done && types.isUint8Array(value)) { + bytes2.push(value); + if ((fr[kLastProgressEventFired] === void 0 || Date.now() - fr[kLastProgressEventFired] >= 50) && !fr[kAborted]) { + fr[kLastProgressEventFired] = Date.now(); + queueMicrotask(() => { + fireAProgressEvent("progress", fr); + }); + } + chunkPromise = reader.read(); + } else if (done) { + queueMicrotask(() => { + fr[kState] = "done"; + try { + const result = packageData(bytes2, type, blob.type, encodingName); + if (fr[kAborted]) { + return; + } + fr[kResult] = result; + fireAProgressEvent("load", fr); + } catch (error) { + fr[kError] = error; + fireAProgressEvent("error", fr); + } + if (fr[kState] !== "loading") { + fireAProgressEvent("loadend", fr); + } + }); + break; + } + } catch (error) { + if (fr[kAborted]) { + return; + } + queueMicrotask(() => { + fr[kState] = "done"; + fr[kError] = error; + fireAProgressEvent("error", fr); + if (fr[kState] !== "loading") { + fireAProgressEvent("loadend", fr); + } + }); + break; + } + } + })(); + } + function fireAProgressEvent(e, reader) { + const event = new ProgressEvent(e, { + bubbles: false, + cancelable: false + }); + reader.dispatchEvent(event); + } + function packageData(bytes2, type, mimeType, encodingName) { + switch (type) { + case "DataURL": { + let dataURL = "data:"; + const parsed = parseMIMEType(mimeType || "application/octet-stream"); + if (parsed !== "failure") { + dataURL += serializeAMimeType(parsed); + } + dataURL += ";base64,"; + const decoder = new StringDecoder("latin1"); + for (const chunk of bytes2) { + dataURL += btoa2(decoder.write(chunk)); + } + dataURL += btoa2(decoder.end()); + return dataURL; + } + case "Text": { + let encoding = "failure"; + if (encodingName) { + encoding = getEncoding(encodingName); + } + if (encoding === "failure" && mimeType) { + const type2 = parseMIMEType(mimeType); + if (type2 !== "failure") { + encoding = getEncoding(type2.parameters.get("charset")); + } + } + if (encoding === "failure") { + encoding = "UTF-8"; + } + return decode(bytes2, encoding); + } + case "ArrayBuffer": { + const sequence = combineByteSequences(bytes2); + return sequence.buffer; + } + case "BinaryString": { + let binaryString = ""; + const decoder = new StringDecoder("latin1"); + for (const chunk of bytes2) { + binaryString += decoder.write(chunk); + } + binaryString += decoder.end(); + return binaryString; + } + } + } + function decode(ioQueue, encoding) { + const bytes2 = combineByteSequences(ioQueue); + const BOMEncoding = BOMSniffing(bytes2); + let slice = 0; + if (BOMEncoding !== null) { + encoding = BOMEncoding; + slice = BOMEncoding === "UTF-8" ? 3 : 2; + } + const sliced = bytes2.slice(slice); + return new TextDecoder(encoding).decode(sliced); + } + function BOMSniffing(ioQueue) { + const [a, b, c] = ioQueue; + if (a === 239 && b === 187 && c === 191) { + return "UTF-8"; + } else if (a === 254 && b === 255) { + return "UTF-16BE"; + } else if (a === 255 && b === 254) { + return "UTF-16LE"; + } + return null; + } + function combineByteSequences(sequences) { + const size = sequences.reduce((a, b) => { + return a + b.byteLength; + }, 0); + let offset = 0; + return sequences.reduce((a, b) => { + a.set(b, offset); + offset += b.byteLength; + return a; + }, new Uint8Array(size)); + } + module.exports = { + staticPropertyDescriptors, + readOperation, + fireAProgressEvent + }; + } +}); + +// viewer/node_modules/undici/lib/web/fileapi/filereader.js +var require_filereader = __commonJS({ + "viewer/node_modules/undici/lib/web/fileapi/filereader.js"(exports, module) { + "use strict"; + var { + staticPropertyDescriptors, + readOperation, + fireAProgressEvent + } = require_util4(); + var { + kState, + kError, + kResult, + kEvents, + kAborted + } = require_symbols3(); + var { webidl } = require_webidl(); + var { kEnumerableProperty } = require_util(); + var FileReader = class _FileReader extends EventTarget { + constructor() { + super(); + this[kState] = "empty"; + this[kResult] = null; + this[kError] = null; + this[kEvents] = { + loadend: null, + error: null, + abort: null, + load: null, + progress: null, + loadstart: null + }; + } + /** + * @see https://w3c.github.io/FileAPI/#dfn-readAsArrayBuffer + * @param {import('buffer').Blob} blob + */ + readAsArrayBuffer(blob) { + webidl.brandCheck(this, _FileReader); + webidl.argumentLengthCheck(arguments, 1, "FileReader.readAsArrayBuffer"); + blob = webidl.converters.Blob(blob, { strict: false }); + readOperation(this, blob, "ArrayBuffer"); + } + /** + * @see https://w3c.github.io/FileAPI/#readAsBinaryString + * @param {import('buffer').Blob} blob + */ + readAsBinaryString(blob) { + webidl.brandCheck(this, _FileReader); + webidl.argumentLengthCheck(arguments, 1, "FileReader.readAsBinaryString"); + blob = webidl.converters.Blob(blob, { strict: false }); + readOperation(this, blob, "BinaryString"); + } + /** + * @see https://w3c.github.io/FileAPI/#readAsDataText + * @param {import('buffer').Blob} blob + * @param {string?} encoding + */ + readAsText(blob, encoding = void 0) { + webidl.brandCheck(this, _FileReader); + webidl.argumentLengthCheck(arguments, 1, "FileReader.readAsText"); + blob = webidl.converters.Blob(blob, { strict: false }); + if (encoding !== void 0) { + encoding = webidl.converters.DOMString(encoding, "FileReader.readAsText", "encoding"); + } + readOperation(this, blob, "Text", encoding); + } + /** + * @see https://w3c.github.io/FileAPI/#dfn-readAsDataURL + * @param {import('buffer').Blob} blob + */ + readAsDataURL(blob) { + webidl.brandCheck(this, _FileReader); + webidl.argumentLengthCheck(arguments, 1, "FileReader.readAsDataURL"); + blob = webidl.converters.Blob(blob, { strict: false }); + readOperation(this, blob, "DataURL"); + } + /** + * @see https://w3c.github.io/FileAPI/#dfn-abort + */ + abort() { + if (this[kState] === "empty" || this[kState] === "done") { + this[kResult] = null; + return; + } + if (this[kState] === "loading") { + this[kState] = "done"; + this[kResult] = null; + } + this[kAborted] = true; + fireAProgressEvent("abort", this); + if (this[kState] !== "loading") { + fireAProgressEvent("loadend", this); + } + } + /** + * @see https://w3c.github.io/FileAPI/#dom-filereader-readystate + */ + get readyState() { + webidl.brandCheck(this, _FileReader); + switch (this[kState]) { + case "empty": + return this.EMPTY; + case "loading": + return this.LOADING; + case "done": + return this.DONE; + } + } + /** + * @see https://w3c.github.io/FileAPI/#dom-filereader-result + */ + get result() { + webidl.brandCheck(this, _FileReader); + return this[kResult]; + } + /** + * @see https://w3c.github.io/FileAPI/#dom-filereader-error + */ + get error() { + webidl.brandCheck(this, _FileReader); + return this[kError]; + } + get onloadend() { + webidl.brandCheck(this, _FileReader); + return this[kEvents].loadend; + } + set onloadend(fn) { + webidl.brandCheck(this, _FileReader); + if (this[kEvents].loadend) { + this.removeEventListener("loadend", this[kEvents].loadend); + } + if (typeof fn === "function") { + this[kEvents].loadend = fn; + this.addEventListener("loadend", fn); + } else { + this[kEvents].loadend = null; + } + } + get onerror() { + webidl.brandCheck(this, _FileReader); + return this[kEvents].error; + } + set onerror(fn) { + webidl.brandCheck(this, _FileReader); + if (this[kEvents].error) { + this.removeEventListener("error", this[kEvents].error); + } + if (typeof fn === "function") { + this[kEvents].error = fn; + this.addEventListener("error", fn); + } else { + this[kEvents].error = null; + } + } + get onloadstart() { + webidl.brandCheck(this, _FileReader); + return this[kEvents].loadstart; + } + set onloadstart(fn) { + webidl.brandCheck(this, _FileReader); + if (this[kEvents].loadstart) { + this.removeEventListener("loadstart", this[kEvents].loadstart); + } + if (typeof fn === "function") { + this[kEvents].loadstart = fn; + this.addEventListener("loadstart", fn); + } else { + this[kEvents].loadstart = null; + } + } + get onprogress() { + webidl.brandCheck(this, _FileReader); + return this[kEvents].progress; + } + set onprogress(fn) { + webidl.brandCheck(this, _FileReader); + if (this[kEvents].progress) { + this.removeEventListener("progress", this[kEvents].progress); + } + if (typeof fn === "function") { + this[kEvents].progress = fn; + this.addEventListener("progress", fn); + } else { + this[kEvents].progress = null; + } + } + get onload() { + webidl.brandCheck(this, _FileReader); + return this[kEvents].load; + } + set onload(fn) { + webidl.brandCheck(this, _FileReader); + if (this[kEvents].load) { + this.removeEventListener("load", this[kEvents].load); + } + if (typeof fn === "function") { + this[kEvents].load = fn; + this.addEventListener("load", fn); + } else { + this[kEvents].load = null; + } + } + get onabort() { + webidl.brandCheck(this, _FileReader); + return this[kEvents].abort; + } + set onabort(fn) { + webidl.brandCheck(this, _FileReader); + if (this[kEvents].abort) { + this.removeEventListener("abort", this[kEvents].abort); + } + if (typeof fn === "function") { + this[kEvents].abort = fn; + this.addEventListener("abort", fn); + } else { + this[kEvents].abort = null; + } + } + }; + FileReader.EMPTY = FileReader.prototype.EMPTY = 0; + FileReader.LOADING = FileReader.prototype.LOADING = 1; + FileReader.DONE = FileReader.prototype.DONE = 2; + Object.defineProperties(FileReader.prototype, { + EMPTY: staticPropertyDescriptors, + LOADING: staticPropertyDescriptors, + DONE: staticPropertyDescriptors, + readAsArrayBuffer: kEnumerableProperty, + readAsBinaryString: kEnumerableProperty, + readAsText: kEnumerableProperty, + readAsDataURL: kEnumerableProperty, + abort: kEnumerableProperty, + readyState: kEnumerableProperty, + result: kEnumerableProperty, + error: kEnumerableProperty, + onloadstart: kEnumerableProperty, + onprogress: kEnumerableProperty, + onload: kEnumerableProperty, + onabort: kEnumerableProperty, + onerror: kEnumerableProperty, + onloadend: kEnumerableProperty, + [Symbol.toStringTag]: { + value: "FileReader", + writable: false, + enumerable: false, + configurable: true + } + }); + Object.defineProperties(FileReader, { + EMPTY: staticPropertyDescriptors, + LOADING: staticPropertyDescriptors, + DONE: staticPropertyDescriptors + }); + module.exports = { + FileReader + }; + } +}); + +// viewer/node_modules/undici/lib/web/cache/symbols.js +var require_symbols4 = __commonJS({ + "viewer/node_modules/undici/lib/web/cache/symbols.js"(exports, module) { + "use strict"; + module.exports = { + kConstruct: require_symbols().kConstruct + }; + } +}); + +// viewer/node_modules/undici/lib/web/cache/util.js +var require_util5 = __commonJS({ + "viewer/node_modules/undici/lib/web/cache/util.js"(exports, module) { + "use strict"; + var assert = __require("node:assert"); + var { URLSerializer } = require_data_url(); + var { isValidHeaderName } = require_util2(); + function urlEquals(A, B, excludeFragment = false) { + const serializedA = URLSerializer(A, excludeFragment); + const serializedB = URLSerializer(B, excludeFragment); + return serializedA === serializedB; + } + function getFieldValues(header) { + assert(header !== null); + const values = []; + for (let value of header.split(",")) { + value = value.trim(); + if (isValidHeaderName(value)) { + values.push(value); + } + } + return values; + } + module.exports = { + urlEquals, + getFieldValues + }; + } +}); + +// viewer/node_modules/undici/lib/web/cache/cache.js +var require_cache = __commonJS({ + "viewer/node_modules/undici/lib/web/cache/cache.js"(exports, module) { + "use strict"; + var { kConstruct } = require_symbols4(); + var { urlEquals, getFieldValues } = require_util5(); + var { kEnumerableProperty, isDisturbed } = require_util(); + var { webidl } = require_webidl(); + var { Response: Response2, cloneResponse, fromInnerResponse } = require_response(); + var { Request: Request2, fromInnerRequest } = require_request2(); + var { kState } = require_symbols2(); + var { fetching } = require_fetch(); + var { urlIsHttpHttpsScheme, createDeferredPromise, readAllBytes } = require_util2(); + var assert = __require("node:assert"); + var Cache = class _Cache { + /** + * @see https://w3c.github.io/ServiceWorker/#dfn-relevant-request-response-list + * @type {requestResponseList} + */ + #relevantRequestResponseList; + constructor() { + if (arguments[0] !== kConstruct) { + webidl.illegalConstructor(); + } + webidl.util.markAsUncloneable(this); + this.#relevantRequestResponseList = arguments[1]; + } + async match(request, options = {}) { + webidl.brandCheck(this, _Cache); + const prefix = "Cache.match"; + webidl.argumentLengthCheck(arguments, 1, prefix); + request = webidl.converters.RequestInfo(request, prefix, "request"); + options = webidl.converters.CacheQueryOptions(options, prefix, "options"); + const p = this.#internalMatchAll(request, options, 1); + if (p.length === 0) { + return; + } + return p[0]; + } + async matchAll(request = void 0, options = {}) { + webidl.brandCheck(this, _Cache); + const prefix = "Cache.matchAll"; + if (request !== void 0) request = webidl.converters.RequestInfo(request, prefix, "request"); + options = webidl.converters.CacheQueryOptions(options, prefix, "options"); + return this.#internalMatchAll(request, options); + } + async add(request) { + webidl.brandCheck(this, _Cache); + const prefix = "Cache.add"; + webidl.argumentLengthCheck(arguments, 1, prefix); + request = webidl.converters.RequestInfo(request, prefix, "request"); + const requests = [request]; + const responseArrayPromise = this.addAll(requests); + return await responseArrayPromise; + } + async addAll(requests) { + webidl.brandCheck(this, _Cache); + const prefix = "Cache.addAll"; + webidl.argumentLengthCheck(arguments, 1, prefix); + const responsePromises = []; + const requestList = []; + for (let request of requests) { + if (request === void 0) { + throw webidl.errors.conversionFailed({ + prefix, + argument: "Argument 1", + types: ["undefined is not allowed"] + }); + } + request = webidl.converters.RequestInfo(request); + if (typeof request === "string") { + continue; + } + const r = request[kState]; + if (!urlIsHttpHttpsScheme(r.url) || r.method !== "GET") { + throw webidl.errors.exception({ + header: prefix, + message: "Expected http/s scheme when method is not GET." + }); + } + } + const fetchControllers = []; + for (const request of requests) { + const r = new Request2(request)[kState]; + if (!urlIsHttpHttpsScheme(r.url)) { + throw webidl.errors.exception({ + header: prefix, + message: "Expected http/s scheme." + }); + } + r.initiator = "fetch"; + r.destination = "subresource"; + requestList.push(r); + const responsePromise = createDeferredPromise(); + fetchControllers.push(fetching({ + request: r, + processResponse(response) { + if (response.type === "error" || response.status === 206 || response.status < 200 || response.status > 299) { + responsePromise.reject(webidl.errors.exception({ + header: "Cache.addAll", + message: "Received an invalid status code or the request failed." + })); + } else if (response.headersList.contains("vary")) { + const fieldValues = getFieldValues(response.headersList.get("vary")); + for (const fieldValue of fieldValues) { + if (fieldValue === "*") { + responsePromise.reject(webidl.errors.exception({ + header: "Cache.addAll", + message: "invalid vary field value" + })); + for (const controller of fetchControllers) { + controller.abort(); + } + return; + } + } + } + }, + processResponseEndOfBody(response) { + if (response.aborted) { + responsePromise.reject(new DOMException("aborted", "AbortError")); + return; + } + responsePromise.resolve(response); + } + })); + responsePromises.push(responsePromise.promise); + } + const p = Promise.all(responsePromises); + const responses = await p; + const operations = []; + let index = 0; + for (const response of responses) { + const operation = { + type: "put", + // 7.3.2 + request: requestList[index], + // 7.3.3 + response + // 7.3.4 + }; + operations.push(operation); + index++; + } + const cacheJobPromise = createDeferredPromise(); + let errorData = null; + try { + this.#batchCacheOperations(operations); + } catch (e) { + errorData = e; + } + queueMicrotask(() => { + if (errorData === null) { + cacheJobPromise.resolve(void 0); + } else { + cacheJobPromise.reject(errorData); + } + }); + return cacheJobPromise.promise; + } + async put(request, response) { + webidl.brandCheck(this, _Cache); + const prefix = "Cache.put"; + webidl.argumentLengthCheck(arguments, 2, prefix); + request = webidl.converters.RequestInfo(request, prefix, "request"); + response = webidl.converters.Response(response, prefix, "response"); + let innerRequest = null; + if (request instanceof Request2) { + innerRequest = request[kState]; + } else { + innerRequest = new Request2(request)[kState]; + } + if (!urlIsHttpHttpsScheme(innerRequest.url) || innerRequest.method !== "GET") { + throw webidl.errors.exception({ + header: prefix, + message: "Expected an http/s scheme when method is not GET" + }); + } + const innerResponse = response[kState]; + if (innerResponse.status === 206) { + throw webidl.errors.exception({ + header: prefix, + message: "Got 206 status" + }); + } + if (innerResponse.headersList.contains("vary")) { + const fieldValues = getFieldValues(innerResponse.headersList.get("vary")); + for (const fieldValue of fieldValues) { + if (fieldValue === "*") { + throw webidl.errors.exception({ + header: prefix, + message: "Got * vary field value" + }); + } + } + } + if (innerResponse.body && (isDisturbed(innerResponse.body.stream) || innerResponse.body.stream.locked)) { + throw webidl.errors.exception({ + header: prefix, + message: "Response body is locked or disturbed" + }); + } + const clonedResponse = cloneResponse(innerResponse); + const bodyReadPromise = createDeferredPromise(); + if (innerResponse.body != null) { + const stream = innerResponse.body.stream; + const reader = stream.getReader(); + readAllBytes(reader).then(bodyReadPromise.resolve, bodyReadPromise.reject); + } else { + bodyReadPromise.resolve(void 0); + } + const operations = []; + const operation = { + type: "put", + // 14. + request: innerRequest, + // 15. + response: clonedResponse + // 16. + }; + operations.push(operation); + const bytes2 = await bodyReadPromise.promise; + if (clonedResponse.body != null) { + clonedResponse.body.source = bytes2; + } + const cacheJobPromise = createDeferredPromise(); + let errorData = null; + try { + this.#batchCacheOperations(operations); + } catch (e) { + errorData = e; + } + queueMicrotask(() => { + if (errorData === null) { + cacheJobPromise.resolve(); + } else { + cacheJobPromise.reject(errorData); + } + }); + return cacheJobPromise.promise; + } + async delete(request, options = {}) { + webidl.brandCheck(this, _Cache); + const prefix = "Cache.delete"; + webidl.argumentLengthCheck(arguments, 1, prefix); + request = webidl.converters.RequestInfo(request, prefix, "request"); + options = webidl.converters.CacheQueryOptions(options, prefix, "options"); + let r = null; + if (request instanceof Request2) { + r = request[kState]; + if (r.method !== "GET" && !options.ignoreMethod) { + return false; + } + } else { + assert(typeof request === "string"); + r = new Request2(request)[kState]; + } + const operations = []; + const operation = { + type: "delete", + request: r, + options + }; + operations.push(operation); + const cacheJobPromise = createDeferredPromise(); + let errorData = null; + let requestResponses; + try { + requestResponses = this.#batchCacheOperations(operations); + } catch (e) { + errorData = e; + } + queueMicrotask(() => { + if (errorData === null) { + cacheJobPromise.resolve(!!requestResponses?.length); + } else { + cacheJobPromise.reject(errorData); + } + }); + return cacheJobPromise.promise; + } + /** + * @see https://w3c.github.io/ServiceWorker/#dom-cache-keys + * @param {any} request + * @param {import('../../types/cache').CacheQueryOptions} options + * @returns {Promise} + */ + async keys(request = void 0, options = {}) { + webidl.brandCheck(this, _Cache); + const prefix = "Cache.keys"; + if (request !== void 0) request = webidl.converters.RequestInfo(request, prefix, "request"); + options = webidl.converters.CacheQueryOptions(options, prefix, "options"); + let r = null; + if (request !== void 0) { + if (request instanceof Request2) { + r = request[kState]; + if (r.method !== "GET" && !options.ignoreMethod) { + return []; + } + } else if (typeof request === "string") { + r = new Request2(request)[kState]; + } + } + const promise = createDeferredPromise(); + const requests = []; + if (request === void 0) { + for (const requestResponse of this.#relevantRequestResponseList) { + requests.push(requestResponse[0]); + } + } else { + const requestResponses = this.#queryCache(r, options); + for (const requestResponse of requestResponses) { + requests.push(requestResponse[0]); + } + } + queueMicrotask(() => { + const requestList = []; + for (const request2 of requests) { + const requestObject = fromInnerRequest( + request2, + new AbortController().signal, + "immutable" + ); + requestList.push(requestObject); + } + promise.resolve(Object.freeze(requestList)); + }); + return promise.promise; + } + /** + * @see https://w3c.github.io/ServiceWorker/#batch-cache-operations-algorithm + * @param {CacheBatchOperation[]} operations + * @returns {requestResponseList} + */ + #batchCacheOperations(operations) { + const cache = this.#relevantRequestResponseList; + const backupCache = [...cache]; + const addedItems = []; + const resultList = []; + try { + for (const operation of operations) { + if (operation.type !== "delete" && operation.type !== "put") { + throw webidl.errors.exception({ + header: "Cache.#batchCacheOperations", + message: 'operation type does not match "delete" or "put"' + }); + } + if (operation.type === "delete" && operation.response != null) { + throw webidl.errors.exception({ + header: "Cache.#batchCacheOperations", + message: "delete operation should not have an associated response" + }); + } + if (this.#queryCache(operation.request, operation.options, addedItems).length) { + throw new DOMException("???", "InvalidStateError"); + } + let requestResponses; + if (operation.type === "delete") { + requestResponses = this.#queryCache(operation.request, operation.options); + if (requestResponses.length === 0) { + return []; + } + for (const requestResponse of requestResponses) { + const idx = cache.indexOf(requestResponse); + assert(idx !== -1); + cache.splice(idx, 1); + } + } else if (operation.type === "put") { + if (operation.response == null) { + throw webidl.errors.exception({ + header: "Cache.#batchCacheOperations", + message: "put operation should have an associated response" + }); + } + const r = operation.request; + if (!urlIsHttpHttpsScheme(r.url)) { + throw webidl.errors.exception({ + header: "Cache.#batchCacheOperations", + message: "expected http or https scheme" + }); + } + if (r.method !== "GET") { + throw webidl.errors.exception({ + header: "Cache.#batchCacheOperations", + message: "not get method" + }); + } + if (operation.options != null) { + throw webidl.errors.exception({ + header: "Cache.#batchCacheOperations", + message: "options must not be defined" + }); + } + requestResponses = this.#queryCache(operation.request); + for (const requestResponse of requestResponses) { + const idx = cache.indexOf(requestResponse); + assert(idx !== -1); + cache.splice(idx, 1); + } + cache.push([operation.request, operation.response]); + addedItems.push([operation.request, operation.response]); + } + resultList.push([operation.request, operation.response]); + } + return resultList; + } catch (e) { + this.#relevantRequestResponseList.length = 0; + this.#relevantRequestResponseList = backupCache; + throw e; + } + } + /** + * @see https://w3c.github.io/ServiceWorker/#query-cache + * @param {any} requestQuery + * @param {import('../../types/cache').CacheQueryOptions} options + * @param {requestResponseList} targetStorage + * @returns {requestResponseList} + */ + #queryCache(requestQuery, options, targetStorage) { + const resultList = []; + const storage = targetStorage ?? this.#relevantRequestResponseList; + for (const requestResponse of storage) { + const [cachedRequest, cachedResponse] = requestResponse; + if (this.#requestMatchesCachedItem(requestQuery, cachedRequest, cachedResponse, options)) { + resultList.push(requestResponse); + } + } + return resultList; + } + /** + * @see https://w3c.github.io/ServiceWorker/#request-matches-cached-item-algorithm + * @param {any} requestQuery + * @param {any} request + * @param {any | null} response + * @param {import('../../types/cache').CacheQueryOptions | undefined} options + * @returns {boolean} + */ + #requestMatchesCachedItem(requestQuery, request, response = null, options) { + const queryURL = new URL(requestQuery.url); + const cachedURL = new URL(request.url); + if (options?.ignoreSearch) { + cachedURL.search = ""; + queryURL.search = ""; + } + if (!urlEquals(queryURL, cachedURL, true)) { + return false; + } + if (response == null || options?.ignoreVary || !response.headersList.contains("vary")) { + return true; + } + const fieldValues = getFieldValues(response.headersList.get("vary")); + for (const fieldValue of fieldValues) { + if (fieldValue === "*") { + return false; + } + const requestValue = request.headersList.get(fieldValue); + const queryValue = requestQuery.headersList.get(fieldValue); + if (requestValue !== queryValue) { + return false; + } + } + return true; + } + #internalMatchAll(request, options, maxResponses = Infinity) { + let r = null; + if (request !== void 0) { + if (request instanceof Request2) { + r = request[kState]; + if (r.method !== "GET" && !options.ignoreMethod) { + return []; + } + } else if (typeof request === "string") { + r = new Request2(request)[kState]; + } + } + const responses = []; + if (request === void 0) { + for (const requestResponse of this.#relevantRequestResponseList) { + responses.push(requestResponse[1]); + } + } else { + const requestResponses = this.#queryCache(r, options); + for (const requestResponse of requestResponses) { + responses.push(requestResponse[1]); + } + } + const responseList = []; + for (const response of responses) { + const responseObject = fromInnerResponse(response, "immutable"); + responseList.push(responseObject.clone()); + if (responseList.length >= maxResponses) { + break; + } + } + return Object.freeze(responseList); + } + }; + Object.defineProperties(Cache.prototype, { + [Symbol.toStringTag]: { + value: "Cache", + configurable: true + }, + match: kEnumerableProperty, + matchAll: kEnumerableProperty, + add: kEnumerableProperty, + addAll: kEnumerableProperty, + put: kEnumerableProperty, + delete: kEnumerableProperty, + keys: kEnumerableProperty + }); + var cacheQueryOptionConverters = [ + { + key: "ignoreSearch", + converter: webidl.converters.boolean, + defaultValue: () => false + }, + { + key: "ignoreMethod", + converter: webidl.converters.boolean, + defaultValue: () => false + }, + { + key: "ignoreVary", + converter: webidl.converters.boolean, + defaultValue: () => false + } + ]; + webidl.converters.CacheQueryOptions = webidl.dictionaryConverter(cacheQueryOptionConverters); + webidl.converters.MultiCacheQueryOptions = webidl.dictionaryConverter([ + ...cacheQueryOptionConverters, + { + key: "cacheName", + converter: webidl.converters.DOMString + } + ]); + webidl.converters.Response = webidl.interfaceConverter(Response2); + webidl.converters["sequence"] = webidl.sequenceConverter( + webidl.converters.RequestInfo + ); + module.exports = { + Cache + }; + } +}); + +// viewer/node_modules/undici/lib/web/cache/cachestorage.js +var require_cachestorage = __commonJS({ + "viewer/node_modules/undici/lib/web/cache/cachestorage.js"(exports, module) { + "use strict"; + var { kConstruct } = require_symbols4(); + var { Cache } = require_cache(); + var { webidl } = require_webidl(); + var { kEnumerableProperty } = require_util(); + var CacheStorage = class _CacheStorage { + /** + * @see https://w3c.github.io/ServiceWorker/#dfn-relevant-name-to-cache-map + * @type {Map} + */ + async has(cacheName) { + webidl.brandCheck(this, _CacheStorage); + const prefix = "CacheStorage.has"; + webidl.argumentLengthCheck(arguments, 1, prefix); + cacheName = webidl.converters.DOMString(cacheName, prefix, "cacheName"); + return this.#caches.has(cacheName); + } + /** + * @see https://w3c.github.io/ServiceWorker/#dom-cachestorage-open + * @param {string} cacheName + * @returns {Promise} + */ + async open(cacheName) { + webidl.brandCheck(this, _CacheStorage); + const prefix = "CacheStorage.open"; + webidl.argumentLengthCheck(arguments, 1, prefix); + cacheName = webidl.converters.DOMString(cacheName, prefix, "cacheName"); + if (this.#caches.has(cacheName)) { + const cache2 = this.#caches.get(cacheName); + return new Cache(kConstruct, cache2); + } + const cache = []; + this.#caches.set(cacheName, cache); + return new Cache(kConstruct, cache); + } + /** + * @see https://w3c.github.io/ServiceWorker/#cache-storage-delete + * @param {string} cacheName + * @returns {Promise} + */ + async delete(cacheName) { + webidl.brandCheck(this, _CacheStorage); + const prefix = "CacheStorage.delete"; + webidl.argumentLengthCheck(arguments, 1, prefix); + cacheName = webidl.converters.DOMString(cacheName, prefix, "cacheName"); + return this.#caches.delete(cacheName); + } + /** + * @see https://w3c.github.io/ServiceWorker/#cache-storage-keys + * @returns {Promise} + */ + async keys() { + webidl.brandCheck(this, _CacheStorage); + const keys = this.#caches.keys(); + return [...keys]; + } + }; + Object.defineProperties(CacheStorage.prototype, { + [Symbol.toStringTag]: { + value: "CacheStorage", + configurable: true + }, + match: kEnumerableProperty, + has: kEnumerableProperty, + open: kEnumerableProperty, + delete: kEnumerableProperty, + keys: kEnumerableProperty + }); + module.exports = { + CacheStorage + }; + } +}); + +// viewer/node_modules/undici/lib/web/cookies/constants.js +var require_constants4 = __commonJS({ + "viewer/node_modules/undici/lib/web/cookies/constants.js"(exports, module) { + "use strict"; + var maxAttributeValueSize = 1024; + var maxNameValuePairSize = 4096; + module.exports = { + maxAttributeValueSize, + maxNameValuePairSize + }; + } +}); + +// viewer/node_modules/undici/lib/web/cookies/util.js +var require_util6 = __commonJS({ + "viewer/node_modules/undici/lib/web/cookies/util.js"(exports, module) { + "use strict"; + function isCTLExcludingHtab(value) { + for (let i = 0; i < value.length; ++i) { + const code = value.charCodeAt(i); + if (code >= 0 && code <= 8 || code >= 10 && code <= 31 || code === 127) { + return true; + } + } + return false; + } + function validateCookieName(name) { + for (let i = 0; i < name.length; ++i) { + const code = name.charCodeAt(i); + if (code < 33 || // exclude CTLs (0-31), SP and HT + code > 126 || // exclude non-ascii and DEL + code === 34 || // " + code === 40 || // ( + code === 41 || // ) + code === 60 || // < + code === 62 || // > + code === 64 || // @ + code === 44 || // , + code === 59 || // ; + code === 58 || // : + code === 92 || // \ + code === 47 || // / + code === 91 || // [ + code === 93 || // ] + code === 63 || // ? + code === 61 || // = + code === 123 || // { + code === 125) { + throw new Error("Invalid cookie name"); + } + } + } + function validateCookieValue(value) { + let len = value.length; + let i = 0; + if (value[0] === '"') { + if (len === 1 || value[len - 1] !== '"') { + throw new Error("Invalid cookie value"); + } + --len; + ++i; + } + while (i < len) { + const code = value.charCodeAt(i++); + if (code < 33 || // exclude CTLs (0-31) + code > 126 || // non-ascii and DEL (127) + code === 34 || // " + code === 44 || // , + code === 59 || // ; + code === 92) { + throw new Error("Invalid cookie value"); + } + } + } + function validateCookiePath(path12) { + for (let i = 0; i < path12.length; ++i) { + const code = path12.charCodeAt(i); + if (code < 32 || // exclude CTLs (0-31) + code === 127 || // DEL + code === 59) { + throw new Error("Invalid cookie path"); + } + } + } + function validateCookieDomain(domain) { + if (domain.startsWith("-") || domain.endsWith(".") || domain.endsWith("-")) { + throw new Error("Invalid cookie domain"); + } + } + var IMFDays = [ + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat" + ]; + var IMFMonths = [ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec" + ]; + var IMFPaddedNumbers = Array(61).fill(0).map((_, i) => i.toString().padStart(2, "0")); + function toIMFDate(date) { + if (typeof date === "number") { + date = new Date(date); + } + return `${IMFDays[date.getUTCDay()]}, ${IMFPaddedNumbers[date.getUTCDate()]} ${IMFMonths[date.getUTCMonth()]} ${date.getUTCFullYear()} ${IMFPaddedNumbers[date.getUTCHours()]}:${IMFPaddedNumbers[date.getUTCMinutes()]}:${IMFPaddedNumbers[date.getUTCSeconds()]} GMT`; + } + function validateCookieMaxAge(maxAge) { + if (maxAge < 0) { + throw new Error("Invalid cookie max-age"); + } + } + function stringify(cookie) { + if (cookie.name.length === 0) { + return null; + } + validateCookieName(cookie.name); + validateCookieValue(cookie.value); + const out = [`${cookie.name}=${cookie.value}`]; + if (cookie.name.startsWith("__Secure-")) { + cookie.secure = true; + } + if (cookie.name.startsWith("__Host-")) { + cookie.secure = true; + cookie.domain = null; + cookie.path = "/"; + } + if (cookie.secure) { + out.push("Secure"); + } + if (cookie.httpOnly) { + out.push("HttpOnly"); + } + if (typeof cookie.maxAge === "number") { + validateCookieMaxAge(cookie.maxAge); + out.push(`Max-Age=${cookie.maxAge}`); + } + if (cookie.domain) { + validateCookieDomain(cookie.domain); + out.push(`Domain=${cookie.domain}`); + } + if (cookie.path) { + validateCookiePath(cookie.path); + out.push(`Path=${cookie.path}`); + } + if (cookie.expires && cookie.expires.toString() !== "Invalid Date") { + out.push(`Expires=${toIMFDate(cookie.expires)}`); + } + if (cookie.sameSite) { + out.push(`SameSite=${cookie.sameSite}`); + } + for (const part of cookie.unparsed) { + if (!part.includes("=")) { + throw new Error("Invalid unparsed"); + } + const [key, ...value] = part.split("="); + out.push(`${key.trim()}=${value.join("=")}`); + } + return out.join("; "); + } + module.exports = { + isCTLExcludingHtab, + validateCookieName, + validateCookiePath, + validateCookieValue, + toIMFDate, + stringify + }; + } +}); + +// viewer/node_modules/undici/lib/web/cookies/parse.js +var require_parse = __commonJS({ + "viewer/node_modules/undici/lib/web/cookies/parse.js"(exports, module) { + "use strict"; + var { maxNameValuePairSize, maxAttributeValueSize } = require_constants4(); + var { isCTLExcludingHtab } = require_util6(); + var { collectASequenceOfCodePointsFast } = require_data_url(); + var assert = __require("node:assert"); + function parseSetCookie(header) { + if (isCTLExcludingHtab(header)) { + return null; + } + let nameValuePair = ""; + let unparsedAttributes = ""; + let name = ""; + let value = ""; + if (header.includes(";")) { + const position = { position: 0 }; + nameValuePair = collectASequenceOfCodePointsFast(";", header, position); + unparsedAttributes = header.slice(position.position); + } else { + nameValuePair = header; + } + if (!nameValuePair.includes("=")) { + value = nameValuePair; + } else { + const position = { position: 0 }; + name = collectASequenceOfCodePointsFast( + "=", + nameValuePair, + position + ); + value = nameValuePair.slice(position.position + 1); + } + name = name.trim(); + value = value.trim(); + if (name.length + value.length > maxNameValuePairSize) { + return null; + } + return { + name, + value, + ...parseUnparsedAttributes(unparsedAttributes) + }; + } + function parseUnparsedAttributes(unparsedAttributes, cookieAttributeList = {}) { + if (unparsedAttributes.length === 0) { + return cookieAttributeList; + } + assert(unparsedAttributes[0] === ";"); + unparsedAttributes = unparsedAttributes.slice(1); + let cookieAv = ""; + if (unparsedAttributes.includes(";")) { + cookieAv = collectASequenceOfCodePointsFast( + ";", + unparsedAttributes, + { position: 0 } + ); + unparsedAttributes = unparsedAttributes.slice(cookieAv.length); + } else { + cookieAv = unparsedAttributes; + unparsedAttributes = ""; + } + let attributeName = ""; + let attributeValue = ""; + if (cookieAv.includes("=")) { + const position = { position: 0 }; + attributeName = collectASequenceOfCodePointsFast( + "=", + cookieAv, + position + ); + attributeValue = cookieAv.slice(position.position + 1); + } else { + attributeName = cookieAv; + } + attributeName = attributeName.trim(); + attributeValue = attributeValue.trim(); + if (attributeValue.length > maxAttributeValueSize) { + return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList); + } + const attributeNameLowercase = attributeName.toLowerCase(); + if (attributeNameLowercase === "expires") { + const expiryTime = new Date(attributeValue); + cookieAttributeList.expires = expiryTime; + } else if (attributeNameLowercase === "max-age") { + const charCode = attributeValue.charCodeAt(0); + if ((charCode < 48 || charCode > 57) && attributeValue[0] !== "-") { + return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList); + } + if (!/^\d+$/.test(attributeValue)) { + return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList); + } + const deltaSeconds = Number(attributeValue); + cookieAttributeList.maxAge = deltaSeconds; + } else if (attributeNameLowercase === "domain") { + let cookieDomain = attributeValue; + if (cookieDomain[0] === ".") { + cookieDomain = cookieDomain.slice(1); + } + cookieDomain = cookieDomain.toLowerCase(); + cookieAttributeList.domain = cookieDomain; + } else if (attributeNameLowercase === "path") { + let cookiePath = ""; + if (attributeValue.length === 0 || attributeValue[0] !== "/") { + cookiePath = "/"; + } else { + cookiePath = attributeValue; + } + cookieAttributeList.path = cookiePath; + } else if (attributeNameLowercase === "secure") { + cookieAttributeList.secure = true; + } else if (attributeNameLowercase === "httponly") { + cookieAttributeList.httpOnly = true; + } else if (attributeNameLowercase === "samesite") { + let enforcement = "Default"; + const attributeValueLowercase = attributeValue.toLowerCase(); + if (attributeValueLowercase.includes("none")) { + enforcement = "None"; + } + if (attributeValueLowercase.includes("strict")) { + enforcement = "Strict"; + } + if (attributeValueLowercase.includes("lax")) { + enforcement = "Lax"; + } + cookieAttributeList.sameSite = enforcement; + } else { + cookieAttributeList.unparsed ??= []; + cookieAttributeList.unparsed.push(`${attributeName}=${attributeValue}`); + } + return parseUnparsedAttributes(unparsedAttributes, cookieAttributeList); + } + module.exports = { + parseSetCookie, + parseUnparsedAttributes + }; + } +}); + +// viewer/node_modules/undici/lib/web/cookies/index.js +var require_cookies = __commonJS({ + "viewer/node_modules/undici/lib/web/cookies/index.js"(exports, module) { + "use strict"; + var { parseSetCookie } = require_parse(); + var { stringify } = require_util6(); + var { webidl } = require_webidl(); + var { Headers: Headers2 } = require_headers(); + function getCookies(headers) { + webidl.argumentLengthCheck(arguments, 1, "getCookies"); + webidl.brandCheck(headers, Headers2, { strict: false }); + const cookie = headers.get("cookie"); + const out = {}; + if (!cookie) { + return out; + } + for (const piece of cookie.split(";")) { + const [name, ...value] = piece.split("="); + out[name.trim()] = value.join("="); + } + return out; + } + function deleteCookie(headers, name, attributes) { + webidl.brandCheck(headers, Headers2, { strict: false }); + const prefix = "deleteCookie"; + webidl.argumentLengthCheck(arguments, 2, prefix); + name = webidl.converters.DOMString(name, prefix, "name"); + attributes = webidl.converters.DeleteCookieAttributes(attributes); + setCookie(headers, { + name, + value: "", + expires: /* @__PURE__ */ new Date(0), + ...attributes + }); + } + function getSetCookies(headers) { + webidl.argumentLengthCheck(arguments, 1, "getSetCookies"); + webidl.brandCheck(headers, Headers2, { strict: false }); + const cookies = headers.getSetCookie(); + if (!cookies) { + return []; + } + return cookies.map((pair) => parseSetCookie(pair)); + } + function setCookie(headers, cookie) { + webidl.argumentLengthCheck(arguments, 2, "setCookie"); + webidl.brandCheck(headers, Headers2, { strict: false }); + cookie = webidl.converters.Cookie(cookie); + const str = stringify(cookie); + if (str) { + headers.append("Set-Cookie", str); + } + } + webidl.converters.DeleteCookieAttributes = webidl.dictionaryConverter([ + { + converter: webidl.nullableConverter(webidl.converters.DOMString), + key: "path", + defaultValue: () => null + }, + { + converter: webidl.nullableConverter(webidl.converters.DOMString), + key: "domain", + defaultValue: () => null + } + ]); + webidl.converters.Cookie = webidl.dictionaryConverter([ + { + converter: webidl.converters.DOMString, + key: "name" + }, + { + converter: webidl.converters.DOMString, + key: "value" + }, + { + converter: webidl.nullableConverter((value) => { + if (typeof value === "number") { + return webidl.converters["unsigned long long"](value); + } + return new Date(value); + }), + key: "expires", + defaultValue: () => null + }, + { + converter: webidl.nullableConverter(webidl.converters["long long"]), + key: "maxAge", + defaultValue: () => null + }, + { + converter: webidl.nullableConverter(webidl.converters.DOMString), + key: "domain", + defaultValue: () => null + }, + { + converter: webidl.nullableConverter(webidl.converters.DOMString), + key: "path", + defaultValue: () => null + }, + { + converter: webidl.nullableConverter(webidl.converters.boolean), + key: "secure", + defaultValue: () => null + }, + { + converter: webidl.nullableConverter(webidl.converters.boolean), + key: "httpOnly", + defaultValue: () => null + }, + { + converter: webidl.converters.USVString, + key: "sameSite", + allowedValues: ["Strict", "Lax", "None"] + }, + { + converter: webidl.sequenceConverter(webidl.converters.DOMString), + key: "unparsed", + defaultValue: () => new Array(0) + } + ]); + module.exports = { + getCookies, + deleteCookie, + getSetCookies, + setCookie + }; + } +}); + +// viewer/node_modules/undici/lib/web/websocket/events.js +var require_events = __commonJS({ + "viewer/node_modules/undici/lib/web/websocket/events.js"(exports, module) { + "use strict"; + var { webidl } = require_webidl(); + var { kEnumerableProperty } = require_util(); + var { kConstruct } = require_symbols(); + var { MessagePort } = __require("node:worker_threads"); + var MessageEvent = class _MessageEvent extends Event { + #eventInit; + constructor(type, eventInitDict = {}) { + if (type === kConstruct) { + super(arguments[1], arguments[2]); + webidl.util.markAsUncloneable(this); + return; + } + const prefix = "MessageEvent constructor"; + webidl.argumentLengthCheck(arguments, 1, prefix); + type = webidl.converters.DOMString(type, prefix, "type"); + eventInitDict = webidl.converters.MessageEventInit(eventInitDict, prefix, "eventInitDict"); + super(type, eventInitDict); + this.#eventInit = eventInitDict; + webidl.util.markAsUncloneable(this); + } + get data() { + webidl.brandCheck(this, _MessageEvent); + return this.#eventInit.data; + } + get origin() { + webidl.brandCheck(this, _MessageEvent); + return this.#eventInit.origin; + } + get lastEventId() { + webidl.brandCheck(this, _MessageEvent); + return this.#eventInit.lastEventId; + } + get source() { + webidl.brandCheck(this, _MessageEvent); + return this.#eventInit.source; + } + get ports() { + webidl.brandCheck(this, _MessageEvent); + if (!Object.isFrozen(this.#eventInit.ports)) { + Object.freeze(this.#eventInit.ports); + } + return this.#eventInit.ports; + } + initMessageEvent(type, bubbles = false, cancelable = false, data = null, origin = "", lastEventId = "", source = null, ports = []) { + webidl.brandCheck(this, _MessageEvent); + webidl.argumentLengthCheck(arguments, 1, "MessageEvent.initMessageEvent"); + return new _MessageEvent(type, { + bubbles, + cancelable, + data, + origin, + lastEventId, + source, + ports + }); + } + static createFastMessageEvent(type, init) { + const messageEvent = new _MessageEvent(kConstruct, type, init); + messageEvent.#eventInit = init; + messageEvent.#eventInit.data ??= null; + messageEvent.#eventInit.origin ??= ""; + messageEvent.#eventInit.lastEventId ??= ""; + messageEvent.#eventInit.source ??= null; + messageEvent.#eventInit.ports ??= []; + return messageEvent; + } + }; + var { createFastMessageEvent } = MessageEvent; + delete MessageEvent.createFastMessageEvent; + var CloseEvent = class _CloseEvent extends Event { + #eventInit; + constructor(type, eventInitDict = {}) { + const prefix = "CloseEvent constructor"; + webidl.argumentLengthCheck(arguments, 1, prefix); + type = webidl.converters.DOMString(type, prefix, "type"); + eventInitDict = webidl.converters.CloseEventInit(eventInitDict); + super(type, eventInitDict); + this.#eventInit = eventInitDict; + webidl.util.markAsUncloneable(this); + } + get wasClean() { + webidl.brandCheck(this, _CloseEvent); + return this.#eventInit.wasClean; + } + get code() { + webidl.brandCheck(this, _CloseEvent); + return this.#eventInit.code; + } + get reason() { + webidl.brandCheck(this, _CloseEvent); + return this.#eventInit.reason; + } + }; + var ErrorEvent = class _ErrorEvent extends Event { + #eventInit; + constructor(type, eventInitDict) { + const prefix = "ErrorEvent constructor"; + webidl.argumentLengthCheck(arguments, 1, prefix); + super(type, eventInitDict); + webidl.util.markAsUncloneable(this); + type = webidl.converters.DOMString(type, prefix, "type"); + eventInitDict = webidl.converters.ErrorEventInit(eventInitDict ?? {}); + this.#eventInit = eventInitDict; + } + get message() { + webidl.brandCheck(this, _ErrorEvent); + return this.#eventInit.message; + } + get filename() { + webidl.brandCheck(this, _ErrorEvent); + return this.#eventInit.filename; + } + get lineno() { + webidl.brandCheck(this, _ErrorEvent); + return this.#eventInit.lineno; + } + get colno() { + webidl.brandCheck(this, _ErrorEvent); + return this.#eventInit.colno; + } + get error() { + webidl.brandCheck(this, _ErrorEvent); + return this.#eventInit.error; + } + }; + Object.defineProperties(MessageEvent.prototype, { + [Symbol.toStringTag]: { + value: "MessageEvent", + configurable: true + }, + data: kEnumerableProperty, + origin: kEnumerableProperty, + lastEventId: kEnumerableProperty, + source: kEnumerableProperty, + ports: kEnumerableProperty, + initMessageEvent: kEnumerableProperty + }); + Object.defineProperties(CloseEvent.prototype, { + [Symbol.toStringTag]: { + value: "CloseEvent", + configurable: true + }, + reason: kEnumerableProperty, + code: kEnumerableProperty, + wasClean: kEnumerableProperty + }); + Object.defineProperties(ErrorEvent.prototype, { + [Symbol.toStringTag]: { + value: "ErrorEvent", + configurable: true + }, + message: kEnumerableProperty, + filename: kEnumerableProperty, + lineno: kEnumerableProperty, + colno: kEnumerableProperty, + error: kEnumerableProperty + }); + webidl.converters.MessagePort = webidl.interfaceConverter(MessagePort); + webidl.converters["sequence"] = webidl.sequenceConverter( + webidl.converters.MessagePort + ); + var eventInit = [ + { + key: "bubbles", + converter: webidl.converters.boolean, + defaultValue: () => false + }, + { + key: "cancelable", + converter: webidl.converters.boolean, + defaultValue: () => false + }, + { + key: "composed", + converter: webidl.converters.boolean, + defaultValue: () => false + } + ]; + webidl.converters.MessageEventInit = webidl.dictionaryConverter([ + ...eventInit, + { + key: "data", + converter: webidl.converters.any, + defaultValue: () => null + }, + { + key: "origin", + converter: webidl.converters.USVString, + defaultValue: () => "" + }, + { + key: "lastEventId", + converter: webidl.converters.DOMString, + defaultValue: () => "" + }, + { + key: "source", + // Node doesn't implement WindowProxy or ServiceWorker, so the only + // valid value for source is a MessagePort. + converter: webidl.nullableConverter(webidl.converters.MessagePort), + defaultValue: () => null + }, + { + key: "ports", + converter: webidl.converters["sequence"], + defaultValue: () => new Array(0) + } + ]); + webidl.converters.CloseEventInit = webidl.dictionaryConverter([ + ...eventInit, + { + key: "wasClean", + converter: webidl.converters.boolean, + defaultValue: () => false + }, + { + key: "code", + converter: webidl.converters["unsigned short"], + defaultValue: () => 0 + }, + { + key: "reason", + converter: webidl.converters.USVString, + defaultValue: () => "" + } + ]); + webidl.converters.ErrorEventInit = webidl.dictionaryConverter([ + ...eventInit, + { + key: "message", + converter: webidl.converters.DOMString, + defaultValue: () => "" + }, + { + key: "filename", + converter: webidl.converters.USVString, + defaultValue: () => "" + }, + { + key: "lineno", + converter: webidl.converters["unsigned long"], + defaultValue: () => 0 + }, + { + key: "colno", + converter: webidl.converters["unsigned long"], + defaultValue: () => 0 + }, + { + key: "error", + converter: webidl.converters.any + } + ]); + module.exports = { + MessageEvent, + CloseEvent, + ErrorEvent, + createFastMessageEvent + }; + } +}); + +// viewer/node_modules/undici/lib/web/websocket/constants.js +var require_constants5 = __commonJS({ + "viewer/node_modules/undici/lib/web/websocket/constants.js"(exports, module) { + "use strict"; + var uid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + var staticPropertyDescriptors = { + enumerable: true, + writable: false, + configurable: false + }; + var states = { + CONNECTING: 0, + OPEN: 1, + CLOSING: 2, + CLOSED: 3 + }; + var sentCloseFrameState = { + NOT_SENT: 0, + PROCESSING: 1, + SENT: 2 + }; + var opcodes = { + CONTINUATION: 0, + TEXT: 1, + BINARY: 2, + CLOSE: 8, + PING: 9, + PONG: 10 + }; + var maxUnsigned16Bit = 2 ** 16 - 1; + var parserStates = { + INFO: 0, + PAYLOADLENGTH_16: 2, + PAYLOADLENGTH_64: 3, + READ_DATA: 4 + }; + var emptyBuffer = Buffer.allocUnsafe(0); + var sendHints = { + string: 1, + typedArray: 2, + arrayBuffer: 3, + blob: 4 + }; + module.exports = { + uid, + sentCloseFrameState, + staticPropertyDescriptors, + states, + opcodes, + maxUnsigned16Bit, + parserStates, + emptyBuffer, + sendHints + }; + } +}); + +// viewer/node_modules/undici/lib/web/websocket/symbols.js +var require_symbols5 = __commonJS({ + "viewer/node_modules/undici/lib/web/websocket/symbols.js"(exports, module) { + "use strict"; + module.exports = { + kWebSocketURL: /* @__PURE__ */ Symbol("url"), + kReadyState: /* @__PURE__ */ Symbol("ready state"), + kController: /* @__PURE__ */ Symbol("controller"), + kResponse: /* @__PURE__ */ Symbol("response"), + kBinaryType: /* @__PURE__ */ Symbol("binary type"), + kSentClose: /* @__PURE__ */ Symbol("sent close"), + kReceivedClose: /* @__PURE__ */ Symbol("received close"), + kByteParser: /* @__PURE__ */ Symbol("byte parser") + }; + } +}); + +// viewer/node_modules/undici/lib/web/websocket/util.js +var require_util7 = __commonJS({ + "viewer/node_modules/undici/lib/web/websocket/util.js"(exports, module) { + "use strict"; + var { kReadyState, kController, kResponse, kBinaryType, kWebSocketURL } = require_symbols5(); + var { states, opcodes } = require_constants5(); + var { ErrorEvent, createFastMessageEvent } = require_events(); + var { isUtf8 } = __require("node:buffer"); + var { collectASequenceOfCodePointsFast, removeHTTPWhitespace } = require_data_url(); + function isConnecting(ws) { + return ws[kReadyState] === states.CONNECTING; + } + function isEstablished(ws) { + return ws[kReadyState] === states.OPEN; + } + function isClosing(ws) { + return ws[kReadyState] === states.CLOSING; + } + function isClosed(ws) { + return ws[kReadyState] === states.CLOSED; + } + function fireEvent(e, target, eventFactory = (type, init) => new Event(type, init), eventInitDict = {}) { + const event = eventFactory(e, eventInitDict); + target.dispatchEvent(event); + } + function websocketMessageReceived(ws, type, data) { + if (ws[kReadyState] !== states.OPEN) { + return; + } + let dataForEvent; + if (type === opcodes.TEXT) { + try { + dataForEvent = utf8Decode(data); + } catch { + failWebsocketConnection(ws, "Received invalid UTF-8 in text frame."); + return; + } + } else if (type === opcodes.BINARY) { + if (ws[kBinaryType] === "blob") { + dataForEvent = new Blob([data]); + } else { + dataForEvent = toArrayBuffer(data); + } + } + fireEvent("message", ws, createFastMessageEvent, { + origin: ws[kWebSocketURL].origin, + data: dataForEvent + }); + } + function toArrayBuffer(buffer) { + if (buffer.byteLength === buffer.buffer.byteLength) { + return buffer.buffer; + } + return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength); + } + function isValidSubprotocol(protocol) { + if (protocol.length === 0) { + return false; + } + for (let i = 0; i < protocol.length; ++i) { + const code = protocol.charCodeAt(i); + if (code < 33 || // CTL, contains SP (0x20) and HT (0x09) + code > 126 || code === 34 || // " + code === 40 || // ( + code === 41 || // ) + code === 44 || // , + code === 47 || // / + code === 58 || // : + code === 59 || // ; + code === 60 || // < + code === 61 || // = + code === 62 || // > + code === 63 || // ? + code === 64 || // @ + code === 91 || // [ + code === 92 || // \ + code === 93 || // ] + code === 123 || // { + code === 125) { + return false; + } + } + return true; + } + function isValidStatusCode(code) { + if (code >= 1e3 && code < 1015) { + return code !== 1004 && // reserved + code !== 1005 && // "MUST NOT be set as a status code" + code !== 1006; + } + return code >= 3e3 && code <= 4999; + } + function failWebsocketConnection(ws, reason) { + const { [kController]: controller, [kResponse]: response } = ws; + controller.abort(); + if (response?.socket && !response.socket.destroyed) { + response.socket.destroy(); + } + if (reason) { + fireEvent("error", ws, (type, init) => new ErrorEvent(type, init), { + error: new Error(reason), + message: reason + }); + } + } + function isControlFrame(opcode) { + return opcode === opcodes.CLOSE || opcode === opcodes.PING || opcode === opcodes.PONG; + } + function isContinuationFrame(opcode) { + return opcode === opcodes.CONTINUATION; + } + function isTextBinaryFrame(opcode) { + return opcode === opcodes.TEXT || opcode === opcodes.BINARY; + } + function isValidOpcode(opcode) { + return isTextBinaryFrame(opcode) || isContinuationFrame(opcode) || isControlFrame(opcode); + } + function parseExtensions(extensions) { + const position = { position: 0 }; + const extensionList = /* @__PURE__ */ new Map(); + while (position.position < extensions.length) { + const pair = collectASequenceOfCodePointsFast(";", extensions, position); + const [name, value = ""] = pair.split("="); + extensionList.set( + removeHTTPWhitespace(name, true, false), + removeHTTPWhitespace(value, false, true) + ); + position.position++; + } + return extensionList; + } + function isValidClientWindowBits(value) { + if (value.length === 0) { + return false; + } + for (let i = 0; i < value.length; i++) { + const byte = value.charCodeAt(i); + if (byte < 48 || byte > 57) { + return false; + } + } + const num = Number.parseInt(value, 10); + return num >= 8 && num <= 15; + } + var hasIntl = typeof process.versions.icu === "string"; + var fatalDecoder = hasIntl ? new TextDecoder("utf-8", { fatal: true }) : void 0; + var utf8Decode = hasIntl ? fatalDecoder.decode.bind(fatalDecoder) : function(buffer) { + if (isUtf8(buffer)) { + return buffer.toString("utf-8"); + } + throw new TypeError("Invalid utf-8 received."); + }; + module.exports = { + isConnecting, + isEstablished, + isClosing, + isClosed, + fireEvent, + isValidSubprotocol, + isValidStatusCode, + failWebsocketConnection, + websocketMessageReceived, + utf8Decode, + isControlFrame, + isContinuationFrame, + isTextBinaryFrame, + isValidOpcode, + parseExtensions, + isValidClientWindowBits + }; + } +}); + +// viewer/node_modules/undici/lib/web/websocket/frame.js +var require_frame = __commonJS({ + "viewer/node_modules/undici/lib/web/websocket/frame.js"(exports, module) { + "use strict"; + var { maxUnsigned16Bit } = require_constants5(); + var BUFFER_SIZE = 16386; + var crypto3; + var buffer = null; + var bufIdx = BUFFER_SIZE; + try { + crypto3 = __require("node:crypto"); + } catch { + crypto3 = { + // not full compatibility, but minimum. + randomFillSync: function randomFillSync(buffer2, _offset, _size) { + for (let i = 0; i < buffer2.length; ++i) { + buffer2[i] = Math.random() * 255 | 0; + } + return buffer2; + } + }; + } + function generateMask() { + if (bufIdx === BUFFER_SIZE) { + bufIdx = 0; + crypto3.randomFillSync(buffer ??= Buffer.allocUnsafe(BUFFER_SIZE), 0, BUFFER_SIZE); + } + return [buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++], buffer[bufIdx++]]; + } + var WebsocketFrameSend = class { + /** + * @param {Buffer|undefined} data + */ + constructor(data) { + this.frameData = data; + } + createFrame(opcode) { + const frameData = this.frameData; + const maskKey = generateMask(); + const bodyLength = frameData?.byteLength ?? 0; + let payloadLength = bodyLength; + let offset = 6; + if (bodyLength > maxUnsigned16Bit) { + offset += 8; + payloadLength = 127; + } else if (bodyLength > 125) { + offset += 2; + payloadLength = 126; + } + const buffer2 = Buffer.allocUnsafe(bodyLength + offset); + buffer2[0] = buffer2[1] = 0; + buffer2[0] |= 128; + buffer2[0] = (buffer2[0] & 240) + opcode; + buffer2[offset - 4] = maskKey[0]; + buffer2[offset - 3] = maskKey[1]; + buffer2[offset - 2] = maskKey[2]; + buffer2[offset - 1] = maskKey[3]; + buffer2[1] = payloadLength; + if (payloadLength === 126) { + buffer2.writeUInt16BE(bodyLength, 2); + } else if (payloadLength === 127) { + buffer2[2] = buffer2[3] = 0; + buffer2.writeUIntBE(bodyLength, 4, 6); + } + buffer2[1] |= 128; + for (let i = 0; i < bodyLength; ++i) { + buffer2[offset + i] = frameData[i] ^ maskKey[i & 3]; + } + return buffer2; + } + }; + module.exports = { + WebsocketFrameSend + }; + } +}); + +// viewer/node_modules/undici/lib/web/websocket/connection.js +var require_connection = __commonJS({ + "viewer/node_modules/undici/lib/web/websocket/connection.js"(exports, module) { + "use strict"; + var { uid, states, sentCloseFrameState, emptyBuffer, opcodes } = require_constants5(); + var { + kReadyState, + kSentClose, + kByteParser, + kReceivedClose, + kResponse + } = require_symbols5(); + var { fireEvent, failWebsocketConnection, isClosing, isClosed, isEstablished, parseExtensions } = require_util7(); + var { channels } = require_diagnostics(); + var { CloseEvent } = require_events(); + var { makeRequest } = require_request2(); + var { fetching } = require_fetch(); + var { Headers: Headers2, getHeadersList } = require_headers(); + var { getDecodeSplit } = require_util2(); + var { WebsocketFrameSend } = require_frame(); + var crypto3; + try { + crypto3 = __require("node:crypto"); + } catch { + } + function establishWebSocketConnection(url, protocols, client, ws, onEstablish, options) { + const requestURL = url; + requestURL.protocol = url.protocol === "ws:" ? "http:" : "https:"; + const request = makeRequest({ + urlList: [requestURL], + client, + serviceWorkers: "none", + referrer: "no-referrer", + mode: "websocket", + credentials: "include", + cache: "no-store", + redirect: "error" + }); + if (options.headers) { + const headersList = getHeadersList(new Headers2(options.headers)); + request.headersList = headersList; + } + const keyValue = crypto3.randomBytes(16).toString("base64"); + request.headersList.append("sec-websocket-key", keyValue); + request.headersList.append("sec-websocket-version", "13"); + for (const protocol of protocols) { + request.headersList.append("sec-websocket-protocol", protocol); + } + const permessageDeflate = "permessage-deflate; client_max_window_bits"; + request.headersList.append("sec-websocket-extensions", permessageDeflate); + const controller = fetching({ + request, + useParallelQueue: true, + dispatcher: options.dispatcher, + processResponse(response) { + if (response.type === "error" || response.status !== 101) { + failWebsocketConnection(ws, "Received network error or non-101 status code."); + return; + } + if (protocols.length !== 0 && !response.headersList.get("Sec-WebSocket-Protocol")) { + failWebsocketConnection(ws, "Server did not respond with sent protocols."); + return; + } + if (response.headersList.get("Upgrade")?.toLowerCase() !== "websocket") { + failWebsocketConnection(ws, 'Server did not set Upgrade header to "websocket".'); + return; + } + if (response.headersList.get("Connection")?.toLowerCase() !== "upgrade") { + failWebsocketConnection(ws, 'Server did not set Connection header to "upgrade".'); + return; + } + const secWSAccept = response.headersList.get("Sec-WebSocket-Accept"); + const digest = crypto3.createHash("sha1").update(keyValue + uid).digest("base64"); + if (secWSAccept !== digest) { + failWebsocketConnection(ws, "Incorrect hash received in Sec-WebSocket-Accept header."); + return; + } + const secExtension = response.headersList.get("Sec-WebSocket-Extensions"); + let extensions; + if (secExtension !== null) { + extensions = parseExtensions(secExtension); + if (!extensions.has("permessage-deflate")) { + failWebsocketConnection(ws, "Sec-WebSocket-Extensions header does not match."); + return; + } + } + const secProtocol = response.headersList.get("Sec-WebSocket-Protocol"); + if (secProtocol !== null) { + const requestProtocols = getDecodeSplit("sec-websocket-protocol", request.headersList); + if (!requestProtocols.includes(secProtocol)) { + failWebsocketConnection(ws, "Protocol was not set in the opening handshake."); + return; + } + } + response.socket.on("data", onSocketData); + response.socket.on("close", onSocketClose); + response.socket.on("error", onSocketError); + if (channels.open.hasSubscribers) { + channels.open.publish({ + address: response.socket.address(), + protocol: secProtocol, + extensions: secExtension + }); + } + onEstablish(response, extensions); + } + }); + return controller; + } + function closeWebSocketConnection(ws, code, reason, reasonByteLength) { + if (isClosing(ws) || isClosed(ws)) { + } else if (!isEstablished(ws)) { + failWebsocketConnection(ws, "Connection was closed before it was established."); + ws[kReadyState] = states.CLOSING; + } else if (ws[kSentClose] === sentCloseFrameState.NOT_SENT) { + ws[kSentClose] = sentCloseFrameState.PROCESSING; + const frame = new WebsocketFrameSend(); + if (code !== void 0 && reason === void 0) { + frame.frameData = Buffer.allocUnsafe(2); + frame.frameData.writeUInt16BE(code, 0); + } else if (code !== void 0 && reason !== void 0) { + frame.frameData = Buffer.allocUnsafe(2 + reasonByteLength); + frame.frameData.writeUInt16BE(code, 0); + frame.frameData.write(reason, 2, "utf-8"); + } else { + frame.frameData = emptyBuffer; + } + const socket = ws[kResponse].socket; + socket.write(frame.createFrame(opcodes.CLOSE)); + ws[kSentClose] = sentCloseFrameState.SENT; + ws[kReadyState] = states.CLOSING; + } else { + ws[kReadyState] = states.CLOSING; + } + } + function onSocketData(chunk) { + if (!this.ws[kByteParser].write(chunk)) { + this.pause(); + } + } + function onSocketClose() { + const { ws } = this; + const { [kResponse]: response } = ws; + response.socket.off("data", onSocketData); + response.socket.off("close", onSocketClose); + response.socket.off("error", onSocketError); + const wasClean = ws[kSentClose] === sentCloseFrameState.SENT && ws[kReceivedClose]; + let code = 1005; + let reason = ""; + const result = ws[kByteParser].closingInfo; + if (result && !result.error) { + code = result.code ?? 1005; + reason = result.reason; + } else if (!ws[kReceivedClose]) { + code = 1006; + } + ws[kReadyState] = states.CLOSED; + fireEvent("close", ws, (type, init) => new CloseEvent(type, init), { + wasClean, + code, + reason + }); + if (channels.close.hasSubscribers) { + channels.close.publish({ + websocket: ws, + code, + reason + }); + } + } + function onSocketError(error) { + const { ws } = this; + ws[kReadyState] = states.CLOSING; + if (channels.socketError.hasSubscribers) { + channels.socketError.publish(error); + } + this.destroy(); + } + module.exports = { + establishWebSocketConnection, + closeWebSocketConnection + }; + } +}); + +// viewer/node_modules/undici/lib/web/websocket/permessage-deflate.js +var require_permessage_deflate = __commonJS({ + "viewer/node_modules/undici/lib/web/websocket/permessage-deflate.js"(exports, module) { + "use strict"; + var { createInflateRaw, Z_DEFAULT_WINDOWBITS } = __require("node:zlib"); + var { isValidClientWindowBits } = require_util7(); + var { MessageSizeExceededError } = require_errors(); + var tail = Buffer.from([0, 0, 255, 255]); + var kBuffer = /* @__PURE__ */ Symbol("kBuffer"); + var kLength = /* @__PURE__ */ Symbol("kLength"); + var PerMessageDeflate = class { + /** @type {import('node:zlib').InflateRaw} */ + #inflate; + #options = {}; + #maxPayloadSize = 0; + /** + * @param {Map} extensions + */ + constructor(extensions, options) { + this.#options.serverNoContextTakeover = extensions.has("server_no_context_takeover"); + this.#options.serverMaxWindowBits = extensions.get("server_max_window_bits"); + this.#maxPayloadSize = options.maxPayloadSize; + } + /** + * Decompress a compressed payload. + * @param {Buffer} chunk Compressed data + * @param {boolean} fin Final fragment flag + * @param {Function} callback Callback function + */ + decompress(chunk, fin, callback) { + if (!this.#inflate) { + let windowBits = Z_DEFAULT_WINDOWBITS; + if (this.#options.serverMaxWindowBits) { + if (!isValidClientWindowBits(this.#options.serverMaxWindowBits)) { + callback(new Error("Invalid server_max_window_bits")); + return; + } + windowBits = Number.parseInt(this.#options.serverMaxWindowBits); + } + try { + this.#inflate = createInflateRaw({ windowBits }); + } catch (err) { + callback(err); + return; + } + this.#inflate[kBuffer] = []; + this.#inflate[kLength] = 0; + this.#inflate.on("data", (data) => { + this.#inflate[kLength] += data.length; + if (this.#maxPayloadSize > 0 && this.#inflate[kLength] > this.#maxPayloadSize) { + callback(new MessageSizeExceededError()); + this.#inflate.removeAllListeners(); + this.#inflate = null; + return; + } + this.#inflate[kBuffer].push(data); + }); + this.#inflate.on("error", (err) => { + this.#inflate = null; + callback(err); + }); + } + this.#inflate.write(chunk); + if (fin) { + this.#inflate.write(tail); + } + this.#inflate.flush(() => { + if (!this.#inflate) { + return; + } + const full = Buffer.concat(this.#inflate[kBuffer], this.#inflate[kLength]); + this.#inflate[kBuffer].length = 0; + this.#inflate[kLength] = 0; + callback(null, full); + }); + } + }; + module.exports = { PerMessageDeflate }; + } +}); + +// viewer/node_modules/undici/lib/web/websocket/receiver.js +var require_receiver = __commonJS({ + "viewer/node_modules/undici/lib/web/websocket/receiver.js"(exports, module) { + "use strict"; + var { Writable } = __require("node:stream"); + var assert = __require("node:assert"); + var { parserStates, opcodes, states, emptyBuffer, sentCloseFrameState } = require_constants5(); + var { kReadyState, kSentClose, kResponse, kReceivedClose } = require_symbols5(); + var { channels } = require_diagnostics(); + var { + isValidStatusCode, + isValidOpcode, + failWebsocketConnection, + websocketMessageReceived, + utf8Decode, + isControlFrame, + isTextBinaryFrame, + isContinuationFrame + } = require_util7(); + var { WebsocketFrameSend } = require_frame(); + var { closeWebSocketConnection } = require_connection(); + var { PerMessageDeflate } = require_permessage_deflate(); + var { MessageSizeExceededError } = require_errors(); + var ByteParser = class extends Writable { + #buffers = []; + #fragmentsBytes = 0; + #byteOffset = 0; + #loop = false; + #state = parserStates.INFO; + #info = {}; + #fragments = []; + /** @type {Map} */ + #extensions; + /** @type {number} */ + #maxPayloadSize; + /** + * @param {import('./websocket').WebSocket} ws + * @param {Map|null} extensions + * @param {{ maxPayloadSize?: number }} [options] + */ + constructor(ws, extensions, options = {}) { + super(); + this.ws = ws; + this.#extensions = extensions == null ? /* @__PURE__ */ new Map() : extensions; + this.#maxPayloadSize = options.maxPayloadSize ?? 0; + if (this.#extensions.has("permessage-deflate")) { + this.#extensions.set("permessage-deflate", new PerMessageDeflate(extensions, options)); + } + } + /** + * @param {Buffer} chunk + * @param {() => void} callback + */ + _write(chunk, _, callback) { + this.#buffers.push(chunk); + this.#byteOffset += chunk.length; + this.#loop = true; + this.run(callback); + } + #validatePayloadLength() { + if (this.#maxPayloadSize > 0 && !isControlFrame(this.#info.opcode) && this.#info.payloadLength > this.#maxPayloadSize) { + failWebsocketConnection(this.ws, "Payload size exceeds maximum allowed size"); + return false; + } + return true; + } + /** + * Runs whenever a new chunk is received. + * Callback is called whenever there are no more chunks buffering, + * or not enough bytes are buffered to parse. + */ + run(callback) { + while (this.#loop) { + if (this.#state === parserStates.INFO) { + if (this.#byteOffset < 2) { + return callback(); + } + const buffer = this.consume(2); + const fin = (buffer[0] & 128) !== 0; + const opcode = buffer[0] & 15; + const masked = (buffer[1] & 128) === 128; + const fragmented = !fin && opcode !== opcodes.CONTINUATION; + const payloadLength = buffer[1] & 127; + const rsv1 = buffer[0] & 64; + const rsv2 = buffer[0] & 32; + const rsv3 = buffer[0] & 16; + if (!isValidOpcode(opcode)) { + failWebsocketConnection(this.ws, "Invalid opcode received"); + return callback(); + } + if (masked) { + failWebsocketConnection(this.ws, "Frame cannot be masked"); + return callback(); + } + if (rsv1 !== 0 && !this.#extensions.has("permessage-deflate")) { + failWebsocketConnection(this.ws, "Expected RSV1 to be clear."); + return; + } + if (rsv2 !== 0 || rsv3 !== 0) { + failWebsocketConnection(this.ws, "RSV1, RSV2, RSV3 must be clear"); + return; + } + if (fragmented && !isTextBinaryFrame(opcode)) { + failWebsocketConnection(this.ws, "Invalid frame type was fragmented."); + return; + } + if (isTextBinaryFrame(opcode) && this.#fragments.length > 0) { + failWebsocketConnection(this.ws, "Expected continuation frame"); + return; + } + if (this.#info.fragmented && fragmented) { + failWebsocketConnection(this.ws, "Fragmented frame exceeded 125 bytes."); + return; + } + if ((payloadLength > 125 || fragmented) && isControlFrame(opcode)) { + failWebsocketConnection(this.ws, "Control frame either too large or fragmented"); + return; + } + if (isContinuationFrame(opcode) && this.#fragments.length === 0 && !this.#info.compressed) { + failWebsocketConnection(this.ws, "Unexpected continuation frame"); + return; + } + if (payloadLength <= 125) { + this.#info.payloadLength = payloadLength; + this.#state = parserStates.READ_DATA; + if (!this.#validatePayloadLength()) { + return; + } + } else if (payloadLength === 126) { + this.#state = parserStates.PAYLOADLENGTH_16; + } else if (payloadLength === 127) { + this.#state = parserStates.PAYLOADLENGTH_64; + } + if (isTextBinaryFrame(opcode)) { + this.#info.binaryType = opcode; + this.#info.compressed = rsv1 !== 0; + } + this.#info.opcode = opcode; + this.#info.masked = masked; + this.#info.fin = fin; + this.#info.fragmented = fragmented; + } else if (this.#state === parserStates.PAYLOADLENGTH_16) { + if (this.#byteOffset < 2) { + return callback(); + } + const buffer = this.consume(2); + this.#info.payloadLength = buffer.readUInt16BE(0); + this.#state = parserStates.READ_DATA; + if (!this.#validatePayloadLength()) { + return; + } + } else if (this.#state === parserStates.PAYLOADLENGTH_64) { + if (this.#byteOffset < 8) { + return callback(); + } + const buffer = this.consume(8); + const upper = buffer.readUInt32BE(0); + const lower = buffer.readUInt32BE(4); + if (upper !== 0 || lower > 2 ** 31 - 1) { + failWebsocketConnection(this.ws, "Received payload length > 2^31 bytes."); + return; + } + this.#info.payloadLength = lower; + this.#state = parserStates.READ_DATA; + if (!this.#validatePayloadLength()) { + return; + } + } else if (this.#state === parserStates.READ_DATA) { + if (this.#byteOffset < this.#info.payloadLength) { + return callback(); + } + const body = this.consume(this.#info.payloadLength); + if (isControlFrame(this.#info.opcode)) { + this.#loop = this.parseControlFrame(body); + this.#state = parserStates.INFO; + } else { + if (!this.#info.compressed) { + this.writeFragments(body); + if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnection(this.ws, new MessageSizeExceededError().message); + return; + } + if (!this.#info.fragmented && this.#info.fin) { + websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); + } + this.#state = parserStates.INFO; + } else { + this.#extensions.get("permessage-deflate").decompress( + body, + this.#info.fin, + (error, data) => { + if (error) { + failWebsocketConnection(this.ws, error.message); + return; + } + this.writeFragments(data); + if (this.#maxPayloadSize > 0 && this.#fragmentsBytes > this.#maxPayloadSize) { + failWebsocketConnection(this.ws, new MessageSizeExceededError().message); + return; + } + if (!this.#info.fin) { + this.#state = parserStates.INFO; + this.#loop = true; + this.run(callback); + return; + } + websocketMessageReceived(this.ws, this.#info.binaryType, this.consumeFragments()); + this.#loop = true; + this.#state = parserStates.INFO; + this.run(callback); + } + ); + this.#loop = false; + break; + } + } + } + } + } + /** + * Take n bytes from the buffered Buffers + * @param {number} n + * @returns {Buffer} + */ + consume(n) { + if (n > this.#byteOffset) { + throw new Error("Called consume() before buffers satiated."); + } else if (n === 0) { + return emptyBuffer; + } + if (this.#buffers[0].length === n) { + this.#byteOffset -= this.#buffers[0].length; + return this.#buffers.shift(); + } + const buffer = Buffer.allocUnsafe(n); + let offset = 0; + while (offset !== n) { + const next = this.#buffers[0]; + const { length } = next; + if (length + offset === n) { + buffer.set(this.#buffers.shift(), offset); + break; + } else if (length + offset > n) { + buffer.set(next.subarray(0, n - offset), offset); + this.#buffers[0] = next.subarray(n - offset); + break; + } else { + buffer.set(this.#buffers.shift(), offset); + offset += next.length; + } + } + this.#byteOffset -= n; + return buffer; + } + writeFragments(fragment) { + this.#fragmentsBytes += fragment.length; + this.#fragments.push(fragment); + } + consumeFragments() { + const fragments = this.#fragments; + if (fragments.length === 1) { + this.#fragmentsBytes = 0; + return fragments.shift(); + } + const output = Buffer.concat(fragments, this.#fragmentsBytes); + this.#fragments = []; + this.#fragmentsBytes = 0; + return output; + } + parseCloseBody(data) { + assert(data.length !== 1); + let code; + if (data.length >= 2) { + code = data.readUInt16BE(0); + } + if (code !== void 0 && !isValidStatusCode(code)) { + return { code: 1002, reason: "Invalid status code", error: true }; + } + let reason = data.subarray(2); + if (reason[0] === 239 && reason[1] === 187 && reason[2] === 191) { + reason = reason.subarray(3); + } + try { + reason = utf8Decode(reason); + } catch { + return { code: 1007, reason: "Invalid UTF-8", error: true }; + } + return { code, reason, error: false }; + } + /** + * Parses control frames. + * @param {Buffer} body + */ + parseControlFrame(body) { + const { opcode, payloadLength } = this.#info; + if (opcode === opcodes.CLOSE) { + if (payloadLength === 1) { + failWebsocketConnection(this.ws, "Received close frame with a 1-byte body."); + return false; + } + this.#info.closeInfo = this.parseCloseBody(body); + if (this.#info.closeInfo.error) { + const { code, reason } = this.#info.closeInfo; + closeWebSocketConnection(this.ws, code, reason, reason.length); + failWebsocketConnection(this.ws, reason); + return false; + } + if (this.ws[kSentClose] !== sentCloseFrameState.SENT) { + let body2 = emptyBuffer; + if (this.#info.closeInfo.code) { + body2 = Buffer.allocUnsafe(2); + body2.writeUInt16BE(this.#info.closeInfo.code, 0); + } + const closeFrame = new WebsocketFrameSend(body2); + this.ws[kResponse].socket.write( + closeFrame.createFrame(opcodes.CLOSE), + (err) => { + if (!err) { + this.ws[kSentClose] = sentCloseFrameState.SENT; + } + } + ); + } + this.ws[kReadyState] = states.CLOSING; + this.ws[kReceivedClose] = true; + return false; + } else if (opcode === opcodes.PING) { + if (!this.ws[kReceivedClose]) { + const frame = new WebsocketFrameSend(body); + this.ws[kResponse].socket.write(frame.createFrame(opcodes.PONG)); + if (channels.ping.hasSubscribers) { + channels.ping.publish({ + payload: body + }); + } + } + } else if (opcode === opcodes.PONG) { + if (channels.pong.hasSubscribers) { + channels.pong.publish({ + payload: body + }); + } + } + return true; + } + get closingInfo() { + return this.#info.closeInfo; + } + }; + module.exports = { + ByteParser + }; + } +}); + +// viewer/node_modules/undici/lib/web/websocket/sender.js +var require_sender = __commonJS({ + "viewer/node_modules/undici/lib/web/websocket/sender.js"(exports, module) { + "use strict"; + var { WebsocketFrameSend } = require_frame(); + var { opcodes, sendHints } = require_constants5(); + var FixedQueue = require_fixed_queue(); + var FastBuffer = Buffer[Symbol.species]; + var SendQueue = class { + /** + * @type {FixedQueue} + */ + #queue = new FixedQueue(); + /** + * @type {boolean} + */ + #running = false; + /** @type {import('node:net').Socket} */ + #socket; + constructor(socket) { + this.#socket = socket; + } + add(item, cb, hint) { + if (hint !== sendHints.blob) { + const frame = createFrame(item, hint); + if (!this.#running) { + this.#socket.write(frame, cb); + } else { + const node2 = { + promise: null, + callback: cb, + frame + }; + this.#queue.push(node2); + } + return; + } + const node = { + promise: item.arrayBuffer().then((ab) => { + node.promise = null; + node.frame = createFrame(ab, hint); + }), + callback: cb, + frame: null + }; + this.#queue.push(node); + if (!this.#running) { + this.#run(); + } + } + async #run() { + this.#running = true; + const queue = this.#queue; + while (!queue.isEmpty()) { + const node = queue.shift(); + if (node.promise !== null) { + await node.promise; + } + this.#socket.write(node.frame, node.callback); + node.callback = node.frame = null; + } + this.#running = false; + } + }; + function createFrame(data, hint) { + return new WebsocketFrameSend(toBuffer(data, hint)).createFrame(hint === sendHints.string ? opcodes.TEXT : opcodes.BINARY); + } + function toBuffer(data, hint) { + switch (hint) { + case sendHints.string: + return Buffer.from(data); + case sendHints.arrayBuffer: + case sendHints.blob: + return new FastBuffer(data); + case sendHints.typedArray: + return new FastBuffer(data.buffer, data.byteOffset, data.byteLength); + } + } + module.exports = { SendQueue }; + } +}); + +// viewer/node_modules/undici/lib/web/websocket/websocket.js +var require_websocket = __commonJS({ + "viewer/node_modules/undici/lib/web/websocket/websocket.js"(exports, module) { + "use strict"; + var { webidl } = require_webidl(); + var { URLSerializer } = require_data_url(); + var { environmentSettingsObject } = require_util2(); + var { staticPropertyDescriptors, states, sentCloseFrameState, sendHints } = require_constants5(); + var { + kWebSocketURL, + kReadyState, + kController, + kBinaryType, + kResponse, + kSentClose, + kByteParser + } = require_symbols5(); + var { + isConnecting, + isEstablished, + isClosing, + isValidSubprotocol, + fireEvent + } = require_util7(); + var { establishWebSocketConnection, closeWebSocketConnection } = require_connection(); + var { ByteParser } = require_receiver(); + var { kEnumerableProperty, isBlobLike } = require_util(); + var { getGlobalDispatcher } = require_global2(); + var { types } = __require("node:util"); + var { ErrorEvent, CloseEvent } = require_events(); + var { SendQueue } = require_sender(); + var WebSocket = class _WebSocket extends EventTarget { + #events = { + open: null, + error: null, + close: null, + message: null + }; + #bufferedAmount = 0; + #protocol = ""; + #extensions = ""; + /** @type {SendQueue} */ + #sendQueue; + /** + * @param {string} url + * @param {string|string[]} protocols + */ + constructor(url, protocols = []) { + super(); + webidl.util.markAsUncloneable(this); + const prefix = "WebSocket constructor"; + webidl.argumentLengthCheck(arguments, 1, prefix); + const options = webidl.converters["DOMString or sequence or WebSocketInit"](protocols, prefix, "options"); + url = webidl.converters.USVString(url, prefix, "url"); + protocols = options.protocols; + const baseURL = environmentSettingsObject.settingsObject.baseUrl; + let urlRecord; + try { + urlRecord = new URL(url, baseURL); + } catch (e) { + throw new DOMException(e, "SyntaxError"); + } + if (urlRecord.protocol === "http:") { + urlRecord.protocol = "ws:"; + } else if (urlRecord.protocol === "https:") { + urlRecord.protocol = "wss:"; + } + if (urlRecord.protocol !== "ws:" && urlRecord.protocol !== "wss:") { + throw new DOMException( + `Expected a ws: or wss: protocol, got ${urlRecord.protocol}`, + "SyntaxError" + ); + } + if (urlRecord.hash || urlRecord.href.endsWith("#")) { + throw new DOMException("Got fragment", "SyntaxError"); + } + if (typeof protocols === "string") { + protocols = [protocols]; + } + if (protocols.length !== new Set(protocols.map((p) => p.toLowerCase())).size) { + throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); + } + if (protocols.length > 0 && !protocols.every((p) => isValidSubprotocol(p))) { + throw new DOMException("Invalid Sec-WebSocket-Protocol value", "SyntaxError"); + } + this[kWebSocketURL] = new URL(urlRecord.href); + const client = environmentSettingsObject.settingsObject; + this[kController] = establishWebSocketConnection( + urlRecord, + protocols, + client, + this, + (response, extensions) => this.#onConnectionEstablished(response, extensions), + options + ); + this[kReadyState] = _WebSocket.CONNECTING; + this[kSentClose] = sentCloseFrameState.NOT_SENT; + this[kBinaryType] = "blob"; + } + /** + * @see https://websockets.spec.whatwg.org/#dom-websocket-close + * @param {number|undefined} code + * @param {string|undefined} reason + */ + close(code = void 0, reason = void 0) { + webidl.brandCheck(this, _WebSocket); + const prefix = "WebSocket.close"; + if (code !== void 0) { + code = webidl.converters["unsigned short"](code, prefix, "code", { clamp: true }); + } + if (reason !== void 0) { + reason = webidl.converters.USVString(reason, prefix, "reason"); + } + if (code !== void 0) { + if (code !== 1e3 && (code < 3e3 || code > 4999)) { + throw new DOMException("invalid code", "InvalidAccessError"); + } + } + let reasonByteLength = 0; + if (reason !== void 0) { + reasonByteLength = Buffer.byteLength(reason); + if (reasonByteLength > 123) { + throw new DOMException( + `Reason must be less than 123 bytes; received ${reasonByteLength}`, + "SyntaxError" + ); + } + } + closeWebSocketConnection(this, code, reason, reasonByteLength); + } + /** + * @see https://websockets.spec.whatwg.org/#dom-websocket-send + * @param {NodeJS.TypedArray|ArrayBuffer|Blob|string} data + */ + send(data) { + webidl.brandCheck(this, _WebSocket); + const prefix = "WebSocket.send"; + webidl.argumentLengthCheck(arguments, 1, prefix); + data = webidl.converters.WebSocketSendData(data, prefix, "data"); + if (isConnecting(this)) { + throw new DOMException("Sent before connected.", "InvalidStateError"); + } + if (!isEstablished(this) || isClosing(this)) { + return; + } + if (typeof data === "string") { + const length = Buffer.byteLength(data); + this.#bufferedAmount += length; + this.#sendQueue.add(data, () => { + this.#bufferedAmount -= length; + }, sendHints.string); + } else if (types.isArrayBuffer(data)) { + this.#bufferedAmount += data.byteLength; + this.#sendQueue.add(data, () => { + this.#bufferedAmount -= data.byteLength; + }, sendHints.arrayBuffer); + } else if (ArrayBuffer.isView(data)) { + this.#bufferedAmount += data.byteLength; + this.#sendQueue.add(data, () => { + this.#bufferedAmount -= data.byteLength; + }, sendHints.typedArray); + } else if (isBlobLike(data)) { + this.#bufferedAmount += data.size; + this.#sendQueue.add(data, () => { + this.#bufferedAmount -= data.size; + }, sendHints.blob); + } + } + get readyState() { + webidl.brandCheck(this, _WebSocket); + return this[kReadyState]; + } + get bufferedAmount() { + webidl.brandCheck(this, _WebSocket); + return this.#bufferedAmount; + } + get url() { + webidl.brandCheck(this, _WebSocket); + return URLSerializer(this[kWebSocketURL]); + } + get extensions() { + webidl.brandCheck(this, _WebSocket); + return this.#extensions; + } + get protocol() { + webidl.brandCheck(this, _WebSocket); + return this.#protocol; + } + get onopen() { + webidl.brandCheck(this, _WebSocket); + return this.#events.open; + } + set onopen(fn) { + webidl.brandCheck(this, _WebSocket); + if (this.#events.open) { + this.removeEventListener("open", this.#events.open); + } + if (typeof fn === "function") { + this.#events.open = fn; + this.addEventListener("open", fn); + } else { + this.#events.open = null; + } + } + get onerror() { + webidl.brandCheck(this, _WebSocket); + return this.#events.error; + } + set onerror(fn) { + webidl.brandCheck(this, _WebSocket); + if (this.#events.error) { + this.removeEventListener("error", this.#events.error); + } + if (typeof fn === "function") { + this.#events.error = fn; + this.addEventListener("error", fn); + } else { + this.#events.error = null; + } + } + get onclose() { + webidl.brandCheck(this, _WebSocket); + return this.#events.close; + } + set onclose(fn) { + webidl.brandCheck(this, _WebSocket); + if (this.#events.close) { + this.removeEventListener("close", this.#events.close); + } + if (typeof fn === "function") { + this.#events.close = fn; + this.addEventListener("close", fn); + } else { + this.#events.close = null; + } + } + get onmessage() { + webidl.brandCheck(this, _WebSocket); + return this.#events.message; + } + set onmessage(fn) { + webidl.brandCheck(this, _WebSocket); + if (this.#events.message) { + this.removeEventListener("message", this.#events.message); + } + if (typeof fn === "function") { + this.#events.message = fn; + this.addEventListener("message", fn); + } else { + this.#events.message = null; + } + } + get binaryType() { + webidl.brandCheck(this, _WebSocket); + return this[kBinaryType]; + } + set binaryType(type) { + webidl.brandCheck(this, _WebSocket); + if (type !== "blob" && type !== "arraybuffer") { + this[kBinaryType] = "blob"; + } else { + this[kBinaryType] = type; + } + } + /** + * @see https://websockets.spec.whatwg.org/#feedback-from-the-protocol + */ + #onConnectionEstablished(response, parsedExtensions) { + this[kResponse] = response; + const maxPayloadSize = this[kController]?.dispatcher?.webSocketOptions?.maxPayloadSize; + const parser = new ByteParser(this, parsedExtensions, { + maxPayloadSize + }); + parser.on("drain", onParserDrain); + parser.on("error", onParserError.bind(this)); + response.socket.ws = this; + this[kByteParser] = parser; + this.#sendQueue = new SendQueue(response.socket); + this[kReadyState] = states.OPEN; + const extensions = response.headersList.get("sec-websocket-extensions"); + if (extensions !== null) { + this.#extensions = extensions; + } + const protocol = response.headersList.get("sec-websocket-protocol"); + if (protocol !== null) { + this.#protocol = protocol; + } + fireEvent("open", this); + } + }; + WebSocket.CONNECTING = WebSocket.prototype.CONNECTING = states.CONNECTING; + WebSocket.OPEN = WebSocket.prototype.OPEN = states.OPEN; + WebSocket.CLOSING = WebSocket.prototype.CLOSING = states.CLOSING; + WebSocket.CLOSED = WebSocket.prototype.CLOSED = states.CLOSED; + Object.defineProperties(WebSocket.prototype, { + CONNECTING: staticPropertyDescriptors, + OPEN: staticPropertyDescriptors, + CLOSING: staticPropertyDescriptors, + CLOSED: staticPropertyDescriptors, + url: kEnumerableProperty, + readyState: kEnumerableProperty, + bufferedAmount: kEnumerableProperty, + onopen: kEnumerableProperty, + onerror: kEnumerableProperty, + onclose: kEnumerableProperty, + close: kEnumerableProperty, + onmessage: kEnumerableProperty, + binaryType: kEnumerableProperty, + send: kEnumerableProperty, + extensions: kEnumerableProperty, + protocol: kEnumerableProperty, + [Symbol.toStringTag]: { + value: "WebSocket", + writable: false, + enumerable: false, + configurable: true + } + }); + Object.defineProperties(WebSocket, { + CONNECTING: staticPropertyDescriptors, + OPEN: staticPropertyDescriptors, + CLOSING: staticPropertyDescriptors, + CLOSED: staticPropertyDescriptors + }); + webidl.converters["sequence"] = webidl.sequenceConverter( + webidl.converters.DOMString + ); + webidl.converters["DOMString or sequence"] = function(V, prefix, argument) { + if (webidl.util.Type(V) === "Object" && Symbol.iterator in V) { + return webidl.converters["sequence"](V); + } + return webidl.converters.DOMString(V, prefix, argument); + }; + webidl.converters.WebSocketInit = webidl.dictionaryConverter([ + { + key: "protocols", + converter: webidl.converters["DOMString or sequence"], + defaultValue: () => new Array(0) + }, + { + key: "dispatcher", + converter: webidl.converters.any, + defaultValue: () => getGlobalDispatcher() + }, + { + key: "headers", + converter: webidl.nullableConverter(webidl.converters.HeadersInit) + } + ]); + webidl.converters["DOMString or sequence or WebSocketInit"] = function(V) { + if (webidl.util.Type(V) === "Object" && !(Symbol.iterator in V)) { + return webidl.converters.WebSocketInit(V); + } + return { protocols: webidl.converters["DOMString or sequence"](V) }; + }; + webidl.converters.WebSocketSendData = function(V) { + if (webidl.util.Type(V) === "Object") { + if (isBlobLike(V)) { + return webidl.converters.Blob(V, { strict: false }); + } + if (ArrayBuffer.isView(V) || types.isArrayBuffer(V)) { + return webidl.converters.BufferSource(V); + } + } + return webidl.converters.USVString(V); + }; + function onParserDrain() { + this.ws[kResponse].socket.resume(); + } + function onParserError(err) { + let message; + let code; + if (err instanceof CloseEvent) { + message = err.reason; + code = err.code; + } else { + message = err.message; + } + fireEvent("error", this, () => new ErrorEvent("error", { error: err, message })); + closeWebSocketConnection(this, code); + } + module.exports = { + WebSocket + }; + } +}); + +// viewer/node_modules/undici/lib/web/eventsource/util.js +var require_util8 = __commonJS({ + "viewer/node_modules/undici/lib/web/eventsource/util.js"(exports, module) { + "use strict"; + function isValidLastEventId(value) { + return value.indexOf("\0") === -1; + } + function isASCIINumber(value) { + if (value.length === 0) return false; + for (let i = 0; i < value.length; i++) { + if (value.charCodeAt(i) < 48 || value.charCodeAt(i) > 57) return false; + } + return true; + } + function delay(ms) { + return new Promise((resolve) => { + setTimeout(resolve, ms).unref(); + }); + } + module.exports = { + isValidLastEventId, + isASCIINumber, + delay + }; + } +}); + +// viewer/node_modules/undici/lib/web/eventsource/eventsource-stream.js +var require_eventsource_stream = __commonJS({ + "viewer/node_modules/undici/lib/web/eventsource/eventsource-stream.js"(exports, module) { + "use strict"; + var { Transform } = __require("node:stream"); + var { isASCIINumber, isValidLastEventId } = require_util8(); + var BOM = [239, 187, 191]; + var LF = 10; + var CR = 13; + var COLON = 58; + var SPACE = 32; + var EventSourceStream = class extends Transform { + /** + * @type {eventSourceSettings} + */ + state = null; + /** + * Leading byte-order-mark check. + * @type {boolean} + */ + checkBOM = true; + /** + * @type {boolean} + */ + crlfCheck = false; + /** + * @type {boolean} + */ + eventEndCheck = false; + /** + * @type {Buffer} + */ + buffer = null; + pos = 0; + event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; + /** + * @param {object} options + * @param {eventSourceSettings} options.eventSourceSettings + * @param {Function} [options.push] + */ + constructor(options = {}) { + options.readableObjectMode = true; + super(options); + this.state = options.eventSourceSettings || {}; + if (options.push) { + this.push = options.push; + } + } + /** + * @param {Buffer} chunk + * @param {string} _encoding + * @param {Function} callback + * @returns {void} + */ + _transform(chunk, _encoding, callback) { + if (chunk.length === 0) { + callback(); + return; + } + if (this.buffer) { + this.buffer = Buffer.concat([this.buffer, chunk]); + } else { + this.buffer = chunk; + } + if (this.checkBOM) { + switch (this.buffer.length) { + case 1: + if (this.buffer[0] === BOM[0]) { + callback(); + return; + } + this.checkBOM = false; + callback(); + return; + case 2: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1]) { + callback(); + return; + } + this.checkBOM = false; + break; + case 3: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = Buffer.alloc(0); + this.checkBOM = false; + callback(); + return; + } + this.checkBOM = false; + break; + default: + if (this.buffer[0] === BOM[0] && this.buffer[1] === BOM[1] && this.buffer[2] === BOM[2]) { + this.buffer = this.buffer.subarray(3); + } + this.checkBOM = false; + break; + } + } + while (this.pos < this.buffer.length) { + if (this.eventEndCheck) { + if (this.crlfCheck) { + if (this.buffer[this.pos] === LF) { + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + this.crlfCheck = false; + continue; + } + this.crlfCheck = false; + } + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { + this.crlfCheck = true; + } + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + if (this.event.data !== void 0 || this.event.event || this.event.id || this.event.retry) { + this.processEvent(this.event); + } + this.clearEvent(); + continue; + } + this.eventEndCheck = false; + continue; + } + if (this.buffer[this.pos] === LF || this.buffer[this.pos] === CR) { + if (this.buffer[this.pos] === CR) { + this.crlfCheck = true; + } + this.parseLine(this.buffer.subarray(0, this.pos), this.event); + this.buffer = this.buffer.subarray(this.pos + 1); + this.pos = 0; + this.eventEndCheck = true; + continue; + } + this.pos++; + } + callback(); + } + /** + * @param {Buffer} line + * @param {EventStreamEvent} event + */ + parseLine(line, event) { + if (line.length === 0) { + return; + } + const colonPosition = line.indexOf(COLON); + if (colonPosition === 0) { + return; + } + let field = ""; + let value = ""; + if (colonPosition !== -1) { + field = line.subarray(0, colonPosition).toString("utf8"); + let valueStart = colonPosition + 1; + if (line[valueStart] === SPACE) { + ++valueStart; + } + value = line.subarray(valueStart).toString("utf8"); + } else { + field = line.toString("utf8"); + value = ""; + } + switch (field) { + case "data": + if (event[field] === void 0) { + event[field] = value; + } else { + event[field] += ` +${value}`; + } + break; + case "retry": + if (isASCIINumber(value)) { + event[field] = value; + } + break; + case "id": + if (isValidLastEventId(value)) { + event[field] = value; + } + break; + case "event": + if (value.length > 0) { + event[field] = value; + } + break; + } + } + /** + * @param {EventSourceStreamEvent} event + */ + processEvent(event) { + if (event.retry && isASCIINumber(event.retry)) { + this.state.reconnectionTime = parseInt(event.retry, 10); + } + if (event.id && isValidLastEventId(event.id)) { + this.state.lastEventId = event.id; + } + if (event.data !== void 0) { + this.push({ + type: event.event || "message", + options: { + data: event.data, + lastEventId: this.state.lastEventId, + origin: this.state.origin + } + }); + } + } + clearEvent() { + this.event = { + data: void 0, + event: void 0, + id: void 0, + retry: void 0 + }; + } + }; + module.exports = { + EventSourceStream + }; + } +}); + +// viewer/node_modules/undici/lib/web/eventsource/eventsource.js +var require_eventsource = __commonJS({ + "viewer/node_modules/undici/lib/web/eventsource/eventsource.js"(exports, module) { + "use strict"; + var { pipeline } = __require("node:stream"); + var { fetching } = require_fetch(); + var { makeRequest } = require_request2(); + var { webidl } = require_webidl(); + var { EventSourceStream } = require_eventsource_stream(); + var { parseMIMEType } = require_data_url(); + var { createFastMessageEvent } = require_events(); + var { isNetworkError: isNetworkError2 } = require_response(); + var { delay } = require_util8(); + var { kEnumerableProperty } = require_util(); + var { environmentSettingsObject } = require_util2(); + var experimentalWarned = false; + var defaultReconnectionTime = 3e3; + var CONNECTING = 0; + var OPEN = 1; + var CLOSED = 2; + var ANONYMOUS = "anonymous"; + var USE_CREDENTIALS = "use-credentials"; + var EventSource = class _EventSource extends EventTarget { + #events = { + open: null, + error: null, + message: null + }; + #url = null; + #withCredentials = false; + #readyState = CONNECTING; + #request = null; + #controller = null; + #dispatcher; + /** + * @type {import('./eventsource-stream').eventSourceSettings} + */ + #state; + /** + * Creates a new EventSource object. + * @param {string} url + * @param {EventSourceInit} [eventSourceInitDict] + * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#the-eventsource-interface + */ + constructor(url, eventSourceInitDict = {}) { + super(); + webidl.util.markAsUncloneable(this); + const prefix = "EventSource constructor"; + webidl.argumentLengthCheck(arguments, 1, prefix); + if (!experimentalWarned) { + experimentalWarned = true; + process.emitWarning("EventSource is experimental, expect them to change at any time.", { + code: "UNDICI-ES" + }); + } + url = webidl.converters.USVString(url, prefix, "url"); + eventSourceInitDict = webidl.converters.EventSourceInitDict(eventSourceInitDict, prefix, "eventSourceInitDict"); + this.#dispatcher = eventSourceInitDict.dispatcher; + this.#state = { + lastEventId: "", + reconnectionTime: defaultReconnectionTime + }; + const settings = environmentSettingsObject; + let urlRecord; + try { + urlRecord = new URL(url, settings.settingsObject.baseUrl); + this.#state.origin = urlRecord.origin; + } catch (e) { + throw new DOMException(e, "SyntaxError"); + } + this.#url = urlRecord.href; + let corsAttributeState = ANONYMOUS; + if (eventSourceInitDict.withCredentials) { + corsAttributeState = USE_CREDENTIALS; + this.#withCredentials = true; + } + const initRequest = { + redirect: "follow", + keepalive: true, + // @see https://html.spec.whatwg.org/multipage/urls-and-fetching.html#cors-settings-attributes + mode: "cors", + credentials: corsAttributeState === "anonymous" ? "same-origin" : "omit", + referrer: "no-referrer" + }; + initRequest.client = environmentSettingsObject.settingsObject; + initRequest.headersList = [["accept", { name: "accept", value: "text/event-stream" }]]; + initRequest.cache = "no-store"; + initRequest.initiator = "other"; + initRequest.urlList = [new URL(this.#url)]; + this.#request = makeRequest(initRequest); + this.#connect(); + } + /** + * Returns the state of this EventSource object's connection. It can have the + * values described below. + * @returns {0|1|2} + * @readonly + */ + get readyState() { + return this.#readyState; + } + /** + * Returns the URL providing the event stream. + * @readonly + * @returns {string} + */ + get url() { + return this.#url; + } + /** + * Returns a boolean indicating whether the EventSource object was + * instantiated with CORS credentials set (true), or not (false, the default). + */ + get withCredentials() { + return this.#withCredentials; + } + #connect() { + if (this.#readyState === CLOSED) return; + this.#readyState = CONNECTING; + const fetchParams = { + request: this.#request, + dispatcher: this.#dispatcher + }; + const processEventSourceEndOfBody = (response) => { + if (isNetworkError2(response)) { + this.dispatchEvent(new Event("error")); + this.close(); + } + this.#reconnect(); + }; + fetchParams.processResponseEndOfBody = processEventSourceEndOfBody; + fetchParams.processResponse = (response) => { + if (isNetworkError2(response)) { + if (response.aborted) { + this.close(); + this.dispatchEvent(new Event("error")); + return; + } else { + this.#reconnect(); + return; + } + } + const contentType = response.headersList.get("content-type", true); + const mimeType = contentType !== null ? parseMIMEType(contentType) : "failure"; + const contentTypeValid = mimeType !== "failure" && mimeType.essence === "text/event-stream"; + if (response.status !== 200 || contentTypeValid === false) { + this.close(); + this.dispatchEvent(new Event("error")); + return; + } + this.#readyState = OPEN; + this.dispatchEvent(new Event("open")); + this.#state.origin = response.urlList[response.urlList.length - 1].origin; + const eventSourceStream = new EventSourceStream({ + eventSourceSettings: this.#state, + push: (event) => { + this.dispatchEvent(createFastMessageEvent( + event.type, + event.options + )); + } + }); + pipeline( + response.body.stream, + eventSourceStream, + (error) => { + if (error?.aborted === false) { + this.close(); + this.dispatchEvent(new Event("error")); + } + } + ); + }; + this.#controller = fetching(fetchParams); + } + /** + * @see https://html.spec.whatwg.org/multipage/server-sent-events.html#sse-processing-model + * @returns {Promise} + */ + async #reconnect() { + if (this.#readyState === CLOSED) return; + this.#readyState = CONNECTING; + this.dispatchEvent(new Event("error")); + await delay(this.#state.reconnectionTime); + if (this.#readyState !== CONNECTING) return; + if (this.#state.lastEventId.length) { + this.#request.headersList.set("last-event-id", this.#state.lastEventId, true); + } + this.#connect(); + } + /** + * Closes the connection, if any, and sets the readyState attribute to + * CLOSED. + */ + close() { + webidl.brandCheck(this, _EventSource); + if (this.#readyState === CLOSED) return; + this.#readyState = CLOSED; + this.#controller.abort(); + this.#request = null; + } + get onopen() { + return this.#events.open; + } + set onopen(fn) { + if (this.#events.open) { + this.removeEventListener("open", this.#events.open); + } + if (typeof fn === "function") { + this.#events.open = fn; + this.addEventListener("open", fn); + } else { + this.#events.open = null; + } + } + get onmessage() { + return this.#events.message; + } + set onmessage(fn) { + if (this.#events.message) { + this.removeEventListener("message", this.#events.message); + } + if (typeof fn === "function") { + this.#events.message = fn; + this.addEventListener("message", fn); + } else { + this.#events.message = null; + } + } + get onerror() { + return this.#events.error; + } + set onerror(fn) { + if (this.#events.error) { + this.removeEventListener("error", this.#events.error); + } + if (typeof fn === "function") { + this.#events.error = fn; + this.addEventListener("error", fn); + } else { + this.#events.error = null; + } + } + }; + var constantsPropertyDescriptors = { + CONNECTING: { + __proto__: null, + configurable: false, + enumerable: true, + value: CONNECTING, + writable: false + }, + OPEN: { + __proto__: null, + configurable: false, + enumerable: true, + value: OPEN, + writable: false + }, + CLOSED: { + __proto__: null, + configurable: false, + enumerable: true, + value: CLOSED, + writable: false + } + }; + Object.defineProperties(EventSource, constantsPropertyDescriptors); + Object.defineProperties(EventSource.prototype, constantsPropertyDescriptors); + Object.defineProperties(EventSource.prototype, { + close: kEnumerableProperty, + onerror: kEnumerableProperty, + onmessage: kEnumerableProperty, + onopen: kEnumerableProperty, + readyState: kEnumerableProperty, + url: kEnumerableProperty, + withCredentials: kEnumerableProperty + }); + webidl.converters.EventSourceInitDict = webidl.dictionaryConverter([ + { + key: "withCredentials", + converter: webidl.converters.boolean, + defaultValue: () => false + }, + { + key: "dispatcher", + // undici only + converter: webidl.converters.any + } + ]); + module.exports = { + EventSource, + defaultReconnectionTime + }; + } +}); + +// viewer/node_modules/undici/index.js +var require_undici = __commonJS({ + "viewer/node_modules/undici/index.js"(exports, module) { + "use strict"; + var Client = require_client(); + var Dispatcher = require_dispatcher(); + var Pool = require_pool(); + var BalancedPool = require_balanced_pool(); + var Agent = require_agent(); + var ProxyAgent = require_proxy_agent(); + var EnvHttpProxyAgent = require_env_http_proxy_agent(); + var RetryAgent = require_retry_agent(); + var errors = require_errors(); + var util = require_util(); + var { InvalidArgumentError } = errors; + var api = require_api(); + var buildConnector = require_connect(); + var MockClient = require_mock_client(); + var MockAgent = require_mock_agent(); + var MockPool = require_mock_pool(); + var mockErrors = require_mock_errors(); + var RetryHandler = require_retry_handler(); + var { getGlobalDispatcher, setGlobalDispatcher } = require_global2(); + var DecoratorHandler = require_decorator_handler(); + var RedirectHandler = require_redirect_handler(); + var createRedirectInterceptor = require_redirect_interceptor(); + Object.assign(Dispatcher.prototype, api); + module.exports.Dispatcher = Dispatcher; + module.exports.Client = Client; + module.exports.Pool = Pool; + module.exports.BalancedPool = BalancedPool; + module.exports.Agent = Agent; + module.exports.ProxyAgent = ProxyAgent; + module.exports.EnvHttpProxyAgent = EnvHttpProxyAgent; + module.exports.RetryAgent = RetryAgent; + module.exports.RetryHandler = RetryHandler; + module.exports.DecoratorHandler = DecoratorHandler; + module.exports.RedirectHandler = RedirectHandler; + module.exports.createRedirectInterceptor = createRedirectInterceptor; + module.exports.interceptors = { + redirect: require_redirect(), + retry: require_retry3(), + dump: require_dump(), + dns: require_dns() + }; + module.exports.buildConnector = buildConnector; + module.exports.errors = errors; + module.exports.util = { + parseHeaders: util.parseHeaders, + headerNameToString: util.headerNameToString + }; + function makeDispatcher(fn) { + return (url, opts, handler) => { + if (typeof opts === "function") { + handler = opts; + opts = null; + } + if (!url || typeof url !== "string" && typeof url !== "object" && !(url instanceof URL)) { + throw new InvalidArgumentError("invalid url"); + } + if (opts != null && typeof opts !== "object") { + throw new InvalidArgumentError("invalid opts"); + } + if (opts && opts.path != null) { + if (typeof opts.path !== "string") { + throw new InvalidArgumentError("invalid opts.path"); + } + let path12 = opts.path; + if (!opts.path.startsWith("/")) { + path12 = `/${path12}`; + } + url = new URL(util.parseOrigin(url).origin + path12); + } else { + if (!opts) { + opts = typeof url === "object" ? url : {}; + } + url = util.parseURL(url); + } + const { agent, dispatcher = getGlobalDispatcher() } = opts; + if (agent) { + throw new InvalidArgumentError("unsupported opts.agent. Did you mean opts.client?"); + } + return fn.call(dispatcher, { + ...opts, + origin: url.origin, + path: url.search ? `${url.pathname}${url.search}` : url.pathname, + method: opts.method || (opts.body ? "PUT" : "GET") + }, handler); + }; + } + module.exports.setGlobalDispatcher = setGlobalDispatcher; + module.exports.getGlobalDispatcher = getGlobalDispatcher; + var fetchImpl = require_fetch().fetch; + module.exports.fetch = async function fetch3(init, options = void 0) { + try { + return await fetchImpl(init, options); + } catch (err) { + if (err && typeof err === "object") { + Error.captureStackTrace(err); + } + throw err; + } + }; + module.exports.Headers = require_headers().Headers; + module.exports.Response = require_response().Response; + module.exports.Request = require_request2().Request; + module.exports.FormData = require_formdata().FormData; + module.exports.File = globalThis.File ?? __require("node:buffer").File; + module.exports.FileReader = require_filereader().FileReader; + var { setGlobalOrigin, getGlobalOrigin } = require_global(); + module.exports.setGlobalOrigin = setGlobalOrigin; + module.exports.getGlobalOrigin = getGlobalOrigin; + var { CacheStorage } = require_cachestorage(); + var { kConstruct } = require_symbols4(); + module.exports.caches = new CacheStorage(kConstruct); + var { deleteCookie, getCookies, getSetCookies, setCookie } = require_cookies(); + module.exports.deleteCookie = deleteCookie; + module.exports.getCookies = getCookies; + module.exports.getSetCookies = getSetCookies; + module.exports.setCookie = setCookie; + var { parseMIMEType, serializeAMimeType } = require_data_url(); + module.exports.parseMIMEType = parseMIMEType; + module.exports.serializeAMimeType = serializeAMimeType; + var { CloseEvent, ErrorEvent, MessageEvent } = require_events(); + module.exports.WebSocket = require_websocket().WebSocket; + module.exports.CloseEvent = CloseEvent; + module.exports.ErrorEvent = ErrorEvent; + module.exports.MessageEvent = MessageEvent; + module.exports.request = makeDispatcher(api.request); + module.exports.stream = makeDispatcher(api.stream); + module.exports.pipeline = makeDispatcher(api.pipeline); + module.exports.connect = makeDispatcher(api.connect); + module.exports.upgrade = makeDispatcher(api.upgrade); + module.exports.MockClient = MockClient; + module.exports.MockPool = MockPool; + module.exports.MockAgent = MockAgent; + module.exports.mockErrors = mockErrors; + var { EventSource } = require_eventsource(); + module.exports.EventSource = EventSource; + } +}); + +// viewer/node_modules/throttleit/index.js +var require_throttleit = __commonJS({ + "viewer/node_modules/throttleit/index.js"(exports, module) { + function throttle3(function_, wait) { + if (typeof function_ !== "function") { + throw new TypeError(`Expected the first argument to be a \`function\`, got \`${typeof function_}\`.`); + } + let timeoutId; + let lastCallTime = 0; + return function throttled(...arguments_) { + clearTimeout(timeoutId); + const now = Date.now(); + const timeSinceLastCall = now - lastCallTime; + const delayForNextCall = wait - timeSinceLastCall; + if (delayForNextCall <= 0) { + lastCallTime = now; + function_.apply(this, arguments_); + } else { + timeoutId = setTimeout(() => { + lastCallTime = Date.now(); + function_.apply(this, arguments_); + }, delayForNextCall); + } + }; + } + module.exports = throttle3; + } +}); + +// viewer/node_modules/@vercel/blob/dist/chunk-3D2SZ6M2.js +import { Readable } from "stream"; +async function toReadableStream(value) { + if (value instanceof ReadableStream) { + return value; + } + if (value instanceof Blob) { + return value.stream(); + } + if (isNodeJsReadableStream(value)) { + return Readable.toWeb(value); + } + let streamValue; + if (value instanceof ArrayBuffer) { + streamValue = new Uint8Array(value); + } else if (isNodeJsBuffer(value)) { + streamValue = value; + } else { + streamValue = stringToUint8Array(value); + } + if (await supportsNewBlobFromArrayBuffer) { + return new Blob([streamValue]).stream(); + } + return new ReadableStream({ + start(controller) { + controller.enqueue(streamValue); + controller.close(); + } + }); +} +function isNodeJsReadableStream(value) { + return typeof value === "object" && typeof value.pipe === "function" && value.readable && typeof value._read === "function" && // @ts-expect-error _readableState does exists on Readable + typeof value._readableState === "object"; +} +function stringToUint8Array(s) { + const enc = new TextEncoder(); + return enc.encode(s); +} +function isNodeJsBuffer(value) { + return (0, import_is_buffer.default)(value); +} +function readEnv(name) { + try { + const value = process.env[name]; + return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0; + } catch { + return void 0; + } +} +function getVercelOidcToken() { + var _a3; + const tokenFromContext = (_a3 = getContext().headers) == null ? void 0 : _a3["x-vercel-oidc-token"]; + if (typeof tokenFromContext === "string" && tokenFromContext.trim() !== "") { + return tokenFromContext.trim(); + } + return readEnv("VERCEL_OIDC_TOKEN"); +} +function bytes(val) { + if (typeof val === "number" && !Number.isNaN(val)) { + return val; + } + if (typeof val !== "string") { + return null; + } + const results = parseRegExp.exec(val); + let floatValue; + let unit = "b"; + if (!results) { + floatValue = parseInt(val, 10); + } else { + const [, res, , , unitMatch] = results; + if (!res) { + return null; + } + floatValue = parseFloat(res); + if (unitMatch) { + unit = unitMatch.toLowerCase(); + } + } + if (Number.isNaN(floatValue)) { + return null; + } + return Math.floor(map[unit] * floatValue); +} +function readEnv2(name) { + try { + const value = process.env[name]; + return typeof value === "string" && value.trim() !== "" ? value.trim() : void 0; + } catch { + return void 0; + } +} +function parseStoreIdFromReadWriteToken(token) { + const [, , , storeId = ""] = token.split("_"); + return storeId; +} +function base64UrlDecodeDelegationSegment(segment) { + let base64 = segment.replace(/-/g, "+").replace(/_/g, "/"); + const padding = 4 - base64.length % 4; + if (padding !== 4) { + base64 += "=".repeat(padding); + } + if (typeof atob === "function") { + return atob(base64); + } + if (typeof Buffer !== "undefined") { + return Buffer.from(base64, "base64").toString("utf8"); + } + throw new BlobError("Cannot decode base64: no atob or Buffer available."); +} +function parseStoreIdFromDelegationToken(delegationToken) { + const dot = delegationToken.indexOf("."); + if (dot < 0) { + throw new BlobError("Invalid delegation token format."); + } + const payloadSeg = delegationToken.slice(0, dot); + let parsed; + try { + parsed = JSON.parse(base64UrlDecodeDelegationSegment(payloadSeg)); + } catch { + throw new BlobError("Invalid delegation token payload."); + } + if (!parsed.storeId || typeof parsed.storeId !== "string") { + throw new BlobError("Delegation token payload is missing `storeId`."); + } + return normalizeStoreId(parsed.storeId); +} +function parseStoreIdFromPresignedUrl(presignedUrlPayload) { + const delegation = presignedUrlPayload.delegationToken; + return parseStoreIdFromDelegationToken(delegation); +} +function normalizeStoreId(storeId) { + return storeId.startsWith("store_") ? storeId.slice("store_".length) : storeId; +} +function resolveBlobAuth(options) { + var _a3, _b2; + if (options == null ? void 0 : options.presignedUrlPayload) { + const storeId = parseStoreIdFromDelegationToken( + options.presignedUrlPayload.delegationToken + ); + return { kind: "presigned", storeId }; + } + if (options == null ? void 0 : options.token) { + const storeId = parseStoreIdFromReadWriteToken(options.token); + return { kind: "readWrite", token: options.token, storeId }; + } + const manualOidcToken = (_a3 = options == null ? void 0 : options.oidcToken) == null ? void 0 : _a3.trim(); + const oidcToken = manualOidcToken || getVercelOidcToken(); + if (oidcToken) { + const manualStoreId = (_b2 = options == null ? void 0 : options.storeId) == null ? void 0 : _b2.trim(); + if (manualStoreId) { + return { + kind: "oidc", + token: oidcToken, + storeId: normalizeStoreId(manualStoreId) + }; + } + const blobStoreId = readEnv2("BLOB_STORE_ID"); + if (blobStoreId) { + return { + kind: "oidc", + token: oidcToken, + storeId: normalizeStoreId(blobStoreId) + }; + } + if (manualOidcToken) { + throw new BlobError( + "oidcToken was passed, but no storeId was found. Pass a `storeId` option or set `BLOB_STORE_ID` to use OIDC auth" + ); + } + } + const readWrite = readEnv2("BLOB_READ_WRITE_TOKEN"); + if (readWrite) { + const storeId = parseStoreIdFromReadWriteToken(readWrite); + return { kind: "readWrite", token: readWrite, storeId }; + } + throw new BlobError( + "No blob credentials found. Pass a `token` option, set `BLOB_READ_WRITE_TOKEN`, or use `oidcToken` (or `VERCEL_OIDC_TOKEN`) with `storeId` or `BLOB_STORE_ID`." + ); +} +function getDownloadUrl(blobUrl) { + const url = new URL(blobUrl); + url.searchParams.set("download", "1"); + return url.toString(); +} +function isPlainObject(value) { + if (typeof value !== "object" || value === null) { + return false; + } + const prototype = Object.getPrototypeOf(value); + return (prototype === null || prototype === Object.prototype || Object.getPrototypeOf(prototype) === null) && !(Symbol.toStringTag in value) && !(Symbol.iterator in value); +} +function getApiUrl(pathname = "") { + let baseUrl = null; + try { + baseUrl = process.env.VERCEL_BLOB_API_URL || process.env.NEXT_PUBLIC_VERCEL_BLOB_API_URL; + } catch { + } + return `${baseUrl || defaultVercelBlobApiUrl}${pathname}`; +} +function computeBodyLength(body) { + if (!body) { + return 0; + } + if (typeof body === "string") { + if (TEXT_ENCODER) { + return TEXT_ENCODER.encode(body).byteLength; + } + return new Blob([body]).size; + } + if ("byteLength" in body && typeof body.byteLength === "number") { + return body.byteLength; + } + if ("size" in body && typeof body.size === "number") { + return body.size; + } + return 0; +} +function isReadableStream(value) { + return globalThis.ReadableStream && // TODO: Can be removed once Node.js 16 is no more required internally + value instanceof ReadableStream; +} +function isStream(value) { + if (isReadableStream(value)) { + return true; + } + if (isNodeJsReadableStream(value)) { + return true; + } + return false; +} +function isUrl(urlOrPathname) { + return urlOrPathname.startsWith("http://") || urlOrPathname.startsWith("https://"); +} +function constructBlobUrl(storeId, pathname, access) { + return `https://${storeId}.${access}.blob.vercel-storage.com/${pathname}`; +} +function debug(message, ...args) { + if (debugIsActive) { + console.debug(`vercel-blob: ${message}`, ...args); + } +} +function isNetworkError(error) { + const isValid = error && isError(error) && error.name === "TypeError" && typeof error.message === "string"; + if (!isValid) { + return false; + } + if (error.message === "Load failed") { + return error.stack === void 0; + } + return errorMessages.has(error.message); +} +function getApiVersion() { + let versionOverride = null; + try { + versionOverride = process.env.VERCEL_BLOB_API_VERSION_OVERRIDE || process.env.NEXT_PUBLIC_VERCEL_BLOB_API_VERSION_OVERRIDE; + } catch { + } + return `${versionOverride != null ? versionOverride : BLOB_API_VERSION}`; +} +function getRetries() { + try { + const retries = process.env.VERCEL_BLOB_RETRIES || "10"; + return parseInt(retries, 10); + } catch { + return 10; + } +} +function createBlobServiceRateLimited(response) { + const retryAfter = response.headers.get("retry-after"); + return new BlobServiceRateLimited( + retryAfter ? parseInt(retryAfter, 10) : void 0 + ); +} +async function getBlobError(response) { + var _a3, _b2, _c; + let code; + let message; + try { + const data = await response.json(); + code = (_b2 = (_a3 = data.error) == null ? void 0 : _a3.code) != null ? _b2 : "unknown_error"; + message = (_c = data.error) == null ? void 0 : _c.message; + } catch { + code = "unknown_error"; + } + if ((message == null ? void 0 : message.includes("contentType")) && message.includes("is not allowed")) { + code = "content_type_not_allowed"; + } + if ((message == null ? void 0 : message.includes('"pathname"')) && message.includes("does not match the token payload")) { + code = "client_token_pathname_mismatch"; + } + if (message === "Token expired") { + code = "client_token_expired"; + } + if (message == null ? void 0 : message.includes("the file length cannot be greater than")) { + code = "file_too_large"; + } + if ((message == null ? void 0 : message.startsWith("OIDC is enabled for this project, but not for the")) && message.includes("environment.")) { + code = "oidc_environment_not_allowed"; + } + let error; + switch (code) { + case "store_suspended": + error = new BlobStoreSuspendedError(); + break; + case "forbidden": + error = new BlobAccessError(); + break; + case "oidc_environment_not_allowed": + error = new BlobOidcEnvironmentNotAllowedError(message); + break; + case "content_type_not_allowed": + error = new BlobContentTypeNotAllowedError(message); + break; + case "client_token_pathname_mismatch": + error = new BlobPathnameMismatchError(message); + break; + case "client_token_expired": + error = new BlobClientTokenExpiredError(); + break; + case "file_too_large": + error = new BlobFileTooLargeError(message); + break; + case "not_found": + error = new BlobNotFoundError(); + break; + case "client_token_not_allowed": + error = new BlobError( + message != null ? message : "This operation is not available when using a client token. Use a read\u2013write or OIDC token on the server." + ); + break; + case "store_not_found": + error = new BlobStoreNotFoundError(); + break; + case "bad_request": + error = new BlobError(message != null ? message : "Bad request"); + break; + case "service_unavailable": + error = new BlobServiceNotAvailable(); + break; + case "rate_limited": + error = createBlobServiceRateLimited(response); + break; + case "precondition_failed": + error = new BlobPreconditionFailedError(); + break; + case "unknown_error": + case "not_allowed": + default: + error = new BlobUnknownError(); + break; + } + return { code, error }; +} +async function requestApi(pathname, init, commandOptions) { + const apiVersion = getApiVersion(); + const auth = resolveBlobAuth(commandOptions); + const bearerToken = auth.kind === "presigned" ? void 0 : auth.token; + const extraHeaders = getProxyThroughAlternativeApiHeaderFromEnv(); + let requestInput = getApiUrl(pathname); + if (commandOptions == null ? void 0 : commandOptions.presignedUrlPayload) { + requestInput = addPresignedParams( + requestInput, + commandOptions.presignedUrlPayload + ); + } + const requestId = `${auth.storeId}:${Date.now()}:${Math.random().toString(16).slice(2)}`; + let retryCount = 0; + let bodyLength = 0; + let totalLoaded = 0; + const sendBodyLength = (commandOptions == null ? void 0 : commandOptions.onUploadProgress) || shouldUseXContentLength(); + if (init.body && // 1. For upload progress we always need to know the total size of the body + // 2. In development we need the header for put() to work correctly when passing a stream + sendBodyLength) { + bodyLength = computeBodyLength(init.body); + } + if (commandOptions == null ? void 0 : commandOptions.onUploadProgress) { + commandOptions.onUploadProgress({ + loaded: 0, + total: bodyLength, + percentage: 0 + }); + } + const apiResponse = await (0, import_async_retry.default)( + async (bail) => { + let res; + try { + res = await blobRequest({ + input: requestInput, + init: { + ...init, + headers: { + "x-api-blob-request-id": requestId, + // Store ID is not encoded in OIDC token, so pass it separately as a header + "x-vercel-blob-store-id": auth.storeId, + "x-api-blob-request-attempt": String(retryCount), + "x-api-version": apiVersion, + ...sendBodyLength ? { "x-content-length": String(bodyLength) } : {}, + ...bearerToken !== void 0 ? { authorization: `Bearer ${bearerToken}` } : {}, + ...extraHeaders, + ...init.headers + } + }, + onUploadProgress: (commandOptions == null ? void 0 : commandOptions.onUploadProgress) ? (loaded) => { + var _a3; + const total = bodyLength !== 0 ? bodyLength : loaded; + totalLoaded = loaded; + const percentage = bodyLength > 0 ? Number((loaded / total * 100).toFixed(2)) : 0; + if (percentage === 100 && bodyLength > 0) { + return; + } + (_a3 = commandOptions.onUploadProgress) == null ? void 0 : _a3.call(commandOptions, { + loaded, + // When passing a stream to put(), we have no way to know the total size of the body. + // Instead of defining total as total?: number we decided to set the total to the currently + // loaded number. This is not inaccurate and way more practical for DX. + // Passing down a stream to put() is very rare + total, + percentage + }); + } : void 0 + }); + } catch (error2) { + if (error2 instanceof DOMException2 && error2.name === "AbortError") { + bail(new BlobRequestAbortedError()); + return; + } + if (isNetworkError(error2)) { + throw error2; + } + if (error2 instanceof TypeError) { + bail(error2); + return; + } + throw error2; + } + if (res.ok) { + return res; + } + const { code, error } = await getBlobError(res); + if (code === "unknown_error" || code === "service_unavailable" || code === "internal_server_error") { + throw error; + } + bail(error); + }, + { + retries: getRetries(), + onRetry: (error) => { + if (error instanceof Error) { + debug(`retrying API request to ${pathname}`, error.message); + } + retryCount = retryCount + 1; + } + } + ); + if (!apiResponse) { + throw new BlobUnknownError(); + } + if (commandOptions == null ? void 0 : commandOptions.onUploadProgress) { + commandOptions.onUploadProgress({ + loaded: totalLoaded, + total: totalLoaded, + percentage: 100 + }); + } + return await apiResponse.json(); +} +function getProxyThroughAlternativeApiHeaderFromEnv() { + const extraHeaders = {}; + try { + if ("VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API" in process.env && process.env.VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API !== void 0) { + extraHeaders["x-proxy-through-alternative-api"] = process.env.VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API; + } else if ("NEXT_PUBLIC_VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API" in process.env && process.env.NEXT_PUBLIC_VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API !== void 0) { + extraHeaders["x-proxy-through-alternative-api"] = process.env.NEXT_PUBLIC_VERCEL_BLOB_PROXY_THROUGH_ALTERNATIVE_API; + } + } catch { + } + return extraHeaders; +} +function shouldUseXContentLength() { + try { + return process.env.VERCEL_BLOB_USE_X_CONTENT_LENGTH === "1"; + } catch { + return false; + } +} +function createPutHeaders(allowedOptions, options) { + const headers = {}; + headers[putOptionHeaderMap.access] = options.access; + if (allowedOptions.includes("contentType") && options.contentType) { + headers[putOptionHeaderMap.contentType] = options.contentType; + } + if (allowedOptions.includes("addRandomSuffix") && options.addRandomSuffix !== void 0) { + headers[putOptionHeaderMap.addRandomSuffix] = options.addRandomSuffix ? "1" : "0"; + } + if (allowedOptions.includes("ifMatch") && options.ifMatch) { + if (options.allowOverwrite === false) { + throw new BlobError( + "ifMatch and allowOverwrite: false are contradictory. ifMatch is used for conditional overwrites, which requires allowOverwrite to be true." + ); + } + headers[putOptionHeaderMap.ifMatch] = options.ifMatch; + if (allowedOptions.includes("allowOverwrite") && options.allowOverwrite === void 0) { + headers[putOptionHeaderMap.allowOverwrite] = "1"; + } + } + if (allowedOptions.includes("allowOverwrite") && options.allowOverwrite !== void 0) { + headers[putOptionHeaderMap.allowOverwrite] = options.allowOverwrite ? "1" : "0"; + } + if (allowedOptions.includes("cacheControlMaxAge") && options.cacheControlMaxAge !== void 0) { + headers[putOptionHeaderMap.cacheControlMaxAge] = options.cacheControlMaxAge.toString(); + } + return headers; +} +async function createPutOptions({ + pathname, + options, + extraChecks, + getToken +}) { + if (!pathname) { + throw new BlobError("pathname is required"); + } + if (pathname.length > MAXIMUM_PATHNAME_LENGTH) { + throw new BlobError( + `pathname is too long, maximum length is ${MAXIMUM_PATHNAME_LENGTH}` + ); + } + for (const invalidCharacter of disallowedPathnameCharacters) { + if (pathname.includes(invalidCharacter)) { + throw new BlobError( + `pathname cannot contain "${invalidCharacter}", please encode it if needed` + ); + } + } + if (!options) { + throw new BlobError("missing options, see usage"); + } + if (options.access !== "public" && options.access !== "private") { + throw new BlobError( + 'access must be "private" or "public", see https://vercel.com/docs/vercel-blob' + ); + } + if (extraChecks) { + extraChecks(options); + } + if (getToken) { + options.token = await getToken(pathname, options); + } + return options; +} +function createCompleteMultipartUploadMethod({ allowedOptions, getToken, extraChecks }) { + return async (pathname, parts, optionsInput) => { + const options = await createPutOptions({ + pathname, + options: optionsInput, + extraChecks, + getToken + }); + const headers = createPutHeaders(allowedOptions, options); + return completeMultipartUpload({ + uploadId: options.uploadId, + key: options.key, + pathname, + headers, + options, + parts + }); + }; +} +async function completeMultipartUpload({ + uploadId, + key, + pathname, + parts, + headers, + options +}) { + const params = new URLSearchParams({ pathname }); + try { + const response = await requestApi( + `/mpu?${params.toString()}`, + { + method: "POST", + headers: { + ...headers, + "content-type": "application/json", + "x-mpu-action": "complete", + "x-mpu-upload-id": uploadId, + // key can be any utf8 character so we need to encode it as HTTP headers can only be us-ascii + // https://www.rfc-editor.org/rfc/rfc7230#swection-3.2.4 + "x-mpu-key": encodeURIComponent(key) + }, + body: JSON.stringify(parts), + signal: options.abortSignal + }, + options + ); + debug("mpu: complete", response); + return response; + } catch (error) { + if (error instanceof TypeError && (error.message === "Failed to fetch" || error.message === "fetch failed")) { + throw new BlobServiceNotAvailable(); + } else { + throw error; + } + } +} +function createCreateMultipartUploadMethod({ allowedOptions, getToken, extraChecks }) { + return async (pathname, optionsInput) => { + const options = await createPutOptions({ + pathname, + options: optionsInput, + extraChecks, + getToken + }); + const headers = createPutHeaders(allowedOptions, options); + const createMultipartUploadResponse = await createMultipartUpload( + pathname, + headers, + options + ); + return { + key: createMultipartUploadResponse.key, + uploadId: createMultipartUploadResponse.uploadId + }; + }; +} +async function createMultipartUpload(pathname, headers, options) { + debug("mpu: create", "pathname:", pathname); + const params = new URLSearchParams({ pathname }); + try { + const response = await requestApi( + `/mpu?${params.toString()}`, + { + method: "POST", + headers: { + ...headers, + "x-mpu-action": "create" + }, + signal: options.abortSignal + }, + options + ); + debug("mpu: create", response); + return response; + } catch (error) { + if (error instanceof TypeError && (error.message === "Failed to fetch" || error.message === "fetch failed")) { + throw new BlobServiceNotAvailable(); + } + throw error; + } +} +function createUploadPartMethod({ allowedOptions, getToken, extraChecks }) { + return async (pathname, body, optionsInput) => { + const options = await createPutOptions({ + pathname, + options: optionsInput, + extraChecks, + getToken + }); + const headers = createPutHeaders(allowedOptions, options); + if (isPlainObject(body)) { + throw new BlobError( + "Body must be a string, buffer or stream. You sent a plain JavaScript object, double check what you're trying to upload." + ); + } + const result = await uploadPart({ + uploadId: options.uploadId, + key: options.key, + pathname, + part: { blob: body, partNumber: options.partNumber }, + headers, + options + }); + return { + etag: result.etag, + partNumber: options.partNumber + }; + }; +} +async function uploadPart({ + uploadId, + key, + pathname, + headers, + options, + internalAbortController = new AbortController(), + part +}) { + var _a3, _b2, _c; + const params = new URLSearchParams({ pathname }); + const responsePromise = requestApi( + `/mpu?${params.toString()}`, + { + signal: internalAbortController.signal, + method: "POST", + headers: { + ...headers, + "x-mpu-action": "upload", + "x-mpu-key": encodeURIComponent(key), + "x-mpu-upload-id": uploadId, + "x-mpu-part-number": part.partNumber.toString() + }, + // weird things between undici types and native fetch types + body: part.blob + }, + options + ); + function handleAbort() { + internalAbortController.abort(); + } + if ((_a3 = options.abortSignal) == null ? void 0 : _a3.aborted) { + handleAbort(); + } else { + (_b2 = options.abortSignal) == null ? void 0 : _b2.addEventListener("abort", handleAbort); + } + const response = await responsePromise; + (_c = options.abortSignal) == null ? void 0 : _c.removeEventListener("abort", handleAbort); + return response; +} +function uploadAllParts({ + uploadId, + key, + pathname, + stream, + headers, + options, + totalToLoad +}) { + debug("mpu: upload init", "key:", key); + const internalAbortController = new AbortController(); + return new Promise((resolve, reject) => { + const partsToUpload = []; + const completedParts = []; + const reader = stream.getReader(); + let activeUploads = 0; + let reading = false; + let currentPartNumber = 1; + let rejected = false; + let currentBytesInMemory = 0; + let doneReading = false; + let bytesSent = 0; + let arrayBuffers = []; + let currentPartBytesRead = 0; + let onUploadProgress; + const totalLoadedPerPartNumber = {}; + if (options.onUploadProgress) { + onUploadProgress = (0, import_throttleit.default)(() => { + var _a3; + const loaded = Object.values(totalLoadedPerPartNumber).reduce( + (acc, cur) => { + return acc + cur; + }, + 0 + ); + const total = totalToLoad || loaded; + const percentage = totalToLoad > 0 ? Number(((loaded / totalToLoad || loaded) * 100).toFixed(2)) : 0; + (_a3 = options.onUploadProgress) == null ? void 0 : _a3.call(options, { loaded, total, percentage }); + }, 150); + } + read().catch(cancel); + async function read() { + debug( + "mpu: upload read start", + "activeUploads:", + activeUploads, + "currentBytesInMemory:", + `${bytes(currentBytesInMemory)}/${bytes(maxBytesInMemory)}`, + "bytesSent:", + bytes(bytesSent) + ); + reading = true; + while (currentBytesInMemory < maxBytesInMemory && !rejected) { + try { + const { value, done } = await reader.read(); + if (done) { + doneReading = true; + debug("mpu: upload read consumed the whole stream"); + if (arrayBuffers.length > 0) { + partsToUpload.push({ + partNumber: currentPartNumber++, + blob: new Blob(arrayBuffers, { + type: "application/octet-stream" + }) + }); + sendParts(); + } else if (activeUploads === 0) { + reader.releaseLock(); + resolve(completedParts); + } + reading = false; + return; + } + currentBytesInMemory += value.byteLength; + let valueOffset = 0; + while (valueOffset < value.byteLength) { + const remainingPartSize = partSizeInBytes - currentPartBytesRead; + const endOffset = Math.min( + valueOffset + remainingPartSize, + value.byteLength + ); + const chunk = value.slice(valueOffset, endOffset); + arrayBuffers.push(chunk); + currentPartBytesRead += chunk.byteLength; + valueOffset = endOffset; + if (currentPartBytesRead === partSizeInBytes) { + partsToUpload.push({ + partNumber: currentPartNumber++, + blob: new Blob(arrayBuffers, { + type: "application/octet-stream" + }) + }); + arrayBuffers = []; + currentPartBytesRead = 0; + sendParts(); + } + } + } catch (error) { + cancel(error); + } + } + debug( + "mpu: upload read end", + "activeUploads:", + activeUploads, + "currentBytesInMemory:", + `${bytes(currentBytesInMemory)}/${bytes(maxBytesInMemory)}`, + "bytesSent:", + bytes(bytesSent) + ); + reading = false; + } + async function sendPart(part) { + activeUploads++; + debug( + "mpu: upload send part start", + "partNumber:", + part.partNumber, + "size:", + part.blob.size, + "activeUploads:", + activeUploads, + "currentBytesInMemory:", + `${bytes(currentBytesInMemory)}/${bytes(maxBytesInMemory)}`, + "bytesSent:", + bytes(bytesSent) + ); + try { + const uploadProgressForPart = options.onUploadProgress ? (event) => { + totalLoadedPerPartNumber[part.partNumber] = event.loaded; + if (onUploadProgress) { + onUploadProgress(); + } + } : void 0; + const completedPart = await uploadPart({ + uploadId, + key, + pathname, + headers, + options: { + ...options, + onUploadProgress: uploadProgressForPart + }, + internalAbortController, + part + }); + debug( + "mpu: upload send part end", + "partNumber:", + part.partNumber, + "activeUploads", + activeUploads, + "currentBytesInMemory:", + `${bytes(currentBytesInMemory)}/${bytes(maxBytesInMemory)}`, + "bytesSent:", + bytes(bytesSent) + ); + if (rejected) { + return; + } + completedParts.push({ + partNumber: part.partNumber, + etag: completedPart.etag + }); + currentBytesInMemory -= part.blob.size; + activeUploads--; + bytesSent += part.blob.size; + if (partsToUpload.length > 0) { + sendParts(); + } + if (doneReading) { + if (activeUploads === 0) { + reader.releaseLock(); + resolve(completedParts); + } + return; + } + if (!reading) { + read().catch(cancel); + } + } catch (error) { + cancel(error); + } + } + function sendParts() { + if (rejected) { + return; + } + debug( + "send parts", + "activeUploads", + activeUploads, + "partsToUpload", + partsToUpload.length + ); + while (activeUploads < maxConcurrentUploads && partsToUpload.length > 0) { + const partToSend = partsToUpload.shift(); + if (partToSend) { + void sendPart(partToSend); + } + } + } + function cancel(error) { + if (rejected) { + return; + } + rejected = true; + internalAbortController.abort(); + reader.releaseLock(); + if (error instanceof TypeError && (error.message === "Failed to fetch" || error.message === "fetch failed")) { + reject(new BlobServiceNotAvailable()); + } else { + reject(error); + } + } + }); +} +function createCreateMultipartUploaderMethod({ allowedOptions, getToken, extraChecks }) { + return async (pathname, optionsInput) => { + const options = await createPutOptions({ + pathname, + options: optionsInput, + extraChecks, + getToken + }); + const headers = createPutHeaders(allowedOptions, options); + const createMultipartUploadResponse = await createMultipartUpload( + pathname, + headers, + options + ); + return { + key: createMultipartUploadResponse.key, + uploadId: createMultipartUploadResponse.uploadId, + async uploadPart(partNumber, body) { + if (isPlainObject(body)) { + throw new BlobError( + "Body must be a string, buffer or stream. You sent a plain JavaScript object, double check what you're trying to upload." + ); + } + const result = await uploadPart({ + uploadId: createMultipartUploadResponse.uploadId, + key: createMultipartUploadResponse.key, + pathname, + part: { partNumber, blob: body }, + headers, + options + }); + return { + etag: result.etag, + partNumber + }; + }, + async complete(parts) { + return completeMultipartUpload({ + uploadId: createMultipartUploadResponse.uploadId, + key: createMultipartUploadResponse.key, + pathname, + parts, + headers, + options + }); + } + }; + }; +} +async function uncontrolledMultipartUpload(pathname, body, headers, options) { + debug("mpu: init", "pathname:", pathname, "headers:", headers); + const optionsWithoutOnUploadProgress = { + ...options, + onUploadProgress: void 0 + }; + if (options.maximumSizeInBytes !== void 0 && !isStream(body) && computeBodyLength(body) > options.maximumSizeInBytes) { + throw new BlobError( + `Body size of ${computeBodyLength(body)} bytes exceeds the maximum allowed size of ${options.maximumSizeInBytes} bytes` + ); + } + const createMultipartUploadResponse = await createMultipartUpload( + pathname, + headers, + optionsWithoutOnUploadProgress + ); + const totalToLoad = computeBodyLength(body); + const stream = await toReadableStream(body); + const parts = await uploadAllParts({ + uploadId: createMultipartUploadResponse.uploadId, + key: createMultipartUploadResponse.key, + pathname, + // @ts-expect-error ReadableStream is compatible at runtime + stream, + headers, + options, + totalToLoad + }); + const blob = await completeMultipartUpload({ + uploadId: createMultipartUploadResponse.uploadId, + key: createMultipartUploadResponse.key, + pathname, + parts, + headers, + options: optionsWithoutOnUploadProgress + }); + return blob; +} +function createPutMethod({ + allowedOptions, + getToken, + getPresignedUrlPayload, + extraChecks +}) { + return async function put2(pathname, body, optionsInput) { + if (!body) { + throw new BlobError("body is required"); + } + if (isPlainObject(body)) { + throw new BlobError( + "Body must be a string, buffer or stream. You sent a plain JavaScript object, double check what you're trying to upload." + ); + } + const options = await createPutOptions({ + pathname, + options: optionsInput, + extraChecks, + getToken + }); + const presignedUrlPayload = await (getPresignedUrlPayload == null ? void 0 : getPresignedUrlPayload( + pathname, + options + )); + const optionsWithPresignedUrlPayload = { + ...options, + presignedUrlPayload + }; + const headers = createPutHeaders(allowedOptions, options); + if (options.multipart === true) { + return uncontrolledMultipartUpload( + pathname, + body, + headers, + optionsWithPresignedUrlPayload + ); + } + const onUploadProgress = options.onUploadProgress ? (0, import_throttleit2.default)(options.onUploadProgress, 100) : void 0; + const params = new URLSearchParams({ pathname }); + const response = await requestApi( + `/?${params.toString()}`, + { + method: "PUT", + body, + headers, + signal: options.abortSignal + }, + { + ...optionsWithPresignedUrlPayload, + onUploadProgress + } + ); + return { + url: response.url, + downloadUrl: response.downloadUrl, + pathname: response.pathname, + contentType: response.contentType, + contentDisposition: response.contentDisposition, + etag: response.etag + }; + }; +} +function contentTypeAllowedByList(contentType, allowed) { + const [type] = contentType.split("/"); + const wildcard = `${type}/*`; + return allowed.includes(contentType) || (type ? allowed.includes(wildcard) : false); +} +function assertAllowedContentTypesSubset(optionsTypes, delegationTypes, label) { + if (!(optionsTypes == null ? void 0 : optionsTypes.length)) { + return; + } + if (!(delegationTypes == null ? void 0 : delegationTypes.length)) { + return; + } + for (const ct of optionsTypes) { + if (!contentTypeAllowedByList(ct, delegationTypes)) { + throw new Error( + `${label}: allowedContentTypes entry "${ct}" is not permitted by the delegation token.` + ); + } + } +} +function assertNumberSubset(name, optionVal, delegationVal, label, mode) { + if (optionVal === void 0) { + return; + } + if (delegationVal === void 0) { + return; + } + if (mode === "lte" && optionVal > delegationVal) { + throw new Error( + `${label}: ${name} must be \u2264 delegation (${String(delegationVal)}).` + ); + } +} +function isPlausibleAbsoluteUrl(s) { + if (typeof URL !== "undefined" && typeof URL.canParse === "function") { + return URL.canParse(s); + } + try { + new URL(s); + return true; + } catch { + return false; + } +} +function validatePresignUrlOnUploadCompletedWire(opt, label) { + if (!opt) { + return; + } + if (typeof opt.callbackUrl !== "string" || opt.callbackUrl.length === 0) { + throw new Error( + `${label}: onUploadCompleted.callbackUrl must be a non-empty string.` + ); + } + if (opt.callbackUrl.length > MAX_PRESIGN_CALLBACK_URL_CHARS) { + throw new Error(`${label}: onUploadCompleted.callbackUrl is too long.`); + } + if (!isPlausibleAbsoluteUrl(opt.callbackUrl)) { + throw new Error( + `${label}: onUploadCompleted.callbackUrl must be a valid URL.` + ); + } + if (opt.tokenPayload !== void 0 && opt.tokenPayload !== null) { + if (typeof opt.tokenPayload !== "string") { + throw new Error( + `${label}: onUploadCompleted.tokenPayload must be a string.` + ); + } + if (opt.tokenPayload.length > MAX_PRESIGN_CALLBACK_TOKEN_PAYLOAD_CHARS) { + throw new Error(`${label}: onUploadCompleted.tokenPayload is too long.`); + } + } +} +function validateUrlOnlyPresignUploadOptions(urlOptions, label) { + if (urlOptions.cacheControlMaxAge !== void 0) { + const n = urlOptions.cacheControlMaxAge; + if (!Number.isInteger(n) || n < 0 || n > MAX_PRESIGN_CACHE_CONTROL_MAX_AGE_SECONDS) { + throw new Error( + `${label}: cacheControlMaxAge must be an integer between 0 and ${MAX_PRESIGN_CACHE_CONTROL_MAX_AGE_SECONDS}.` + ); + } + } + if (urlOptions.ifMatch !== void 0) { + const im = urlOptions.ifMatch; + if (typeof im !== "string" || im.length === 0) { + throw new Error(`${label}: ifMatch must be a non-empty string.`); + } + if (im.length > MAX_PRESIGN_IF_MATCH_LENGTH) { + throw new Error(`${label}: ifMatch is too long.`); + } + if (IF_MATCH_CONTROL_CHARS_RE.test(im)) { + throw new Error( + `${label}: ifMatch contains disallowed control characters.` + ); + } + } +} +function sortedContentTypesCsv(types) { + return [...types].sort((a, b) => a < b ? -1 : a > b ? 1 : 0).join(","); +} +function resolvePresignUrlValidUntilMs(args) { + const { delegationValidUntil, urlOptions, nowMs } = args; + let t; + if ((urlOptions == null ? void 0 : urlOptions.validUntil) !== void 0) { + if (typeof urlOptions.validUntil !== "number" || !Number.isFinite(urlOptions.validUntil)) { + throw new Error("presignUrl: validUntil must be a finite number (ms)."); + } + t = Math.trunc(urlOptions.validUntil); + } else { + t = Math.trunc(delegationValidUntil); + } + if (Number.isFinite(delegationValidUntil)) { + t = Math.min(t, Math.trunc(delegationValidUntil)); + } + if (t <= nowMs) { + throw new Error( + "presignUrl: resolved URL expiry is not after the current time; issue a new delegation token or pass a later validUntil." + ); + } + return t; +} +function buildPresignCanonicalQueryEntries(args) { + const { operation, delegation, urlOptions, nowMs } = args; + const label = "presignUrl"; + const resolvedUntil = resolvePresignUrlValidUntilMs({ + delegationValidUntil: delegation.validUntil, + urlOptions, + nowMs + }); + const delegUntil = Math.trunc(delegation.validUntil); + const entries = []; + if (resolvedUntil < delegUntil) { + entries.push([BLOB_PRESIGN_QUERY_VALID_UNTIL, String(resolvedUntil)]); + } + if (operation === "delete") { + if ((urlOptions == null ? void 0 : urlOptions.ifMatch) !== void 0) { + entries.push([BLOB_PRESIGN_QUERY_IF_MATCH, urlOptions.ifMatch]); + } + return entries; + } + if (operation !== "put" || !urlOptions) { + return entries; + } + assertAllowedContentTypesSubset( + urlOptions.allowedContentTypes, + delegation.allowedContentTypes, + label + ); + assertNumberSubset( + "maximumSizeInBytes", + urlOptions.maximumSizeInBytes, + delegation.maximumSizeInBytes, + label, + "lte" + ); + validateUrlOnlyPresignUploadOptions(urlOptions, label); + validatePresignUrlOnUploadCompletedWire(urlOptions.onUploadCompleted, label); + if (urlOptions.allowedContentTypes !== void 0) { + const csv = sortedContentTypesCsv(urlOptions.allowedContentTypes); + if (csv.length > 16384) { + throw new Error(`${label}: allowedContentTypes query value is too long.`); + } + entries.push([BLOB_PRESIGN_QUERY_ALLOWED_CONTENT_TYPES, csv]); + } + if (urlOptions.maximumSizeInBytes !== void 0) { + entries.push([ + BLOB_PRESIGN_QUERY_MAXIMUM_SIZE, + String(Math.trunc(urlOptions.maximumSizeInBytes)) + ]); + } + if (urlOptions.addRandomSuffix !== void 0) { + entries.push([ + BLOB_PRESIGN_QUERY_ADD_RANDOM_SUFFIX, + urlOptions.addRandomSuffix ? "true" : "false" + ]); + } + if (urlOptions.allowOverwrite !== void 0) { + entries.push([ + BLOB_PRESIGN_QUERY_ALLOW_OVERWRITE, + urlOptions.allowOverwrite ? "true" : "false" + ]); + } + if (urlOptions.cacheControlMaxAge !== void 0) { + entries.push([ + BLOB_PRESIGN_QUERY_CACHE_CONTROL_MAX_AGE, + String(Math.trunc(urlOptions.cacheControlMaxAge)) + ]); + } + if (urlOptions.ifMatch !== void 0) { + entries.push([BLOB_PRESIGN_QUERY_IF_MATCH, urlOptions.ifMatch]); + } + if (urlOptions.onUploadCompleted !== void 0) { + const { callbackUrl, tokenPayload } = urlOptions.onUploadCompleted; + if (callbackUrl.length > MAX_PRESIGN_CALLBACK_URL_CHARS) { + throw new Error(`${label}: onUploadCompleted.callbackUrl is too long.`); + } + entries.push([BLOB_PRESIGN_QUERY_CALLBACK_URL, callbackUrl]); + if (tokenPayload !== void 0 && tokenPayload !== null && tokenPayload !== "") { + if (tokenPayload.length > MAX_PRESIGN_CALLBACK_TOKEN_PAYLOAD_CHARS) { + throw new Error( + `${label}: onUploadCompleted.tokenPayload is too long.` + ); + } + entries.push([BLOB_PRESIGN_QUERY_CALLBACK_TOKEN_PAYLOAD, tokenPayload]); + } + } + return entries; +} +function assertIssueSignedTokenValidUntilOption(validUntil) { + const now = Date.now(); + if (typeof validUntil !== "number" || !Number.isInteger(validUntil) || !Number.isFinite(validUntil)) { + throw new BlobError( + "`issueSignedToken`: validUntil must be an integer milliseconds timestamp." + ); + } + if (validUntil <= now) { + throw new BlobError( + "`issueSignedToken`: validUntil must be in the future." + ); + } +} +async function issueSignedToken(options) { + if (!options) { + throw new BlobError("`issueSignedToken` requires an options object"); + } + const body = {}; + if (options.pathname !== void 0) { + body.pathname = options.pathname; + } + if (options.operations !== void 0) { + if (options.operations.length === 0) { + throw new BlobError("`operations` must be a non-empty array if provided"); + } + body.operations = dedupeOps(options.operations); + } + if (options.validUntil !== void 0) { + assertIssueSignedTokenValidUntilOption(options.validUntil); + body.validUntil = options.validUntil; + } + if (options.maximumSizeInBytes !== void 0) { + body.maximumSizeInBytes = options.maximumSizeInBytes; + } + if (options.allowedContentTypes !== void 0) { + body.allowedContentTypes = options.allowedContentTypes; + } + return requestApi( + "/signed-token", + { + method: "POST", + headers: { "content-type": "application/json" }, + body: JSON.stringify(body), + signal: options.abortSignal + }, + options + ); +} +function dedupeOps(operations) { + return Array.from(new Set(operations)); +} +function base64UrlDecodeToString(segment) { + let base64 = segment.replace(/-/g, "+").replace(/_/g, "/"); + const padding = 4 - base64.length % 4; + if (padding !== 4) { + base64 += "=".repeat(padding); + } + if (typeof atob === "function") { + return atob(base64); + } + if (typeof Buffer !== "undefined") { + return Buffer.from(base64, "base64").toString("utf8"); + } + throw new BlobError("Cannot decode base64: no atob or Buffer available."); +} +function tryDecodePayload(delegationToken) { + const dot = delegationToken.indexOf("."); + if (dot < 0) { + return null; + } + const payloadSeg = delegationToken.slice(0, dot); + try { + return JSON.parse( + base64UrlDecodeToString(payloadSeg) + ); + } catch { + return null; + } +} +function uint8ToBase64(bytes2) { + if (typeof Buffer !== "undefined") { + return Buffer.from( + bytes2.buffer, + bytes2.byteOffset, + bytes2.byteLength + ).toString("base64"); + } + let s = ""; + for (let i = 0; i < bytes2.length; i++) { + s += String.fromCharCode(bytes2[i]); + } + return btoa(s); +} +async function hmacSha256Base64Url(key, data) { + var _a3; + if (!((_a3 = globalThis.crypto) == null ? void 0 : _a3.subtle)) { + throw new BlobError( + "HMAC is not available: expected globalThis.crypto.subtle (Node 20+ or a modern browser)." + ); + } + const enc = new TextEncoder(); + const cryptoKey = await globalThis.crypto.subtle.importKey( + "raw", + enc.encode(key), + { name: "HMAC", hash: "SHA-256" }, + false, + ["sign"] + ); + const buf = await globalThis.crypto.subtle.sign( + "HMAC", + cryptoKey, + enc.encode(data) + ); + return toBase64Url(uint8ToBase64(new Uint8Array(buf))); +} +function toBase64Url(base64) { + return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, ""); +} +async function presign(signedToken, options) { + var _a3, _b2, _c, _d; + if (!(signedToken == null ? void 0 : signedToken.clientSigningToken) || !(signedToken == null ? void 0 : signedToken.delegationToken)) { + throw new BlobError( + "`clientSigningToken` and `delegationToken` from `issueSignedToken` are required." + ); + } + const scope = tryDecodePayload(signedToken.delegationToken); + if (!scope) { + throw new BlobError("Invalid or unreadable `delegationToken` payload."); + } + const p = scope.pathname; + if (p && p !== "*") { + if (options.pathname !== p) { + throw new BlobError( + `Blob path does not match the signed token scope; expected \`${p}\`, got \`${options.pathname}\`.` + ); + } + } + if (Number.isFinite(scope.validUntil) && Date.now() > scope.validUntil) { + throw new BlobError( + "The signed delegation has expired; issue a new token first." + ); + } + if (options.operation === "get" && !((_a3 = scope.operations) == null ? void 0 : _a3.includes("get"))) { + throw new BlobError( + 'The delegation token is not valid for `GET` requests. Include `"get"` in `operations` when calling `issueSignedToken`.' + ); + } + if (options.operation === "head" && !((_b2 = scope.operations) == null ? void 0 : _b2.includes("head"))) { + throw new BlobError( + 'The delegation token is not valid for `HEAD` requests. Include `"head"` in `operations` when calling `issueSignedToken`.' + ); + } + if (options.operation === "put" && !((_c = scope.operations) == null ? void 0 : _c.includes("put"))) { + throw new BlobError( + 'The delegation token is not valid for presigned write requests. Include `"put"` in `operations` when calling `issueSignedToken`.' + ); + } + if (options.operation === "delete" && !((_d = scope.operations) == null ? void 0 : _d.includes("delete"))) { + throw new BlobError( + 'The delegation token is not valid for presigned delete requests. Include `"delete"` in `operations` when calling `issueSignedToken`.' + ); + } + const delegationForOptions = { + validUntil: scope.validUntil, + maximumSizeInBytes: scope.maximumSizeInBytes, + allowedContentTypes: scope.allowedContentTypes + }; + let presignEntries; + try { + presignEntries = buildPresignCanonicalQueryEntries({ + operation: options.operation, + delegation: delegationForOptions, + urlOptions: options, + nowMs: Date.now() + }); + } catch (e) { + const msg = e instanceof Error ? e.message : String(e); + throw new BlobError(msg); + } + const canonical = canonicalString( + options.pathname, + presignEntries, + options.operation + ); + const signature = await hmacSha256Base64Url( + signedToken.clientSigningToken, + canonical + ); + return { + delegationToken: signedToken.delegationToken, + signature, + params: Object.fromEntries(presignEntries) + }; +} +function buildPresignedGetUrl(pathnameOrUrl, presignedUrlPayload, options) { + const storeId = parseStoreIdFromDelegationToken( + presignedUrlPayload.delegationToken + ); + const blobUrl = isUrl(pathnameOrUrl) ? pathnameOrUrl : constructBlobUrl(storeId, pathnameOrUrl, options.access); + return addPresignedParams(blobUrl, presignedUrlPayload); +} +function buildPresignedPutUrl(pathname, presignedUrlPayload) { + const params = new URLSearchParams({ pathname }); + const apiUrl = getApiUrl(`/?${params.toString()}`); + return addPresignedParams(apiUrl, presignedUrlPayload); +} +function buildPresignedDeleteUrl(pathname, presignedUrlPayload) { + const params = new URLSearchParams({ pathname }); + const apiUrl = getApiUrl(`/?${params.toString()}`); + return addPresignedParams(apiUrl, presignedUrlPayload); +} +async function presignUrl(signedToken, options) { + const payload = await presign(signedToken, options); + if (options.operation === "get" || options.operation === "head") { + return { + presignedUrl: buildPresignedGetUrl(options.pathname, payload, options) + }; + } + if (options.operation === "put") { + return { + presignedUrl: buildPresignedPutUrl(options.pathname, payload) + }; + } + if (options.operation === "delete") { + return { + presignedUrl: buildPresignedDeleteUrl(options.pathname, payload) + }; + } + throw new BlobError(`Unknown operation`); +} +function canonicalString(pathname, presignEntries, operation) { + var _a3; + const lines = [`operation=${operation}`, `pathname=${pathname}`]; + for (const k of PRESIGN_CANONICAL_QUERY_KEYS) { + const v = (_a3 = presignEntries.find(([key]) => key === k)) == null ? void 0 : _a3[1]; + if (v) { + lines.push(`${k}=${v}`); + } + } + lines.sort((a, b) => compareUtf8(a, b)); + return lines.join("\n"); +} +function compareUtf8(a, b) { + const ab = utf8Encoder.encode(a); + const bb = utf8Encoder.encode(b); + const n = Math.min(ab.length, bb.length); + for (let i = 0; i < n; i++) { + const d = ab[i] - bb[i]; + if (d !== 0) { + return d; + } + } + return ab.length - bb.length; +} +async function createFolder(pathname, options = { access: "public" }) { + var _a3; + const access = (_a3 = options.access) != null ? _a3 : "public"; + const folderPathname = pathname.endsWith("/") ? pathname : `${pathname}/`; + const headers = {}; + headers[putOptionHeaderMap.access] = access; + headers[putOptionHeaderMap.addRandomSuffix] = "0"; + const params = new URLSearchParams({ pathname: folderPathname }); + const response = await requestApi( + `/?${params.toString()}`, + { + method: "PUT", + headers, + signal: options.abortSignal + }, + options + ); + return { + url: response.url, + pathname: response.pathname + }; +} +var import_is_buffer, import_async_retry, import_undici, import_throttleit, import_throttleit2, supportsNewBlobFromArrayBuffer, SYMBOL_FOR_REQ_CONTEXT, getContext, parseRegExp, map, defaultVercelBlobApiUrl, BlobError, disallowedPathnameCharacters, supportsRequestStreams, TEXT_ENCODER, createChunkTransformStream, addPresignedParams, debugIsActive, _a, _b, _a2, DOMException2, objectToString, isError, errorMessages, hasFetch, hasFetchWithUploadProgress, CHUNK_SIZE, blobFetch, hasXhr, blobXhr, blobRequest, MAXIMUM_PATHNAME_LENGTH, BlobAccessError, BlobOidcEnvironmentNotAllowedError, BlobContentTypeNotAllowedError, BlobPathnameMismatchError, BlobClientTokenExpiredError, BlobFileTooLargeError, BlobStoreNotFoundError, BlobStoreSuspendedError, BlobUnknownError, BlobNotFoundError, BlobServiceNotAvailable, BlobServiceRateLimited, BlobRequestAbortedError, BlobPreconditionFailedError, BLOB_API_VERSION, putOptionHeaderMap, maxConcurrentUploads, partSizeInBytes, maxBytesInMemory, BLOB_PRESIGN_QUERY_VALID_UNTIL, BLOB_PRESIGN_QUERY_MAXIMUM_SIZE, BLOB_PRESIGN_QUERY_ALLOWED_CONTENT_TYPES, BLOB_PRESIGN_QUERY_ADD_RANDOM_SUFFIX, BLOB_PRESIGN_QUERY_ALLOW_OVERWRITE, BLOB_PRESIGN_QUERY_CACHE_CONTROL_MAX_AGE, BLOB_PRESIGN_QUERY_IF_MATCH, BLOB_PRESIGN_QUERY_CALLBACK_URL, BLOB_PRESIGN_QUERY_CALLBACK_TOKEN_PAYLOAD, PRESIGN_CANONICAL_QUERY_KEYS, MAX_PRESIGN_CALLBACK_URL_CHARS, MAX_PRESIGN_CALLBACK_TOKEN_PAYLOAD_CHARS, MAX_PRESIGN_CACHE_CONTROL_MAX_AGE_SECONDS, MAX_PRESIGN_IF_MATCH_LENGTH, IF_MATCH_CONTROL_CHARS_RE, utf8Encoder; +var init_chunk_3D2SZ6M2 = __esm({ + "viewer/node_modules/@vercel/blob/dist/chunk-3D2SZ6M2.js"() { + init_lib(); + import_is_buffer = __toESM(require_is_buffer(), 1); + import_async_retry = __toESM(require_lib(), 1); + import_undici = __toESM(require_undici(), 1); + import_throttleit = __toESM(require_throttleit(), 1); + import_throttleit2 = __toESM(require_throttleit(), 1); + supportsNewBlobFromArrayBuffer = new Promise((resolve) => { + try { + const helloAsArrayBuffer = new Uint8Array([104, 101, 108, 108, 111]); + const blob = new Blob([helloAsArrayBuffer]); + blob.text().then((text) => { + resolve(text === "hello"); + }).catch(() => { + resolve(false); + }); + } catch { + resolve(false); + } + }); + SYMBOL_FOR_REQ_CONTEXT = /* @__PURE__ */ Symbol.for("@vercel/request-context"); + getContext = () => { + var _a3, _b2, _c; + const fromSymbol = globalThis; + return (_c = (_b2 = (_a3 = fromSymbol[SYMBOL_FOR_REQ_CONTEXT]) == null ? void 0 : _a3.get) == null ? void 0 : _b2.call(_a3)) != null ? _c : {}; + }; + parseRegExp = /^((-|\+)?(\d+(?:\.\d+)?)) *(kb|mb|gb|tb|pb)$/i; + map = { + b: 1, + kb: 1 << 10, + mb: 1 << 20, + gb: 1 << 30, + tb: 1024 ** 4, + pb: 1024 ** 5 + }; + defaultVercelBlobApiUrl = "https://vercel.com/api/blob"; + BlobError = class extends Error { + constructor(message) { + super(`Vercel Blob: ${message}`); + } + }; + disallowedPathnameCharacters = ["//"]; + supportsRequestStreams = (() => { + if (isNodeProcess()) { + return true; + } + const apiUrl = getApiUrl(); + if (apiUrl.startsWith("http://localhost")) { + return false; + } + let duplexAccessed = false; + const hasContentType = new Request(getApiUrl(), { + body: new ReadableStream(), + method: "POST", + // @ts-expect-error -- TypeScript doesn't yet have duplex but it's in the spec: https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1729 + get duplex() { + duplexAccessed = true; + return "half"; + } + }).headers.has("Content-Type"); + return duplexAccessed && !hasContentType; + })(); + TEXT_ENCODER = typeof TextEncoder === "function" ? new TextEncoder() : null; + createChunkTransformStream = (chunkSize, onProgress) => { + let buffer = new Uint8Array(0); + return new TransformStream({ + transform(chunk, controller) { + const newBuffer = new Uint8Array(buffer.length + chunk.byteLength); + newBuffer.set(buffer); + newBuffer.set(new Uint8Array(chunk), buffer.length); + buffer = newBuffer; + while (buffer.length >= chunkSize) { + const newChunk = buffer.slice(0, chunkSize); + controller.enqueue(newChunk); + onProgress == null ? void 0 : onProgress(newChunk.byteLength); + buffer = buffer.slice(chunkSize); + } + }, + flush(controller) { + if (buffer.length > 0) { + controller.enqueue(buffer); + onProgress == null ? void 0 : onProgress(buffer.byteLength); + } + } + }); + }; + addPresignedParams = (url, presignedUrlPayload) => { + const urlObj = new URL(url); + for (const [key, value] of Object.entries(presignedUrlPayload.params)) { + urlObj.searchParams.set(key, value); + } + urlObj.searchParams.set( + "vercel-blob-delegation", + presignedUrlPayload.delegationToken + ); + urlObj.searchParams.set( + "vercel-blob-signature", + presignedUrlPayload.signature + ); + return urlObj.toString(); + }; + debugIsActive = false; + try { + if (((_a = process.env.DEBUG) == null ? void 0 : _a.includes("blob")) || ((_b = process.env.NEXT_PUBLIC_DEBUG) == null ? void 0 : _b.includes("blob"))) { + debugIsActive = true; + } + } catch { + } + DOMException2 = (_a2 = globalThis.DOMException) != null ? _a2 : (() => { + try { + atob("~"); + } catch (err) { + return Object.getPrototypeOf(err).constructor; + } + })(); + objectToString = Object.prototype.toString; + isError = (value) => objectToString.call(value) === "[object Error]"; + errorMessages = /* @__PURE__ */ new Set([ + "network error", + // Chrome + "Failed to fetch", + // Chrome + "NetworkError when attempting to fetch resource.", + // Firefox + "The Internet connection appears to be offline.", + // Safari 16 + "Load failed", + // Safari 17+ + "Network request failed", + // `cross-fetch` + "fetch failed", + // Undici (Node.js) + "terminated" + // Undici (Node.js) + ]); + hasFetch = typeof import_undici.fetch === "function"; + hasFetchWithUploadProgress = hasFetch && supportsRequestStreams; + CHUNK_SIZE = 64 * 1024; + blobFetch = async ({ + input, + init, + onUploadProgress + }) => { + debug("using fetch"); + let body; + if (init.body) { + if (onUploadProgress) { + const stream = await toReadableStream(init.body); + let loaded = 0; + const chunkTransformStream = createChunkTransformStream( + CHUNK_SIZE, + (newLoaded) => { + loaded += newLoaded; + onUploadProgress(loaded); + } + ); + body = stream.pipeThrough(chunkTransformStream); + } else { + body = init.body; + } + } + const duplex = supportsRequestStreams && body && isStream(body) ? "half" : void 0; + return (0, import_undici.fetch)( + input, + // @ts-expect-error -- Blob and Nodejs Blob are triggering type errors, fine with it + { + ...init, + ...init.body ? { body } : {}, + duplex + } + ); + }; + hasXhr = typeof XMLHttpRequest !== "undefined"; + blobXhr = async ({ + input, + init, + onUploadProgress + }) => { + debug("using xhr"); + let body = null; + if (init.body) { + if (isReadableStream(init.body)) { + body = await new Response(init.body).blob(); + } else { + body = init.body; + } + } + return new Promise((resolve, reject) => { + const xhr = new XMLHttpRequest(); + xhr.open(init.method || "GET", input.toString(), true); + if (onUploadProgress) { + xhr.upload.addEventListener("progress", (event) => { + if (event.lengthComputable) { + onUploadProgress(event.loaded); + } + }); + } + xhr.onload = () => { + var _a3; + if ((_a3 = init.signal) == null ? void 0 : _a3.aborted) { + reject(new DOMException("The user aborted the request.", "AbortError")); + return; + } + const headers = new Headers(); + const rawHeaders = xhr.getAllResponseHeaders().trim().split(/[\r\n]+/); + rawHeaders.forEach((line) => { + const parts = line.split(": "); + const key = parts.shift(); + const value = parts.join(": "); + if (key) headers.set(key.toLowerCase(), value); + }); + const response = new Response(xhr.response, { + status: xhr.status, + statusText: xhr.statusText, + headers + }); + resolve(response); + }; + xhr.onerror = () => { + reject(new TypeError("Network request failed")); + }; + xhr.ontimeout = () => { + reject(new TypeError("Network request timed out")); + }; + xhr.onabort = () => { + reject(new DOMException("The user aborted a request.", "AbortError")); + }; + if (init.headers) { + const headers = new Headers(init.headers); + headers.forEach((value, key) => { + xhr.setRequestHeader(key, value); + }); + } + if (init.signal) { + init.signal.addEventListener("abort", () => { + xhr.abort(); + }); + if (init.signal.aborted) { + xhr.abort(); + return; + } + } + xhr.send(body); + }); + }; + blobRequest = async ({ + input, + init, + onUploadProgress + }) => { + if (onUploadProgress) { + if (hasFetchWithUploadProgress) { + return blobFetch({ input, init, onUploadProgress }); + } + if (hasXhr) { + return blobXhr({ input, init, onUploadProgress }); + } + } + if (hasFetch) { + return blobFetch({ input, init }); + } + if (hasXhr) { + return blobXhr({ input, init }); + } + throw new Error("No request implementation available"); + }; + MAXIMUM_PATHNAME_LENGTH = 950; + BlobAccessError = class extends BlobError { + constructor() { + super("Access denied, please provide a valid token for this resource."); + } + }; + BlobOidcEnvironmentNotAllowedError = class extends BlobError { + constructor(message) { + super( + message != null ? message : "OIDC is enabled for this project, but not for this token's environment." + ); + } + }; + BlobContentTypeNotAllowedError = class extends BlobError { + constructor(message) { + super(`Content type mismatch, ${message}.`); + } + }; + BlobPathnameMismatchError = class extends BlobError { + constructor(message) { + super( + `Pathname mismatch, ${message}. Check the pathname used in upload() or put() matches the one from the client token.` + ); + } + }; + BlobClientTokenExpiredError = class extends BlobError { + constructor() { + super("Client token has expired."); + } + }; + BlobFileTooLargeError = class extends BlobError { + constructor(message) { + super(`File is too large, ${message}.`); + } + }; + BlobStoreNotFoundError = class extends BlobError { + constructor() { + super("This store does not exist."); + } + }; + BlobStoreSuspendedError = class extends BlobError { + constructor() { + super("This store has been suspended."); + } + }; + BlobUnknownError = class extends BlobError { + constructor() { + super("Unknown error, please visit https://vercel.com/help."); + } + }; + BlobNotFoundError = class extends BlobError { + constructor() { + super("The requested blob does not exist"); + } + }; + BlobServiceNotAvailable = class extends BlobError { + constructor() { + super("The blob service is currently not available. Please try again."); + } + }; + BlobServiceRateLimited = class extends BlobError { + constructor(seconds) { + super( + `Too many requests please lower the number of concurrent requests ${seconds ? ` - try again in ${seconds} seconds` : ""}.` + ); + this.retryAfter = seconds != null ? seconds : 0; + } + }; + BlobRequestAbortedError = class extends BlobError { + constructor() { + super("The request was aborted."); + } + }; + BlobPreconditionFailedError = class extends BlobError { + constructor() { + super("Precondition failed: ETag mismatch."); + } + }; + BLOB_API_VERSION = 12; + putOptionHeaderMap = { + cacheControlMaxAge: "x-cache-control-max-age", + addRandomSuffix: "x-add-random-suffix", + allowOverwrite: "x-allow-overwrite", + contentType: "x-content-type", + access: "x-vercel-blob-access", + ifMatch: "x-if-match" + }; + maxConcurrentUploads = typeof window !== "undefined" ? 6 : 8; + partSizeInBytes = 8 * 1024 * 1024; + maxBytesInMemory = maxConcurrentUploads * partSizeInBytes * 2; + BLOB_PRESIGN_QUERY_VALID_UNTIL = "vercel-blob-valid-until"; + BLOB_PRESIGN_QUERY_MAXIMUM_SIZE = "vercel-blob-maximum-size-in-bytes"; + BLOB_PRESIGN_QUERY_ALLOWED_CONTENT_TYPES = "vercel-blob-allowed-content-types"; + BLOB_PRESIGN_QUERY_ADD_RANDOM_SUFFIX = "vercel-blob-add-random-suffix"; + BLOB_PRESIGN_QUERY_ALLOW_OVERWRITE = "vercel-blob-allow-overwrite"; + BLOB_PRESIGN_QUERY_CACHE_CONTROL_MAX_AGE = "vercel-blob-cache-control-max-age"; + BLOB_PRESIGN_QUERY_IF_MATCH = "vercel-blob-if-match"; + BLOB_PRESIGN_QUERY_CALLBACK_URL = "vercel-blob-callback-url"; + BLOB_PRESIGN_QUERY_CALLBACK_TOKEN_PAYLOAD = "vercel-blob-callback-token-payload"; + PRESIGN_CANONICAL_QUERY_KEYS = [ + BLOB_PRESIGN_QUERY_ADD_RANDOM_SUFFIX, + BLOB_PRESIGN_QUERY_ALLOW_OVERWRITE, + BLOB_PRESIGN_QUERY_ALLOWED_CONTENT_TYPES, + BLOB_PRESIGN_QUERY_CACHE_CONTROL_MAX_AGE, + BLOB_PRESIGN_QUERY_CALLBACK_TOKEN_PAYLOAD, + BLOB_PRESIGN_QUERY_CALLBACK_URL, + BLOB_PRESIGN_QUERY_IF_MATCH, + BLOB_PRESIGN_QUERY_MAXIMUM_SIZE, + BLOB_PRESIGN_QUERY_VALID_UNTIL + ]; + MAX_PRESIGN_CALLBACK_URL_CHARS = 4096; + MAX_PRESIGN_CALLBACK_TOKEN_PAYLOAD_CHARS = 8192; + MAX_PRESIGN_CACHE_CONTROL_MAX_AGE_SECONDS = 365 * 24 * 60 * 60; + MAX_PRESIGN_IF_MATCH_LENGTH = 256; + IF_MATCH_CONTROL_CHARS_RE = /[\x00-\x1f\x7f]/; + utf8Encoder = new TextEncoder(); + } +}); + +// viewer/node_modules/@vercel/blob/dist/index.js +var dist_exports = {}; +__export(dist_exports, { + BlobAccessError: () => BlobAccessError, + BlobClientTokenExpiredError: () => BlobClientTokenExpiredError, + BlobContentTypeNotAllowedError: () => BlobContentTypeNotAllowedError, + BlobError: () => BlobError, + BlobFileTooLargeError: () => BlobFileTooLargeError, + BlobNotFoundError: () => BlobNotFoundError, + BlobPathnameMismatchError: () => BlobPathnameMismatchError, + BlobPreconditionFailedError: () => BlobPreconditionFailedError, + BlobRequestAbortedError: () => BlobRequestAbortedError, + BlobServiceNotAvailable: () => BlobServiceNotAvailable, + BlobServiceRateLimited: () => BlobServiceRateLimited, + BlobStoreNotFoundError: () => BlobStoreNotFoundError, + BlobStoreSuspendedError: () => BlobStoreSuspendedError, + BlobUnknownError: () => BlobUnknownError, + completeMultipartUpload: () => completeMultipartUpload2, + copy: () => copy, + createFolder: () => createFolder, + createMultipartUpload: () => createMultipartUpload2, + createMultipartUploader: () => createMultipartUploader, + del: () => del, + get: () => get, + getDownloadUrl: () => getDownloadUrl, + head: () => head, + issueSignedToken: () => issueSignedToken, + list: () => list, + parseStoreIdFromDelegationToken: () => parseStoreIdFromDelegationToken, + parseStoreIdFromPresignedUrl: () => parseStoreIdFromPresignedUrl, + presignUrl: () => presignUrl, + put: () => put, + uploadPart: () => uploadPart2 +}); +async function del(urlOrPathname, options) { + const urls = Array.isArray(urlOrPathname) ? urlOrPathname : [urlOrPathname]; + if ((options == null ? void 0 : options.ifMatch) && urls.length > 1) { + throw new BlobError("ifMatch can only be used when deleting a single URL."); + } + const headers = { + "content-type": "application/json" + }; + if (options == null ? void 0 : options.ifMatch) { + headers["x-if-match"] = options.ifMatch; + } + await requestApi( + "/delete", + { + method: "POST", + headers, + body: JSON.stringify({ urls }), + signal: options == null ? void 0 : options.abortSignal + }, + options + ); +} +async function head(urlOrPathname, options) { + const searchParams = new URLSearchParams({ url: urlOrPathname }); + const response = await requestApi( + `?${searchParams.toString()}`, + // HEAD can't have body as a response, so we use GET + { + method: "GET", + signal: options == null ? void 0 : options.abortSignal + }, + options + ); + return { + url: response.url, + downloadUrl: response.downloadUrl, + pathname: response.pathname, + size: response.size, + contentType: response.contentType, + contentDisposition: response.contentDisposition, + cacheControl: response.cacheControl, + uploadedAt: new Date(response.uploadedAt), + etag: response.etag + }; +} +function extractPathnameFromUrl(url) { + try { + const parsedUrl = new URL(url); + return parsedUrl.pathname.slice(1); + } catch { + return url; + } +} +async function get(urlOrPathname, options) { + if (!urlOrPathname) { + throw new BlobError("url or pathname is required"); + } + if (!options) { + throw new BlobError("missing options, see usage"); + } + if (options.access !== "public" && options.access !== "private") { + throw new BlobError( + 'access must be "private" or "public", see https://vercel.com/docs/vercel-blob' + ); + } + const auth = resolveBlobAuth(options); + if (auth.kind === "presigned") { + throw new BlobError("Presigned URLs are not supported for the get method"); + } + let blobUrl; + let pathname; + const access = options.access; + if (isUrl(urlOrPathname)) { + blobUrl = urlOrPathname; + pathname = extractPathnameFromUrl(urlOrPathname); + try { + const { hostname } = new URL(blobUrl); + if (!hostname.endsWith(".blob.vercel-storage.com")) { + throw new BlobError( + "Invalid URL: the URL does not point to a Vercel Blob store. Use a pathname instead, see https://vercel.com/docs/vercel-blob" + ); + } + } catch (error) { + if (error instanceof BlobError) throw error; + throw new BlobError("Invalid URL: unable to parse the provided URL"); + } + } else { + if (!auth.storeId) { + throw new BlobError("Invalid token: unable to extract store ID"); + } + pathname = urlOrPathname; + blobUrl = constructBlobUrl(auth.storeId, pathname, access); + } + const requestHeaders = { + ...options.ifNoneMatch ? { "If-None-Match": options.ifNoneMatch } : {}, + authorization: `Bearer ${auth.token}`, + ...options.headers + // low-level escape hatch, applied last to override anything + }; + let fetchUrl = blobUrl; + if (options.useCache === false) { + const url = new URL(blobUrl); + url.searchParams.set("cache", "0"); + fetchUrl = url.toString(); + } + const response = await (0, import_undici2.fetch)(fetchUrl, { + method: "GET", + headers: requestHeaders, + signal: options.abortSignal + }); + if (response.status === 304) { + const downloadUrlObj = new URL(blobUrl); + downloadUrlObj.searchParams.set("download", "1"); + const lastModified2 = response.headers.get("last-modified"); + return { + statusCode: 304, + stream: null, + headers: response.headers, + blob: { + url: blobUrl, + downloadUrl: downloadUrlObj.toString(), + pathname, + contentType: null, + contentDisposition: response.headers.get("content-disposition") || "", + cacheControl: response.headers.get("cache-control") || "", + size: null, + uploadedAt: lastModified2 ? new Date(lastModified2) : /* @__PURE__ */ new Date(), + etag: response.headers.get("etag") || "" + } + }; + } + if (response.status === 404) { + return null; + } + if (!response.ok) { + throw new BlobError( + `Failed to fetch blob: ${response.status} ${response.statusText}` + ); + } + const stream = response.body; + if (!stream) { + throw new BlobError("Response body is null"); + } + const contentLength = response.headers.get("content-length"); + const lastModified = response.headers.get("last-modified"); + const downloadUrl = new URL(blobUrl); + downloadUrl.searchParams.set("download", "1"); + return { + statusCode: 200, + stream, + headers: response.headers, + blob: { + url: blobUrl, + downloadUrl: downloadUrl.toString(), + pathname, + contentType: response.headers.get("content-type") || "application/octet-stream", + contentDisposition: response.headers.get("content-disposition") || "", + cacheControl: response.headers.get("cache-control") || "", + size: contentLength ? parseInt(contentLength, 10) : 0, + uploadedAt: lastModified ? new Date(lastModified) : /* @__PURE__ */ new Date(), + etag: response.headers.get("etag") || "" + } + }; +} +async function list(options) { + var _a3; + const searchParams = new URLSearchParams(); + if (options == null ? void 0 : options.limit) { + searchParams.set("limit", options.limit.toString()); + } + if (options == null ? void 0 : options.prefix) { + searchParams.set("prefix", options.prefix); + } + if (options == null ? void 0 : options.cursor) { + searchParams.set("cursor", options.cursor); + } + if (options == null ? void 0 : options.mode) { + searchParams.set("mode", options.mode); + } + const response = await requestApi( + `?${searchParams.toString()}`, + { + method: "GET", + signal: options == null ? void 0 : options.abortSignal + }, + options + ); + if ((options == null ? void 0 : options.mode) === "folded") { + return { + folders: (_a3 = response.folders) != null ? _a3 : [], + cursor: response.cursor, + hasMore: response.hasMore, + blobs: response.blobs.map(mapBlobResult) + }; + } + return { + cursor: response.cursor, + hasMore: response.hasMore, + blobs: response.blobs.map(mapBlobResult) + }; +} +function mapBlobResult(blobResult) { + return { + url: blobResult.url, + downloadUrl: blobResult.downloadUrl, + pathname: blobResult.pathname, + size: blobResult.size, + uploadedAt: new Date(blobResult.uploadedAt), + etag: blobResult.etag + }; +} +async function copy(fromUrlOrPathname, toPathname, options) { + if (!options) { + throw new BlobError("missing options, see usage"); + } + if (options.access !== "public" && options.access !== "private") { + throw new BlobError( + 'access must be "private" or "public", see https://vercel.com/docs/vercel-blob' + ); + } + if (toPathname.length > MAXIMUM_PATHNAME_LENGTH) { + throw new BlobError( + `pathname is too long, maximum length is ${MAXIMUM_PATHNAME_LENGTH}` + ); + } + for (const invalidCharacter of disallowedPathnameCharacters) { + if (toPathname.includes(invalidCharacter)) { + throw new BlobError( + `pathname cannot contain "${invalidCharacter}", please encode it if needed` + ); + } + } + const headers = {}; + headers["x-vercel-blob-access"] = options.access; + if (options.addRandomSuffix !== void 0) { + headers["x-add-random-suffix"] = options.addRandomSuffix ? "1" : "0"; + } + if (options.allowOverwrite !== void 0) { + headers["x-allow-overwrite"] = options.allowOverwrite ? "1" : "0"; + } + if (options.contentType) { + headers["x-content-type"] = options.contentType; + } + if (options.cacheControlMaxAge !== void 0) { + headers["x-cache-control-max-age"] = options.cacheControlMaxAge.toString(); + } + if (options.ifMatch) { + headers["x-if-match"] = options.ifMatch; + } + const params = new URLSearchParams({ + pathname: toPathname, + fromUrl: fromUrlOrPathname + }); + const response = await requestApi( + `?${params.toString()}`, + { + method: "PUT", + headers, + signal: options.abortSignal + }, + options + ); + return { + url: response.url, + downloadUrl: response.downloadUrl, + pathname: response.pathname, + contentType: response.contentType, + contentDisposition: response.contentDisposition, + etag: response.etag + }; +} +var import_undici2, put, createMultipartUpload2, createMultipartUploader, uploadPart2, completeMultipartUpload2; +var init_dist = __esm({ + "viewer/node_modules/@vercel/blob/dist/index.js"() { + init_chunk_3D2SZ6M2(); + import_undici2 = __toESM(require_undici(), 1); + put = createPutMethod({ + allowedOptions: [ + "cacheControlMaxAge", + "addRandomSuffix", + "allowOverwrite", + "contentType", + "ifMatch" + ] + }); + createMultipartUpload2 = createCreateMultipartUploadMethod({ + allowedOptions: [ + "cacheControlMaxAge", + "addRandomSuffix", + "allowOverwrite", + "contentType", + "ifMatch" + ] + }); + createMultipartUploader = createCreateMultipartUploaderMethod({ + allowedOptions: [ + "cacheControlMaxAge", + "addRandomSuffix", + "allowOverwrite", + "contentType", + "ifMatch" + ] + }); + uploadPart2 = createUploadPartMethod({ + allowedOptions: [ + "cacheControlMaxAge", + "addRandomSuffix", + "allowOverwrite", + "contentType" + ] + }); + completeMultipartUpload2 = createCompleteMultipartUploadMethod({ + allowedOptions: [ + "cacheControlMaxAge", + "addRandomSuffix", + "allowOverwrite", + "contentType" + ] + }); + } +}); + +// viewer/src/server/server.mjs +import fs9 from "node:fs"; +import http from "node:http"; +import path11 from "node:path"; +import { fileURLToPath as fileURLToPath3 } from "node:url"; + +// viewer/src/server/localAssetBackend.mjs +import fs6 from "node:fs"; +import path7 from "node:path"; +import { spawn as spawn2 } from "node:child_process"; + +// viewer/packages/cadjs/src/lib/cadDirectoryScanner.mjs +import crypto from "node:crypto"; +import fs2 from "node:fs"; +import path3 from "node:path"; +import { fileURLToPath } from "node:url"; + +// viewer/packages/cadjs/src/common/stepSidecars.mjs +import path from "node:path"; +function isPerStepViewerDirectoryName(name) { + const normalized = String(name || "").toLowerCase(); + return normalized.startsWith(".") && (normalized.endsWith(".step") || normalized.endsWith(".stp")); +} +function isInlineStepGlbArtifactPath(filePath) { + const name = path.basename(String(filePath || "")).toLowerCase(); + return name.startsWith(".") && (name.endsWith(".step.glb") || name.endsWith(".stp.glb")); +} +function isInlineStepParameterPath(filePath) { + const name = path.basename(String(filePath || "")).toLowerCase(); + return name.startsWith(".") && name.endsWith(".step.js"); +} +function isPathInsidePerStepViewerDirectory(filePath) { + return String(filePath || "").split(path.sep).some((part) => isPerStepViewerDirectoryName(part)); +} +function inlineStepGlbArtifactPathForSource(sourcePath) { + return path.join(path.dirname(sourcePath), `.${path.basename(sourcePath)}.glb`); +} +function stepParameterPathForStepSource(sourcePath) { + const stem = path.basename(sourcePath, path.extname(sourcePath)); + return path.join(path.dirname(sourcePath), `.${stem}.step.js`); +} + +// viewer/packages/cadjs/src/common/stepTopology.mjs +var STEP_TOPOLOGY_EXTENSION = "STEP_topology"; +var STEP_TOPOLOGY_SCHEMA_VERSION = 2; +var STEP_EDGE_BARYCENTRIC_ATTRIBUTE = "_CAD_EDGE_BARYCENTRIC"; +var STEP_EDGE_CLASS_ATTRIBUTE = "_CAD_EDGE_CLASS"; +var STEP_EDGE_FLAGS = Object.freeze({ + DEGENERATE: 1 << 1, + SEAM: 1 << 2, + NOT_REFERENCEABLE: 1 << 3, + BOUNDARY: 1 << 4, + NON_MANIFOLD: 1 << 5, + HARD: 1 << 6, + TANGENT: 1 << 7, + UNKNOWN_CONTINUITY: 1 << 8 +}); +var STEP_EDGE_VISIBILITY_CLASSES = Object.freeze({ + FEATURE: "feature", + TANGENT: "tangent", + SEAM: "seam", + DEGENERATE: "degenerate", + BOUNDARY: "boundary", + NON_MANIFOLD: "nonManifold", + UNKNOWN: "unknown" +}); +var STEP_EDGE_SURFACE_CLASS_CODES = Object.freeze({ + none: 0, + feature: 1, + tangent: 2, + seam: 3, + degenerate: 4, + boundary: 5, + nonManifold: 6, + unknown: 7 +}); +var STEP_EDGE_RENDER_VISIBILITY_CLASSES = Object.freeze([ + STEP_EDGE_VISIBILITY_CLASSES.FEATURE, + STEP_EDGE_VISIBILITY_CLASSES.TANGENT, + STEP_EDGE_VISIBILITY_CLASSES.SEAM, + STEP_EDGE_VISIBILITY_CLASSES.DEGENERATE +]); +function isCurrentStepTopologySchemaVersion(value) { + return Number(value) === STEP_TOPOLOGY_SCHEMA_VERSION; +} + +// viewer/packages/cadjs/src/lib/pathUtils.mjs +import path2 from "node:path"; +function toPosixPath(value) { + return String(value || "").split(path2.sep).join("/"); +} +function relativePathStaysInsideRoot(relativePath) { + return relativePath === "" || relativePath !== ".." && !relativePath.startsWith(`..${path2.sep}`) && !path2.isAbsolute(relativePath); +} +function pathIsInside(childPath, parentPath) { + const relativePath = path2.relative(path2.resolve(parentPath), path2.resolve(childPath)); + return Boolean(relativePath) && relativePathStaysInsideRoot(relativePath); +} +function resolveWorkspaceRoot({ + workspaceRoot: workspaceRoot2 = "", + env = process.env, + cwd = process.cwd(), + appRoot = "", + defaultWorkspaceRoot: defaultWorkspaceRoot2 = "" +} = {}) { + const explicitRoot = workspaceRoot2 || ""; + if (explicitRoot) { + return path2.resolve(cwd, explicitRoot); + } + const resolvedAppRoot = appRoot ? path2.resolve(appRoot) : ""; + for (const candidate of [env.INIT_CWD, cwd]) { + if (!candidate) { + continue; + } + const resolvedCandidate = path2.resolve(candidate); + if (!resolvedAppRoot || resolvedCandidate !== resolvedAppRoot && !pathIsInside(resolvedCandidate, resolvedAppRoot)) { + return resolvedCandidate; + } + } + return defaultWorkspaceRoot2 ? path2.resolve(defaultWorkspaceRoot2) : path2.resolve(cwd); +} + +// viewer/packages/cadjs/src/lib/step/stepMetadata.mjs +import fs from "node:fs"; +var TEXT_TO_CAD_GENERATOR_PROPERTY = "cadpy:generator"; +var TEXT_TO_CAD_ENTRY_KIND_PROPERTY = "cadpy:entryKind"; +var TEXT_TO_CAD_SOURCE_PATH_PROPERTY = "cadpy:sourcePath"; +var TEXT_TO_CAD_SOURCE_HASH_PROPERTY = "cadpy:sourceHash"; +var TEXT_TO_CAD_SOURCE_FINGERPRINT_PROPERTY = "cadpy:sourceFingerprint"; +var STEP_STRING_PATTERN = "'(?:''|[^'])*'"; +function unescapeStepString(value) { + const raw = String(value || "").trim(); + const unquoted = raw.startsWith("'") && raw.endsWith("'") ? raw.slice(1, -1) : raw; + return unquoted.replace(/''/g, "'"); +} +function normalizeTextToCadEntryKind(value) { + const normalized = String(value || "").trim().toLowerCase(); + return normalized === "part" || normalized === "assembly" ? normalized : ""; +} +function readTextToCadStepMetadataText(stepText) { + const text = String(stepText || ""); + const descriptiveItems = /* @__PURE__ */ new Map(); + const descriptivePattern = new RegExp( + `#(\\d+)\\s*=\\s*DESCRIPTIVE_REPRESENTATION_ITEM\\s*\\(\\s*(${STEP_STRING_PATTERN})\\s*,\\s*(${STEP_STRING_PATTERN})\\s*\\)\\s*;`, + "gis" + ); + for (const match of text.matchAll(descriptivePattern)) { + descriptiveItems.set(`#${match[1]}`, { + value: unescapeStepString(match[3]) + }); + } + const representations = /* @__PURE__ */ new Map(); + const representationPattern = new RegExp( + `#(\\d+)\\s*=\\s*REPRESENTATION\\s*\\(\\s*(${STEP_STRING_PATTERN})\\s*,\\s*\\(([^)]*)\\)\\s*,\\s*#\\d+\\s*\\)\\s*;`, + "gis" + ); + for (const match of text.matchAll(representationPattern)) { + representations.set(`#${match[1]}`, { + itemRefs: Array.from(String(match[3] || "").matchAll(/#\d+/g), (itemMatch) => itemMatch[0]) + }); + } + const propertyDefinitions = /* @__PURE__ */ new Map(); + const propertyPattern = new RegExp( + `#(\\d+)\\s*=\\s*PROPERTY_DEFINITION\\s*\\(\\s*(${STEP_STRING_PATTERN})\\s*,\\s*(${STEP_STRING_PATTERN})\\s*,\\s*#[0-9]+\\s*\\)\\s*;`, + "gis" + ); + for (const match of text.matchAll(propertyPattern)) { + const propertyName = unescapeStepString(match[3]); + if (propertyName === TEXT_TO_CAD_GENERATOR_PROPERTY || propertyName === TEXT_TO_CAD_ENTRY_KIND_PROPERTY || propertyName === TEXT_TO_CAD_SOURCE_PATH_PROPERTY || propertyName === TEXT_TO_CAD_SOURCE_HASH_PROPERTY || propertyName === TEXT_TO_CAD_SOURCE_FINGERPRINT_PROPERTY || propertyName === "cadpy:entry_kind") { + propertyDefinitions.set(`#${match[1]}`, propertyName); + } + } + const metadata = {}; + const linkPattern = /#\d+\s*=\s*PROPERTY_DEFINITION_REPRESENTATION\s*\(\s*(#\d+)\s*,\s*(#\d+)\s*\)\s*;/gis; + for (const match of text.matchAll(linkPattern)) { + const propertyName = propertyDefinitions.get(match[1]); + const representation = representations.get(match[2]); + if (!propertyName || !representation) { + continue; + } + const item = representation.itemRefs.map((itemRef) => descriptiveItems.get(itemRef)).find(Boolean); + if (!item) { + continue; + } + if (propertyName === TEXT_TO_CAD_GENERATOR_PROPERTY) { + metadata.generator = item.value; + } else if (propertyName === TEXT_TO_CAD_ENTRY_KIND_PROPERTY || propertyName === "cadpy:entry_kind") { + const entryKind = normalizeTextToCadEntryKind(item.value); + if (entryKind) { + metadata.entryKind = entryKind; + } + } else if (propertyName === TEXT_TO_CAD_SOURCE_HASH_PROPERTY) { + metadata.sourceHash = item.value; + } else if (propertyName === TEXT_TO_CAD_SOURCE_FINGERPRINT_PROPERTY) { + metadata.sourceFingerprint = item.value; + } else if (propertyName === TEXT_TO_CAD_SOURCE_PATH_PROPERTY) { + metadata.sourcePath = item.value; + } + } + return metadata; +} +function readTextToCadStepMetadataFile(stepPath) { + return readTextToCadStepMetadataText(fs.readFileSync(stepPath, "utf-8")); +} + +// viewer/packages/cadjs/src/lib/cadDirectoryScanner.mjs +var DEFAULT_VIEWER_ROOT_DIR = ""; +var CAD_CATALOG_SCHEMA_VERSION = 4; +var SOURCE_EXTENSIONS = /* @__PURE__ */ new Set([".step", ".stp", ".stl", ".3mf", ".glb", ".gcode", ".dxf", ".urdf", ".srdf", ".sdf"]); +var REGENERATE_STEP_COMMAND = "python -m cadpy.step_artifact --repo-root . --step"; +var PYTHON_SOURCE_HASH_SKIPPED_PATH_PARTS = /* @__PURE__ */ new Set([ + "__pycache__", + ".cache", + ".eggs", + ".env", + ".git", + ".hg", + ".mypy_cache", + ".pytest_cache", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "build", + "dist", + "env", + "node_modules", + "site-packages", + "venv" +]); +var CADJS_PACKAGE_ROOT = path3.resolve(path3.dirname(fileURLToPath(import.meta.url)), "..", "..", ".."); +var VIEWER_SKIPPED_DIRECTORIES = /* @__PURE__ */ new Set([ + ".agents", + ".cache", + ".viewer", + ".git", + ".venv", + "__pycache__", + "build", + "coverage", + "dist", + "node_modules", + "viewer" +]); +var SRDF_URDF_METADATA_PATTERN = /<\s*(?:tcad|explorer):urdf\b[^>]*\bpath\s*=\s*["']([^"']+)["'][^>]*>/i; +var STEP_EDGE_RENDER_CLASS_ORDER = Object.freeze(["feature", "tangent", "seam", "degenerate"]); +var TEXT_TO_CAD_COMMENT_METADATA_RE = //g; +var PYTHON_GENERATOR_BY_KIND = Object.freeze({ + dxf: "gen_dxf", + step: "gen_step", + stp: "gen_step", + urdf: "gen_urdf", + srdf: "gen_srdf", + sdf: "gen_sdf" +}); +function encodeUrlPath(repoRelativePath2) { + return `/${repoRelativePath2.split("/").map((part) => encodeURIComponent(part)).join("/")}`; +} +function relativePathStaysInsideRoot2(relativePath) { + return relativePath === "" || relativePath !== ".." && !relativePath.startsWith(`..${path3.sep}`) && !path3.isAbsolute(relativePath); +} +function normalizeStepEdgeRenderVisibilityClasses(value) { + const rawValues = Array.isArray(value) ? value : value === void 0 || value === null ? [] : [value]; + const validValues = new Set(Object.values(STEP_EDGE_VISIBILITY_CLASSES)); + const normalized = []; + for (const raw of rawValues) { + const classId = String(raw || "").trim(); + if (validValues.has(classId) && !normalized.includes(classId)) { + normalized.push(classId); + } + } + if (!normalized.includes(STEP_EDGE_VISIBILITY_CLASSES.FEATURE)) { + normalized.unshift(STEP_EDGE_VISIBILITY_CLASSES.FEATURE); + } + return [ + ...STEP_EDGE_RENDER_CLASS_ORDER.filter((classId) => normalized.includes(classId)), + ...normalized.filter((classId) => !STEP_EDGE_RENDER_CLASS_ORDER.includes(classId)) + ]; +} +function normalizeViewerRootDir(value = DEFAULT_VIEWER_ROOT_DIR) { + const rawValue = String(value ?? "").trim(); + const slashNormalized = rawValue.replace(/\\/g, "/"); + const normalized = path3.posix.normalize(slashNormalized); + if (!normalized || normalized === ".") { + return DEFAULT_VIEWER_ROOT_DIR; + } + if (normalized === ".." || normalized.startsWith("../")) { + throw new Error(`CAD Viewer root directory must stay inside the workspace: ${rawValue}`); + } + return normalized.replace(/(?!^\/)\/+$/, ""); +} +function resolveViewerRoot(repoRoot, rootDir = DEFAULT_VIEWER_ROOT_DIR) { + const normalizedDir = normalizeViewerRootDir(rootDir); + const resolvedRepoRoot = path3.resolve(repoRoot); + const rootPath = normalizedDir ? path3.resolve(resolvedRepoRoot, normalizedDir) : resolvedRepoRoot; + const relativePath = path3.relative(resolvedRepoRoot, rootPath); + if (!relativePathStaysInsideRoot2(relativePath)) { + throw new Error(`CAD Viewer root directory must stay inside the workspace: ${normalizedDir}`); + } + return { + dir: normalizedDir, + rootPath, + rootName: normalizedDir ? path3.basename(rootPath) : path3.basename(resolvedRepoRoot) + }; +} +function repoRelativePath(repoRoot, filePath) { + return toPosixPath(path3.relative(path3.resolve(repoRoot), path3.resolve(filePath))); +} +function scanRelativePath(rootPath, filePath) { + return toPosixPath(path3.relative(path3.resolve(rootPath), path3.resolve(filePath))); +} +function fileStats(filePath) { + try { + const stats = fs2.statSync(filePath, { bigint: true }); + return stats.isFile() ? stats : null; + } catch { + return null; + } +} +function sha256File(filePath) { + const hash = crypto.createHash("sha256"); + const fd = fs2.openSync(filePath, "r"); + try { + const buffer = Buffer.alloc(1024 * 1024); + let bytesRead = 0; + do { + bytesRead = fs2.readSync(fd, buffer, 0, buffer.length, null); + if (bytesRead > 0) { + hash.update(buffer.subarray(0, bytesRead)); + } + } while (bytesRead > 0); + } finally { + fs2.closeSync(fd); + } + return hash.digest("hex"); +} +function pathIsInside2(filePath, rootPath) { + const relative = path3.relative(path3.resolve(rootPath), path3.resolve(filePath)); + return relativePathStaysInsideRoot2(relative); +} +function dedupePaths(paths) { + const result = []; + const seen = /* @__PURE__ */ new Set(); + for (const rawPath of paths) { + const resolved = path3.resolve(rawPath); + if (!seen.has(resolved)) { + seen.add(resolved); + result.push(resolved); + } + } + return result; +} +function pythonSourceSearchPaths(repoRoot, scriptPath) { + const resolvedRepoRoot = path3.resolve(repoRoot); + const cadRoot = path3.resolve(resolvedRepoRoot, "cad"); + const resolvedScriptPath = path3.resolve(scriptPath); + const paths = [ + resolvedRepoRoot, + cadRoot, + CADJS_PACKAGE_ROOT, + path3.resolve(resolvedRepoRoot, "skills", "cad", "scripts"), + path3.dirname(resolvedScriptPath) + ]; + const stopAt = path3.dirname(resolvedRepoRoot); + let current = path3.dirname(resolvedScriptPath); + for (; ; ) { + if (fs2.existsSync(path3.join(current, "STEP", "__init__.py")) || fs2.existsSync(path3.join(current, "robot_common", "__init__.py"))) { + paths.push(current); + } + if (current === stopAt) { + break; + } + const next = path3.dirname(current); + if (next === current) { + break; + } + current = next; + } + return dedupePaths(paths); +} +function pythonSourceManifestRoots(repoRoot) { + const resolvedRepoRoot = path3.resolve(repoRoot); + return dedupePaths([ + path3.resolve(resolvedRepoRoot, "cad"), + resolvedRepoRoot, + CADJS_PACKAGE_ROOT + ]); +} +function isTrackablePythonSource(filePath, allowedRoots) { + const resolved = path3.resolve(filePath); + if (path3.extname(resolved) !== ".py" || !fileStats(resolved)) { + return false; + } + if (resolved.split(path3.sep).some((part) => PYTHON_SOURCE_HASH_SKIPPED_PATH_PARTS.has(part))) { + return false; + } + return allowedRoots.some((root) => pathIsInside2(resolved, root)); +} +function packageInitFiles(baseDir, packageParts, allowedRoots) { + const files = /* @__PURE__ */ new Set(); + for (let index = 1; index <= packageParts.length; index += 1) { + const initPath = path3.join(baseDir, ...packageParts.slice(0, index), "__init__.py"); + if (isTrackablePythonSource(initPath, allowedRoots)) { + files.add(path3.resolve(initPath)); + } + } + return files; +} +function resolvePythonModuleFromDirectory(baseDir, moduleName, allowedRoots) { + const parts = String(moduleName || "").split(".").filter(Boolean); + if (!parts.length) { + return /* @__PURE__ */ new Set(); + } + const files = /* @__PURE__ */ new Set(); + const moduleDir = path3.join(baseDir, ...parts); + const leafModule = `${moduleDir}.py`; + if (isTrackablePythonSource(leafModule, allowedRoots)) { + for (const filePath of packageInitFiles(baseDir, parts.slice(0, -1), allowedRoots)) { + files.add(filePath); + } + files.add(path3.resolve(leafModule)); + return files; + } + const packageInit = path3.join(moduleDir, "__init__.py"); + if (isTrackablePythonSource(packageInit, allowedRoots)) { + for (const filePath of packageInitFiles(baseDir, parts, allowedRoots)) { + files.add(filePath); + } + } + return files; +} +function resolvePythonModule(moduleName, searchPaths, allowedRoots) { + const files = /* @__PURE__ */ new Set(); + if (!moduleName) { + return files; + } + for (const baseDir of searchPaths) { + for (const filePath of resolvePythonModuleFromDirectory(baseDir, moduleName, allowedRoots)) { + files.add(filePath); + } + } + return files; +} +function splitPythonImportAliases(rawAliases) { + return String(rawAliases || "").replace(/[()]/g, "").split(",").map((alias) => alias.trim().split(/\s+as\s+/i)[0].trim()).filter((alias) => alias && alias !== "*"); +} +function stripPythonStringAndCommentLiterals(text) { + let result = ""; + for (let index = 0; index < text.length; ) { + const char = text[index]; + if (char === "#") { + while (index < text.length && text[index] !== "\n") { + result += " "; + index += 1; + } + continue; + } + if (char === "'" || char === '"') { + const quote = char; + const triple = text.slice(index, index + 3) === quote.repeat(3); + const endToken = triple ? quote.repeat(3) : quote; + const startLength = triple ? 3 : 1; + result += " ".repeat(startLength); + index += startLength; + while (index < text.length) { + if (!triple && text[index] === "\\") { + result += " "; + index += 1; + if (index < text.length) { + result += text[index] === "\n" ? "\n" : " "; + index += 1; + } + continue; + } + if (text.slice(index, index + endToken.length) === endToken) { + result += " ".repeat(endToken.length); + index += endToken.length; + break; + } + result += text[index] === "\n" ? "\n" : " "; + index += 1; + } + continue; + } + result += char; + index += 1; + } + return result; +} +function normalizePythonImportText(text) { + const stripped = stripPythonStringAndCommentLiterals(text).replace(/\\\r?\n/g, " "); + let result = ""; + let parenDepth = 0; + for (const char of stripped) { + if (char === "(" || char === "[" || char === "{") { + parenDepth += 1; + } else if ((char === ")" || char === "]" || char === "}") && parenDepth > 0) { + parenDepth -= 1; + } + result += char === "\n" && parenDepth > 0 ? " " : char; + } + return result; +} +function pythonImportDependencies(filePath, searchPaths, allowedRoots) { + let text = ""; + try { + text = normalizePythonImportText(fs2.readFileSync(filePath, "utf-8")); + } catch { + return []; + } + const dependencies = /* @__PURE__ */ new Set(); + const importRe = /^\s*import\s+([^\n#]+)/gm; + for (const match of text.matchAll(importRe)) { + for (const alias of splitPythonImportAliases(match[1])) { + for (const file of resolvePythonModule(alias, searchPaths, allowedRoots)) { + dependencies.add(file); + } + } + } + const fromRe = /^\s*from\s+(\.*)([A-Za-z_][\w.]*)?\s+import\s+([^\n#]+)/gm; + for (const match of text.matchAll(fromRe)) { + const level = String(match[1] || "").length; + const moduleName = String(match[2] || ""); + const aliases = splitPythonImportAliases(match[3]); + if (level > 0) { + let baseDir = path3.dirname(filePath); + for (let index = 1; index < level; index += 1) { + baseDir = path3.dirname(baseDir); + } + for (const file of resolvePythonModuleFromDirectory(baseDir, moduleName, allowedRoots)) { + dependencies.add(file); + } + for (const alias of aliases) { + const childName = moduleName ? `${moduleName}.${alias}` : alias; + for (const file of resolvePythonModuleFromDirectory(baseDir, childName, allowedRoots)) { + dependencies.add(file); + } + } + continue; + } + for (const file of resolvePythonModule(moduleName, searchPaths, allowedRoots)) { + dependencies.add(file); + } + for (const alias of aliases) { + const childName = moduleName ? `${moduleName}.${alias}` : alias; + for (const file of resolvePythonModule(childName, searchPaths, allowedRoots)) { + dependencies.add(file); + } + } + } + return [...dependencies].sort(); +} +function pythonSourceManifestPath(repoRoot, filePath) { + const resolved = path3.resolve(filePath); + for (const root of pythonSourceManifestRoots(repoRoot)) { + if (pathIsInside2(resolved, root)) { + return toPosixPath(path3.relative(root, resolved)); + } + } + return toPosixPath(resolved); +} +function comparePythonSourceManifestPath(left, right) { + return Buffer.compare(Buffer.from(left, "utf8"), Buffer.from(right, "utf8")); +} +function pythonSourceIdentity(repoRoot, scriptPath) { + const resolvedScriptPath = path3.resolve(scriptPath); + const searchPaths = pythonSourceSearchPaths(repoRoot, resolvedScriptPath); + const allowedRoots = searchPaths.map((entry) => path3.resolve(entry)); + const queue = [resolvedScriptPath]; + const seen = /* @__PURE__ */ new Set(); + const files = /* @__PURE__ */ new Map(); + while (queue.length) { + const current = path3.resolve(queue.shift()); + if (seen.has(current) || !isTrackablePythonSource(current, allowedRoots)) { + continue; + } + seen.add(current); + files.set(current, sha256File(current)); + for (const dependency of pythonImportDependencies(current, searchPaths, allowedRoots)) { + if (!seen.has(dependency)) { + queue.push(dependency); + } + } + } + const manifestFiles = [...files.entries()].map(([filePath, hash]) => ({ path: pythonSourceManifestPath(repoRoot, filePath), hash })).sort((a, b) => comparePythonSourceManifestPath(a.path, b.path)); + const digest = crypto.createHash("sha256"); + for (const file of manifestFiles) { + digest.update(file.path, "utf8"); + digest.update("\0"); + digest.update(file.hash, "ascii"); + digest.update("\0"); + } + return { + sourcePath: pythonSourceManifestPath(repoRoot, resolvedScriptPath), + sourceHash: files.get(resolvedScriptPath) || "", + sourceFingerprint: digest.digest("hex"), + files: manifestFiles + }; +} +function normalizeManifestPath(manifestPath) { + const value = String(manifestPath || "").trim(); + if (!value || value.includes("\0")) { + return ""; + } + return value.replace(/\\/g, "/"); +} +function resolveManifestSourcePath(repoRoot, manifestPath, baseDir = repoRoot) { + const value = normalizeManifestPath(manifestPath); + if (!value) { + return null; + } + const resolved = path3.isAbsolute(value) ? path3.resolve(value) : path3.resolve(baseDir, value); + if (!pathIsInside2(resolved, repoRoot)) { + return null; + } + return resolved; +} +function normalizeManifestRelativePath(manifestPath) { + const value = String(manifestPath || "").trim().replace(/\\/g, "/").replace(/^\/+/, ""); + if (!value || value === "." || value.startsWith("../")) { + return ""; + } + return value; +} +function manifestIdentityRootForStep(repoRoot, actualStepPath, manifestStepPath) { + const resolvedRepoRoot = path3.resolve(repoRoot); + const normalizedStepPath = normalizeManifestRelativePath(manifestStepPath); + if (!normalizedStepPath || !actualStepPath) { + return resolvedRepoRoot; + } + const actualRepoPath = repoRelativePath(resolvedRepoRoot, actualStepPath); + if (actualRepoPath === normalizedStepPath) { + return resolvedRepoRoot; + } + if (!actualRepoPath.endsWith(`/${normalizedStepPath}`)) { + return resolvedRepoRoot; + } + const prefix = actualRepoPath.slice(0, actualRepoPath.length - normalizedStepPath.length).replace(/\/+$/, ""); + if (!prefix) { + return resolvedRepoRoot; + } + const resolvedPrefix = path3.resolve(resolvedRepoRoot, ...prefix.split("/").filter(Boolean)); + return pathIsInside2(resolvedPrefix, resolvedRepoRoot) ? resolvedPrefix : resolvedRepoRoot; +} +function sourcePathFromManifest(repoRoot, manifestPath, { identityRoot = null, baseDir = null } = {}) { + const value = normalizeManifestPath(manifestPath); + if (!value) { + return { sourcePath: "", manifestSourcePath: "", filePath: null, identityRoot: path3.resolve(repoRoot) }; + } + const resolvedRepoRoot = path3.resolve(repoRoot); + const resolvedIdentityRoot = identityRoot && pathIsInside2(identityRoot, resolvedRepoRoot) ? path3.resolve(identityRoot) : resolvedRepoRoot; + const roots = dedupePaths([ + baseDir ? path3.resolve(baseDir) : null, + resolvedIdentityRoot, + resolvedRepoRoot + ].filter(Boolean)); + const candidates = []; + for (const root of roots) { + if (!pathIsInside2(root, resolvedRepoRoot)) { + continue; + } + const filePath2 = resolveManifestSourcePath(resolvedRepoRoot, value, root); + if (!filePath2) { + continue; + } + candidates.push({ + sourcePath: repoRelativePath(resolvedRepoRoot, filePath2), + manifestSourcePath: value, + filePath: filePath2, + identityRoot: resolvedIdentityRoot + }); + } + const candidate = candidates.find((entry) => fileStats(entry.filePath)) || candidates[0]; + if (candidate) { + return candidate; + } + const filePath = resolveManifestSourcePath(resolvedRepoRoot, value, resolvedRepoRoot); + return { + sourcePath: value, + manifestSourcePath: value, + filePath, + identityRoot: resolvedIdentityRoot + }; +} +function commonAncestorPath(paths) { + const resolvedPaths = paths.filter(Boolean).map((entry) => path3.resolve(entry)); + if (!resolvedPaths.length) { + return ""; + } + let current = path3.dirname(resolvedPaths[0]); + for (; ; ) { + if (resolvedPaths.every((entry) => pathIsInside2(entry, current))) { + return current; + } + const parent = path3.dirname(current); + if (parent === current) { + return current; + } + current = parent; + } +} +function pythonIdentityRootCandidates({ repoRoot, sourceFilePath, anchorPath = "", preferredRoot = null }) { + const resolvedRepoRoot = path3.resolve(repoRoot); + const commonRoot = commonAncestorPath([sourceFilePath, anchorPath || sourceFilePath]); + const roots = []; + if (preferredRoot) { + roots.push(path3.resolve(preferredRoot)); + } + if (commonRoot) { + let current = path3.resolve(commonRoot); + for (; ; ) { + roots.push(current); + if (current === resolvedRepoRoot || !pathIsInside2(current, resolvedRepoRoot)) { + break; + } + const parent = path3.dirname(current); + if (parent === current) { + break; + } + current = parent; + } + } + roots.push(resolvedRepoRoot); + return dedupePaths(roots).filter((root) => pathIsInside2(root, resolvedRepoRoot) && pathIsInside2(sourceFilePath, root)); +} +function pythonSourceIdentityForArtifact({ + repoRoot, + sourceFilePath, + anchorPath = "", + preferredRoot = null, + artifactFingerprint = "" +}) { + let fallback = null; + for (const root of pythonIdentityRootCandidates({ repoRoot, sourceFilePath, anchorPath, preferredRoot })) { + try { + const identity = pythonSourceIdentity(root, sourceFilePath); + const result = { identity, identityRoot: root }; + if (!fallback) { + fallback = result; + } + if (artifactFingerprint && identity.sourceFingerprint === artifactFingerprint) { + return result; + } + } catch { + } + } + return fallback || { identity: null, identityRoot: path3.resolve(repoRoot) }; +} +function sourceIdentityWithCurrentPythonFingerprint({ + repoRoot, + sourceIdentity, + anchorPath, + artifactFingerprint +}) { + if (!sourceIdentity?.filePath) { + return { currentIdentity: null, currentHash: "", currentSourceHash: "" }; + } + const { identity } = pythonSourceIdentityForArtifact({ + repoRoot, + sourceFilePath: sourceIdentity.filePath, + anchorPath, + preferredRoot: sourceIdentity.identityRoot, + artifactFingerprint + }); + return { + currentIdentity: identity, + currentHash: identity?.sourceFingerprint || "", + currentSourceHash: identity?.sourceHash || "" + }; +} +function fileHasGenStep(filePath) { + try { + return /\bgen_step\s*\(/.test(fs2.readFileSync(filePath, "utf-8")); + } catch { + return false; + } +} +function generatorSourcePathFromManifest(repoRoot, manifestPath, { identityRoot = null, baseDir = null } = {}) { + const candidate = sourcePathFromManifest(repoRoot, manifestPath, { identityRoot, baseDir }); + if (candidate.sourcePath && candidate.filePath && path3.extname(candidate.filePath).toLowerCase() === ".py" && path3.basename(candidate.filePath) !== "__init__.py" && fileHasGenStep(candidate.filePath)) { + return candidate; + } + return { + sourcePath: "", + manifestSourcePath: candidate.manifestSourcePath || "", + filePath: null, + identityRoot: candidate.identityRoot || path3.resolve(repoRoot) + }; +} +function fileHasPythonGenerator(filePath, generatorName) { + if (!generatorName) { + return false; + } + try { + const source = fs2.readFileSync(filePath, "utf-8"); + return new RegExp(`\\b${generatorName}\\s*\\(`).test(source); + } catch { + return false; + } +} +function generatorSourcePathFromMetadata(repoRoot, manifestPath, generatorName, { baseDir = null } = {}) { + const candidate = sourcePathFromManifest(repoRoot, manifestPath, { baseDir }); + if (candidate.sourcePath && candidate.filePath && path3.extname(candidate.filePath).toLowerCase() === ".py" && path3.basename(candidate.filePath) !== "__init__.py" && fileHasPythonGenerator(candidate.filePath, generatorName)) { + return candidate; + } + return { sourcePath: "", filePath: null }; +} +function readXmlTextToCadMetadata(filePath) { + let text = ""; + try { + text = fs2.readFileSync(filePath, "utf-8"); + } catch { + return {}; + } + const metadata = {}; + for (const match of text.matchAll(TEXT_TO_CAD_COMMENT_METADATA_RE)) { + metadata[String(match[1] || "").trim()] = String(match[2] || "").trim(); + } + return metadata; +} +function readDxfTextToCadMetadata(filePath) { + let lines = []; + try { + lines = fs2.readFileSync(filePath, "utf-8").split(/\r?\n/); + } catch { + return {}; + } + const metadata = {}; + for (let index = 0; index + 1 < lines.length; index += 1) { + if (String(lines[index] || "").trim() !== "999") { + continue; + } + const value = String(lines[index + 1] || "").trim(); + if (!value.startsWith("cadpy:")) { + continue; + } + const [key, ...rest] = value.slice("cadpy:".length).split("="); + const normalizedKey = String(key || "").trim(); + if (rest.length && /^[A-Za-z][A-Za-z0-9]*$/.test(normalizedKey)) { + metadata[normalizedKey] = rest.join("=").trim(); + } + } + return metadata; +} +function readGeneratedFileMetadata(filePath, kind) { + const normalizedKind = String(kind || "").trim().toLowerCase(); + if (normalizedKind === "dxf") { + return readDxfTextToCadMetadata(filePath); + } + if (["urdf", "srdf", "sdf"].includes(normalizedKind)) { + return readXmlTextToCadMetadata(filePath); + } + if (normalizedKind === "step" || normalizedKind === "stp") { + try { + return readTextToCadStepMetadataFile(filePath); + } catch { + return {}; + } + } + return {}; +} +function generatedSourceStatusForFile({ repoRoot, sourcePath, kind }) { + const normalizedKind = String(kind || "").trim().toLowerCase(); + const generatorName = PYTHON_GENERATOR_BY_KIND[normalizedKind] || ""; + if (!generatorName) { + return null; + } + const metadata = readGeneratedFileMetadata(sourcePath, normalizedKind); + const metadataSourcePath = String(metadata.sourcePath || "").trim(); + if (!metadataSourcePath) { + return null; + } + const sourceIdentity = generatorSourcePathFromMetadata( + repoRoot, + metadataSourcePath, + generatorName, + { baseDir: path3.dirname(sourcePath) } + ); + const base = { + sourceKind: "python", + source: { + file: sourceIdentity.sourcePath || metadataSourcePath, + sourcePath: sourceIdentity.sourcePath || metadataSourcePath, + ...metadata.sourceHash ? { sourceHash: String(metadata.sourceHash) } : {}, + ...metadata.sourceFingerprint ? { sourceFingerprint: String(metadata.sourceFingerprint) } : {} + } + }; + if (!sourceIdentity.filePath) { + return { + ...base, + sourceStatus: { + ok: false, + status: "missing", + stale: false, + sourceKind: "python", + sourcePath: metadataSourcePath, + message: "Python generator source is unavailable." + } + }; + } + const artifactFingerprint = String(metadata.sourceFingerprint || "").trim(); + const { + currentHash, + currentSourceHash + } = sourceIdentityWithCurrentPythonFingerprint({ + repoRoot, + sourceIdentity, + anchorPath: sourcePath, + artifactFingerprint + }); + if (!artifactFingerprint) { + return { + ...base, + source: { + ...base.source, + file: sourceIdentity.sourcePath, + sourcePath: sourceIdentity.sourcePath, + sourceHash: String(metadata.sourceHash || ""), + sourceFingerprint: "" + }, + sourceStatus: { + ok: false, + status: "missing_identity", + stale: false, + sourceKind: "python", + sourcePath: sourceIdentity.sourcePath, + sourceHash: String(metadata.sourceHash || ""), + currentSourceHash, + currentHash, + message: "Generated file is missing Python sourceFingerprint metadata." + } + }; + } + const stale = Boolean(artifactFingerprint && artifactFingerprint !== currentHash); + return { + ...base, + source: { + ...base.source, + file: sourceIdentity.sourcePath, + sourcePath: sourceIdentity.sourcePath, + sourceHash: String(metadata.sourceHash || ""), + sourceFingerprint: String(metadata.sourceFingerprint || "") + }, + sourceStatus: { + ok: !stale, + status: stale ? "stale" : "current", + stale, + sourceKind: "python", + sourcePath: sourceIdentity.sourcePath, + artifactHash: artifactFingerprint, + currentHash, + sourceHash: String(metadata.sourceHash || ""), + currentSourceHash, + message: stale ? "Generated file doesn't match the Python generator fingerprint." : "" + } + }; +} +function assetForPath(repoRoot, filePath) { + const stats = fileStats(filePath); + if (!stats) { + return null; + } + const version = `${stats.size.toString(36)}-${stats.mtimeNs.toString(36)}`; + const repoPath = repoRelativePath(repoRoot, filePath); + return { + url: `${encodeUrlPath(repoPath)}?v=${encodeURIComponent(version)}`, + hash: sha256File(filePath), + bytes: Number(stats.size) + }; +} +function assetUrlForPath(repoRoot, filePath) { + return encodeUrlPath(repoRelativePath(repoRoot, filePath)); +} +function readExact(fd, length, position) { + const buffer = Buffer.alloc(length); + const bytesRead = fs2.readSync(fd, buffer, 0, length, position); + return bytesRead === length ? buffer : null; +} +function glbBufferViewRange(gltf, binOffset, binLength, viewIndex) { + const view = Array.isArray(gltf?.bufferViews) ? gltf.bufferViews[Number(viewIndex)] : null; + if (!view || Number(view.buffer || 0) !== 0) { + return null; + } + const byteOffset = binOffset + Number(view.byteOffset || 0); + const byteLength = Number(view.byteLength || 0); + if (!Number.isFinite(byteOffset) || !Number.isFinite(byteLength) || byteLength < 0) { + return null; + } + if (byteOffset < binOffset || byteOffset + byteLength > binOffset + binLength) { + return null; + } + return { byteOffset, byteLength }; +} +function parseJsonBufferView(fd, gltf, binOffset, binLength, viewIndex, encoding = "utf-8") { + const range = glbBufferViewRange(gltf, binOffset, binLength, viewIndex); + if (!range) { + throw new Error("STEP topology buffer view range is invalid"); + } + const bytes2 = readExact(fd, range.byteLength, range.byteOffset); + if (!bytes2) { + throw new Error("STEP topology buffer view range is invalid"); + } + const payload = JSON.parse(bytes2.toString(String(encoding || "utf-8"))); + if (!payload || typeof payload !== "object" || Array.isArray(payload)) { + throw new Error("STEP topology JSON buffer view is not an object"); + } + return payload; +} +function gltfPrimitivesHaveSurfaceEdgeAttributes(gltf) { + const meshes = Array.isArray(gltf?.meshes) ? gltf.meshes : []; + let primitiveCount = 0; + for (const mesh of meshes) { + for (const primitive of Array.isArray(mesh?.primitives) ? mesh.primitives : []) { + primitiveCount += 1; + const attributes = primitive?.attributes || {}; + if (attributes[STEP_EDGE_BARYCENTRIC_ATTRIBUTE] === void 0 || attributes[STEP_EDGE_CLASS_ATTRIBUTE] === void 0) { + return false; + } + } + } + return primitiveCount > 0; +} +function readGlbTopologyContainer(filePath) { + let fd = null; + try { + fd = fs2.openSync(filePath, "r"); + const header = readExact(fd, 12, 0); + if (!header || header.readUInt32LE(0) !== 1179937895 || header.readUInt32LE(4) !== 2) { + throw new Error("Not a GLB v2 file"); + } + const totalLength = Math.min(header.readUInt32LE(8), fs2.fstatSync(fd).size); + let offset = 12; + let gltf = null; + let binOffset = 0; + let binLength = 0; + while (offset + 8 <= totalLength) { + const chunkHeader = readExact(fd, 8, offset); + if (!chunkHeader) { + throw new Error("Invalid GLB chunk header"); + } + const chunkLength = chunkHeader.readUInt32LE(0); + const chunkType = chunkHeader.toString("latin1", 4, 8); + offset += 8; + if (offset + chunkLength > totalLength) { + throw new Error("Invalid GLB chunk length"); + } + if (chunkType === "JSON") { + const jsonBytes = readExact(fd, chunkLength, offset); + if (!jsonBytes) { + throw new Error("GLB is missing JSON chunk"); + } + gltf = JSON.parse(jsonBytes.toString("utf8").trim()); + } else if (chunkType === "BIN\0") { + binOffset = offset; + binLength = chunkLength; + } + offset += chunkLength; + } + return { + fd, + gltf, + binOffset, + binLength + }; + } catch { + if (fd !== null) { + fs2.closeSync(fd); + } + throw new Error("Invalid GLB topology container"); + } +} +function stepArtifactError({ code, reason, repoRoot, cadPath, sourcePath, glbPath, details = {} }) { + const glbRelPath = repoRelativePath(repoRoot, glbPath); + return { + ok: false, + error: { + code, + message: `${reason}: ${glbRelPath}.`, + cadPath, + stepPath: repoRelativePath(repoRoot, sourcePath), + glbPath: glbRelPath, + regenerateCommand: REGENERATE_STEP_COMMAND, + ...details + } + }; +} +function staleSourceIdentityError({ + repoRoot, + cadPath, + sourcePath, + glbPath, + sourceKind, + manifestSourcePath = "", + artifactHash, + currentHash +}) { + const normalizedKind = String(sourceKind || "step").trim().toLowerCase() === "python" ? "python" : "step"; + const reason = normalizedKind === "python" ? "Generated GLB doesn't match the hash of the Python generator script" : "Generated GLB doesn't match the hash of the STEP file"; + return stepArtifactError({ + code: "stale_source_identity", + reason, + repoRoot, + cadPath, + sourcePath, + glbPath, + details: { + stale: true, + sourceKind: normalizedKind, + ...manifestSourcePath ? { sourcePath: manifestSourcePath } : {}, + artifactHash, + currentHash + } + }); +} +function validateStepTopologyArtifact({ repoRoot, sourcePath, cadPath }) { + const glbPath = inlineStepGlbArtifactPathForSource(sourcePath); + let stepHash = ""; + let sourceHash = ""; + let artifactSourcePath = ""; + const fail = (code, reason) => ({ + topology: null, + stepArtifact: stepArtifactError({ code, reason, repoRoot, cadPath, sourcePath, glbPath }), + glbPath, + stepHash, + sourceHash + }); + if (!fileStats(glbPath)) { + return fail( + "missing_glb", + "STEP topology validation requires the generated GLB artifact, but it is missing" + ); + } + let container = null; + try { + container = readGlbTopologyContainer(glbPath); + const extension = container.gltf?.extensions?.[STEP_TOPOLOGY_EXTENSION]; + if (!extension || typeof extension !== "object" || Array.isArray(extension)) { + return fail( + "missing_step_topology", + "STEP topology validation requires readable STEP_topology indexView in the GLB" + ); + } + if (!isCurrentStepTopologySchemaVersion(extension.schemaVersion)) { + return fail( + "unsupported_step_topology", + `STEP topology validation requires STEP_topology schemaVersion ${STEP_TOPOLOGY_SCHEMA_VERSION} in the GLB` + ); + } + const manifest = parseJsonBufferView( + container.fd, + container.gltf, + container.binOffset, + container.binLength, + extension.indexView, + extension.encoding + ); + const topology = { + index: manifest, + entryKind: String(extension.entryKind || manifest.entryKind || "").trim().toLowerCase(), + hasSelector: false, + hasDisplayEdges: false + }; + if (!isCurrentStepTopologySchemaVersion(manifest.schemaVersion)) { + return { + topology, + stepArtifact: stepArtifactError({ + code: "unsupported_step_topology", + reason: `STEP topology validation requires STEP_topology schemaVersion ${STEP_TOPOLOGY_SCHEMA_VERSION} in the GLB`, + repoRoot, + cadPath, + sourcePath, + glbPath + }), + glbPath, + stepHash + }; + } + const artifactSourceKind = String(manifest.sourceKind || "step").trim().toLowerCase(); + const artifactUsesPythonSource = artifactSourceKind === "python"; + const artifactNormalizedSourceKind = artifactUsesPythonSource ? "python" : "step"; + const artifactIdentityDetails = () => ({ + sourceKind: artifactNormalizedSourceKind, + ...artifactSourcePath ? { sourcePath: artifactSourcePath } : {} + }); + const manifestIdentityRoot = manifestIdentityRootForStep(repoRoot, sourcePath, manifest.stepPath); + const sourceIdentity = artifactUsesPythonSource ? generatorSourcePathFromManifest(repoRoot, manifest.sourcePath, { + identityRoot: manifestIdentityRoot, + baseDir: path3.dirname(glbPath) + }) : sourcePathFromManifest(repoRoot, manifest.sourcePath, { + identityRoot: manifestIdentityRoot, + baseDir: path3.dirname(glbPath) + }); + artifactSourcePath = sourceIdentity.sourcePath; + if (!artifactSourcePath || !sourceIdentity.filePath) { + return { + topology, + stepArtifact: stepArtifactError({ + code: "missing_source_path", + reason: "GLB STEP_topology is missing required sourcePath identity", + repoRoot, + cadPath, + sourcePath, + glbPath, + details: { + sourceKind: artifactNormalizedSourceKind + } + }), + glbPath, + stepHash, + sourceHash + }; + } + stepHash = String(manifest.stepHash || "").trim(); + sourceHash = String(manifest.sourceHash || "").trim(); + const sourceFingerprint = String(manifest.sourceFingerprint || "").trim(); + const sourceIdentityPresent = artifactUsesPythonSource ? Boolean(sourceFingerprint) : Boolean(stepHash); + if (!sourceIdentityPresent) { + return { + topology, + stepArtifact: stepArtifactError({ + code: "missing_source_identity", + reason: artifactUsesPythonSource ? "GLB STEP_topology is missing Python generator identity" : "GLB STEP_topology is missing STEP file identity", + repoRoot, + cadPath, + sourcePath, + glbPath, + details: artifactIdentityDetails() + }), + glbPath, + stepHash, + sourceHash, + sourceFingerprint + }; + } + const currentSourceIdentity = artifactUsesPythonSource ? pythonSourceIdentityForArtifact({ + repoRoot, + sourceFilePath: sourceIdentity.filePath, + anchorPath: sourcePath, + preferredRoot: sourceIdentity.identityRoot || manifestIdentityRoot, + artifactFingerprint: sourceFingerprint + }).identity : null; + const currentSourceFingerprint = artifactUsesPythonSource ? currentSourceIdentity?.sourceFingerprint || "" : fileStats(sourceIdentity.filePath || sourcePath) ? sha256File(sourceIdentity.filePath || sourcePath) : ""; + const artifactSourceFingerprint = artifactUsesPythonSource ? sourceFingerprint : stepHash; + if (currentSourceFingerprint && artifactSourceFingerprint !== currentSourceFingerprint) { + return { + topology, + stepArtifact: staleSourceIdentityError({ + repoRoot, + cadPath, + sourcePath, + glbPath, + sourceKind: artifactSourceKind, + manifestSourcePath: artifactSourcePath, + artifactHash: artifactSourceFingerprint, + currentHash: currentSourceFingerprint + }), + glbPath, + stepHash, + sourceHash, + sourceFingerprint + }; + } + let edgeRendering = null; + try { + const edgeManifest = parseJsonBufferView( + container.fd, + container.gltf, + container.binOffset, + container.binLength, + extension.edgeView, + extension.encoding + ); + const edgeVisibilityClasses = edgeManifest?.edgeRendering && typeof edgeManifest.edgeRendering === "object" ? normalizeStepEdgeRenderVisibilityClasses(edgeManifest.edgeRendering.visibilityClasses) : []; + const indexEdgeVisibilityClasses = manifest?.edgeRendering && typeof manifest.edgeRendering === "object" ? normalizeStepEdgeRenderVisibilityClasses(manifest.edgeRendering.visibilityClasses) : []; + if (!isCurrentStepTopologySchemaVersion(edgeManifest.schemaVersion) || String(edgeManifest.profile || "") !== "surface-edges" || String(edgeManifest.sourcePath || "").trim() !== String(manifest.sourcePath || "").trim() || (artifactUsesPythonSource ? String(edgeManifest.sourceKind || "").trim().toLowerCase() !== "python" || String(edgeManifest.sourceFingerprint || "").trim() !== sourceFingerprint : String(edgeManifest.stepHash || "").trim() !== stepHash) || !edgeVisibilityClasses.length || edgeVisibilityClasses.join("\n") !== indexEdgeVisibilityClasses.join("\n") || !edgeVisibilityClasses.includes(STEP_EDGE_VISIBILITY_CLASSES.FEATURE) || !edgeManifest?.buffers?.views?.surfaceHalfEdges) { + return { + topology, + stepArtifact: stepArtifactError({ + code: "missing_edge_topology", + reason: `STEP topology validation requires STEP_topology edgeView schemaVersion ${STEP_TOPOLOGY_SCHEMA_VERSION} in the GLB`, + repoRoot, + cadPath, + sourcePath, + glbPath, + details: artifactIdentityDetails() + }), + glbPath, + stepHash, + sourceHash, + sourceFingerprint + }; + } + edgeRendering = edgeManifest.edgeRendering && typeof edgeManifest.edgeRendering === "object" ? { + visibilityClasses: edgeVisibilityClasses, + generatedVisibilityClasses: (Array.isArray(edgeManifest.edgeRendering.generatedVisibilityClasses) ? edgeManifest.edgeRendering.generatedVisibilityClasses : edgeVisibilityClasses).map((classId) => String(classId || "").trim()).filter((classId, index, list2) => edgeVisibilityClasses.includes(classId) && STEP_EDGE_RENDER_CLASS_ORDER.includes(classId) && list2.indexOf(classId) === index), + visibilityClassCounts: edgeManifest.edgeRendering.visibilityClassCounts || {}, + generatedVisibilityClassCounts: edgeManifest.edgeRendering.generatedVisibilityClassCounts || {} + } : null; + if (!gltfPrimitivesHaveSurfaceEdgeAttributes(container.gltf)) { + return { + topology, + stepArtifact: stepArtifactError({ + code: "missing_surface_edge_attributes", + reason: `STEP topology validation requires ${STEP_EDGE_BARYCENTRIC_ATTRIBUTE} and ${STEP_EDGE_CLASS_ATTRIBUTE} on every STEP mesh primitive`, + repoRoot, + cadPath, + sourcePath, + glbPath, + details: artifactIdentityDetails() + }), + glbPath, + stepHash, + sourceHash, + sourceFingerprint + }; + } + } catch { + return { + topology, + stepArtifact: stepArtifactError({ + code: "missing_edge_topology", + reason: "STEP topology validation requires readable STEP_topology edgeView in the GLB", + repoRoot, + cadPath, + sourcePath, + glbPath, + details: artifactIdentityDetails() + }), + glbPath, + stepHash, + sourceHash, + sourceFingerprint + }; + } + topology.hasDisplayEdges = true; + try { + const selectorManifest = parseJsonBufferView( + container.fd, + container.gltf, + container.binOffset, + container.binLength, + extension.selectorView, + extension.encoding + ); + if (!isCurrentStepTopologySchemaVersion(selectorManifest.schemaVersion)) { + return { + topology, + stepArtifact: stepArtifactError({ + code: "unsupported_step_topology", + reason: `STEP topology validation requires STEP_topology schemaVersion ${STEP_TOPOLOGY_SCHEMA_VERSION} in the GLB`, + repoRoot, + cadPath, + sourcePath, + glbPath, + details: artifactIdentityDetails() + }), + glbPath, + stepHash, + sourceHash, + sourceFingerprint + }; + } + } catch { + return { + topology, + stepArtifact: stepArtifactError({ + code: "missing_selector_topology", + reason: "STEP topology validation requires readable STEP_topology selectorView in the GLB", + repoRoot, + cadPath, + sourcePath, + glbPath, + details: artifactIdentityDetails() + }), + glbPath, + stepHash, + sourceHash, + sourceFingerprint + }; + } + topology.hasSelector = true; + const stepArtifact = { + ok: true, + glbPath: repoRelativePath(repoRoot, glbPath), + ...artifactSourcePath ? { sourcePath: artifactSourcePath } : {}, + sourceKind: artifactUsesPythonSource ? "python" : "step", + ...edgeRendering ? { edgeRendering } : {}, + ...artifactUsesPythonSource ? { + sourceHash, + ...sourceFingerprint ? { sourceFingerprint } : {} + } : { + stepHash + } + }; + return { + topology, + stepArtifact, + glbPath, + stepHash, + sourceHash, + sourceFingerprint + }; + } catch { + return fail( + "missing_step_topology", + "STEP topology validation requires readable STEP_topology indexView in the GLB" + ); + } finally { + if (container?.fd !== null && container?.fd !== void 0) { + try { + fs2.closeSync(container.fd); + } catch { + } + } + } +} +function readStepSourceStatus({ + repoRoot, + stepPath, + pythonSourcePath = "", + cadPath = "" +} = {}) { + if (!repoRoot) { + throw new Error("repoRoot is required"); + } + if (!stepPath) { + throw new Error("stepPath is required"); + } + const resolvedRepoRoot = path3.resolve(repoRoot); + const resolvedStepPath = path3.resolve(stepPath); + const extension = path3.extname(resolvedStepPath) || ".step"; + const normalizedCadPath = cadPath || cadPathForStepSource(resolvedRepoRoot, resolvedStepPath, extension); + const validation = validateStepTopologyArtifact({ + repoRoot: resolvedRepoRoot, + sourcePath: resolvedStepPath, + cadPath: normalizedCadPath + }); + const stepArtifact = validation.stepArtifact || {}; + const stepArtifactError2 = stepArtifact.error && typeof stepArtifact.error === "object" ? stepArtifact.error : {}; + const artifact = catalogArtifactFromValidation(stepArtifact) || null; + let resolvedPythonSourcePath = pythonSourcePath ? path3.resolve(pythonSourcePath) : ""; + const artifactSourceKind = String( + stepArtifact.sourceKind || stepArtifactError2.sourceKind || "" + ).trim().toLowerCase(); + if (artifactSourceKind === "step") { + resolvedPythonSourcePath = ""; + } else if (!resolvedPythonSourcePath && artifactSourceKind === "python") { + const manifestSourcePath = String(stepArtifact.sourcePath || stepArtifactError2.sourcePath || "").trim(); + if (manifestSourcePath) { + resolvedPythonSourcePath = path3.resolve(resolvedRepoRoot, manifestSourcePath); + } + } + const sourceKind = resolvedPythonSourcePath || artifactSourceKind === "python" ? "python" : "step"; + const file = repoRelativePath(resolvedRepoRoot, resolvedStepPath); + const base = { + ok: true, + file, + stepPath: file, + sourceKind, + artifact, + ...resolvedPythonSourcePath ? { sourcePath: repoRelativePath(resolvedRepoRoot, resolvedPythonSourcePath) } : {} + }; + if (!fileStats(resolvedStepPath)) { + return { + ...base, + ok: false, + step: { + ok: false, + status: "missing", + missing: true, + stale: false, + message: "STEP file is missing." + } + }; + } + if (sourceKind !== "python") { + return { + ...base, + step: { + ok: true, + status: "current", + missing: false, + stale: false + } + }; + } + if (!resolvedPythonSourcePath || !fileStats(resolvedPythonSourcePath)) { + return { + ...base, + step: { + ok: true, + status: "unknown", + missing: false, + stale: false, + message: "Python source identity is unavailable." + } + }; + } + const manifestIdentityRoot = artifactSourceKind === "python" ? manifestIdentityRootForStep(resolvedRepoRoot, resolvedStepPath, validation.topology?.index?.stepPath) : ""; + const resolvedIdentityRoot = manifestIdentityRoot && pathIsInside2(manifestIdentityRoot, resolvedRepoRoot) ? path3.resolve(manifestIdentityRoot) : resolvedRepoRoot; + const currentIdentity = pythonSourceIdentityForArtifact({ + repoRoot: resolvedRepoRoot, + sourceFilePath: resolvedPythonSourcePath, + anchorPath: resolvedStepPath, + preferredRoot: resolvedIdentityRoot, + artifactFingerprint: String(validation.topology?.index?.sourceFingerprint || "") + }).identity || pythonSourceIdentity(resolvedIdentityRoot, resolvedPythonSourcePath); + const currentHash = currentIdentity.sourceFingerprint; + let metadata = {}; + try { + metadata = readTextToCadStepMetadataFile(resolvedStepPath); + } catch { + metadata = {}; + } + const stepSourceHash = String(metadata.sourceHash || "").trim(); + const stepSourceFingerprint = String(metadata.sourceFingerprint || "").trim(); + if (!stepSourceFingerprint) { + return { + ...base, + ok: false, + step: { + ok: false, + status: "missing_identity", + missing: false, + stale: false, + metadataMissing: true, + sourceHash: stepSourceHash, + currentHash, + currentSourceHash: currentIdentity.sourceHash, + message: "STEP file is missing Python source identity metadata." + } + }; + } + if (stepSourceFingerprint !== currentHash) { + return { + ...base, + ok: false, + step: { + ok: false, + status: "stale", + missing: false, + stale: true, + artifactHash: stepSourceFingerprint, + currentHash, + sourceHash: stepSourceHash, + currentSourceHash: currentIdentity.sourceHash, + message: stepSourceFingerprint ? "STEP file doesn't match the hash of the Python generator script." : "STEP file is missing Python source identity metadata." + } + }; + } + return { + ...base, + step: { + ok: true, + status: "current", + missing: false, + stale: false, + currentHash, + sourceHash: stepSourceHash, + currentSourceHash: currentIdentity.sourceHash + } + }; +} +function stepKindFromTopology(topology) { + const index = topology?.index && typeof topology.index === "object" ? topology.index : topology; + if (topology?.entryKind === "assembly" || index?.entryKind === "assembly") { + return "assembly"; + } + return index?.assembly?.root && typeof index.assembly.root === "object" ? "assembly" : "part"; +} +function sourceFormatFromExtension(extension) { + const normalized = extension.toLowerCase().replace(/^\./, ""); + return normalized === "stp" ? "stp" : normalized; +} +function isPerUrdfViewerDirectoryName(name) { + const normalized = String(name || "").toLowerCase(); + return normalized.startsWith(".") && normalized.endsWith(".urdf"); +} +function isHiddenDirectoryName(name) { + return String(name || "").startsWith("."); +} +function isPathInsidePerUrdfViewerDirectory(filePath) { + return String(filePath || "").split(path3.sep).some((part) => isPerUrdfViewerDirectoryName(part)); +} +function fileRefForSource(rootPath, sourcePath) { + return scanRelativePath(rootPath, sourcePath); +} +function cadPathForStepSource(repoRoot, sourcePath, extension) { + const relativePath = repoRelativePath(repoRoot, sourcePath); + return relativePath.slice(0, -extension.length); +} +function sourcePathForInlineStepGlbArtifact(glbPath) { + const name = path3.basename(glbPath); + if (!isInlineStepGlbArtifactPath(glbPath)) { + return null; + } + return path3.join(path3.dirname(glbPath), name.slice(1, -".glb".length)); +} +function sourcePathForInlineStepParameter(parameterPath) { + const name = path3.basename(parameterPath); + if (!isInlineStepParameterPath(parameterPath)) { + return null; + } + return path3.join(path3.dirname(parameterPath), name.slice(1, -".js".length)); +} +function catalogArtifactFromValidation(stepArtifact) { + if (!stepArtifact || typeof stepArtifact !== "object") { + return void 0; + } + if (stepArtifact.ok) { + return void 0; + } + const rawError = stepArtifact.error && typeof stepArtifact.error === "object" ? stepArtifact.error : {}; + const error = String(rawError.code || stepArtifact.error || "step_artifact_error").trim(); + const message = String(rawError.message || "").trim(); + const sourceKind = String(rawError.sourceKind || "").trim(); + const artifactHash = String(rawError.artifactHash || "").trim(); + const currentHash = String(rawError.currentHash || "").trim(); + const sourceHash = String(rawError.sourceHash || "").trim(); + const sourceFingerprint = String(rawError.sourceFingerprint || "").trim(); + const stepPath = String(rawError.stepPath || "").trim(); + const glbPath = String(rawError.glbPath || "").trim(); + const cadPath = String(rawError.cadPath || "").trim(); + return { + ok: false, + error, + ...rawError.stale ? { stale: true } : {}, + ...stepPath ? { stepPath } : {}, + ...glbPath ? { glbPath } : {}, + ...cadPath ? { cadPath } : {}, + ...sourceKind ? { sourceKind } : {}, + ...sourceHash ? { sourceHash } : {}, + ...sourceFingerprint ? { sourceFingerprint } : {}, + ...artifactHash ? { artifactHash } : {}, + ...currentHash ? { currentHash } : {}, + ...message ? { message } : {} + }; +} +function readStepCatalogMetadata({ repoRoot, glbPath, sourcePath = "" } = {}) { + if (!fileStats(glbPath)) { + return {}; + } + let container = null; + try { + container = readGlbTopologyContainer(glbPath); + const extension = container.gltf?.extensions?.[STEP_TOPOLOGY_EXTENSION]; + if (!extension || typeof extension !== "object" || Array.isArray(extension)) { + return {}; + } + if (!isCurrentStepTopologySchemaVersion(extension.schemaVersion)) { + return {}; + } + const manifest = parseJsonBufferView( + container.fd, + container.gltf, + container.binOffset, + container.binLength, + extension.indexView, + extension.encoding + ); + const sourceKind = String(manifest?.sourceKind || "step").trim().toLowerCase() === "python" ? "python" : "step"; + const manifestIdentityRoot = manifestIdentityRootForStep(repoRoot, sourcePathForInlineStepGlbArtifact(glbPath) || sourcePath, manifest?.stepPath); + const sourceIdentity = sourceKind === "python" ? generatorSourcePathFromManifest(repoRoot, manifest?.sourcePath, { + identityRoot: manifestIdentityRoot, + baseDir: path3.dirname(glbPath) + }) : sourcePathFromManifest(repoRoot, manifest?.sourcePath, { + identityRoot: manifestIdentityRoot, + baseDir: path3.dirname(glbPath) + }); + return { + topology: { + index: manifest, + entryKind: String(extension.entryKind || manifest?.entryKind || "").trim().toLowerCase(), + hasSelector: Boolean(extension.selectorView), + hasDisplayEdges: Boolean(extension.edgeView) + }, + sourceKind, + sourcePath: sourceIdentity.sourcePath, + sourceHash: String(manifest?.sourceHash || ""), + sourceFingerprint: String(manifest?.sourceFingerprint || ""), + stepHash: String(manifest?.stepHash || "") + }; + } catch { + return {}; + } finally { + if (container?.fd !== null && container?.fd !== void 0) { + try { + fs2.closeSync(container.fd); + } catch { + } + } + } +} +function pythonStepSourceFromStepMetadata(repoRoot, stepPath) { + const metadata = readGeneratedFileMetadata(stepPath, "step"); + const metadataSourcePath = String(metadata.sourcePath || "").trim(); + if (!metadataSourcePath) { + return null; + } + const sourceIdentity = sourcePathFromManifest(repoRoot, metadataSourcePath, { baseDir: path3.dirname(stepPath) }); + if (!sourceIdentity.sourcePath) { + return null; + } + const sourceExtension = path3.extname(sourceIdentity.filePath || sourceIdentity.sourcePath).toLowerCase(); + if (sourceExtension !== ".py") { + return null; + } + return { + sourcePath: sourceIdentity.sourcePath, + sourceHash: String(metadata.sourceHash || ""), + sourceFingerprint: String(metadata.sourceFingerprint || "") + }; +} +function createStepEntry({ repoRoot, rootPath, sourcePath, extension, includeArtifactStatus = true }) { + const cadPath = cadPathForStepSource(repoRoot, sourcePath, extension); + const validation = includeArtifactStatus ? validateStepTopologyArtifact({ + repoRoot, + sourcePath, + cadPath + }) : null; + const glbPath = validation?.glbPath || inlineStepGlbArtifactPathForSource(sourcePath); + const catalogMetadata = includeArtifactStatus ? {} : readStepCatalogMetadata({ repoRoot, glbPath, sourcePath }); + const topology = validation?.topology || catalogMetadata.topology || null; + const stepArtifact = validation?.stepArtifact || {}; + const glbAsset = assetForPath(repoRoot, glbPath); + const stepModuleAsset = assetForPath(repoRoot, stepParameterPathForStepSource(sourcePath)); + const artifact = includeArtifactStatus ? catalogArtifactFromValidation(stepArtifact) : void 0; + const artifactSourceKind = String( + stepArtifact.sourceKind || stepArtifact.error?.sourceKind || catalogMetadata.sourceKind || artifact?.sourceKind || "" + ).trim().toLowerCase(); + const metadataPythonSource = (!includeArtifactStatus || artifact) && artifactSourceKind !== "python" ? pythonStepSourceFromStepMetadata(repoRoot, sourcePath) : null; + const sourceKind = artifactSourceKind === "python" || metadataPythonSource ? "python" : "step"; + const artifactSourcePath = String( + stepArtifact.sourcePath || stepArtifact.error?.sourcePath || catalogMetadata.sourcePath || "" + ).trim(); + const pythonSourcePath = artifactSourcePath || metadataPythonSource?.sourcePath || ""; + return { + file: fileRefForSource(rootPath, sourcePath), + kind: stepKindFromTopology(topology), + url: glbAsset?.url || assetUrlForPath(repoRoot, glbPath), + hash: glbAsset?.hash || "", + bytes: glbAsset?.bytes || 0, + sourceKind, + ...sourceKind === "python" && pythonSourcePath ? { + source: { + file: pythonSourcePath, + sourcePath: pythonSourcePath, + ...stepArtifact.sourceHash || catalogMetadata.sourceHash || metadataPythonSource?.sourceHash ? { sourceHash: stepArtifact.sourceHash || catalogMetadata.sourceHash || metadataPythonSource.sourceHash } : {}, + ...stepArtifact.sourceFingerprint || catalogMetadata.sourceFingerprint || metadataPythonSource?.sourceFingerprint ? { sourceFingerprint: stepArtifact.sourceFingerprint || catalogMetadata.sourceFingerprint || metadataPythonSource.sourceFingerprint } : {} + } + } : {}, + ...stepModuleAsset ? { moduleUrl: stepModuleAsset.url } : {}, + ...artifact ? { artifact } : {} + }; +} +function linkedUrdfPathForSrdf(sourcePath, repoRoot) { + let xmlText = ""; + try { + xmlText = fs2.readFileSync(sourcePath, "utf-8"); + } catch { + return null; + } + const match = SRDF_URDF_METADATA_PATTERN.exec(xmlText); + const rawRef = String(match?.[1] || "").trim(); + if (!rawRef || rawRef.includes("\\") || rawRef.startsWith("/")) { + return null; + } + const resolved = path3.resolve(path3.dirname(sourcePath), rawRef); + const relativeToRepo = path3.relative(path3.resolve(repoRoot), resolved); + if (!relativePathStaysInsideRoot2(relativeToRepo) || path3.extname(resolved).toLowerCase() !== ".urdf") { + return null; + } + return fileStats(resolved) ? resolved : null; +} +function createSingleAssetEntry({ repoRoot, rootPath, sourcePath, extension }) { + const kind = sourceFormatFromExtension(extension); + const asset = assetForPath(repoRoot, sourcePath); + const file = fileRefForSource(rootPath, sourcePath); + const generatedSource = generatedSourceStatusForFile({ repoRoot, sourcePath, kind }); + const entry = { + file, + kind, + url: asset?.url || assetUrlForPath(repoRoot, sourcePath), + hash: asset?.hash || "", + bytes: asset?.bytes || 0, + ...generatedSource?.sourceKind === "python" ? { sourceKind: "python" } : {}, + ...generatedSource?.source ? { source: generatedSource.source } : {}, + ...generatedSource?.sourceStatus ? { sourceStatus: generatedSource.sourceStatus } : {} + }; + if (kind === "srdf") { + const linkedUrdfPath = linkedUrdfPathForSrdf(sourcePath, repoRoot); + if (linkedUrdfPath) { + const urdfAsset = assetForPath(repoRoot, linkedUrdfPath); + if (urdfAsset) { + entry.relations = { + urdf: { + file: fileRefForSource(rootPath, linkedUrdfPath), + ...urdfAsset + } + }; + } + } + } + return entry; +} +function shouldSkipDirectory(name) { + return VIEWER_SKIPPED_DIRECTORIES.has(name) || isHiddenDirectoryName(name) || isPerStepViewerDirectoryName(name) || isPerUrdfViewerDirectoryName(name); +} +function scanPathIncluded(includePath, rootPath, entryPath, isDirectory) { + if (typeof includePath !== "function") { + return true; + } + return includePath({ + filePath: entryPath, + relativePath: scanRelativePath(rootPath, entryPath), + isDirectory + }) !== false; +} +function collectCadSourceFiles(rootPath, { scanRootPath = rootPath, includePath = null } = {}, result = []) { + let entries = []; + try { + entries = fs2.readdirSync(rootPath, { withFileTypes: true }); + } catch { + return result; + } + for (const entry of entries) { + const entryPath = path3.join(rootPath, entry.name); + if (entry.isDirectory()) { + if (!shouldSkipDirectory(entry.name) && scanPathIncluded(includePath, scanRootPath, entryPath, true)) { + collectCadSourceFiles(entryPath, { scanRootPath, includePath }, result); + } + continue; + } + if (!entry.isFile()) { + continue; + } + if (!scanPathIncluded(includePath, scanRootPath, entryPath, false)) { + continue; + } + const extension = path3.extname(entry.name).toLowerCase(); + if (isInlineStepGlbArtifactPath(entryPath)) { + const sourcePath = sourcePathForInlineStepGlbArtifact(entryPath); + if (sourcePath && !fileStats(sourcePath)) { + result.push(entryPath); + } + continue; + } + if (SOURCE_EXTENSIONS.has(extension) && !isInlineStepGlbArtifactPath(entryPath)) { + result.push(entryPath); + continue; + } + } + return result; +} +function compareEntries(a, b) { + return String(a.file || "").localeCompare(String(b.file || ""), void 0, { + numeric: true, + sensitivity: "base" + }); +} +function pathHasSkippedDirectory(rootPath, filePath) { + const relativePath = scanRelativePath(rootPath, filePath); + if (!relativePathStaysInsideRoot2(relativePath)) { + return true; + } + const parts = relativePath.split("/").filter(Boolean); + return parts.slice(0, -1).some((part) => shouldSkipDirectory(part)); +} +function logicalStepSourcePathForInlineArtifactPath(filePath) { + if (isInlineStepGlbArtifactPath(filePath)) { + return sourcePathForInlineStepGlbArtifact(filePath); + } + if (isInlineStepParameterPath(filePath)) { + return sourcePathForInlineStepParameter(filePath); + } + return null; +} +function logicalStepSourceExistsForSidecar(sourcePath) { + return Boolean( + sourcePath && (fileStats(sourcePath) || fileStats(inlineStepGlbArtifactPathForSource(sourcePath)) || fileStats(stepParameterPathForStepSource(sourcePath))) + ); +} +function catalogFileRefForPath({ repoRoot, rootDir = DEFAULT_VIEWER_ROOT_DIR, filePath } = {}) { + if (!repoRoot) { + throw new Error("repoRoot is required"); + } + if (!filePath) { + throw new Error("filePath is required"); + } + const resolved = resolveViewerRoot(repoRoot, rootDir); + const resolvedFilePath = path3.resolve(filePath); + if (!pathIsInside2(resolvedFilePath, resolved.rootPath) || pathHasSkippedDirectory(resolved.rootPath, resolvedFilePath)) { + return ""; + } + const logicalStepSourcePath = logicalStepSourcePathForInlineArtifactPath(resolvedFilePath); + if (logicalStepSourcePath) { + return fileRefForSource(resolved.rootPath, logicalStepSourcePath); + } + if (isPathInsidePerStepViewerDirectory(resolvedFilePath) || isPathInsidePerUrdfViewerDirectory(resolvedFilePath)) { + return ""; + } + const extension = path3.extname(resolvedFilePath).toLowerCase(); + return SOURCE_EXTENSIONS.has(extension) ? fileRefForSource(resolved.rootPath, resolvedFilePath) : ""; +} +function scanCadFile({ + repoRoot, + rootDir = DEFAULT_VIEWER_ROOT_DIR, + filePath, + includeArtifactStatus = true +} = {}) { + if (!repoRoot) { + throw new Error("repoRoot is required"); + } + if (!filePath) { + throw new Error("filePath is required"); + } + const resolved = resolveViewerRoot(repoRoot, rootDir); + const resolvedFilePath = path3.resolve(filePath); + if (!pathIsInside2(resolvedFilePath, resolved.rootPath) || pathHasSkippedDirectory(resolved.rootPath, resolvedFilePath)) { + return null; + } + const logicalStepSourcePath = logicalStepSourcePathForInlineArtifactPath(resolvedFilePath); + if (logicalStepSourcePath) { + if (!logicalStepSourceExistsForSidecar(logicalStepSourcePath)) { + return null; + } + return createStepEntry({ + repoRoot, + rootPath: resolved.rootPath, + sourcePath: logicalStepSourcePath, + extension: path3.extname(logicalStepSourcePath).toLowerCase(), + includeArtifactStatus + }); + } + if (isPathInsidePerStepViewerDirectory(resolvedFilePath) || isPathInsidePerUrdfViewerDirectory(resolvedFilePath)) { + return null; + } + const extension = path3.extname(resolvedFilePath).toLowerCase(); + if (!SOURCE_EXTENSIONS.has(extension) || !fileStats(resolvedFilePath)) { + if ((extension === ".step" || extension === ".stp") && fileStats(inlineStepGlbArtifactPathForSource(resolvedFilePath))) { + return createStepEntry({ + repoRoot, + rootPath: resolved.rootPath, + sourcePath: resolvedFilePath, + extension, + includeArtifactStatus + }); + } + return null; + } + if (extension === ".step" || extension === ".stp") { + return createStepEntry({ + repoRoot, + rootPath: resolved.rootPath, + sourcePath: resolvedFilePath, + extension, + includeArtifactStatus + }); + } + return createSingleAssetEntry({ + repoRoot, + rootPath: resolved.rootPath, + sourcePath: resolvedFilePath, + extension + }); +} +function scanCadDirectory({ + repoRoot, + rootDir = DEFAULT_VIEWER_ROOT_DIR, + includePath = null, + includeArtifactStatus = true +} = {}) { + if (!repoRoot) { + throw new Error("repoRoot is required"); + } + const resolved = resolveViewerRoot(repoRoot, rootDir); + const entries = collectCadSourceFiles(resolved.rootPath, { + scanRootPath: resolved.rootPath, + includePath + }).map((sourcePath) => { + const logicalSourcePath = isInlineStepGlbArtifactPath(sourcePath) ? sourcePathForInlineStepGlbArtifact(sourcePath) : sourcePath; + const extension = path3.extname(logicalSourcePath).toLowerCase(); + if (extension === ".step" || extension === ".stp") { + return createStepEntry({ + repoRoot, + rootPath: resolved.rootPath, + sourcePath: logicalSourcePath, + extension, + includeArtifactStatus + }); + } + return createSingleAssetEntry({ + repoRoot, + rootPath: resolved.rootPath, + sourcePath, + extension + }); + }).sort(compareEntries); + return { + schemaVersion: CAD_CATALOG_SCHEMA_VERSION, + entries + }; +} +function sortCatalogEntries(entries) { + return [...Array.isArray(entries) ? entries : []].sort(compareEntries); +} +function isServedCadAsset(filePath) { + const extension = path3.extname(filePath).toLowerCase(); + if (isInlineStepGlbArtifactPath(filePath)) { + return true; + } + if (isInlineStepParameterPath(filePath)) { + return true; + } + if (isPathInsidePerStepViewerDirectory(filePath)) { + return false; + } + if (isPathInsidePerUrdfViewerDirectory(filePath)) { + return false; + } + if (SOURCE_EXTENSIONS.has(extension)) { + return true; + } + return false; +} + +// viewer/packages/cadjs/src/lib/generationStatus.mjs +import fs3 from "node:fs"; +import path4 from "node:path"; +var GENERATION_STATUS_SCHEMA_VERSION = 1; +var GENERATION_LOCK_SUFFIX = ".generation.lock.json"; +var DEFAULT_ACTIVE_STATUS_MAX_AGE_MS = 3e4; +var IGNORED_STATUS_SCAN_DIRS = /* @__PURE__ */ new Set([ + ".cache", + ".git", + ".hg", + ".mypy_cache", + ".pytest_cache", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + "build", + "dist", + "env", + "node_modules", + "site-packages", + "venv", + "__pycache__" +]); +function emptyGenerationStatus() { + return { + schemaVersion: GENERATION_STATUS_SCHEMA_VERSION, + runs: [], + files: {} + }; +} +function generationStatusDir(repoRoot, rootDir = DEFAULT_VIEWER_ROOT_DIR) { + const resolvedRepoRoot = path4.resolve(repoRoot); + return resolveViewerRoot(resolvedRepoRoot, normalizeViewerRootDir(rootDir)).rootPath; +} +function pathIsInside3(filePath, rootPath) { + const relative = path4.relative(path4.resolve(rootPath), path4.resolve(filePath)); + return relative === "" || relative !== ".." && !relative.startsWith(`..${path4.sep}`) && !path4.isAbsolute(relative); +} +function isGenerationLockFileName(name) { + return String(name || "").startsWith(".") && String(name || "").endsWith(GENERATION_LOCK_SUFFIX); +} +function resolveStatusPath(repoRoot, value, { statusPath = "", rootPath = "" } = {}) { + const raw = String(value || "").trim(); + if (!raw) { + return ""; + } + if (raw.includes("\0")) { + return ""; + } + if (path4.isAbsolute(raw)) { + return path4.resolve(raw); + } + const normalized = raw.replace(/\\/g, "/"); + const statusDir = statusPath ? path4.dirname(statusPath) : ""; + const repoCandidate = path4.resolve(repoRoot, normalized); + const shouldPreferStatusDir = statusDir && (normalized.startsWith("../") || normalized.startsWith("./") || !normalized.includes("/")); + if (shouldPreferStatusDir) { + return path4.resolve(statusDir, normalized); + } + if (rootPath && pathIsInside3(repoCandidate, rootPath)) { + return repoCandidate; + } + return repoCandidate; +} +function processIsAlive(pid) { + const normalizedPid = Number(pid); + if (!Number.isInteger(normalizedPid) || normalizedPid <= 0) { + return false; + } + try { + process.kill(normalizedPid, 0); + return true; + } catch (error) { + return error?.code === "EPERM"; + } +} +function timestampMs(value) { + const ms = Date.parse(String(value || "")); + return Number.isFinite(ms) ? ms : 0; +} +function statusIsActive(payload, { nowMs = Date.now(), maxAgeMs = DEFAULT_ACTIVE_STATUS_MAX_AGE_MS } = {}) { + if (String(payload?.status || "").trim().toLowerCase() !== "running") { + return false; + } + if (!processIsAlive(payload?.pid)) { + return false; + } + const updatedAtMs = timestampMs(payload?.updatedAt || payload?.startedAt); + return !updatedAtMs || nowMs - updatedAtMs <= maxAgeMs; +} +function readStatusPayload(statusPath) { + try { + const payload = JSON.parse(fs3.readFileSync(statusPath, "utf8")); + return payload && typeof payload === "object" ? payload : null; + } catch { + return null; + } +} +function listStatusFiles(repoRoot, rootDir = DEFAULT_VIEWER_ROOT_DIR) { + const statusRoot = generationStatusDir(repoRoot, rootDir); + const statusFiles = []; + const visit = (directory) => { + let entries = []; + try { + entries = fs3.readdirSync(directory, { withFileTypes: true }); + } catch { + return; + } + for (const entry of entries) { + const entryPath = path4.join(directory, entry.name); + if (entry.isDirectory()) { + if (!IGNORED_STATUS_SCAN_DIRS.has(entry.name)) { + visit(entryPath); + } + continue; + } + if (entry.isFile() && isGenerationLockFileName(entry.name)) { + statusFiles.push(entryPath); + } + } + }; + visit(statusRoot); + return statusFiles; +} +function outputEntries(payload) { + return (Array.isArray(payload?.outputs) ? payload.outputs : []).map((output) => { + if (typeof output === "string") { + return { path: output, kind: path4.extname(output).toLowerCase().replace(".", "") }; + } + return { + path: String(output?.path || "").trim(), + kind: String(output?.kind || "").trim().toLowerCase() + }; + }).filter((output) => output.path); +} +function readGenerationStatus({ + repoRoot, + rootDir = DEFAULT_VIEWER_ROOT_DIR, + nowMs = Date.now(), + maxAgeMs = DEFAULT_ACTIVE_STATUS_MAX_AGE_MS +} = {}) { + if (!repoRoot) { + throw new Error("repoRoot is required"); + } + const resolvedRepoRoot = path4.resolve(repoRoot); + const resolvedRoot = resolveViewerRoot(resolvedRepoRoot, normalizeViewerRootDir(rootDir)); + const status = emptyGenerationStatus(); + const runsById = /* @__PURE__ */ new Map(); + for (const statusPath of listStatusFiles(resolvedRepoRoot, rootDir)) { + const payload = readStatusPayload(statusPath); + if (!payload || !statusIsActive(payload, { nowMs, maxAgeMs })) { + continue; + } + const runId = String(payload.id || path4.basename(statusPath, GENERATION_LOCK_SUFFIX)); + let run = runsById.get(runId); + if (!run) { + run = { + id: runId, + pid: Number(payload.pid) || 0, + startedAt: String(payload.startedAt || ""), + updatedAt: String(payload.updatedAt || ""), + sourcePath: sourcePathFromStatusPayload(resolvedRepoRoot, payload.sourcePath, statusPath), + generator: String(payload.generator || ""), + files: [] + }; + runsById.set(runId, run); + } + for (const output of outputEntries(payload)) { + const outputPath = resolveStatusPath(resolvedRepoRoot, output.path, { + statusPath, + rootPath: resolvedRoot.rootPath + }); + if (!outputPath || !pathIsInside3(outputPath, resolvedRoot.rootPath)) { + continue; + } + const file = toPosixPath(path4.relative(resolvedRoot.rootPath, outputPath)); + if (!file || file.startsWith("../")) { + continue; + } + const fileStatus = { + running: true, + runId: run.id, + pid: run.pid, + startedAt: run.startedAt, + updatedAt: run.updatedAt, + sourcePath: run.sourcePath, + generator: run.generator, + kind: output.kind + }; + status.files[file] = fileStatus; + if (!run.files.includes(file)) { + run.files.push(file); + } + } + } + status.runs = Array.from(runsById.values()).filter((run) => run.files.length); + return status; +} +function sourcePathFromStatusPayload(repoRoot, value, statusPath) { + const raw = String(value || "").trim(); + if (!raw) { + return ""; + } + const resolved = resolveStatusPath(repoRoot, raw, { statusPath, rootPath: repoRoot }); + return resolved && pathIsInside3(resolved, repoRoot) ? toPosixPath(path4.relative(path4.resolve(repoRoot), resolved)) : raw.replace(/\\/g, "/"); +} + +// viewer/packages/cadjs/src/lib/step/stepArtifactCompiler.mjs +import fs5 from "node:fs"; +import path6 from "node:path"; + +// viewer/packages/cadjs/src/lib/step/pythonStepArtifact.mjs +import { spawn } from "node:child_process"; +import fs4 from "node:fs"; +import path5 from "node:path"; +import { fileURLToPath as fileURLToPath2 } from "node:url"; +var MODULE_DIR = path5.dirname(fileURLToPath2(import.meta.url)); +var PACKAGE_ROOT = path5.resolve(MODULE_DIR, "../../.."); +function firstExistingFile(paths) { + return paths.find((candidate) => fs4.existsSync(candidate)) || ""; +} +function firstExistingDirectory(paths) { + return paths.find((candidate) => { + try { + return fs4.statSync(candidate).isDirectory(); + } catch { + return false; + } + }) || ""; +} +function findUpFile(relativePath) { + let current = MODULE_DIR; + for (; ; ) { + const candidate = path5.join(current, relativePath); + if (fs4.existsSync(candidate)) { + return candidate; + } + const next = path5.dirname(current); + if (next === current) { + return ""; + } + current = next; + } +} +function findUpDirectory(relativePath) { + let current = MODULE_DIR; + for (; ; ) { + const candidate = path5.join(current, relativePath); + if (firstExistingDirectory([candidate])) { + return candidate; + } + const next = path5.dirname(current); + if (next === current) { + return ""; + } + current = next; + } +} +function cadPythonExecutable(repoRoot) { + const configured = String(process.env.VIEWER_CAD_PYTHON || process.env.CAD_PYTHON || "").trim(); + if (configured) { + return configured; + } + const resolvedRepoRoot = path5.resolve(repoRoot || ""); + return firstExistingFile([ + path5.join(resolvedRepoRoot, ".venv", "bin", "python"), + path5.join(process.cwd(), ".venv", "bin", "python"), + path5.join(PACKAGE_ROOT, ".venv", "bin", "python"), + findUpFile(path5.join(".venv", "bin", "python")) + ]) || "python3"; +} +function cadPythonEnv() { + const pythonPathEntries = []; + for (const configured of [ + process.env.VIEWER_CAD_PYTHONPATH, + process.env.CAD_PYTHONPATH, + process.env.VIEWER_CADPY_PYTHONPATH + ]) { + const value = String(configured || "").trim(); + if (value) { + pythonPathEntries.push(value); + } + } + for (const discovered of [ + findUpDirectory(path5.join("scripts", "packages", "cadpy", "src")), + findUpDirectory(path5.join("scripts", "packages")), + findUpDirectory(path5.join("viewer", "packages", "cadpy", "src")), + findUpDirectory(path5.join("packages", "cadpy", "src")), + path5.join(PACKAGE_ROOT, "vendor", "python"), + findUpDirectory(path5.join("runtime", "vendor", "python")), + findUpDirectory(path5.join("vendor", "python")) + ]) { + if (discovered) { + pythonPathEntries.push(discovered); + } + } + const existingPythonPath = String(process.env.PYTHONPATH || "").trim(); + if (existingPythonPath) { + pythonPathEntries.push(existingPythonPath); + } + return { + ...process.env, + ...pythonPathEntries.length ? { PYTHONPATH: pythonPathEntries.join(path5.delimiter) } : {} + }; +} +function ensurePythonStepTopologyArtifact({ + repoRoot, + stepPath, + sourcePath = "", + force = false, + skipStepWrite = false, + writeStepAfterArtifact = false, + resolveOnFirstResult = false, + verbose = false, + meshTolerance = null, + meshAngularTolerance = null +} = {}) { + const resolvedRepoRoot = path5.resolve(repoRoot || ""); + const resolvedStepPath = path5.resolve(stepPath || ""); + const args = [ + "-m", + "cadpy.step_artifact", + "--repo-root", + resolvedRepoRoot, + "--step", + resolvedStepPath + ]; + const resolvedSourcePath = sourcePath ? path5.resolve(sourcePath) : ""; + if (resolvedSourcePath) { + args.push("--source-path", resolvedSourcePath); + } + if (force) { + args.push("--force"); + } + if (skipStepWrite) { + args.push("--skip-step-write"); + } + if (writeStepAfterArtifact) { + args.push("--write-step-after-artifact"); + } + if (meshTolerance !== null && meshTolerance !== void 0) { + args.push("--mesh-tolerance", String(meshTolerance)); + } + if (meshAngularTolerance !== null && meshAngularTolerance !== void 0) { + args.push("--mesh-angular-tolerance", String(meshAngularTolerance)); + } + if (verbose || process.env.VIEWER_STEP_ARTIFACT_VERBOSE === "1") { + args.push("--verbose"); + } + return new Promise((resolve) => { + let resolved = false; + const resolveOnce = (result) => { + if (resolved) { + return; + } + resolved = true; + resolve(result); + }; + const normalizeResult = (result) => { + if (result?.ok) { + result.stepPath = resolvedStepPath; + result.glbPath = inlineStepGlbArtifactPathForSource(resolvedStepPath); + } + return result; + }; + const maybeResolveEarly = () => { + if (!resolveOnFirstResult || resolved) { + return; + } + for (const line of stdout.split(/\r?\n/)) { + const trimmed = line.trim(); + if (!trimmed.startsWith("{")) { + continue; + } + try { + const result = normalizeResult(JSON.parse(trimmed)); + if (result?.ok) { + resolveOnce(result); + return; + } + } catch { + } + } + }; + const child = spawn(cadPythonExecutable(resolvedRepoRoot), args, { + cwd: resolvedRepoRoot, + env: cadPythonEnv(resolvedRepoRoot), + stdio: ["ignore", "pipe", "pipe"] + }); + let stdout = ""; + let stderr = ""; + child.stdout.setEncoding("utf8"); + child.stderr.setEncoding("utf8"); + child.stdout.on("data", (chunk) => { + stdout += chunk; + maybeResolveEarly(); + }); + child.stderr.on("data", (chunk) => { + stderr += chunk; + }); + child.on("error", (error) => { + resolveOnce({ + ok: false, + stepPath: resolvedStepPath, + error: error instanceof Error ? error.message : String(error) + }); + }); + child.on("close", (code) => { + const output = stdout.trim(); + const lastJsonLine = output.split(/\r?\n/).reverse().find((line) => line.trim().startsWith("{")); + if (code === 0 && lastJsonLine) { + try { + resolveOnce(normalizeResult(JSON.parse(lastJsonLine))); + return; + } catch { + } + } + resolveOnce({ + ok: false, + stepPath: resolvedStepPath, + exitCode: code, + error: (stderr || stdout || `STEP artifact generator exited with code ${code}`).trim() + }); + }); + }); +} + +// viewer/packages/cadjs/src/lib/step/stepArtifactCompiler.mjs +var STEP_SUFFIXES = /* @__PURE__ */ new Set([".step", ".stp"]); +function sameStemPythonGeneratorPath(stepPath) { + const extension = path6.extname(stepPath).toLowerCase(); + if (!STEP_SUFFIXES.has(extension)) { + return ""; + } + const candidatePath = path6.join( + path6.dirname(stepPath), + `${path6.basename(stepPath, extension)}.py` + ); + try { + return /\bgen_step\s*\(/.test(fs5.readFileSync(candidatePath, "utf-8")) ? candidatePath : ""; + } catch { + return ""; + } +} +function cadPathForStepSource2(repoRoot, sourcePath) { + const relativePath = repoRelativePath(repoRoot, sourcePath); + return relativePath.slice(0, -path6.extname(relativePath).length); +} +function canBuildStepArtifact(artifact) { + const code = String(artifact?.stepArtifact?.error?.code || ""); + return !artifact?.stepArtifact?.ok && [ + "missing_glb", + "missing_step_topology", + "missing_edge_topology", + "missing_surface_edge_attributes", + "missing_selector_topology", + "missing_source_path", + "missing_source_identity", + "stale_source_identity", + "unsupported_step_topology" + ].includes(code); +} +async function compileStepTopologyArtifact({ + repoRoot, + stepPath, + sourcePath = "", + targetPath = inlineStepGlbArtifactPathForSource(stepPath), + force = true, + skipStepWrite = false, + writeStepAfterArtifact = false, + meshTolerance = null, + meshAngularTolerance = null +} = {}) { + if (!repoRoot) { + throw new Error("repoRoot is required"); + } + if (!stepPath) { + throw new Error("stepPath is required"); + } + const resolvedRepoRoot = path6.resolve(repoRoot); + const resolvedStepPath = path6.resolve(stepPath); + const resolvedSourcePath = sourcePath ? path6.resolve(sourcePath) : ""; + const resolvedTargetPath = path6.resolve(targetPath); + const pythonResult = await ensurePythonStepTopologyArtifact({ + repoRoot: resolvedRepoRoot, + stepPath: resolvedStepPath, + sourcePath: resolvedSourcePath, + force, + skipStepWrite, + writeStepAfterArtifact, + resolveOnFirstResult: writeStepAfterArtifact, + meshTolerance, + meshAngularTolerance + }); + if (!pythonResult?.ok) { + throw new Error(pythonResult?.error || `Failed to generate STEP topology artifact: ${resolvedStepPath}`); + } + const pythonGlbPath = path6.resolve(pythonResult.glbPath || inlineStepGlbArtifactPathForSource(resolvedStepPath)); + if (pythonGlbPath !== resolvedTargetPath) { + fs5.mkdirSync(path6.dirname(resolvedTargetPath), { recursive: true }); + fs5.copyFileSync(pythonGlbPath, resolvedTargetPath); + } + return { + ...pythonResult, + ok: true, + stepPath: resolvedStepPath, + glbPath: resolvedTargetPath + }; +} +async function ensureStepTopologyArtifact({ + repoRoot, + stepPath, + sourcePath = "", + force = false, + skipStepWrite = false, + writeStepAfterArtifact = false, + meshTolerance = null, + meshAngularTolerance = null +} = {}) { + const resolvedRepoRoot = path6.resolve(repoRoot); + const resolvedStepPath = path6.resolve(stepPath); + const resolvedSourcePath = sourcePath ? path6.resolve(sourcePath) : ""; + const cadPath = cadPathForStepSource2(resolvedRepoRoot, resolvedStepPath); + const current = validateStepTopologyArtifact({ + repoRoot: resolvedRepoRoot, + sourcePath: resolvedStepPath, + cadPath + }); + const currentArtifactError = current.stepArtifact?.error && typeof current.stepArtifact.error === "object" ? current.stepArtifact.error : {}; + const currentSourceKind = String( + current.stepArtifact?.sourceKind || currentArtifactError.sourceKind || "" + ).trim().toLowerCase(); + const currentSourcePath = String( + current.stepArtifact?.sourcePath || currentArtifactError.sourcePath || "" + ).trim(); + const inferredSourcePath = resolvedSourcePath || (currentSourceKind === "python" && currentSourcePath ? path6.resolve(resolvedRepoRoot, currentSourcePath) : ""); + const resolvedSkipStepWrite = Boolean( + skipStepWrite || currentSourceKind === "python" || inferredSourcePath || sameStemPythonGeneratorPath(resolvedStepPath) + ); + const hasMeshOverride = meshTolerance !== null && meshTolerance !== void 0 || meshAngularTolerance !== null && meshAngularTolerance !== void 0; + if (!force && !hasMeshOverride && (current.stepArtifact?.ok || !current.stepArtifact?.ok && !canBuildStepArtifact(current))) { + return { + ok: Boolean(current.stepArtifact?.ok), + skipped: true, + reason: current.stepArtifact?.error?.code || "", + stepPath: resolvedStepPath, + glbPath: current.glbPath, + validation: current.stepArtifact + }; + } + const targetPath = inlineStepGlbArtifactPathForSource(resolvedStepPath); + const result = await compileStepTopologyArtifact({ + repoRoot: resolvedRepoRoot, + stepPath: resolvedStepPath, + sourcePath: inferredSourcePath || void 0, + targetPath, + force, + skipStepWrite: resolvedSkipStepWrite, + writeStepAfterArtifact: Boolean(writeStepAfterArtifact && resolvedSkipStepWrite), + meshTolerance, + meshAngularTolerance + }); + const next = validateStepTopologyArtifact({ + repoRoot: resolvedRepoRoot, + sourcePath: resolvedStepPath, + cadPath + }); + return { + ...result, + ok: Boolean(next.stepArtifact?.ok), + validation: next.stepArtifact + }; +} + +// viewer/src/server/localAssetBackend.mjs +function toPosixPath2(value) { + return String(value || "").split(path7.sep).join("/"); +} +function absoluteFileRef(filePath) { + return toPosixPath2(path7.resolve(filePath)); +} +function relativeFileRef(rootPath, filePath) { + return toPosixPath2(path7.relative(path7.resolve(rootPath), path7.resolve(filePath))); +} +function pathIsInsideOrEqual(childPath, parentPath) { + const relativePath = path7.relative(path7.resolve(parentPath), path7.resolve(childPath)); + return relativePath === "" || relativePath !== ".." && !relativePath.startsWith(`..${path7.sep}`) && !path7.isAbsolute(relativePath); +} +function normalizedFileRef(value) { + const raw = String(value || "").trim().replace(/\\/g, "/"); + if (!raw) { + return ""; + } + if (raw.includes("\0")) { + throw new Error("File path contains an invalid null byte"); + } + return path7.isAbsolute(raw) ? absoluteFileRef(raw) : raw.replace(/^\/+/, ""); +} +function normalizedAbsoluteDir(value) { + const raw = String(value || "").trim(); + if (!raw) { + return ""; + } + if (raw.includes("\0")) { + throw new Error("CAD Viewer directory contains an invalid null byte"); + } + if (!path7.isAbsolute(raw)) { + throw new Error("CAD Viewer ?dir= must be an absolute filesystem path"); + } + return path7.resolve(raw); +} +function requireDirectory(rootPath) { + let stats = null; + try { + stats = fs6.statSync(rootPath); + } catch { + throw new Error(`CAD Viewer directory not found: ${rootPath}`); + } + if (!stats.isDirectory()) { + throw new Error(`CAD Viewer directory is not a directory: ${rootPath}`); + } +} +function catalogEntryForFileRef(catalog, fileRef) { + const normalized = normalizedFileRef(fileRef); + if (!normalized || !Array.isArray(catalog?.entries)) { + return null; + } + return catalog.entries.find((entry) => normalizedFileRef(entry?.file) === normalized || normalizedFileRef(entry?.rootRelativeFile) === normalized) || null; +} +function ensurePathInsideRoot(filePath, resolvedRoot) { + if (!(filePath === resolvedRoot.rootPath || pathIsInside(filePath, resolvedRoot.rootPath))) { + throw new Error("Requested file is outside the active CAD Viewer root"); + } +} +function normalizedFileAssetKind(value) { + const asset = String(value || "output").trim().toLowerCase(); + if (asset === "asset") { + return "artifact"; + } + if (asset === "output" || asset === "source" || asset === "artifact") { + return asset; + } + throw new Error(`Unsupported file asset: ${asset || "(missing)"}`); +} +function fileHasGenStep2(filePath) { + try { + return /\bgen_step\s*\(/.test(fs6.readFileSync(filePath, "utf-8")); + } catch { + return false; + } +} +function sameStemPythonGeneratorPath2(stepPath) { + const extension = path7.extname(stepPath).toLowerCase(); + if (extension !== ".step" && extension !== ".stp") { + return ""; + } + const candidate = path7.join(path7.dirname(stepPath), `${path7.basename(stepPath, extension)}.py`); + return fileHasGenStep2(candidate) ? candidate : ""; +} +function stepArtifactGenerationError(result) { + const directError = String(result?.error || "").trim(); + if (directError) { + return directError; + } + const validationError = result?.validation?.error; + const validationMessage = String(validationError?.message || "").trim(); + if (validationMessage) { + return validationMessage; + } + const reason = String(result?.reason || "").trim(); + if (reason) { + return `STEP artifact was not generated: ${reason}`; + } + return "STEP artifact generation failed."; +} +function entryIsPythonBackedStep(entry) { + const artifactSourceKind = String(entry?.artifact?.sourceKind || "").trim().toLowerCase(); + if (artifactSourceKind === "python") { + return true; + } + const sourceKind = String(entry?.sourceKind || entry?.stepSourceKind || "").trim().toLowerCase(); + if (sourceKind === "python") { + return true; + } + const sourcePath = String(entry?.source?.sourcePath || entry?.source?.file || "").trim().toLowerCase(); + return sourcePath.endsWith(".py"); +} +function stepFileHasPythonSourceMetadata(stepPath) { + try { + const metadata = readTextToCadStepMetadataFile(stepPath); + return String(metadata?.sourcePath || "").trim().toLowerCase().endsWith(".py"); + } catch { + return false; + } +} +function contentTypeForPath(filePath) { + const extension = path7.extname(filePath).toLowerCase(); + if (extension === ".js" || extension === ".mjs") { + return "text/javascript; charset=utf-8"; + } + if (extension === ".json") { + return "application/json; charset=utf-8"; + } + if (extension === ".wasm") { + return "application/wasm"; + } + if (extension === ".glb") { + return "model/gltf-binary"; + } + if (extension === ".stl") { + return "model/stl"; + } + if (extension === ".3mf") { + return "model/3mf"; + } + if (extension === ".step" || extension === ".stp") { + return "application/step"; + } + if (extension === ".dxf") { + return "application/dxf"; + } + if (extension === ".gcode" || extension === ".py") { + return "text/plain; charset=utf-8"; + } + if (extension === ".urdf" || extension === ".srdf" || extension === ".sdf") { + return "application/xml; charset=utf-8"; + } + if (extension === ".svg") { + return "image/svg+xml"; + } + if (extension === ".png") { + return "image/png"; + } + return "application/octet-stream"; +} +function defaultSourceFileOpener(filePath) { + let command = ""; + let args = []; + if (process.platform === "darwin") { + command = "open"; + args = ["-R", filePath]; + } else if (process.platform === "win32") { + command = "explorer.exe"; + args = [`/select,${filePath}`]; + } else { + command = "xdg-open"; + args = [path7.dirname(filePath)]; + } + const child = spawn2(command, args, { + detached: true, + stdio: "ignore" + }); + child.unref(); + return { + command + }; +} +function emptyCatalog() { + return { + schemaVersion: CAD_CATALOG_SCHEMA_VERSION, + entries: [] + }; +} +function normalizeCatalog(catalog) { + return { + schemaVersion: CAD_CATALOG_SCHEMA_VERSION, + entries: Array.isArray(catalog?.entries) ? catalog.entries : [] + }; +} +function queryValueFromAssetUrl(rawUrl, name) { + try { + return new URL(String(rawUrl || ""), "http://cad.local").searchParams.get(name) || ""; + } catch { + return ""; + } +} +function assetPathFromCatalogUrl(scanRepoRoot, rawUrl) { + const text = String(rawUrl || "").trim(); + if (!text) { + return ""; + } + try { + const url = new URL(text, "http://cad.local"); + const explicitFile = url.searchParams.get("file"); + if (explicitFile) { + return path7.resolve(explicitFile); + } + return path7.resolve(scanRepoRoot, decodeURIComponent(url.pathname).replace(/^\/+/, "")); + } catch { + return path7.resolve(scanRepoRoot, text.replace(/[?#].*$/, "").replace(/^\/+/, "")); + } +} +function localAssetUrlForPath(filePath, rawUrl = "") { + const url = new URL("/__cad/asset", "http://cad.local"); + url.searchParams.set("file", absoluteFileRef(filePath)); + const version = queryValueFromAssetUrl(rawUrl, "v"); + if (version) { + url.searchParams.set("v", version); + } + return `${url.pathname}${url.search}`; +} +function absolutePathFromCatalogValue(scanRepoRoot, value) { + const text = String(value || "").trim(); + if (!text) { + return ""; + } + if (path7.isAbsolute(text)) { + return path7.resolve(text); + } + return path7.resolve(scanRepoRoot, text); +} +function absolutizeArtifact(artifact, scanRepoRoot) { + if (!artifact || typeof artifact !== "object") { + return artifact; + } + const next = { ...artifact }; + for (const key of ["stepPath", "glbPath", "sourcePath", "cadPath"]) { + if (next[key]) { + next[key] = absoluteFileRef(absolutePathFromCatalogValue(scanRepoRoot, next[key])); + } + } + return next; +} +function absolutizeSource(source, scanRepoRoot) { + if (!source || typeof source !== "object") { + return source; + } + const next = { ...source }; + for (const key of ["file", "path", "sourcePath"]) { + if (next[key]) { + next[key] = absoluteFileRef(absolutePathFromCatalogValue(scanRepoRoot, next[key])); + } + } + return next; +} +function absolutizeSourceStatus(sourceStatus, scanRepoRoot) { + if (!sourceStatus || typeof sourceStatus !== "object") { + return sourceStatus; + } + const next = { ...sourceStatus }; + for (const key of ["sourcePath", "stepPath", "glbPath"]) { + if (next[key]) { + next[key] = absoluteFileRef(absolutePathFromCatalogValue(scanRepoRoot, next[key])); + } + } + return next; +} +function absolutizeCatalogEntry(entry, { rootPath, scanRepoRoot }) { + if (!entry || typeof entry !== "object") { + return entry; + } + const outputPath = path7.resolve(rootPath, String(entry.file || "")); + const next = { + ...entry, + file: absoluteFileRef(outputPath), + rootRelativeFile: relativeFileRef(rootPath, outputPath) + }; + if (entry.url) { + const assetPath = assetPathFromCatalogUrl(scanRepoRoot, entry.url); + next.url = localAssetUrlForPath(assetPath, entry.url); + next.assetFile = absoluteFileRef(assetPath); + } + if (entry.moduleUrl) { + const modulePath = assetPathFromCatalogUrl(scanRepoRoot, entry.moduleUrl); + next.moduleUrl = localAssetUrlForPath(modulePath, entry.moduleUrl); + next.moduleFile = absoluteFileRef(modulePath); + } + if (entry.source) { + next.source = absolutizeSource(entry.source, scanRepoRoot); + } + if (entry.sourceStatus) { + next.sourceStatus = absolutizeSourceStatus(entry.sourceStatus, scanRepoRoot); + } + if (entry.artifact) { + next.artifact = absolutizeArtifact(entry.artifact, scanRepoRoot); + } + if (entry.relations && typeof entry.relations === "object") { + next.relations = { ...entry.relations }; + for (const [key, relation] of Object.entries(entry.relations)) { + if (!relation || typeof relation !== "object") { + continue; + } + const relationFilePath = path7.resolve(rootPath, String(relation.file || "")); + const nextRelation = { + ...relation, + file: absoluteFileRef(relationFilePath), + rootRelativeFile: relativeFileRef(rootPath, relationFilePath) + }; + if (relation.url) { + const relationAssetPath = assetPathFromCatalogUrl(scanRepoRoot, relation.url); + nextRelation.url = localAssetUrlForPath(relationAssetPath, relation.url); + nextRelation.assetFile = absoluteFileRef(relationAssetPath); + } + next.relations[key] = nextRelation; + } + } + return next; +} +function absolutizeCatalog(catalog, context) { + return normalizeCatalog({ + ...catalog, + entries: (Array.isArray(catalog?.entries) ? catalog.entries : []).map((entry) => absolutizeCatalogEntry(entry, context)).filter(Boolean) + }); +} +function absolutizeGenerationStatus(status, rootPath) { + const files = {}; + for (const [file, value] of Object.entries(status?.files || {})) { + const absolute = absoluteFileRef(path7.resolve(rootPath, String(file || ""))); + files[absolute] = { + ...value, + file: absolute, + rootRelativeFile: relativeFileRef(rootPath, absolute) + }; + } + return { + schemaVersion: 1, + runs: (Array.isArray(status?.runs) ? status.runs : []).map((run) => ({ + ...run, + files: (Array.isArray(run?.files) ? run.files : []).map((file) => absoluteFileRef(path7.resolve(rootPath, String(file || "")))).filter(Boolean) + })), + files + }; +} +function createLocalAssetBackend({ + workspaceRoot: workspaceRoot2 = process.cwd(), + rootDir = "", + defaultFile = "", + githubUrl = "", + stepArtifactGenerator = ensureStepTopologyArtifact, + sourceFileOpener = defaultSourceFileOpener +} = {}) { + const baseWorkspaceRoot = path7.resolve(workspaceRoot2 || process.cwd()); + const defaultRootDir = rootDir ? absoluteFileRef(path7.isAbsolute(String(rootDir)) ? rootDir : path7.resolve(baseWorkspaceRoot, String(rootDir))) : ""; + const catalogCache = /* @__PURE__ */ new Map(); + function resolveRoot(rootDir2 = defaultRootDir) { + const rootPath = normalizedAbsoluteDir(rootDir2 || defaultRootDir); + if (!rootPath) { + throw new Error("CAD Viewer local filesystem requests must include an absolute ?dir= path"); + } + requireDirectory(rootPath); + return { + dir: absoluteFileRef(rootPath), + rootPath, + rootName: path7.basename(rootPath) + }; + } + function resolveRootForFile(fileRef = "") { + const normalized = normalizedFileRef(fileRef); + if (!normalized || !path7.isAbsolute(normalized)) { + throw new Error("CAD Viewer requests without ?dir= must include an absolute ?file= path"); + } + const rootPath = path7.dirname(path7.resolve(normalized)); + return { + dir: "", + rootPath, + rootName: path7.basename(rootPath) + }; + } + function resolveRequestRoot({ rootDir: rootDir2 = defaultRootDir, fileRef = "" } = {}) { + return rootDir2 || defaultRootDir ? resolveRoot(rootDir2 || defaultRootDir) : resolveRootForFile(fileRef); + } + function scanContextForRoot(resolvedRoot) { + const rootPath = path7.resolve(resolvedRoot.rootPath); + const scanRepoRoot = pathIsInsideOrEqual(rootPath, baseWorkspaceRoot) ? baseWorkspaceRoot : rootPath; + const scanRootDir = scanRepoRoot === rootPath ? "" : toPosixPath2(path7.relative(scanRepoRoot, rootPath)); + return { + rootPath, + scanRepoRoot, + scanRootDir + }; + } + function readCatalog({ rootDir: nextRootDir = defaultRootDir, fileRef = "" } = {}) { + const normalizedDir = nextRootDir ? absoluteFileRef(normalizedAbsoluteDir(nextRootDir)) : ""; + const normalizedFile = normalizedFileRef(fileRef); + const cacheKey = normalizedDir ? `dir:${normalizedDir}` : normalizedFile ? `file:${normalizedFile}` : "empty"; + if (!catalogCache.has(cacheKey)) { + return refreshCatalog({ rootDir: normalizedDir, fileRef: normalizedFile }); + } + if (normalizedDir && normalizedFile) { + const resolvedRoot = resolveRoot(normalizedDir); + const requestedPath = filePathFromRef(normalizedFile, resolvedRoot); + if (requestedPath === resolvedRoot.rootPath || pathIsInside(requestedPath, resolvedRoot.rootPath)) { + return refreshCatalogForPath({ rootDir: resolvedRoot.dir, filePath: requestedPath }); + } + } + return catalogCache.get(cacheKey); + } + function readCatalogSafe({ rootDir: nextRootDir = defaultRootDir, fileRef = "" } = {}) { + try { + return readCatalog({ rootDir: nextRootDir, fileRef }); + } catch { + return emptyCatalog(); + } + } + function refreshCatalog({ rootDir: nextRootDir = defaultRootDir, fileRef = "" } = {}) { + if (!nextRootDir && !fileRef) { + catalogCache.set("empty", emptyCatalog()); + return catalogCache.get("empty"); + } + const resolvedRoot = nextRootDir ? resolveRoot(nextRootDir) : resolveRootForFile(fileRef); + const context = scanContextForRoot(resolvedRoot); + const rawCatalog = nextRootDir ? scanCadDirectory({ + repoRoot: context.scanRepoRoot, + rootDir: context.scanRootDir, + includeArtifactStatus: false + }) : normalizeCatalog({ + entries: [ + scanCadFile({ + repoRoot: context.scanRepoRoot, + rootDir: context.scanRootDir, + filePath: path7.resolve(normalizedFileRef(fileRef)), + includeArtifactStatus: false + }) + ].filter(Boolean) + }); + const catalog = absolutizeCatalog(rawCatalog, context); + catalogCache.set(nextRootDir ? `dir:${resolvedRoot.dir}` : `file:${normalizedFileRef(fileRef)}`, catalog); + return catalog; + } + function replaceCatalogEntry(catalog, fileRef, nextEntry) { + const normalizedRef = normalizedFileRef(fileRef); + if (!normalizedRef) { + return normalizeCatalog(catalog); + } + const previousEntries = Array.isArray(catalog?.entries) ? catalog.entries : []; + const entries = previousEntries.filter((entry) => normalizedFileRef(entry?.file) !== normalizedRef); + if (nextEntry) { + entries.push(nextEntry); + } + return normalizeCatalog({ + ...catalog, + entries: sortCatalogEntries(entries) + }); + } + function refreshCatalogEntryForFile({ rootDir: nextRootDir = defaultRootDir, filePath } = {}) { + const resolvedRoot = resolveRoot(nextRootDir); + const context = scanContextForRoot(resolvedRoot); + const currentCatalog = readCatalog({ rootDir: resolvedRoot.dir }); + const rawEntry = scanCadFile({ + repoRoot: context.scanRepoRoot, + rootDir: context.scanRootDir, + filePath, + includeArtifactStatus: false + }); + const nextEntry = rawEntry ? absolutizeCatalogEntry(rawEntry, context) : null; + const rawFileRef = rawEntry?.file || catalogFileRefForPath({ + repoRoot: context.scanRepoRoot, + rootDir: context.scanRootDir, + filePath + }); + const fileRef = nextEntry?.file || (rawFileRef ? absoluteFileRef(path7.resolve(resolvedRoot.rootPath, rawFileRef)) : absoluteFileRef(filePath)); + const nextCatalog = replaceCatalogEntry(currentCatalog, fileRef, nextEntry); + catalogCache.set(`dir:${resolvedRoot.dir}`, nextCatalog); + return nextCatalog; + } + function refreshCatalogForPythonSource({ rootDir: nextRootDir = defaultRootDir, filePath } = {}) { + const resolvedRoot = resolveRoot(nextRootDir); + const resolvedFilePath = path7.resolve(filePath); + const sourcePath = absoluteFileRef(resolvedFilePath); + const currentCatalog = readCatalog({ rootDir: resolvedRoot.dir }); + const matchingFileRefs = new Set( + currentCatalog.entries.filter((entry) => normalizedFileRef(entry?.source?.sourcePath || entry?.source?.file) === sourcePath).map((entry) => normalizedFileRef(entry.file)).filter(Boolean) + ); + const sameStemStepPath = path7.join(path7.dirname(resolvedFilePath), `${path7.basename(resolvedFilePath, ".py")}.step`); + if (sameStemStepPath === resolvedRoot.rootPath || pathIsInside(sameStemStepPath, resolvedRoot.rootPath)) { + const context2 = scanContextForRoot(resolvedRoot); + const rawSameStemEntry = scanCadFile({ + repoRoot: context2.scanRepoRoot, + rootDir: context2.scanRootDir, + filePath: sameStemStepPath, + includeArtifactStatus: false + }); + const sameStemEntry = rawSameStemEntry ? absolutizeCatalogEntry(rawSameStemEntry, context2) : null; + const sameStemFileRef = sameStemEntry?.file || absoluteFileRef(sameStemStepPath); + if (sameStemEntry || catalogEntryForFileRef(currentCatalog, sameStemFileRef)) { + matchingFileRefs.add(sameStemFileRef); + } + } + if (!matchingFileRefs.size) { + return refreshCatalog({ rootDir: resolvedRoot.dir }); + } + let nextCatalog = currentCatalog; + const context = scanContextForRoot(resolvedRoot); + for (const fileRef of matchingFileRefs) { + const outputPath = path7.resolve(fileRef); + const rawEntry = scanCadFile({ + repoRoot: context.scanRepoRoot, + rootDir: context.scanRootDir, + filePath: outputPath, + includeArtifactStatus: false + }); + nextCatalog = replaceCatalogEntry( + nextCatalog, + fileRef, + rawEntry ? absolutizeCatalogEntry(rawEntry, context) : null + ); + } + catalogCache.set(`dir:${resolvedRoot.dir}`, nextCatalog); + return nextCatalog; + } + function refreshCatalogForPath({ rootDir: nextRootDir = defaultRootDir, filePath } = {}) { + const extension = path7.extname(String(filePath || "")).toLowerCase(); + if (extension === ".py") { + return refreshCatalogForPythonSource({ rootDir: nextRootDir, filePath }); + } + return refreshCatalogEntryForFile({ rootDir: nextRootDir, filePath }); + } + function filePathFromRef(fileRef, resolvedRoot) { + const normalized = normalizedFileRef(fileRef); + if (!normalized) { + return ""; + } + return path7.isAbsolute(normalized) ? path7.resolve(normalized) : path7.resolve(resolvedRoot.rootPath, normalized); + } + function resolveStepSource(fileRef, { resolvedRoot = resolveRequestRoot({ fileRef }), catalog = null } = {}) { + const normalizedRef = normalizedFileRef(fileRef); + if (!normalizedRef) { + throw new Error("Missing STEP file"); + } + const candidates = path7.isAbsolute(normalizedRef) ? [ + path7.resolve(normalizedRef), + path7.resolve(resolvedRoot.rootPath, normalizedRef.replace(/^\/+/, "")) + ] : [ + path7.resolve(resolvedRoot.rootPath, normalizedRef) + ]; + for (const candidatePath2 of [...new Set(candidates)]) { + if ((candidatePath2 === resolvedRoot.rootPath || pathIsInside(candidatePath2, resolvedRoot.rootPath)) && fs6.existsSync(candidatePath2)) { + const extension = path7.extname(candidatePath2).toLowerCase(); + if (extension === ".py") { + if (!fileHasGenStep2(candidatePath2)) { + throw new Error(`Python generator is not a gen_step() source: ${normalizedRef}`); + } + return { + stepPath: path7.join(path7.dirname(candidatePath2), `${path7.basename(candidatePath2, extension)}.step`), + sourcePath: candidatePath2, + skipStepWrite: true + }; + } + if (extension !== ".step" && extension !== ".stp") { + throw new Error("Only STEP/STP sources or same-stem Python generators can generate STEP topology artifacts"); + } + const generatorPath = sameStemPythonGeneratorPath2(candidatePath2); + return { + stepPath: candidatePath2, + sourcePath: generatorPath, + skipStepWrite: Boolean(generatorPath) + }; + } + } + const candidatePath = candidates.find((candidate) => candidate === resolvedRoot.rootPath || pathIsInside(candidate, resolvedRoot.rootPath)); + if (candidatePath) { + const extension = path7.extname(candidatePath).toLowerCase(); + const generatorPath = sameStemPythonGeneratorPath2(candidatePath); + if ((extension === ".step" || extension === ".stp") && generatorPath) { + return { stepPath: candidatePath, sourcePath: generatorPath, skipStepWrite: true }; + } + throw new Error(`STEP file not found: ${normalizedRef}`); + } + throw new Error("Requested STEP file is outside the active CAD Viewer root"); + } + function resolveStepSourceStatus(fileRef, { resolvedRoot = resolveRequestRoot({ fileRef }), catalog = null } = {}) { + try { + return resolveStepSource(fileRef, { resolvedRoot, catalog }); + } catch (error) { + const normalizedRef = normalizedFileRef(fileRef); + if (!normalizedRef) { + throw error; + } + const candidatePath = filePathFromRef(normalizedRef, resolvedRoot); + if (!(candidatePath === resolvedRoot.rootPath || pathIsInside(candidatePath, resolvedRoot.rootPath))) { + throw error; + } + const extension = path7.extname(candidatePath).toLowerCase(); + if (extension !== ".step" && extension !== ".stp") { + throw error; + } + const generatorPath = sameStemPythonGeneratorPath2(candidatePath); + return { + stepPath: candidatePath, + sourcePath: generatorPath, + skipStepWrite: Boolean(generatorPath) + }; + } + } + function requireCatalogEntryForFileRef(fileRef, { + resolvedRoot = resolveRequestRoot({ fileRef }), + rootDir: nextRootDir = defaultRootDir, + catalog = null + } = {}) { + const normalizedRef = normalizedFileRef(fileRef); + if (!normalizedRef) { + throw new Error("Missing file"); + } + const currentCatalog = catalog || readCatalogSafe({ rootDir: nextRootDir, fileRef: normalizedRef }); + const entry = catalogEntryForFileRef(currentCatalog, normalizedRef); + if (!entry) { + throw new Error(`CAD catalog entry not found: ${normalizedRef}`); + } + return { entry, relativeFileRef: normalizedRef, currentCatalog, resolvedRoot }; + } + function resolveOutputFilePath(fileRef, options = {}) { + const { entry, relativeFileRef: relativeFileRef2, resolvedRoot } = requireCatalogEntryForFileRef(fileRef, options); + const outputRef = normalizedFileRef(entry?.file || relativeFileRef2); + const outputPath = filePathFromRef(outputRef, resolvedRoot); + ensurePathInsideRoot(outputPath, resolvedRoot); + if (!fs6.existsSync(outputPath) || !fs6.statSync(outputPath).isFile()) { + throw new Error(`Output file not found: ${outputRef || relativeFileRef2}`); + } + return outputPath; + } + function artifactFileRefFromEntry2(entry) { + const explicitAssetFile = normalizedFileRef(entry?.assetFile || entry?.asset?.file || entry?.artifactFile || entry?.artifact?.file); + if (explicitAssetFile) { + return explicitAssetFile; + } + const rawUrl = String(entry?.url || "").trim(); + if (!rawUrl) { + throw new Error("Artifact asset is not available for this file"); + } + const assetPath = assetPathFromCatalogUrl("/", rawUrl); + return absoluteFileRef(assetPath); + } + function resolveArtifactFilePath(fileRef, options = {}) { + const { entry, relativeFileRef: relativeFileRef2, resolvedRoot } = requireCatalogEntryForFileRef(fileRef, options); + const artifactRef = artifactFileRefFromEntry2(entry); + if (!artifactRef) { + throw new Error(`Artifact asset is not available for ${relativeFileRef2}`); + } + const artifactPath = filePathFromRef(artifactRef, resolvedRoot); + ensurePathInsideRoot(artifactPath, resolvedRoot); + if (!fs6.existsSync(artifactPath) || !fs6.statSync(artifactPath).isFile()) { + throw new Error(`Artifact file not found: ${artifactRef}`); + } + return artifactPath; + } + function resolveSourceCodeFilePath(fileRef, options = {}) { + const { entry, relativeFileRef: relativeFileRef2, currentCatalog, resolvedRoot } = requireCatalogEntryForFileRef(fileRef, options); + const explicitSourceRef = normalizedFileRef(entry?.source?.file || entry?.sourceFile || ""); + if (explicitSourceRef) { + const sourceCandidates = [ + filePathFromRef(explicitSourceRef, resolvedRoot), + path7.resolve(baseWorkspaceRoot, explicitSourceRef) + ]; + for (const sourcePath of [...new Set(sourceCandidates)]) { + if ((sourcePath === resolvedRoot.rootPath || pathIsInside(sourcePath, resolvedRoot.rootPath)) && fs6.existsSync(sourcePath) && fs6.statSync(sourcePath).isFile()) { + return sourcePath; + } + } + } + const extension = path7.extname(relativeFileRef2).toLowerCase(); + if (extension === ".step" || extension === ".stp") { + const { stepPath, sourcePath } = resolveStepSourceStatus(relativeFileRef2, { resolvedRoot, catalog: currentCatalog }); + if (sourcePath && fs6.existsSync(sourcePath) && fs6.statSync(sourcePath).isFile()) { + ensurePathInsideRoot(sourcePath, resolvedRoot); + return sourcePath; + } + ensurePathInsideRoot(stepPath, resolvedRoot); + } + throw new Error(`Source code is not available for ${relativeFileRef2}`); + } + function resolveFileAssetAccess({ + fileRef, + asset = "output", + resolvedRoot = resolveRequestRoot({ fileRef }), + rootDir: nextRootDir = defaultRootDir, + catalog = null + } = {}) { + const assetKind = normalizedFileAssetKind(asset); + const filePath = assetKind === "source" ? resolveSourceCodeFilePath(fileRef, { resolvedRoot, rootDir: nextRootDir, catalog }) : assetKind === "artifact" ? resolveArtifactFilePath(fileRef, { resolvedRoot, rootDir: nextRootDir, catalog }) : resolveOutputFilePath(fileRef, { resolvedRoot, rootDir: nextRootDir, catalog }); + return { + asset: assetKind, + file: absoluteFileRef(filePath), + rootRelativeFile: relativeFileRef(resolvedRoot.rootPath, filePath), + path: filePath, + filename: path7.basename(filePath), + contentType: contentTypeForPath(filePath) + }; + } + async function openFileAsset(request = {}) { + const access = resolveFileAssetAccess(request); + await sourceFileOpener(access.path); + return { + asset: access.asset, + file: access.file, + filename: access.filename, + opened: true + }; + } + function resolveSourceFileAccess(request = {}) { + return resolveFileAssetAccess({ ...request, asset: "source" }); + } + async function openSourceFile(request = {}) { + return openFileAsset({ ...request, asset: "source" }); + } + async function generateStepArtifact({ fileRef, force = false, resolvedRoot = resolveRequestRoot({ fileRef }), catalog = null } = {}) { + const { stepPath, sourcePath, skipStepWrite } = resolveStepSource(fileRef, { resolvedRoot, catalog }); + const normalizedRef = normalizedFileRef(fileRef); + const currentCatalog = catalog || readCatalogSafe({ rootDir: resolvedRoot.dir, fileRef: normalizedRef }); + const entry = catalogEntryForFileRef(currentCatalog, normalizedRef); + if (sourcePath || entryIsPythonBackedStep(entry) || stepFileHasPythonSourceMetadata(stepPath)) { + throw new Error( + "CAD Viewer only regenerates GLB artifacts for imported STEP files. Regenerate Python-backed STEP files with their generator script." + ); + } + const context = scanContextForRoot(resolvedRoot); + const result = await stepArtifactGenerator({ + repoRoot: context.scanRepoRoot, + stepPath, + sourcePath, + force, + skipStepWrite, + writeStepAfterArtifact: Boolean(skipStepWrite) + }); + return { + ok: Boolean(result?.ok), + error: result?.ok ? "" : stepArtifactGenerationError(result), + result, + stepPath + }; + } + function readStepSourceStatusForFile({ fileRef, resolvedRoot = resolveRequestRoot({ fileRef }), catalog = null } = {}) { + const { stepPath, sourcePath } = resolveStepSourceStatus(fileRef, { resolvedRoot, catalog }); + const context = scanContextForRoot(resolvedRoot); + const status = readStepSourceStatus({ + repoRoot: context.scanRepoRoot, + stepPath, + pythonSourcePath: sourcePath + }); + return absolutizeSourceStatus({ + ...status, + ...status?.artifact ? { artifact: absolutizeArtifact(status.artifact, context.scanRepoRoot) } : {} + }, context.scanRepoRoot); + } + function readGeneratorStatus({ rootDir: nextRootDir = defaultRootDir } = {}) { + if (!nextRootDir) { + return { + schemaVersion: 1, + runs: [], + files: {} + }; + } + const resolvedRoot = resolveRoot(nextRootDir); + const context = scanContextForRoot(resolvedRoot); + return absolutizeGenerationStatus(readGenerationStatus({ + repoRoot: context.scanRepoRoot, + rootDir: context.scanRootDir + }), resolvedRoot.rootPath); + } + function generationStatusDir2(rootDir2 = defaultRootDir) { + const resolvedRoot = resolveRoot(rootDir2); + const context = scanContextForRoot(resolvedRoot); + return generationStatusDir(context.scanRepoRoot, context.scanRootDir); + } + function isGenerationStatusPath(filePath, rootDir2 = defaultRootDir) { + if (!rootDir2) { + return false; + } + const resolvedRoot = resolveRoot(rootDir2); + const resolvedPath = path7.resolve(filePath); + const name = path7.basename(resolvedPath); + return (resolvedPath === resolvedRoot.rootPath || pathIsInside(resolvedPath, resolvedRoot.rootPath)) && name.startsWith(".") && name.endsWith(".generation.lock.json"); + } + function entryForSourcePath(catalog, resolvedRoot, sourcePath) { + const fileRef = absoluteFileRef(sourcePath); + return Array.isArray(catalog?.entries) ? catalog.entries.find((entry) => normalizedFileRef(entry?.file) === fileRef) || null : null; + } + function assetPathForFileRef(fileRef, { resolvedRoot = null, rootDir: rootDir2 = "" } = {}) { + const normalizedRef = normalizedFileRef(fileRef); + if (!normalizedRef || !path7.isAbsolute(normalizedRef)) { + return null; + } + const candidatePath = path7.resolve(normalizedRef); + if (!isServedCadAsset(candidatePath)) { + return null; + } + const activeRoot = resolvedRoot || (rootDir2 ? resolveRoot(rootDir2) : null); + if (activeRoot && !(candidatePath === activeRoot.rootPath || pathIsInside(candidatePath, activeRoot.rootPath))) { + const error = new Error("Forbidden"); + error.statusCode = 403; + throw error; + } + return candidatePath; + } + async function writeAsset({ fileRef, body, resolvedRoot = resolveRequestRoot({ fileRef }) } = {}) { + const normalizedRef = normalizedFileRef(fileRef); + if (!normalizedRef) { + throw new Error("Missing asset path"); + } + const filePath = filePathFromRef(normalizedRef, resolvedRoot); + if (!(filePath === resolvedRoot.rootPath || pathIsInside(filePath, resolvedRoot.rootPath))) { + throw new Error("Asset writes must stay inside the active CAD Viewer root"); + } + if (!isServedCadAsset(filePath)) { + throw new Error(`Unsupported CAD Viewer asset write: ${normalizedRef}`); + } + const bytes2 = Buffer.isBuffer(body) ? body : Buffer.from(body || ""); + fs6.mkdirSync(path7.dirname(filePath), { recursive: true }); + fs6.writeFileSync(filePath, bytes2); + return { + path: filePath, + bytes: bytes2.length, + contentType: contentTypeForPath(filePath) + }; + } + return { + kind: "local-fs", + canGenerateStepArtifacts: true, + repoRoot: baseWorkspaceRoot, + rootDir: "", + defaultFile, + githubUrl, + resolveRoot, + resolveRequestRoot, + readCatalog, + readCatalogSafe, + refreshCatalog, + refreshCatalogForPath, + resolveStepSource, + readStepSourceStatus: readStepSourceStatusForFile, + resolveFileAssetAccess, + openFileAsset, + resolveSourceFileAccess, + openSourceFile, + readGenerationStatus: readGeneratorStatus, + generationStatusDir: generationStatusDir2, + isGenerationStatusPath, + generateStepArtifact, + entryForSourcePath, + assetPathForFileRef, + writeAsset, + contentTypeForPath + }; +} + +// viewer/src/server/httpHandlers.mjs +import fs7 from "node:fs"; +import path8 from "node:path"; +var STATIC_CONTENT_TYPES = /* @__PURE__ */ new Map([ + [".css", "text/css; charset=utf-8"], + [".html", "text/html; charset=utf-8"], + [".ico", "image/x-icon"], + [".js", "text/javascript; charset=utf-8"], + [".json", "application/json; charset=utf-8"], + [".map", "application/json; charset=utf-8"], + [".svg", "image/svg+xml"], + [".wasm", "application/wasm"] +]); +function contentTypeForStaticAsset(filePath) { + return STATIC_CONTENT_TYPES.get(path8.extname(String(filePath || "")).toLowerCase()) || ""; +} +function sendJson(res, statusCode, payload) { + res.statusCode = statusCode; + res.setHeader("content-type", "application/json; charset=utf-8"); + res.setHeader("cache-control", "no-store"); + res.end(JSON.stringify(payload)); +} +function downloadFilename(value) { + const rawFilename = path8.basename(String(value || "").replace(/\\/g, "/")) || "download"; + return rawFilename.replace(/[\x00-\x1f"\\]/g, "_"); +} +function encodeContentDispositionFilename(value) { + return encodeURIComponent(value).replace(/['()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`); +} +function attachmentContentDisposition(filename) { + const safeFilename = downloadFilename(filename); + const quotedFilename = safeFilename.replace(/[^\x20-\x7e]/g, "_"); + return `attachment; filename="${quotedFilename}"; filename*=UTF-8''${encodeContentDispositionFilename(safeFilename)}`; +} +function errorMessage(error) { + return error instanceof Error ? error.message : String(error); +} +function requestRootDir(requestUrl) { + return String(requestUrl?.searchParams?.get("dir") || "").trim(); +} +function requestFileRef(requestUrl) { + return String(requestUrl?.searchParams?.get("file") || "").trim(); +} +function requestHeader(req, name) { + const headers = req?.headers || {}; + const value = headers[String(name || "").toLowerCase()]; + return Array.isArray(value) ? value[0] : String(value || ""); +} +function requestRefererUrl(req) { + const value = requestHeader(req, "referer") || requestHeader(req, "referrer"); + if (!value) { + return null; + } + try { + return new URL(value, "http://localhost"); + } catch { + return null; + } +} +function siblingFileRef(sourceFileRef, relativeFileRef2) { + const source = String(sourceFileRef || "").replace(/\\/g, "/"); + const relative = String(relativeFileRef2 || "").replace(/\\/g, "/").replace(/^\/+/g, ""); + if (!source || !relative) { + return ""; + } + if (path8.isAbsolute(source)) { + return path8.resolve(path8.dirname(source), relative); + } + const sourceDir = path8.posix.dirname(source); + return path8.posix.normalize(path8.posix.join(sourceDir === "." ? "" : sourceDir, relative)); +} +function legacyCadAssetFileRef(requestUrl, req) { + if (!requestUrl.pathname.startsWith("/__cad/") || requestUrl.pathname === "/__cad/asset") { + return ""; + } + const relativePath = decodeURIComponent(requestUrl.pathname.slice("/__cad/".length)); + if (!relativePath || !path8.extname(relativePath)) { + return ""; + } + const refererUrl = requestRefererUrl(req); + return siblingFileRef(requestFileRef(refererUrl), relativePath); +} +function fileAssetRequest(backend2, requestUrl, { + rootDir, + catalog +} = {}) { + const fileRef = requestFileRef(requestUrl); + const request = { + fileRef, + asset: requestUrl.searchParams.get("asset") || "output", + rootDir, + catalog + }; + if (typeof backend2.resolveRequestRoot === "function") { + request.resolvedRoot = backend2.resolveRequestRoot({ rootDir, fileRef }); + } else if (typeof backend2.resolveRoot === "function" && rootDir) { + request.resolvedRoot = backend2.resolveRoot(rootDir); + } + return request; +} +function sendBufferDownload(res, { + body, + filename, + contentType +} = {}) { + const bytes2 = Buffer.isBuffer(body) ? body : Buffer.from(body || ""); + res.statusCode = 200; + res.setHeader("content-type", contentType || "application/octet-stream"); + res.setHeader("cache-control", "no-store"); + res.setHeader("content-disposition", attachmentContentDisposition(filename)); + res.setHeader("content-length", String(bytes2.length)); + res.end(bytes2); +} +function serveStaticFile(filePath, req, res, next, { contentType, headers = {} } = {}) { + fs7.stat(filePath, (error, stats) => { + if (res.destroyed) { + return; + } + if (error || !stats.isFile()) { + next(); + return; + } + if (contentType) { + res.setHeader("content-type", contentType); + } + for (const [name, value] of Object.entries(headers)) { + if (value !== void 0 && value !== null && value !== "") { + res.setHeader(name, value); + } + } + res.setHeader("cache-control", "no-store"); + res.setHeader("content-length", String(stats.size)); + const stream = fs7.createReadStream(filePath); + res.on("close", () => { + if (!res.writableEnded) { + stream.destroy(); + } + }); + stream.on("error", () => { + if (!res.headersSent) { + next(); + } else { + res.destroy(); + } + }); + stream.pipe(res); + }); +} +function createCadViewerApiMiddleware({ + backend: backend2, + serverInfo = () => ({}), + enableStepArtifactBackend = false, + claimDisabledStepArtifactRoute = false, + preferFileDownloadRedirects = false, + onCatalogChanged = () => { + }, + onCatalogActivated = () => { + }, + rootDir +} = {}) { + if (!backend2) { + throw new Error("createCadViewerApiMiddleware requires backend"); + } + return async function cadViewerApiMiddleware(req, res, next) { + const requestUrl = new URL(req.url || "/", "http://localhost"); + const activeRootDir = requestRootDir(requestUrl) || rootDir || ""; + const activeFileRef = requestFileRef(requestUrl); + if (requestUrl.pathname === "/__cad/server") { + sendJson(res, 200, serverInfo({ rootDir: activeRootDir, fileRef: activeFileRef })); + return; + } + if (requestUrl.pathname === "/__cad/catalog") { + try { + const catalog = await backend2.readCatalog({ rootDir: activeRootDir, fileRef: activeFileRef }); + if (typeof backend2.resolveRequestRoot === "function" && (activeRootDir || activeFileRef)) { + onCatalogActivated( + backend2.resolveRequestRoot({ rootDir: activeRootDir, fileRef: activeFileRef }), + { rootDir: activeRootDir, fileRef: activeFileRef } + ); + } else if (activeRootDir && typeof backend2.resolveRoot === "function") { + onCatalogActivated(backend2.resolveRoot(activeRootDir), { rootDir: activeRootDir, fileRef: activeFileRef }); + } + sendJson(res, 200, catalog); + } catch (error) { + sendJson(res, 400, { + error: errorMessage(error) + }); + } + return; + } + if (requestUrl.pathname === "/__cad/generation-status") { + if (typeof backend2.readGenerationStatus !== "function") { + sendJson(res, 501, { + error: "Generation status is not available for this CAD Viewer backend" + }); + return; + } + try { + sendJson(res, 200, await backend2.readGenerationStatus({ rootDir: activeRootDir })); + } catch (error) { + sendJson(res, 400, { + error: errorMessage(error) + }); + } + return; + } + if (requestUrl.pathname === "/__cad/download") { + const method = String(req.method || "GET").toUpperCase(); + if (method !== "GET") { + res.setHeader("allow", "GET"); + sendJson(res, 405, { + error: "Use GET to download a file asset" + }); + return; + } + try { + const catalog = await backend2.readCatalog({ rootDir: activeRootDir, fileRef: activeFileRef }); + const request = fileAssetRequest(backend2, requestUrl, { rootDir: activeRootDir, catalog }); + if (preferFileDownloadRedirects && typeof backend2.resolveFileAssetAccess === "function") { + const access2 = await backend2.resolveFileAssetAccess(request); + if (access2?.url) { + res.statusCode = 302; + res.setHeader("location", access2.url); + res.setHeader("cache-control", "no-store"); + res.end(""); + return; + } + } + if (typeof backend2.readFileAsset === "function") { + const result = await backend2.readFileAsset(request); + sendBufferDownload(res, result); + return; + } + if (typeof backend2.resolveFileAssetAccess !== "function") { + sendJson(res, 501, { + error: "File downloads are not available for this CAD Viewer backend" + }); + return; + } + const access = await backend2.resolveFileAssetAccess(request); + if (access?.path) { + serveStaticFile(access.path, req, res, () => { + sendJson(res, 404, { + error: "File asset not found" + }); + }, { + contentType: access.contentType || backend2.contentTypeForPath?.(access.path) || "application/octet-stream", + headers: { + "content-disposition": attachmentContentDisposition(access.filename || access.file || access.path) + } + }); + return; + } + if (access?.url) { + res.statusCode = 302; + res.setHeader("location", access.url); + res.setHeader("cache-control", "no-store"); + res.end(""); + return; + } + sendJson(res, 404, { + error: "File asset not found" + }); + } catch (error) { + sendJson(res, 400, { + ok: false, + error: errorMessage(error) + }); + } + return; + } + if (requestUrl.pathname === "/__cad/asset") { + const method = String(req.method || "GET").toUpperCase(); + if (method !== "GET") { + res.setHeader("allow", "GET"); + sendJson(res, 405, { + error: "Use GET to read a CAD Viewer asset" + }); + return; + } + try { + if (typeof backend2.assetPathForFileRef !== "function") { + sendJson(res, 501, { + error: "Direct CAD Viewer assets are not available for this backend" + }); + return; + } + const assetPath = backend2.assetPathForFileRef(activeFileRef, { + rootDir: activeRootDir, + ...typeof backend2.resolveRequestRoot === "function" && (activeRootDir || activeFileRef) ? { resolvedRoot: backend2.resolveRequestRoot({ rootDir: activeRootDir, fileRef: activeFileRef }) } : {} + }); + if (!assetPath) { + sendJson(res, 404, { + error: "CAD Viewer asset not found" + }); + return; + } + serveStaticFile(assetPath, req, res, () => { + sendJson(res, 404, { + error: "CAD Viewer asset not found" + }); + }, { + contentType: backend2.contentTypeForPath?.(assetPath) || "application/octet-stream" + }); + } catch (error) { + if (Number(error?.statusCode) === 403) { + sendJson(res, 403, { + error: "Forbidden" + }); + return; + } + sendJson(res, 400, { + error: errorMessage(error) + }); + } + return; + } + if (requestUrl.pathname === "/__cad/reveal") { + const method = String(req.method || "GET").toUpperCase(); + if (method !== "POST") { + res.setHeader("allow", "POST"); + sendJson(res, 405, { + error: "Use POST to reveal a file asset" + }); + return; + } + try { + if (typeof backend2.openFileAsset !== "function") { + sendJson(res, 405, { + error: "Revealing files is only available for the local filesystem backend" + }); + return; + } + const catalog = await backend2.readCatalog({ rootDir: activeRootDir, fileRef: activeFileRef }); + const request = fileAssetRequest(backend2, requestUrl, { rootDir: activeRootDir, catalog }); + const result = await backend2.openFileAsset(request); + sendJson(res, 200, { + ok: true, + ...result + }); + } catch (error) { + sendJson(res, 400, { + ok: false, + error: errorMessage(error) + }); + } + return; + } + if (requestUrl.pathname === "/__cad/step-source-status") { + if (typeof backend2.readStepSourceStatus !== "function") { + sendJson(res, 501, { + error: "STEP source status is not available for this CAD Viewer backend" + }); + return; + } + try { + const catalog = await backend2.readCatalog({ rootDir: activeRootDir, fileRef: activeFileRef }); + const request = { + fileRef: activeFileRef, + rootDir: activeRootDir, + catalog + }; + if (typeof backend2.resolveRequestRoot === "function") { + request.resolvedRoot = backend2.resolveRequestRoot({ rootDir: activeRootDir, fileRef: activeFileRef }); + } else if (typeof backend2.resolveRoot === "function" && activeRootDir) { + request.resolvedRoot = backend2.resolveRoot(activeRootDir); + } + sendJson(res, 200, await backend2.readStepSourceStatus(request)); + } catch (error) { + sendJson(res, 400, { + error: errorMessage(error) + }); + } + return; + } + if (requestUrl.pathname === "/__cad/step-artifact") { + if (!enableStepArtifactBackend) { + if (claimDisabledStepArtifactRoute) { + sendJson(res, 501, { + error: "STEP artifact generation is not enabled for this CAD Viewer backend" + }); + return; + } + next(); + return; + } + if (req.method !== "POST") { + sendJson(res, 405, { + error: "Use POST to generate a STEP artifact" + }); + return; + } + try { + const catalog = await backend2.readCatalog({ rootDir: activeRootDir, fileRef: activeFileRef }); + if (typeof backend2.resolveRoot !== "function") { + const result2 = await backend2.generateStepArtifact({ + fileRef: activeFileRef, + force: requestUrl.searchParams.get("force") === "1", + rootDir: activeRootDir, + catalog + }); + const nextCatalog2 = result2?.catalog || (typeof backend2.refreshCatalog === "function" ? await backend2.refreshCatalog({ rootDir: activeRootDir, fileRef: activeFileRef }) : await backend2.readCatalog({ rootDir: activeRootDir, fileRef: activeFileRef })); + sendJson(res, result2?.ok ? 200 : 500, { + ok: Boolean(result2?.ok), + error: result2?.ok ? "" : String(result2?.error || "STEP artifact generation failed."), + result: result2?.result ?? result2, + entry: result2?.entry ?? null, + catalog: nextCatalog2 + }); + return; + } + const resolvedRoot = typeof backend2.resolveRequestRoot === "function" ? backend2.resolveRequestRoot({ rootDir: activeRootDir, fileRef: activeFileRef }) : backend2.resolveRoot(activeRootDir); + const result = await backend2.generateStepArtifact({ + fileRef: activeFileRef, + force: requestUrl.searchParams.get("force") === "1", + resolvedRoot, + catalog + }); + const nextCatalog = typeof backend2.refreshCatalog === "function" ? await backend2.refreshCatalog({ rootDir: activeRootDir, fileRef: activeFileRef }) : await backend2.readCatalog({ rootDir: activeRootDir, fileRef: activeFileRef }); + onCatalogChanged(resolvedRoot); + sendJson(res, result.ok ? 200 : 500, { + ok: result.ok, + error: result.error, + result: result.result, + entry: backend2.entryForSourcePath(nextCatalog, resolvedRoot, result.stepPath), + catalog: nextCatalog + }); + } catch (error) { + sendJson(res, 400, { + error: errorMessage(error) + }); + } + return; + } + next(); + }; +} +function createLocalAssetMiddleware({ backend: backend2, rootDir } = {}) { + if (!backend2) { + throw new Error("createLocalAssetMiddleware requires backend"); + } + return function localAssetMiddleware(req, res, next) { + const requestUrl = new URL(req.url || "/", "http://localhost"); + const fallbackFileRef = legacyCadAssetFileRef(requestUrl, req); + if (requestUrl.pathname !== "/__cad/asset" && !fallbackFileRef || typeof backend2.assetPathForFileRef !== "function") { + next(); + return; + } + let assetPath = null; + try { + const refererUrl = requestRefererUrl(req); + const activeRootDir = requestRootDir(requestUrl) || requestRootDir(refererUrl) || rootDir || ""; + const activeFileRef = requestFileRef(requestUrl) || fallbackFileRef; + assetPath = backend2.assetPathForFileRef(activeFileRef, { + rootDir: activeRootDir, + ...typeof backend2.resolveRequestRoot === "function" && (activeRootDir || activeFileRef) ? { resolvedRoot: backend2.resolveRequestRoot({ rootDir: activeRootDir, fileRef: activeFileRef }) } : {} + }); + } catch (error) { + if (Number(error?.statusCode) === 403) { + res.statusCode = 403; + res.end("Forbidden"); + return; + } + next(); + return; + } + if (!assetPath) { + next(); + return; + } + serveStaticFile(assetPath, req, res, next, { + contentType: backend2.contentTypeForPath?.(assetPath) || void 0 + }); + }; +} +function serveDistAsset({ distRoot: distRoot2, indexHtmlPath = path8.join(distRoot2, "index.html") } = {}) { + return function distAssetMiddleware(req, res, next) { + const requestUrl = new URL(req.url || "/", "http://localhost"); + const requestPath = requestUrl.pathname === "/" ? "/index.html" : requestUrl.pathname; + let filePath = ""; + try { + filePath = path8.resolve(distRoot2, decodeURIComponent(requestPath).replace(/^\/+/, "")); + } catch { + res.statusCode = 400; + res.end("Bad request"); + return; + } + if (!(filePath === distRoot2 || filePath.startsWith(`${distRoot2}${path8.sep}`))) { + res.statusCode = 403; + res.end("Forbidden"); + return; + } + const fileExists = fs7.existsSync(filePath); + const isStaticAssetRequest = requestPath.startsWith("/assets/") || path8.extname(requestPath); + if (!fileExists && isStaticAssetRequest) { + res.statusCode = 404; + res.setHeader("content-type", "text/plain; charset=utf-8"); + res.setHeader("cache-control", "no-store"); + res.end("Not found"); + return; + } + const fallbackPath = fileExists ? filePath : indexHtmlPath; + serveStaticFile(fallbackPath, req, res, next, { + contentType: contentTypeForStaticAsset(fallbackPath) || void 0 + }); + }; +} + +// viewer/src/server/vercelBlobAssetBackend.mjs +import crypto2 from "node:crypto"; +import fs8 from "node:fs"; +import os from "node:os"; +import path9 from "node:path"; +function normalizePrefix(value) { + const rawValue = String(value || "").trim(); + if (!rawValue) { + return ""; + } + try { + return new URL(rawValue).pathname.replace(/^\/+|\/+$/g, ""); + } catch { + return rawValue.replace(/^\/+|\/+$/g, ""); + } +} +function joinBlobPath(prefix, fileRef) { + const normalizedRef = normalizeFileRef(fileRef); + return [normalizePrefix(prefix), normalizedRef].filter(Boolean).join("/"); +} +function publicBlobUrlForRef(prefix, fileRef) { + const rawPrefix = String(prefix || "").trim(); + if (!rawPrefix) { + return ""; + } + try { + const url = new URL(rawPrefix); + const prefixPath = url.pathname.replace(/^\/+|\/+$/g, ""); + const normalizedRef = normalizeFileRef(fileRef); + if (!normalizedRef) { + return ""; + } + url.pathname = `/${[prefixPath, normalizedRef].filter(Boolean).join("/")}`; + url.search = ""; + url.hash = ""; + return url.toString(); + } catch { + return ""; + } +} +function normalizeFileRef(value) { + const normalized = path9.posix.normalize(String(value || "").trim().replace(/\\/g, "/").replace(/^\/+/, "")); + return normalized && normalized !== "." && !normalized.startsWith("../") ? normalized : ""; +} +function catalogEntryForFileRef2(catalog, fileRef) { + const normalized = normalizeFileRef(fileRef); + if (!normalized || !Array.isArray(catalog?.entries)) { + return null; + } + return catalog.entries.find((entry) => normalizeFileRef(entry?.file) === normalized) || null; +} +function normalizeString(value) { + return String(value || "").trim(); +} +function sourceUrlFromEntry(entry) { + return normalizeString(entry?.sourceUrl || entry?.source?.url); +} +function stepUrlFromEntry(entry) { + const explicitStepUrl = normalizeString(entry?.stepUrl || entry?.step?.url); + if (explicitStepUrl) { + return explicitStepUrl; + } + const sourceKind = String(entry?.sourceKind || entry?.stepSourceKind || "").trim().toLowerCase(); + return sourceKind === "python" ? "" : sourceUrlFromEntry(entry); +} +function outputUrlFromEntry(entry, fileRef) { + const extension = path9.posix.extname(normalizeFileRef(fileRef)).toLowerCase(); + if (extension === ".step" || extension === ".stp") { + return stepUrlFromEntry(entry); + } + return normalizeString(entry?.outputUrl || entry?.output?.url || entry?.url); +} +function sourceFileRefFromEntry(entry) { + return normalizeFileRef(entry?.sourceFile || entry?.source?.file || entry?.source?.path) || normalizeFileRef(filenameFromUrl(sourceUrlFromEntry(entry))); +} +function stepFileRefFromEntry(entry, fallback = "") { + return normalizeFileRef(entry?.stepFile || entry?.step?.file || entry?.step?.path) || normalizeFileRef(fallback); +} +function filenameFromUrl(url) { + try { + return path9.posix.basename(new URL(url).pathname); + } catch { + return ""; + } +} +function artifactFileRefFromEntry(entry) { + return normalizeFileRef(entry?.assetFile || entry?.asset?.file || entry?.artifactFile || entry?.artifact?.file) || normalizeFileRef(filenameFromUrl(entry?.url)); +} +function normalizedFileAssetKind2(value) { + const asset = String(value || "output").trim().toLowerCase(); + if (asset === "asset") { + return "artifact"; + } + if (asset === "output" || asset === "source" || asset === "artifact") { + return asset; + } + throw new Error(`Unsupported file asset: ${asset || "(missing)"}`); +} +function contentTypeForFileRef(fileRef, fallback = "") { + const extension = path9.posix.extname(normalizeFileRef(fileRef)).toLowerCase(); + if (fallback) { + return fallback; + } + if (extension === ".glb") { + return "model/gltf-binary"; + } + if (extension === ".stl") { + return "model/stl"; + } + if (extension === ".3mf") { + return "model/3mf"; + } + if (extension === ".step" || extension === ".stp") { + return "application/step"; + } + if (extension === ".dxf") { + return "application/dxf"; + } + if (extension === ".gcode") { + return "text/plain; charset=utf-8"; + } + if (extension === ".js" || extension === ".mjs") { + return "text/javascript; charset=utf-8"; + } + if (extension === ".json") { + return "application/json; charset=utf-8"; + } + if (extension === ".urdf" || extension === ".srdf" || extension === ".sdf") { + return "application/xml; charset=utf-8"; + } + return "application/octet-stream"; +} +function glbRefForStepEntry(entry, catalog, requestedFileRef) { + const sourceRef = normalizeFileRef(entry?.file || requestedFileRef); + if (!sourceRef) { + return ""; + } + return normalizeFileRef(path9.posix.join(path9.posix.dirname(sourceRef), `.${path9.posix.basename(sourceRef)}.glb`)); +} +function sha256Buffer(buffer) { + return crypto2.createHash("sha256").update(buffer).digest("hex"); +} +async function fetchBytes(url, { fetchImpl }) { + if (!fetchImpl) { + throw new Error("Vercel Blob backend requires fetch to download STEP sources"); + } + const response = await fetchImpl(url); + if (!response.ok) { + throw new Error(`Failed to download STEP source from Blob: ${response.status} ${response.statusText}`); + } + return Buffer.from(await response.arrayBuffer()); +} +function resolveInside(rootPath, fileRef) { + const normalized = normalizeFileRef(fileRef); + if (!normalized) { + throw new Error("Missing Blob file path"); + } + const resolved = path9.resolve(rootPath, normalized); + const relative = path9.relative(rootPath, resolved); + if (relative.startsWith("..") || path9.isAbsolute(relative)) { + throw new Error(`Blob file path must stay inside the temporary workspace: ${fileRef}`); + } + return resolved; +} +function updateCatalogEntry(catalog, previousEntry, nextEntry) { + return { + ...catalog, + entries: Array.isArray(catalog?.entries) ? catalog.entries.map((entry) => entry === previousEntry ? nextEntry : entry) : [] + }; +} +async function loadBlobClient(client) { + if (client) { + return client; + } + try { + return await Promise.resolve().then(() => (init_dist(), dist_exports)); + } catch (error) { + throw new Error( + `Vercel Blob backend requires @vercel/blob to be installed: ${error instanceof Error ? error.message : String(error)}` + ); + } +} +async function readJsonFromUrl(url, { fetchImpl = globalThis.fetch } = {}) { + if (!fetchImpl) { + throw new Error("Vercel Blob backend requires fetch to read catalog URLs"); + } + const response = await fetchImpl(url); + if (!response.ok) { + throw new Error(`Failed to read Vercel Blob catalog: ${response.status} ${response.statusText}`); + } + return response.json(); +} +async function readJsonFromBlobGetResult(result, pathname) { + if (!result) { + throw new Error(`Vercel Blob catalog not found: ${pathname}`); + } + if (!result.stream) { + throw new Error(`Vercel Blob catalog response had no body: ${pathname}`); + } + return new Response(result.stream).json(); +} +function hasBlobSdkReadCredentials(token) { + return Boolean( + normalizeString(token) || normalizeString(process.env.BLOB_READ_WRITE_TOKEN) || normalizeString(process.env.VERCEL_OIDC_TOKEN) && normalizeString(process.env.BLOB_STORE_ID) + ); +} +function createVercelBlobAssetBackend({ + prefix = "", + catalogPath = "catalog.json", + catalogUrl = "", + client = null, + fetchImpl = globalThis.fetch, + artifactCompiler = ensureStepTopologyArtifact, + stepArtifactGenerator = void 0, + token = process.env.VIEWER_VERCEL_BLOB_READ_WRITE_TOKEN || process.env.BLOB_READ_WRITE_TOKEN, + readOnly = false +} = {}) { + const normalizedPrefix = normalizePrefix(prefix); + const normalizedCatalogPath = joinBlobPath(normalizedPrefix, catalogPath || "catalog.json"); + const resolvedCatalogUrl = catalogUrl || publicBlobUrlForRef(prefix, catalogPath || "catalog.json"); + const canGenerateStepArtifacts = !readOnly && (stepArtifactGenerator === void 0 || typeof stepArtifactGenerator === "function"); + async function blobClient() { + return loadBlobClient(client); + } + async function readCatalog() { + if (resolvedCatalogUrl) { + return readJsonFromUrl(resolvedCatalogUrl, { fetchImpl }); + } + if (hasBlobSdkReadCredentials(token)) { + const blob2 = await blobClient(); + if (typeof blob2.get === "function") { + const getOptions = { access: "public" }; + if (token) { + getOptions.token = token; + } + return readJsonFromBlobGetResult( + await blob2.get(normalizedCatalogPath, getOptions), + normalizedCatalogPath + ); + } + } + const blob = await blobClient(); + const listing = await blob.list({ prefix: normalizedCatalogPath, token }); + const catalogBlob = Array.isArray(listing?.blobs) ? listing.blobs.find((entry) => entry.pathname === normalizedCatalogPath) || listing.blobs[0] : null; + if (!catalogBlob?.url) { + throw new Error(`Vercel Blob catalog not found: ${normalizedCatalogPath}`); + } + return readJsonFromUrl(catalogBlob.url, { fetchImpl }); + } + async function writeAsset({ fileRef, body, contentType = "application/octet-stream" } = {}) { + const pathname = joinBlobPath(normalizedPrefix, fileRef); + if (!pathname) { + throw new Error("Missing Vercel Blob asset path"); + } + const blob = await blobClient(); + return blob.put(pathname, body, { + access: "public", + addRandomSuffix: false, + allowOverwrite: true, + contentType, + token + }); + } + async function writeCatalog(catalog) { + return writeAsset({ + fileRef: catalogPath || "catalog.json", + body: JSON.stringify({ + schemaVersion: 4, + entries: Array.isArray(catalog?.entries) ? catalog.entries : [] + }, null, 2), + contentType: "application/json; charset=utf-8" + }); + } + async function refreshCatalog() { + return readCatalog(); + } + async function urlForBlobRef(fileRef) { + const pathname = joinBlobPath(normalizedPrefix, fileRef); + if (!pathname) { + return ""; + } + const blob = await blobClient(); + const listing = await blob.list({ prefix: pathname, token }); + const match = Array.isArray(listing?.blobs) ? listing.blobs.find((entry) => entry.pathname === pathname) : null; + return match?.url || ""; + } + async function resolveFileAssetAccess({ fileRef, asset = "output", catalog = null } = {}) { + const assetKind = normalizedFileAssetKind2(asset); + const requestedFileRef = normalizeFileRef(fileRef); + if (assetKind === "source") { + throw new Error( + `Source code is not available in Vercel Blob deployments for ${requestedFileRef || "(missing)"}` + ); + } + const currentCatalog = catalog || await readCatalog(); + const entry = catalogEntryForFileRef2(currentCatalog, requestedFileRef); + if (!entry) { + throw new Error(`CAD catalog entry not found: ${requestedFileRef || "(missing)"}`); + } + const outputRef = normalizeFileRef(entry.file || requestedFileRef); + const outputExtension = path9.posix.extname(outputRef).toLowerCase(); + const explicitSourceUrl = sourceUrlFromEntry(entry); + const explicitSourceRef = sourceFileRefFromEntry(entry); + const explicitStepUrl = stepUrlFromEntry(entry); + const explicitStepRef = stepFileRefFromEntry(entry, outputRef); + const explicitArtifactUrl = normalizeString(entry?.url); + const explicitArtifactRef = artifactFileRefFromEntry(entry); + const fileRefForAsset = assetKind === "source" ? explicitSourceRef : assetKind === "artifact" ? explicitArtifactRef : outputExtension === ".step" || outputExtension === ".stp" ? explicitStepRef : outputRef; + const fallbackUrl = assetKind === "source" ? explicitSourceUrl : assetKind === "artifact" ? explicitArtifactUrl : outputUrlFromEntry(entry, fileRefForAsset || outputRef || requestedFileRef); + const blobUrl = fallbackUrl || !fileRefForAsset ? "" : await urlForBlobRef(fileRefForAsset); + const url = fallbackUrl || blobUrl; + if (!fileRefForAsset || !url) { + throw new Error( + assetKind === "source" ? `Source code is not available in Vercel Blob for ${requestedFileRef || "(missing)"}` : assetKind === "artifact" ? `Artifact file is not available in Vercel Blob for ${requestedFileRef || "(missing)"}` : `Output file is not available in Vercel Blob for ${requestedFileRef || "(missing)"}` + ); + } + return { + asset: assetKind, + file: fileRefForAsset, + url, + filename: path9.posix.basename(fileRefForAsset) || filenameFromUrl(url), + contentType: contentTypeForFileRef(fileRefForAsset) + }; + } + async function readFileAsset(request = {}) { + if (!fetchImpl) { + throw new Error("Vercel Blob backend requires fetch to download file assets"); + } + const access = await resolveFileAssetAccess(request); + const response = await fetchImpl(access.url); + if (!response.ok) { + throw new Error(`Failed to download file asset from Blob: ${response.status} ${response.statusText}`); + } + const contentType = response.headers?.get?.("content-type") || access.contentType; + return { + ...access, + body: Buffer.from(await response.arrayBuffer()), + contentType: contentTypeForFileRef(access.file, contentType) + }; + } + async function resolveSourceFileAccess(request = {}) { + return resolveFileAssetAccess({ ...request, asset: "source" }); + } + async function readSourceFile(request = {}) { + return readFileAsset({ ...request, asset: "source" }); + } + async function readStepSourceStatus2({ fileRef, catalog = null } = {}) { + const requestedFileRef = normalizeFileRef(fileRef); + const currentCatalog = catalog || await readCatalog(); + const entry = catalogEntryForFileRef2(currentCatalog, requestedFileRef); + if (!entry) { + throw new Error(`STEP catalog entry not found: ${requestedFileRef || "(missing)"}`); + } + const repoStepRef = stepFileRefFromEntry(entry, entry.file || requestedFileRef); + const sourceUrl = stepUrlFromEntry(entry) || (readOnly ? "" : await urlForBlobRef(repoStepRef)); + return { + ok: Boolean(sourceUrl), + file: repoStepRef, + stepPath: repoStepRef, + sourceKind: "step", + step: sourceUrl ? { + ok: true, + status: "current", + missing: false, + stale: false + } : { + ok: false, + status: "missing", + missing: true, + stale: false, + message: "STEP file is missing." + } + }; + } + async function generateStepArtifactFromBlob({ fileRef, force = false, catalog = null } = {}) { + const requestedFileRef = normalizeFileRef(fileRef); + const currentCatalog = catalog || await readCatalog(); + const entry = catalogEntryForFileRef2(currentCatalog, requestedFileRef); + if (!entry) { + throw new Error(`STEP catalog entry not found: ${requestedFileRef || "(missing)"}`); + } + const repoStepRef = normalizeFileRef(entry.file || requestedFileRef); + const sourceUrl = await urlForBlobRef(repoStepRef); + if (!sourceUrl) { + throw new Error(`STEP source is not available in Vercel Blob for ${requestedFileRef}`); + } + const repoSourceRef = repoStepRef; + const glbRef = glbRefForStepEntry(entry, currentCatalog, requestedFileRef); + if (!repoStepRef || !repoSourceRef || !glbRef) { + throw new Error(`STEP catalog entry is missing source or GLB artifact paths: ${requestedFileRef}`); + } + const tempRoot = fs8.mkdtempSync(path9.join(os.tmpdir(), "cad-viewer-blob-step-")); + try { + const stepPath = resolveInside(tempRoot, repoStepRef); + const sourcePath = ""; + const downloadedSourcePath = stepPath; + fs8.mkdirSync(path9.dirname(downloadedSourcePath), { recursive: true }); + fs8.writeFileSync(downloadedSourcePath, await fetchBytes(sourceUrl, { fetchImpl })); + const result = await artifactCompiler({ + repoRoot: tempRoot, + stepPath, + force + }); + const generatedGlbPath = inlineStepGlbArtifactPathForSource(stepPath); + if (!result?.ok || !fs8.existsSync(generatedGlbPath)) { + return { + ok: false, + error: result?.error || result?.validation?.error?.message || "STEP artifact generation failed.", + result, + entry, + catalog: currentCatalog + }; + } + const body = fs8.readFileSync(generatedGlbPath); + const hash = sha256Buffer(body); + const upload = await writeAsset({ + fileRef: glbRef, + body, + contentType: "model/gltf-binary" + }); + const glbAsset = { + url: upload.url, + hash, + bytes: body.length + }; + const nextEntry = { + file: repoStepRef, + kind: ["part", "assembly"].includes(String(result?.entryKind || "").trim().toLowerCase()) ? String(result.entryKind).trim().toLowerCase() : String(entry.kind || "part").trim().toLowerCase(), + ...glbAsset + }; + const nextCatalog = updateCatalogEntry(currentCatalog, entry, nextEntry); + await writeCatalog(nextCatalog); + return { + ok: true, + error: "", + result: { + ...result, + upload + }, + entry: nextEntry, + catalog: nextCatalog + }; + } finally { + fs8.rmSync(tempRoot, { recursive: true, force: true }); + } + } + async function generateStepArtifact(request = {}) { + if (stepArtifactGenerator === null) { + throw new Error( + "Vercel Blob backend does not run local CAD generation. Provide stepArtifactGenerator to delegate generation to a CAD-capable worker, then upload generated assets with writeAsset()." + ); + } + if (typeof stepArtifactGenerator === "function") { + return stepArtifactGenerator({ + ...request, + writeAsset, + writeCatalog + }); + } + return generateStepArtifactFromBlob({ + ...request, + writeAsset, + writeCatalog + }); + } + const backend2 = { + kind: "vercel-blob", + readOnly: Boolean(readOnly), + canGenerateStepArtifacts, + prefix: normalizedPrefix, + catalogPath: normalizedCatalogPath, + readCatalog, + readStepSourceStatus: readStepSourceStatus2, + resolveFileAssetAccess, + readFileAsset, + resolveSourceFileAccess, + readSourceFile, + refreshCatalog, + urlForBlobRef + }; + if (!readOnly) { + return { + ...backend2, + writeAsset, + writeCatalog, + generateStepArtifact + }; + } + return backend2; +} + +// viewer/src/server/viewerEnv.mjs +var VIEWER_ASSET_BACKENDS = Object.freeze({ + LOCAL_FS: "local-fs", + VERCEL_BLOB: "vercel-blob" +}); +var DEPRECATED_LOCAL_ROOT_ENV_VARS = Object.freeze([ + "VIEWER_LOCAL_ROOT_DIR", + "VIEWER_LOCAL_WORKSPACE_ROOT" +]); +var VALID_VIEWER_ASSET_BACKENDS = new Set(Object.values(VIEWER_ASSET_BACKENDS)); +function envValue(env, name, fallback = "") { + return String(env?.[name] ?? fallback).trim(); +} +function normalizeViewerAssetBackend(value, fallback = VIEWER_ASSET_BACKENDS.LOCAL_FS) { + const normalized = String(value || fallback || "").trim().toLowerCase(); + if (VALID_VIEWER_ASSET_BACKENDS.has(normalized)) { + return normalized; + } + throw new Error( + `Unsupported VIEWER_ASSET_BACKEND: ${normalized || "(missing)"}. Expected one of: ${[...VALID_VIEWER_ASSET_BACKENDS].join(", ")}.` + ); +} +function assertNoDeprecatedLocalRootEnv(env = process.env) { + const configured = DEPRECATED_LOCAL_ROOT_ENV_VARS.filter((name) => String(env?.[name] || "").trim()); + if (configured.length) { + throw new Error( + `${configured.join(", ")} ${configured.length === 1 ? "is" : "are"} no longer supported. Pass an absolute ?dir= path in the Viewer URL instead.` + ); + } +} +function vercelBlobCatalogUrlFromPrefix(prefix, catalogPath = "catalog.json") { + const rawPrefix = envValue({ prefix }, "prefix"); + if (!rawPrefix) { + return ""; + } + const normalizedCatalogPath = String(catalogPath || "catalog.json").trim().replace(/^\/+/, ""); + if (!normalizedCatalogPath) { + return ""; + } + try { + const url = new URL(rawPrefix); + const pathname = url.pathname.replace(/^\/+|\/+$/g, ""); + url.pathname = `/${[pathname, normalizedCatalogPath].filter(Boolean).join("/")}`; + url.search = ""; + url.hash = ""; + return url.toString(); + } catch { + return ""; + } +} +function normalizeVercelBlobStoreId(value) { + const normalized = String(value || "").trim().replace(/^store_/i, ""); + return /^[a-z0-9]+$/i.test(normalized) ? normalized.toLowerCase() : ""; +} +function vercelBlobStoreIdFromToken(value) { + const token = String(value || "").trim(); + const parts = token.split("_"); + if (parts[0] !== "vercel" || parts[1] !== "blob") { + return ""; + } + const tokenKindLength = parts[2] === "read" && parts[3] === "write" ? 2 : 1; + return normalizeVercelBlobStoreId(parts[2 + tokenKindLength]); +} +function vercelBlobStoreIdFromEnv(env = process.env) { + return normalizeVercelBlobStoreId(envValue(env, "VIEWER_VERCEL_BLOB_STORE_ID")) || normalizeVercelBlobStoreId(envValue(env, "BLOB_STORE_ID")) || vercelBlobStoreIdFromToken(envValue(env, "VIEWER_VERCEL_BLOB_READ_WRITE_TOKEN")) || vercelBlobStoreIdFromToken(envValue(env, "BLOB_READ_WRITE_TOKEN")); +} +function vercelBlobPrefixFromEnv(env = process.env) { + const prefix = envValue(env, "VIEWER_VERCEL_BLOB_PREFIX"); + const storeId = vercelBlobStoreIdFromEnv(env); + if (!prefix || !storeId) { + return prefix; + } + try { + const url = new URL(prefix); + const hostname = url.hostname.toLowerCase(); + if (hostname.endsWith(".public.blob.vercel-storage.com") || hostname === "blob.vercel-storage.com") { + url.hostname = `${storeId}.public.blob.vercel-storage.com`; + return url.toString(); + } + } catch { + const pathname = prefix.replace(/^\/+|\/+$/g, ""); + return `https://${storeId}.public.blob.vercel-storage.com${pathname ? `/${pathname}` : ""}`; + } + return prefix; +} +function vercelBlobConfigFromEnv(env = process.env) { + const prefix = vercelBlobPrefixFromEnv(env); + const catalogPath = envValue(env, "VIEWER_VERCEL_BLOB_CATALOG_PATH", "catalog.json") || "catalog.json"; + return { + prefix, + catalogPath, + catalogUrl: vercelBlobCatalogUrlFromPrefix(prefix, catalogPath), + token: envValue(env, "VIEWER_VERCEL_BLOB_READ_WRITE_TOKEN") || envValue(env, "BLOB_READ_WRITE_TOKEN") || void 0 + }; +} + +// viewer/src/server/vercelApi.mjs +function vercelUrlFromHost(value) { + const rawValue = String(value || "").trim(); + if (!rawValue) { + return ""; + } + try { + const url = new URL(rawValue.includes("://") ? rawValue : `https://${rawValue}`); + const pathname = url.pathname.replace(/\/+$/g, ""); + return `${url.protocol}//${url.host}${pathname === "/" ? "" : pathname}`; + } catch { + return ""; + } +} +function hostedViewerPublicUrlFromEnv(env = process.env) { + const candidates = [ + "VERCEL_PROJECT_PRODUCTION_URL", + "VERCEL_URL", + "VERCEL_BRANCH_URL" + ]; + for (const name of candidates) { + const url = vercelUrlFromHost(envValue(env, name)); + if (url) { + return url; + } + } + return ""; +} +function buildHostedViewerServerInfo({ + backend: backend2, + env = process.env, + rootDir = "" +} = {}) { + return { + schemaVersion: 1, + app: "cad-viewer", + backend: backend2?.kind || "vercel-blob", + rootDir, + catalogPath: backend2?.catalogPath || vercelBlobConfigFromEnv(env).catalogPath, + stepArtifactGenerationAvailable: false, + url: hostedViewerPublicUrlFromEnv(env) + }; +} + +// viewer/packages/cadjs/src/lib/viewerServerInfo.mjs +import path10 from "node:path"; +var VIEWER_SERVER_INFO_SCHEMA_VERSION = 1; +var VIEWER_SERVER_API_VERSION = 2; +var VIEWER_SERVER_APP_ID = "cad-viewer"; +var DEFAULT_VIEWER_HOST = "127.0.0.1"; +var DEFAULT_VIEWER_PORT = 4178; +function normalizeViewerPort(value, fallback = DEFAULT_VIEWER_PORT) { + const parsed = Number.parseInt(String(value ?? ""), 10); + if (Number.isInteger(parsed) && parsed > 0 && parsed <= 65535) { + return parsed; + } + return fallback; +} +function buildViewerServerInfo({ + workspaceRoot: workspaceRoot2, + rootDir = DEFAULT_VIEWER_ROOT_DIR, + port: port2 = DEFAULT_VIEWER_PORT, + pid = process.pid, + host: host2 = DEFAULT_VIEWER_HOST, + backend: backend2 = "local-fs", + dynamicRoot = false, + stepArtifactGenerationAvailable = true, + viewerVersion: viewerVersion2 = "", + serverFeatures = [] +} = {}) { + if (!workspaceRoot2) { + throw new Error("workspaceRoot is required"); + } + const resolvedWorkspaceRoot = path10.resolve(workspaceRoot2); + const rawRootDir = String(rootDir || "").trim(); + const resolvedViewerRoot = rawRootDir ? path10.isAbsolute(rawRootDir) ? { + dir: path10.resolve(rawRootDir), + rootPath: path10.resolve(rawRootDir), + rootName: path10.basename(path10.resolve(rawRootDir)) + } : resolveViewerRoot(resolvedWorkspaceRoot, normalizeViewerRootDir(rawRootDir)) : { + dir: DEFAULT_VIEWER_ROOT_DIR, + rootPath: "", + rootName: "" + }; + const normalizedPort = normalizeViewerPort(port2); + return { + schemaVersion: VIEWER_SERVER_INFO_SCHEMA_VERSION, + serverApiVersion: VIEWER_SERVER_API_VERSION, + app: VIEWER_SERVER_APP_ID, + viewerVersion: String(viewerVersion2 || ""), + serverFeatures: Array.isArray(serverFeatures) ? serverFeatures.map((feature) => String(feature || "").trim()).filter(Boolean) : [], + backend: backend2, + dynamicRoot: Boolean(dynamicRoot), + workspaceRoot: resolvedWorkspaceRoot, + rootDir: resolvedViewerRoot.dir, + rootPath: resolvedViewerRoot.rootPath, + rootName: resolvedViewerRoot.rootName, + port: normalizedPort, + pid: Number.isInteger(pid) ? pid : process.pid, + stepArtifactGenerationAvailable: stepArtifactGenerationAvailable !== false, + url: `http://${host2}:${normalizedPort}` + }; +} + +// viewer/packages/cadjs/src/lib/viewerConfig.mjs +var DEFAULT_VIEWER_GITHUB_URL = "https://github.com/earthtojake/text-to-cad"; +function normalizeViewerDefaultFile(value = "") { + const rawValue = String(value ?? "").trim(); + return rawValue.replace(/\\/g, "/").replace(/^\/+/, "").replace(/\/+$/, ""); +} +function normalizeViewerGithubUrl(value = "", fallback = DEFAULT_VIEWER_GITHUB_URL) { + return normalizeViewerGithubUrlCandidate(value) || normalizeViewerGithubUrlCandidate(fallback); +} +function normalizeViewerGithubUrlCandidate(value = "") { + const rawValue = String(value ?? "").trim(); + if (!rawValue) { + return ""; + } + const urlValue = /^[a-z][a-z\d+.-]*:\/\//i.test(rawValue) ? rawValue : `https://${rawValue.replace(/^\/+/, "")}`; + try { + const url = new URL(urlValue); + return ["http:", "https:"].includes(url.protocol) ? url.href : ""; + } catch { + return ""; + } +} + +// viewer/src/server/serverLifetime.mjs +var MAX_SERVER_LIFETIME_MS = 2147483647; +function parseServerLifetimeMs(value, flag = "--shutdown-after") { + const rawValue = String(value ?? "").trim().toLowerCase(); + const match = /^(\d+(?:\.\d+)?)(ms|s|m|h)?$/.exec(rawValue); + if (!match) { + throw new Error(`${flag} must be a positive duration such as 30m, 2h, or 43200000.`); + } + const amount = Number.parseFloat(match[1]); + const unit = match[2] || "ms"; + const multiplier = { + ms: 1, + s: 1e3, + m: 60 * 1e3, + h: 60 * 60 * 1e3 + }[unit]; + const parsed = Math.round(amount * multiplier); + if (!Number.isFinite(parsed) || parsed <= 0 || parsed > MAX_SERVER_LIFETIME_MS) { + throw new Error(`${flag} must be between 1ms and ${MAX_SERVER_LIFETIME_MS}ms.`); + } + return parsed; +} +function normalizeServerLifetimeMs(value, defaultMs = null) { + const rawValue = String(value ?? "").trim(); + if (!rawValue) { + return defaultMs; + } + const parsed = Number.parseInt(rawValue, 10); + if (!Number.isInteger(parsed) || parsed <= 0 || parsed > MAX_SERVER_LIFETIME_MS) { + return defaultMs; + } + return parsed; +} +function formatServerLifetime(ms) { + if (ms % (60 * 60 * 1e3) === 0) { + return `${ms / (60 * 60 * 1e3)}h`; + } + if (ms % (60 * 1e3) === 0) { + return `${ms / (60 * 1e3)}m`; + } + if (ms % 1e3 === 0) { + return `${ms / 1e3}s`; + } + return `${ms}ms`; +} +function closeHttpServer(server2) { + return new Promise((resolve, reject) => { + server2.close((error) => { + if (error) { + reject(error); + return; + } + resolve(); + }); + }); +} +function scheduleProcessShutdown({ + lifetimeMs, + label = "CAD Viewer server", + close = async () => { + } +} = {}) { + const normalizedLifetimeMs = normalizeServerLifetimeMs(lifetimeMs); + if (normalizedLifetimeMs === null) { + return null; + } + const timer = setTimeout(() => { + console.log(`${label} reached ${formatServerLifetime(normalizedLifetimeMs)} lifetime; shutting down.`); + const forceExit = setTimeout(() => process.exit(0), 5e3); + forceExit.unref?.(); + Promise.resolve().then(() => close()).then( + () => process.exit(0), + (error) => { + console.error(`${label} shutdown failed: ${error instanceof Error ? error.message : String(error)}`); + process.exit(1); + } + ); + }, normalizedLifetimeMs); + timer.unref?.(); + return timer; +} + +// viewer/src/server/serverArgs.mjs +function requiredValue(argv, index, flag) { + const value = argv[index + 1]; + if (!value || value.startsWith("--")) { + throw new Error(`${flag} requires a value`); + } + return value; +} +function parsePort(value, flag) { + const parsed = Number.parseInt(String(value ?? ""), 10); + if (!Number.isInteger(parsed) || parsed <= 0 || parsed > 65535) { + throw new Error(`${flag} must be a TCP port from 1 to 65535`); + } + return parsed; +} +function parseServerArgs(argv = []) { + const options = { + port: null, + host: "", + shutdownAfterMs: null, + help: false + }; + for (let index = 0; index < argv.length; index += 1) { + const arg = argv[index]; + if (arg === "--help" || arg === "-h") { + options.help = true; + continue; + } + if (arg.startsWith("--root-dir=")) { + throw new Error("--root-dir has been removed; pass an absolute ?dir= path in the Viewer URL."); + } + if (arg === "--root-dir") { + throw new Error("--root-dir has been removed; pass an absolute ?dir= path in the Viewer URL."); + } + if (arg.startsWith("--port=")) { + options.port = parsePort(arg.slice("--port=".length), "--port"); + continue; + } + if (arg === "--port") { + options.port = parsePort(requiredValue(argv, index, arg), arg); + index += 1; + continue; + } + if (arg.startsWith("--host=")) { + options.host = arg.slice("--host=".length).trim(); + continue; + } + if (arg === "--host") { + options.host = requiredValue(argv, index, arg).trim(); + index += 1; + continue; + } + if (arg.startsWith("--shutdown-after=")) { + options.shutdownAfterMs = parseServerLifetimeMs(arg.slice("--shutdown-after=".length), "--shutdown-after"); + continue; + } + if (arg === "--shutdown-after") { + options.shutdownAfterMs = parseServerLifetimeMs(requiredValue(argv, index, arg), arg); + index += 1; + continue; + } + throw new Error(`Unknown argument: ${arg}`); + } + return options; +} +function serverHelpText() { + return `Usage: node backend/server.mjs [options] + +Options: + --port Port to bind. Defaults to 4178. + --host Host to bind. Defaults to 127.0.0.1. + --shutdown-after